refactor: build registry

This commit is contained in:
zernonia 2024-11-21 15:23:29 +08:00
parent ac14ca835a
commit aec80c9342
567 changed files with 3828 additions and 3728 deletions

View File

@ -0,0 +1 @@
// The content of this directory is autogenerated by the registry server.

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,6 @@ import type {
} from '../src/registry/schema'
// @sts-nocheck
import { existsSync, promises as fs } from 'node:fs'
import { tmpdir } from 'node:os'
import path from 'node:path'
import { template } from 'lodash-es'
import { rimraf } from 'rimraf'
@ -21,7 +20,6 @@ import {
registryEntrySchema,
registrySchema,
} from '../src/registry/schema'
import { fixImport } from './fix-import'
const REGISTRY_PATH = path.join(process.cwd(), 'src/public/r')
@ -38,10 +36,10 @@ const REGISTRY_INDEX_WHITELIST: z.infer<typeof registryItemTypeSchema>[] = [
// compilerOptions: {},
// })
async function createTempSourceFile(filename: string) {
const dir = await fs.mkdtemp(path.join(tmpdir(), 'shadcn-'))
return path.join(dir, filename)
}
// async function createTempSourceFile(filename: string) {
// const dir = await fs.mkdtemp(path.join(tmpdir(), 'shadcn-'))
// return path.join(dir, filename)
// }
// ----------------------------------------------------------------------------
// Build __registry__/index.ts.
@ -70,206 +68,207 @@ export const Index: Record<string, any> = {
}
const type = item.type.split(':')[1]
let sourceFilename = ''
const sourceFilename = ''
// const chunks: any = []
if (item.type === 'registry:block') {
const file = resolveFiles[0]
console.log(item, file)
let raw: string
try {
const filename = path.basename(file)
raw = await fs.readFile(file, 'utf8')
}
catch (error) {
continue
}
// const tempFile = await createTempSourceFile(filename)
// const sourceFile = project.createSourceFile(tempFile, raw, {
// scriptKind: ScriptKind.TS,
// })
// if (item.type === 'registry:block') {
// const file = resolveFiles[0]
// let raw: string
// try {
// if (file) {
// const filename = path.basename(file)
// }
// raw = await fs.readFile(file, 'utf8')
// }
// catch (error) {
// continue
// }
// // const tempFile = await createTempSourceFile(filename)
// // const sourceFile = project.createSourceFile(tempFile, raw, {
// // scriptKind: ScriptKind.TS,
// // })
// const description = sourceFile
// .getVariableDeclaration('description')
// ?.getInitializerOrThrow()
// .asKindOrThrow(SyntaxKind.StringLiteral)
// .getLiteralValue()
// // const description = sourceFile
// // .getVariableDeclaration('description')
// // ?.getInitializerOrThrow()
// // .asKindOrThrow(SyntaxKind.StringLiteral)
// // .getLiteralValue()
// item.description = description ?? ''
// // item.description = description ?? ''
// // Find all imports.
// const imports = new Map<
// string,
// {
// module: string
// text: string
// isDefault?: boolean
// }
// >()
// sourceFile.getImportDeclarations().forEach((node) => {
// const module = node.getModuleSpecifier().getLiteralValue()
// node.getNamedImports().forEach((item) => {
// imports.set(item.getText(), {
// module,
// text: node.getText(),
// })
// })
// // // Find all imports.
// // const imports = new Map<
// // string,
// // {
// // module: string
// // text: string
// // isDefault?: boolean
// // }
// // >()
// // sourceFile.getImportDeclarations().forEach((node) => {
// // const module = node.getModuleSpecifier().getLiteralValue()
// // node.getNamedImports().forEach((item) => {
// // imports.set(item.getText(), {
// // module,
// // text: node.getText(),
// // })
// // })
// const defaultImport = node.getDefaultImport()
// if (defaultImport) {
// imports.set(defaultImport.getText(), {
// module,
// text: defaultImport.getText(),
// isDefault: true,
// })
// }
// })
// // const defaultImport = node.getDefaultImport()
// // if (defaultImport) {
// // imports.set(defaultImport.getText(), {
// // module,
// // text: defaultImport.getText(),
// // isDefault: true,
// // })
// // }
// // })
// Find all opening tags with x-chunk attribute.
// const components = sourceFile
// .getDescendantsOfKind(SyntaxKind.JsxOpeningElement)
// .filter((node) => {
// return node.getAttribute('x-chunk') !== undefined
// })
// // Find all opening tags with x-chunk attribute.
// // const components = sourceFile
// // .getDescendantsOfKind(SyntaxKind.JsxOpeningElement)
// // .filter((node) => {
// // return node.getAttribute('x-chunk') !== undefined
// // })
// chunks = await Promise.all(
// components.map(async (component, index) => {
// const chunkName = `${item.name}-chunk-${index}`
// // chunks = await Promise.all(
// // components.map(async (component, index) => {
// // const chunkName = `${item.name}-chunk-${index}`
// // Get the value of x-chunk attribute.
// const attr = component
// .getAttributeOrThrow('x-chunk')
// .asKindOrThrow(SyntaxKind.JsxAttribute)
// // // Get the value of x-chunk attribute.
// // const attr = component
// // .getAttributeOrThrow('x-chunk')
// // .asKindOrThrow(SyntaxKind.JsxAttribute)
// const description = attr
// .getInitializerOrThrow()
// .asKindOrThrow(SyntaxKind.StringLiteral)
// .getLiteralValue()
// // const description = attr
// // .getInitializerOrThrow()
// // .asKindOrThrow(SyntaxKind.StringLiteral)
// // .getLiteralValue()
// // Delete the x-chunk attribute.
// attr.remove()
// // // Delete the x-chunk attribute.
// // attr.remove()
// // Add a new attribute to the component.
// component.addAttribute({
// name: 'x-chunk',
// initializer: `"${chunkName}"`,
// })
// // // Add a new attribute to the component.
// // component.addAttribute({
// // name: 'x-chunk',
// // initializer: `"${chunkName}"`,
// // })
// // Get the value of x-chunk-container attribute.
// const containerAttr = component
// .getAttribute('x-chunk-container')
// ?.asKindOrThrow(SyntaxKind.JsxAttribute)
// // // Get the value of x-chunk-container attribute.
// // const containerAttr = component
// // .getAttribute('x-chunk-container')
// // ?.asKindOrThrow(SyntaxKind.JsxAttribute)
// const containerClassName = containerAttr
// ?.getInitializer()
// ?.asKindOrThrow(SyntaxKind.StringLiteral)
// .getLiteralValue()
// // const containerClassName = containerAttr
// // ?.getInitializer()
// // ?.asKindOrThrow(SyntaxKind.StringLiteral)
// // .getLiteralValue()
// containerAttr?.remove()
// // containerAttr?.remove()
// const parentJsxElement = component.getParentIfKindOrThrow(
// SyntaxKind.JsxElement,
// )
// // const parentJsxElement = component.getParentIfKindOrThrow(
// // SyntaxKind.JsxElement,
// // )
// // Find all opening tags on component.
// const children = parentJsxElement
// .getDescendantsOfKind(SyntaxKind.JsxOpeningElement)
// .map((node) => {
// return node.getTagNameNode().getText()
// })
// .concat(
// parentJsxElement
// .getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement)
// .map((node) => {
// return node.getTagNameNode().getText()
// }),
// )
// // // Find all opening tags on component.
// // const children = parentJsxElement
// // .getDescendantsOfKind(SyntaxKind.JsxOpeningElement)
// // .map((node) => {
// // return node.getTagNameNode().getText()
// // })
// // .concat(
// // parentJsxElement
// // .getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement)
// // .map((node) => {
// // return node.getTagNameNode().getText()
// // }),
// // )
// const componentImports = new Map<
// string,
// string | string[] | Set<string>
// >()
// children.forEach((child) => {
// const importLine = imports.get(child)
// if (importLine) {
// const imports = componentImports.get(importLine.module) || []
// // const componentImports = new Map<
// // string,
// // string | string[] | Set<string>
// // >()
// // children.forEach((child) => {
// // const importLine = imports.get(child)
// // if (importLine) {
// // const imports = componentImports.get(importLine.module) || []
// const newImports = importLine.isDefault
// ? importLine.text
// : new Set([...imports, child])
// // const newImports = importLine.isDefault
// // ? importLine.text
// // : new Set([...imports, child])
// componentImports.set(
// importLine.module,
// importLine?.isDefault ? newImports : Array.from(newImports),
// )
// }
// })
// // componentImports.set(
// // importLine.module,
// // importLine?.isDefault ? newImports : Array.from(newImports),
// // )
// // }
// // })
// const componnetImportLines = Array.from(
// componentImports.keys(),
// ).map((key) => {
// const values = componentImports.get(key)
// const specifier = Array.isArray(values)
// ? `{${values.join(',')}}`
// : values
// // const componnetImportLines = Array.from(
// // componentImports.keys(),
// // ).map((key) => {
// // const values = componentImports.get(key)
// // const specifier = Array.isArray(values)
// // ? `{${values.join(',')}}`
// // : values
// return `import ${specifier} from "${key}"`
// })
// // return `import ${specifier} from "${key}"`
// // })
// const code = `
// 'use client'
// // const code = `
// // 'use client'
// ${componnetImportLines.join('\n')}
// // ${componnetImportLines.join('\n')}
// export default function Component() {
// return (${parentJsxElement.getText()})
// }`
// // export default function Component() {
// // return (${parentJsxElement.getText()})
// // }`
// const targetFile = file.replace(item.name, `${chunkName}`)
// const targetFilePath = path.join(
// cwd(),
// `registry/${style.name}/${type}/${chunkName}.ts`,
// )
// // const targetFile = file.replace(item.name, `${chunkName}`)
// // const targetFilePath = path.join(
// // cwd(),
// // `registry/${style.name}/${type}/${chunkName}.ts`,
// // )
// // Write component file.
// rimraf.sync(targetFilePath)
// await fs.writeFile(targetFilePath, code, 'utf8')
// // // Write component file.
// // rimraf.sync(targetFilePath)
// // await fs.writeFile(targetFilePath, code, 'utf8')
// return {
// name: chunkName,
// description,
// component: `React.lazy(() => import("@/registry/${style.name}/${type}/${chunkName}")),`,
// file: targetFile,
// container: {
// className: containerClassName,
// },
// }
// }),
// )
// // return {
// // name: chunkName,
// // description,
// // component: `React.lazy(() => import("@/registry/${style.name}/${type}/${chunkName}")),`,
// // file: targetFile,
// // container: {
// // className: containerClassName,
// // },
// // }
// // }),
// // )
// // Write the source file for blocks only.
sourceFilename = `__registry__/${style.name}/${type}/${item.name}.ts`
// // // Write the source file for blocks only.
// sourceFilename = `__registry__/${style.name}/${type}/${item.name}.ts`
if (item.files) {
const files = item.files.map(file =>
typeof file === 'string'
? { type: 'registry:page', path: file }
: file,
)
if (files?.length) {
sourceFilename = `__registry__/${style.name}/${files[0].path}`
}
}
// if (item.files) {
// const files = item.files.map(file =>
// typeof file === 'string'
// ? { type: 'registry:page', path: file }
// : file,
// )
// if (files?.length) {
// sourceFilename = `__registry__/${style.name}/${files[0].path}`
// }
// }
const sourcePath = path.join(process.cwd(), sourceFilename)
if (!existsSync(sourcePath)) {
await fs.mkdir(sourcePath, { recursive: true })
}
// const sourcePath = path.join(process.cwd(), sourceFilename)
// if (!existsSync(sourcePath)) {
// await fs.mkdir(sourcePath, { recursive: true })
// }
rimraf.sync(sourcePath)
// await fs.writeFile(sourcePath, sourceFile.getText())
await fs.writeFile(sourcePath, raw)
}
// rimraf.sync(sourcePath)
// // await fs.writeFile(sourcePath, sourceFile.getText())
// await fs.writeFile(sourcePath, raw)
// }
let componentPath = `@/registry/${style.name}/${type}/${item.name}`
@ -340,14 +339,7 @@ export const Index: Record<string, any> = {
return {
...item,
files: item.files?.map((_file) => {
const file
= typeof _file === 'string'
? {
path: _file,
type: item.type,
}
: _file
const file = { path: _file.path, type: item.type }
return file
}),
}
@ -386,27 +378,19 @@ async function buildStyles(registry: Registry) {
if (item.files) {
files = await Promise.all(
item.files.map(async (_file) => {
const file
= typeof _file === 'string'
? {
path: _file,
type: item.type,
content: '',
target: '',
}
: _file
const file = {
path: _file.path,
type: _file.type,
content: '',
target: _file.target ?? '',
}
let content: string
try {
content = await fs.readFile(
path.join(process.cwd(), 'registry', style.name, file.path),
path.join(process.cwd(), 'src', 'registry', style.name, file.path),
'utf8',
)
// Only fix imports for v0- blocks.
if (item.name.startsWith('v0-')) {
content = fixImport(content)
}
}
catch (error) {
return
@ -422,30 +406,30 @@ async function buildStyles(registry: Registry) {
// sourceFile.getVariableDeclaration('containerClassName')?.remove()
// sourceFile.getVariableDeclaration('description')?.remove()
let target = file.target || ''
const target = file.target || ''
if ((!target || target === '') && item.name.startsWith('v0-')) {
const fileName = file.path.split('/').pop()
if (
file.type === 'registry:block'
|| file.type === 'registry:component'
|| file.type === 'registry:example'
) {
target = `components/${fileName}`
}
// if ((!target || target === '') && item.name.startsWith('v0-')) {
// const fileName = file.path.split('/').pop()
// if (
// file.type === 'registry:block'
// || file.type === 'registry:component'
// || file.type === 'registry:example'
// ) {
// target = `components/${fileName}`
// }
if (file.type === 'registry:ui') {
target = `components/ui/${fileName}`
}
// if (file.type === 'registry:ui') {
// target = `components/ui/${fileName}`
// }
if (file.type === 'registry:hook') {
target = `hooks/${fileName}`
}
// if (file.type === 'registry:hook') {
// target = `hooks/${fileName}`
// }
if (file.type === 'registry:lib') {
target = `lib/${fileName}`
}
}
// if (file.type === 'registry:lib') {
// target = `lib/${fileName}`
// }
// }
return {
path: file.path,
@ -458,6 +442,9 @@ async function buildStyles(registry: Registry) {
)
}
// if (item.type === 'registry:block' && item.name === 'Sidebar01')
// console.log(item.name, item.files?.[0], files?.[0])
const payload = registryEntrySchema
.omit({
// source: true,
@ -473,7 +460,7 @@ async function buildStyles(registry: Registry) {
if (payload.success) {
await fs.writeFile(
path.join(targetPath, `${item.name}.json`),
JSON.stringify(payload.data, null, 2),
`${JSON.stringify(payload.data, null, 2)}\r\n`,
'utf8',
)
}
@ -501,10 +488,10 @@ async function buildStylesIndex() {
const dependencies = [
'tailwindcss-animate',
'class-variance-authority',
'lucide-react',
'lucide-vue-next',
]
// TODO: Remove this when we migrate to lucide-react.
// TODO: Remove this when we migrate to lucide-vue-next.
// if (style.name === "new-york") {
// dependencies.push("@radix-ui/react-icons")
// }
@ -575,7 +562,7 @@ async function buildThemes() {
await fs.writeFile(
path.join(colorsTargetPath, 'index.json'),
JSON.stringify(colorsData, null, 2),
`${JSON.stringify(colorsData, null, 2)}\r\n`,
'utf8',
)
@ -697,7 +684,7 @@ async function buildThemes() {
await fs.writeFile(
path.join(REGISTRY_PATH, `colors/${baseColor}.json`),
JSON.stringify(base, null, 2),
`${JSON.stringify(base, null, 2)}\r\n`,
'utf8',
)

View File

@ -99,4 +99,4 @@
},
"inlineColorsTemplate": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n ",
"cssVarsTemplate": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n :root {\n --background: 0 0% 100%;\n --foreground: 224 71.4% 4.1%;\n --card: 0 0% 100%;\n --card-foreground: 224 71.4% 4.1%;\n --popover: 0 0% 100%;\n --popover-foreground: 224 71.4% 4.1%;\n --primary: 220.9 39.3% 11%;\n --primary-foreground: 210 20% 98%;\n --secondary: 220 14.3% 95.9%;\n --secondary-foreground: 220.9 39.3% 11%;\n --muted: 220 14.3% 95.9%;\n --muted-foreground: 220 8.9% 46.1%;\n --accent: 220 14.3% 95.9%;\n --accent-foreground: 220.9 39.3% 11%;\n --destructive: 0 84.2% 60.2%;\n --destructive-foreground: 210 20% 98%;\n --border: 220 13% 91%;\n --input: 220 13% 91%;\n --ring: 224 71.4% 4.1%;\n --radius: 0.5rem;\n --chart-1: 12 76% 61%;\n --chart-2: 173 58% 39%;\n --chart-3: 197 37% 24%;\n --chart-4: 43 74% 66%;\n --chart-5: 27 87% 67%;\n }\n\n .dark {\n --background: 224 71.4% 4.1%;\n --foreground: 210 20% 98%;\n --card: 224 71.4% 4.1%;\n --card-foreground: 210 20% 98%;\n --popover: 224 71.4% 4.1%;\n --popover-foreground: 210 20% 98%;\n --primary: 210 20% 98%;\n --primary-foreground: 220.9 39.3% 11%;\n --secondary: 215 27.9% 16.9%;\n --secondary-foreground: 210 20% 98%;\n --muted: 215 27.9% 16.9%;\n --muted-foreground: 217.9 10.6% 64.9%;\n --accent: 215 27.9% 16.9%;\n --accent-foreground: 210 20% 98%;\n --destructive: 0 62.8% 30.6%;\n --destructive-foreground: 210 20% 98%;\n --border: 215 27.9% 16.9%;\n --input: 215 27.9% 16.9%;\n --ring: 216 12.2% 83.9%;\n --chart-1: 220 70% 50%;\n --chart-2: 160 60% 45%;\n --chart-3: 30 80% 55%;\n --chart-4: 280 65% 60%;\n --chart-5: 340 75% 55%;\n }\n}\n\n@layer base {\n * {\n @apply border-border;\n }\n body {\n @apply bg-background text-foreground;\n }\n}"
}
}

View File

@ -1996,4 +1996,4 @@
"hslChannel": "343.1 87.7% 15.9%"
}
]
}
}

View File

@ -99,4 +99,4 @@
},
"inlineColorsTemplate": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n ",
"cssVarsTemplate": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n :root {\n --background: 0 0% 100%;\n --foreground: 0 0% 3.9%;\n --card: 0 0% 100%;\n --card-foreground: 0 0% 3.9%;\n --popover: 0 0% 100%;\n --popover-foreground: 0 0% 3.9%;\n --primary: 0 0% 9%;\n --primary-foreground: 0 0% 98%;\n --secondary: 0 0% 96.1%;\n --secondary-foreground: 0 0% 9%;\n --muted: 0 0% 96.1%;\n --muted-foreground: 0 0% 45.1%;\n --accent: 0 0% 96.1%;\n --accent-foreground: 0 0% 9%;\n --destructive: 0 84.2% 60.2%;\n --destructive-foreground: 0 0% 98%;\n --border: 0 0% 89.8%;\n --input: 0 0% 89.8%;\n --ring: 0 0% 3.9%;\n --radius: 0.5rem;\n --chart-1: 12 76% 61%;\n --chart-2: 173 58% 39%;\n --chart-3: 197 37% 24%;\n --chart-4: 43 74% 66%;\n --chart-5: 27 87% 67%;\n }\n\n .dark {\n --background: 0 0% 3.9%;\n --foreground: 0 0% 98%;\n --card: 0 0% 3.9%;\n --card-foreground: 0 0% 98%;\n --popover: 0 0% 3.9%;\n --popover-foreground: 0 0% 98%;\n --primary: 0 0% 98%;\n --primary-foreground: 0 0% 9%;\n --secondary: 0 0% 14.9%;\n --secondary-foreground: 0 0% 98%;\n --muted: 0 0% 14.9%;\n --muted-foreground: 0 0% 63.9%;\n --accent: 0 0% 14.9%;\n --accent-foreground: 0 0% 98%;\n --destructive: 0 62.8% 30.6%;\n --destructive-foreground: 0 0% 98%;\n --border: 0 0% 14.9%;\n --input: 0 0% 14.9%;\n --ring: 0 0% 83.1%;\n --chart-1: 220 70% 50%;\n --chart-2: 160 60% 45%;\n --chart-3: 30 80% 55%;\n --chart-4: 280 65% 60%;\n --chart-5: 340 75% 55%;\n }\n}\n\n@layer base {\n * {\n @apply border-border;\n }\n body {\n @apply bg-background text-foreground;\n }\n}"
}
}

View File

@ -99,4 +99,4 @@
},
"inlineColorsTemplate": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n ",
"cssVarsTemplate": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n :root {\n --background: 0 0% 100%;\n --foreground: 222.2 84% 4.9%;\n --card: 0 0% 100%;\n --card-foreground: 222.2 84% 4.9%;\n --popover: 0 0% 100%;\n --popover-foreground: 222.2 84% 4.9%;\n --primary: 222.2 47.4% 11.2%;\n --primary-foreground: 210 40% 98%;\n --secondary: 210 40% 96.1%;\n --secondary-foreground: 222.2 47.4% 11.2%;\n --muted: 210 40% 96.1%;\n --muted-foreground: 215.4 16.3% 46.9%;\n --accent: 210 40% 96.1%;\n --accent-foreground: 222.2 47.4% 11.2%;\n --destructive: 0 84.2% 60.2%;\n --destructive-foreground: 210 40% 98%;\n --border: 214.3 31.8% 91.4%;\n --input: 214.3 31.8% 91.4%;\n --ring: 222.2 84% 4.9%;\n --radius: 0.5rem;\n --chart-1: 12 76% 61%;\n --chart-2: 173 58% 39%;\n --chart-3: 197 37% 24%;\n --chart-4: 43 74% 66%;\n --chart-5: 27 87% 67%;\n }\n\n .dark {\n --background: 222.2 84% 4.9%;\n --foreground: 210 40% 98%;\n --card: 222.2 84% 4.9%;\n --card-foreground: 210 40% 98%;\n --popover: 222.2 84% 4.9%;\n --popover-foreground: 210 40% 98%;\n --primary: 210 40% 98%;\n --primary-foreground: 222.2 47.4% 11.2%;\n --secondary: 217.2 32.6% 17.5%;\n --secondary-foreground: 210 40% 98%;\n --muted: 217.2 32.6% 17.5%;\n --muted-foreground: 215 20.2% 65.1%;\n --accent: 217.2 32.6% 17.5%;\n --accent-foreground: 210 40% 98%;\n --destructive: 0 62.8% 30.6%;\n --destructive-foreground: 210 40% 98%;\n --border: 217.2 32.6% 17.5%;\n --input: 217.2 32.6% 17.5%;\n --ring: 212.7 26.8% 83.9%;\n --chart-1: 220 70% 50%;\n --chart-2: 160 60% 45%;\n --chart-3: 30 80% 55%;\n --chart-4: 280 65% 60%;\n --chart-5: 340 75% 55%;\n }\n}\n\n@layer base {\n * {\n @apply border-border;\n }\n body {\n @apply bg-background text-foreground;\n }\n}"
}
}

View File

@ -99,4 +99,4 @@
},
"inlineColorsTemplate": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n ",
"cssVarsTemplate": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n :root {\n --background: 0 0% 100%;\n --foreground: 20 14.3% 4.1%;\n --card: 0 0% 100%;\n --card-foreground: 20 14.3% 4.1%;\n --popover: 0 0% 100%;\n --popover-foreground: 20 14.3% 4.1%;\n --primary: 24 9.8% 10%;\n --primary-foreground: 60 9.1% 97.8%;\n --secondary: 60 4.8% 95.9%;\n --secondary-foreground: 24 9.8% 10%;\n --muted: 60 4.8% 95.9%;\n --muted-foreground: 25 5.3% 44.7%;\n --accent: 60 4.8% 95.9%;\n --accent-foreground: 24 9.8% 10%;\n --destructive: 0 84.2% 60.2%;\n --destructive-foreground: 60 9.1% 97.8%;\n --border: 20 5.9% 90%;\n --input: 20 5.9% 90%;\n --ring: 20 14.3% 4.1%;\n --radius: 0.5rem;\n --chart-1: 12 76% 61%;\n --chart-2: 173 58% 39%;\n --chart-3: 197 37% 24%;\n --chart-4: 43 74% 66%;\n --chart-5: 27 87% 67%;\n }\n\n .dark {\n --background: 20 14.3% 4.1%;\n --foreground: 60 9.1% 97.8%;\n --card: 20 14.3% 4.1%;\n --card-foreground: 60 9.1% 97.8%;\n --popover: 20 14.3% 4.1%;\n --popover-foreground: 60 9.1% 97.8%;\n --primary: 60 9.1% 97.8%;\n --primary-foreground: 24 9.8% 10%;\n --secondary: 12 6.5% 15.1%;\n --secondary-foreground: 60 9.1% 97.8%;\n --muted: 12 6.5% 15.1%;\n --muted-foreground: 24 5.4% 63.9%;\n --accent: 12 6.5% 15.1%;\n --accent-foreground: 60 9.1% 97.8%;\n --destructive: 0 62.8% 30.6%;\n --destructive-foreground: 60 9.1% 97.8%;\n --border: 12 6.5% 15.1%;\n --input: 12 6.5% 15.1%;\n --ring: 24 5.7% 82.9%;\n --chart-1: 220 70% 50%;\n --chart-2: 160 60% 45%;\n --chart-3: 30 80% 55%;\n --chart-4: 280 65% 60%;\n --chart-5: 340 75% 55%;\n }\n}\n\n@layer base {\n * {\n @apply border-border;\n }\n body {\n @apply bg-background text-foreground;\n }\n}"
}
}

View File

@ -99,4 +99,4 @@
},
"inlineColorsTemplate": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n ",
"cssVarsTemplate": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n :root {\n --background: 0 0% 100%;\n --foreground: 240 10% 3.9%;\n --card: 0 0% 100%;\n --card-foreground: 240 10% 3.9%;\n --popover: 0 0% 100%;\n --popover-foreground: 240 10% 3.9%;\n --primary: 240 5.9% 10%;\n --primary-foreground: 0 0% 98%;\n --secondary: 240 4.8% 95.9%;\n --secondary-foreground: 240 5.9% 10%;\n --muted: 240 4.8% 95.9%;\n --muted-foreground: 240 3.8% 46.1%;\n --accent: 240 4.8% 95.9%;\n --accent-foreground: 240 5.9% 10%;\n --destructive: 0 84.2% 60.2%;\n --destructive-foreground: 0 0% 98%;\n --border: 240 5.9% 90%;\n --input: 240 5.9% 90%;\n --ring: 240 10% 3.9%;\n --radius: 0.5rem;\n --chart-1: 12 76% 61%;\n --chart-2: 173 58% 39%;\n --chart-3: 197 37% 24%;\n --chart-4: 43 74% 66%;\n --chart-5: 27 87% 67%;\n }\n\n .dark {\n --background: 240 10% 3.9%;\n --foreground: 0 0% 98%;\n --card: 240 10% 3.9%;\n --card-foreground: 0 0% 98%;\n --popover: 240 10% 3.9%;\n --popover-foreground: 0 0% 98%;\n --primary: 0 0% 98%;\n --primary-foreground: 240 5.9% 10%;\n --secondary: 240 3.7% 15.9%;\n --secondary-foreground: 0 0% 98%;\n --muted: 240 3.7% 15.9%;\n --muted-foreground: 240 5% 64.9%;\n --accent: 240 3.7% 15.9%;\n --accent-foreground: 0 0% 98%;\n --destructive: 0 62.8% 30.6%;\n --destructive-foreground: 0 0% 98%;\n --border: 240 3.7% 15.9%;\n --input: 240 3.7% 15.9%;\n --ring: 240 4.9% 83.9%;\n --chart-1: 220 70% 50%;\n --chart-2: 160 60% 45%;\n --chart-3: 30 80% 55%;\n --chart-4: 280 65% 60%;\n --chart-5: 340 75% 55%;\n }\n}\n\n@layer base {\n * {\n @apply border-border;\n }\n body {\n @apply bg-background text-foreground;\n }\n}"
}
}

View File

@ -1,150 +0,0 @@
{
"AlertCircle": {
"lucide": "AlertCircle",
"radix": "ExclamationTriangleIcon"
},
"ArrowLeft": {
"lucide": "ArrowLeft",
"radix": "ArrowLeftIcon"
},
"ArrowRight": {
"lucide": "ArrowRight",
"radix": "ArrowRightIcon"
},
"ArrowUpDown": {
"lucide": "ArrowUpDown",
"radix": "CaretSortIcon"
},
"BellRing": {
"lucide": "BellRing",
"radix": "BellIcon"
},
"Bold": {
"lucide": "Bold",
"radix": "FontBoldIcon"
},
"Calculator": {
"lucide": "Calculator",
"radix": "ComponentPlaceholderIcon"
},
"Calendar": {
"lucide": "Calendar",
"radix": "CalendarIcon"
},
"Check": {
"lucide": "Check",
"radix": "CheckIcon"
},
"ChevronDown": {
"lucide": "ChevronDown",
"radix": "ChevronDownIcon"
},
"ChevronLeft": {
"lucide": "ChevronLeft",
"radix": "ChevronLeftIcon"
},
"ChevronRight": {
"lucide": "ChevronRight",
"radix": "ChevronRightIcon"
},
"ChevronUp": {
"lucide": "ChevronUp",
"radix": "ChevronUpIcon"
},
"ChevronsUpDown": {
"lucide": "ChevronsUpDown",
"radix": "CaretSortIcon"
},
"Circle": {
"lucide": "Circle",
"radix": "DotFilledIcon"
},
"Copy": {
"lucide": "Copy",
"radix": "CopyIcon"
},
"CreditCard": {
"lucide": "CreditCard",
"radix": "ComponentPlaceholderIcon"
},
"GripVertical": {
"lucide": "GripVertical",
"radix": "DragHandleDots2Icon"
},
"Italic": {
"lucide": "Italic",
"radix": "FontItalicIcon"
},
"Loader2": {
"lucide": "Loader2",
"radix": "ReloadIcon"
},
"Mail": {
"lucide": "Mail",
"radix": "EnvelopeClosedIcon"
},
"MailOpen": {
"lucide": "MailOpen",
"radix": "EnvelopeOpenIcon"
},
"Minus": {
"lucide": "Minus",
"radix": "MinusIcon"
},
"Moon": {
"lucide": "Moon",
"radix": "MoonIcon"
},
"MoreHorizontal": {
"lucide": "MoreHorizontal",
"radix": "DotsHorizontalIcon"
},
"PanelLeft": {
"lucide": "PanelLeft",
"radix": "ViewVerticalIcon"
},
"Plus": {
"lucide": "Plus",
"radix": "PlusIcon"
},
"Search": {
"lucide": "Search",
"radix": "MagnifyingGlassIcon"
},
"Send": {
"lucide": "Send",
"radix": "PaperPlaneIcon"
},
"Settings": {
"lucide": "Settings",
"radix": "GearIcon"
},
"Slash": {
"lucide": "Slash",
"radix": "SlashIcon"
},
"Smile": {
"lucide": "Smile",
"radix": "FaceIcon"
},
"Sun": {
"lucide": "Sun",
"radix": "SunIcon"
},
"Terminal": {
"lucide": "Terminal",
"radix": "RocketIcon"
},
"Underline": {
"lucide": "Underline",
"radix": "UnderlineIcon"
},
"User": {
"lucide": "User",
"radix": "PersonIcon"
},
"X": {
"lucide": "X",
"radix": "Cross2Icon"
}
}

File diff suppressed because one or more lines are too long

View File

@ -13,4 +13,4 @@
"target": "AccordionDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "AlertDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "AlertDestructiveDemo.vue"
}
]
}
}

View File

@ -14,4 +14,4 @@
"target": "AlertDialogDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "AreaChartCustomTooltip.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "AreaChartDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "AreaChartSparkline.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "AspectRatioDemo.vue"
}
]
}
}

View File

@ -2,6 +2,18 @@
"name": "Authentication01",
"type": "registry:block",
"dependencies": [],
"registryDependencies": [],
"files": []
}
"registryDependencies": [
"button",
"card",
"input",
"label"
],
"files": [
{
"path": "block/Authentication01.vue",
"content": "<script lang=\"ts\">\nexport const description\n = 'A simple login form with email and password. The submit button says \\'Sign in\\'.'\nexport const iframeHeight = '600px'\nexport const containerClass = 'w-full h-screen flex items-center justify-center px-4'\n</script>\n\n<script setup lang=\"ts\">\nimport { Button } from '@/registry/default/ui/button'\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/registry/default/ui/card'\nimport { Input } from '@/registry/default/ui/input'\nimport { Label } from '@/registry/default/ui/label'\n</script>\n\n<template>\n <Card class=\"w-full max-w-sm\">\n <CardHeader>\n <CardTitle class=\"text-2xl\">\n Login\n </CardTitle>\n <CardDescription>\n Enter your email below to login to your account.\n </CardDescription>\n </CardHeader>\n <CardContent class=\"grid gap-4\">\n <div class=\"grid gap-2\">\n <Label for=\"email\">Email</Label>\n <Input id=\"email\" type=\"email\" placeholder=\"m@example.com\" required />\n </div>\n <div class=\"grid gap-2\">\n <Label for=\"password\">Password</Label>\n <Input id=\"password\" type=\"password\" required />\n </div>\n </CardContent>\n <CardFooter>\n <Button class=\"w-full\">\n Sign in\n </Button>\n </CardFooter>\n </Card>\n</template>\n",
"type": "registry:block",
"target": "Authentication01.vue"
}
]
}

View File

@ -2,6 +2,18 @@
"name": "Authentication02",
"type": "registry:block",
"dependencies": [],
"registryDependencies": [],
"files": []
}
"registryDependencies": [
"button",
"card",
"input",
"label"
],
"files": [
{
"path": "block/Authentication02.vue",
"content": "<script lang=\"ts\">\nexport const description\n = 'A login form with email and password. There\\'s an option to login with Google and a link to sign up if you don\\'t have an account.'\nexport const iframeHeight = '600px'\nexport const containerClass = 'w-full h-screen flex items-center justify-center px-4'\n</script>\n\n<script setup lang=\"ts\">\nimport { Button } from '@/registry/default/ui/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/registry/default/ui/card'\nimport { Input } from '@/registry/default/ui/input'\nimport { Label } from '@/registry/default/ui/label'\n</script>\n\n<template>\n <Card class=\"mx-auto max-w-sm\">\n <CardHeader>\n <CardTitle class=\"text-2xl\">\n Login\n </CardTitle>\n <CardDescription>\n Enter your email below to login to your account\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div class=\"grid gap-4\">\n <div class=\"grid gap-2\">\n <Label for=\"email\">Email</Label>\n <Input\n id=\"email\"\n type=\"email\"\n placeholder=\"m@example.com\"\n required\n />\n </div>\n <div class=\"grid gap-2\">\n <div class=\"flex items-center\">\n <Label for=\"password\">Password</Label>\n <a href=\"#\" class=\"ml-auto inline-block text-sm underline\">\n Forgot your password?\n </a>\n </div>\n <Input id=\"password\" type=\"password\" required />\n </div>\n <Button type=\"submit\" class=\"w-full\">\n Login\n </Button>\n <Button variant=\"outline\" class=\"w-full\">\n Login with Google\n </Button>\n </div>\n <div class=\"mt-4 text-center text-sm\">\n Don't have an account?\n <a href=\"#\" class=\"underline\">\n Sign up\n </a>\n </div>\n </CardContent>\n </Card>\n</template>\n",
"type": "registry:block",
"target": "Authentication02.vue"
}
]
}

View File

@ -2,6 +2,18 @@
"name": "Authentication03",
"type": "registry:block",
"dependencies": [],
"registryDependencies": [],
"files": []
}
"registryDependencies": [
"button",
"card",
"input",
"label"
],
"files": [
{
"path": "block/Authentication03.vue",
"content": "<script lang=\"ts\">\nexport const description\n = 'A sign up form with first name, last name, email and password inside a card. There\\'s an option to sign up with GitHub and a link to login if you already have an account'\nexport const iframeHeight = '600px'\nexport const containerClass = 'w-full h-screen flex items-center justify-center px-4'\n</script>\n\n<script setup lang=\"ts\">\nimport { Button } from '@/registry/default/ui/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/registry/default/ui/card'\nimport { Input } from '@/registry/default/ui/input'\nimport { Label } from '@/registry/default/ui/label'\n</script>\n\n<template>\n <Card class=\"mx-auto max-w-sm\">\n <CardHeader>\n <CardTitle class=\"text-xl\">\n Sign Up\n </CardTitle>\n <CardDescription>\n Enter your information to create an account\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div class=\"grid gap-4\">\n <div class=\"grid grid-cols-2 gap-4\">\n <div class=\"grid gap-2\">\n <Label for=\"first-name\">First name</Label>\n <Input id=\"first-name\" placeholder=\"Max\" required />\n </div>\n <div class=\"grid gap-2\">\n <Label for=\"last-name\">Last name</Label>\n <Input id=\"last-name\" placeholder=\"Robinson\" required />\n </div>\n </div>\n <div class=\"grid gap-2\">\n <Label for=\"email\">Email</Label>\n <Input\n id=\"email\"\n type=\"email\"\n placeholder=\"m@example.com\"\n required\n />\n </div>\n <div class=\"grid gap-2\">\n <Label for=\"password\">Password</Label>\n <Input id=\"password\" type=\"password\" />\n </div>\n <Button type=\"submit\" class=\"w-full\">\n Create an account\n </Button>\n <Button variant=\"outline\" class=\"w-full\">\n Sign up with GitHub\n </Button>\n </div>\n <div class=\"mt-4 text-center text-sm\">\n Already have an account?\n <a href=\"#\" class=\"underline\">\n Sign in\n </a>\n </div>\n </CardContent>\n </Card>\n</template>\n",
"type": "registry:block",
"target": "Authentication03.vue"
}
]
}

View File

@ -2,6 +2,17 @@
"name": "Authentication04",
"type": "registry:block",
"dependencies": [],
"registryDependencies": [],
"files": []
}
"registryDependencies": [
"button",
"input",
"label"
],
"files": [
{
"path": "block/Authentication04.vue",
"content": "<script lang=\"ts\">\nexport const description\n = 'A login page with two columns. The first column has the login form with email and password. There\\'s a Forgot your passwork link and a link to sign up if you do not have an account. The second column has a cover image.'\nexport const iframeHeight = '800px'\nexport const containerClass = 'w-full h-full p-4 lg:p-0'\n</script>\n\n<script setup lang=\"ts\">\nimport { Button } from '@/registry/default/ui/button'\nimport { Input } from '@/registry/default/ui/input'\nimport { Label } from '@/registry/default/ui/label'\n</script>\n\n<template>\n <div class=\"w-full lg:grid lg:min-h-[600px] lg:grid-cols-2 xl:min-h-[800px]\">\n <div class=\"flex items-center justify-center py-12\">\n <div class=\"mx-auto grid w-[350px] gap-6\">\n <div class=\"grid gap-2 text-center\">\n <h1 class=\"text-3xl font-bold\">\n Login\n </h1>\n <p class=\"text-balance text-muted-foreground\">\n Enter your email below to login to your account\n </p>\n </div>\n <div class=\"grid gap-4\">\n <div class=\"grid gap-2\">\n <Label for=\"email\">Email</Label>\n <Input\n id=\"email\"\n type=\"email\"\n placeholder=\"m@example.com\"\n required\n />\n </div>\n <div class=\"grid gap-2\">\n <div class=\"flex items-center\">\n <Label for=\"password\">Password</Label>\n <a\n href=\"/forgot-password\"\n class=\"ml-auto inline-block text-sm underline\"\n >\n Forgot your password?\n </a>\n </div>\n <Input id=\"password\" type=\"password\" required />\n </div>\n <Button type=\"submit\" class=\"w-full\">\n Login\n </Button>\n <Button variant=\"outline\" class=\"w-full\">\n Login with Google\n </Button>\n </div>\n <div class=\"mt-4 text-center text-sm\">\n Don't have an account?\n <a href=\"#\" class=\"underline\">\n Sign up\n </a>\n </div>\n </div>\n </div>\n <div class=\"hidden bg-muted lg:block\">\n <img\n src=\"/placeholder.svg\"\n alt=\"Image\"\n width=\"1920\"\n height=\"1080\"\n class=\"h-full w-full object-cover dark:brightness-[0.2] dark:grayscale\"\n >\n </div>\n </div>\n</template>\n",
"type": "registry:block",
"target": "Authentication04.vue"
}
]
}

View File

@ -15,4 +15,4 @@
"target": "AutoFormApi.vue"
}
]
}
}

View File

@ -15,4 +15,4 @@
"target": "AutoFormArray.vue"
}
]
}
}

View File

@ -15,4 +15,4 @@
"target": "AutoFormBasic.vue"
}
]
}
}

View File

@ -15,4 +15,4 @@
"target": "AutoFormConfirmPassword.vue"
}
]
}
}

View File

@ -19,4 +19,4 @@
"target": "AutoFormControlled.vue"
}
]
}
}

View File

@ -15,4 +15,4 @@
"target": "AutoFormDependencies.vue"
}
]
}
}

View File

@ -15,4 +15,4 @@
"target": "AutoFormInputWithoutLabel.vue"
}
]
}
}

View File

@ -15,4 +15,4 @@
"target": "AutoFormSubObject.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "AvatarDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "BadgeDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "BadgeDestructiveDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "BadgeOutlineDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "BadgeSecondaryDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "BarChartCustomTooltip.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "BarChartDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "BarChartRounded.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "BarChartStacked.vue"
}
]
}
}

View File

@ -14,4 +14,4 @@
"target": "BreadcrumbDemo.vue"
}
]
}
}

View File

@ -14,4 +14,4 @@
"target": "BreadcrumbDropdown.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "BreadcrumbEllipsisDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "BreadcrumbLinkDemo.vue"
}
]
}
}

View File

@ -18,4 +18,4 @@
"target": "BreadcrumbResponsive.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "BreadcrumbSeparatorDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "ButtonAsChildDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "ButtonDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "ButtonDestructiveDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "ButtonGhostDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "ButtonIconDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "ButtonLinkDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "ButtonLoadingDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "ButtonOutlineDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "ButtonSecondaryDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "ButtonWithIconDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "CalendarDemo.vue"
}
]
}
}

View File

@ -7,19 +7,19 @@
"zod"
],
"registryDependencies": [
"utils",
"button",
"calendar",
"form",
"popover",
"toast",
"utils"
"toast"
],
"files": [
{
"path": "example/CalendarForm.vue",
"content": "<script setup lang=\"ts\">\nimport { Button } from '@/registry/default/ui/button'\nimport { Calendar } from '@/registry/default/ui/calendar'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/registry/default/ui/form'\nimport { Popover, PopoverContent, PopoverTrigger } from '@/registry/default/ui/popover'\nimport { toast } from '@/registry/default/ui/toast'\nimport { cn } from '@/lib/utils'\nimport { CalendarDate, DateFormatter, getLocalTimeZone, parseDate, today } from '@internationalized/date'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport { Calendar as CalendarIcon } from 'lucide-vue-next'\nimport { toDate } from 'reka-ui/date'\nimport { useForm } from 'vee-validate'\nimport { computed, h, ref } from 'vue'\nimport { z } from 'zod'\n\nconst df = new DateFormatter('en-US', {\n dateStyle: 'long',\n})\n\nconst formSchema = toTypedSchema(z.object({\n dob: z\n .string()\n .refine(v => v, { message: 'A date of birth is required.' }),\n}))\n\nconst placeholder = ref()\n\nconst { handleSubmit, setFieldValue, values } = useForm({\n validationSchema: formSchema,\n})\n\nconst value = computed({\n get: () => values.dob ? parseDate(values.dob) : undefined,\n set: val => val,\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"space-y-8\" @submit=\"onSubmit\">\n <FormField name=\"dob\">\n <FormItem class=\"flex flex-col\">\n <FormLabel>Date of birth</FormLabel>\n <Popover>\n <PopoverTrigger as-child>\n <FormControl>\n <Button\n variant=\"outline\" :class=\"cn(\n 'w-[240px] ps-3 text-start font-normal',\n !value && 'text-muted-foreground',\n )\"\n >\n <span>{{ value ? df.format(toDate(value)) : \"Pick a date\" }}</span>\n <CalendarIcon class=\"ms-auto h-4 w-4 opacity-50\" />\n </Button>\n <input hidden>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent class=\"w-auto p-0\">\n <Calendar\n v-model:placeholder=\"placeholder\"\n v-model=\"value\"\n calendar-label=\"Date of birth\"\n initial-focus\n :min-value=\"new CalendarDate(1900, 1, 1)\"\n :max-value=\"today(getLocalTimeZone())\"\n @update:model-value=\"(v) => {\n if (v) {\n setFieldValue('dob', v.toString())\n }\n else {\n setFieldValue('dob', undefined)\n }\n }\"\n />\n </PopoverContent>\n </Popover>\n <FormDescription>\n Your date of birth is used to calculate your age.\n </FormDescription>\n <FormMessage />\n </FormItem>\n </FormField>\n <Button type=\"submit\">\n Submit\n </Button>\n </Form>\n</template>\n",
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/registry/default/ui/button'\nimport { Calendar } from '@/registry/default/ui/calendar'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/registry/default/ui/form'\nimport { Popover, PopoverContent, PopoverTrigger } from '@/registry/default/ui/popover'\nimport { toast } from '@/registry/default/ui/toast'\nimport { CalendarDate, DateFormatter, getLocalTimeZone, parseDate, today } from '@internationalized/date'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport { Calendar as CalendarIcon } from 'lucide-vue-next'\nimport { toDate } from 'reka-ui/date'\nimport { useForm } from 'vee-validate'\nimport { computed, h, ref } from 'vue'\nimport { z } from 'zod'\n\nconst df = new DateFormatter('en-US', {\n dateStyle: 'long',\n})\n\nconst formSchema = toTypedSchema(z.object({\n dob: z\n .string()\n .refine(v => v, { message: 'A date of birth is required.' }),\n}))\n\nconst placeholder = ref()\n\nconst { handleSubmit, setFieldValue, values } = useForm({\n validationSchema: formSchema,\n})\n\nconst value = computed({\n get: () => values.dob ? parseDate(values.dob) : undefined,\n set: val => val,\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"space-y-8\" @submit=\"onSubmit\">\n <FormField name=\"dob\">\n <FormItem class=\"flex flex-col\">\n <FormLabel>Date of birth</FormLabel>\n <Popover>\n <PopoverTrigger as-child>\n <FormControl>\n <Button\n variant=\"outline\" :class=\"cn(\n 'w-[240px] ps-3 text-start font-normal',\n !value && 'text-muted-foreground',\n )\"\n >\n <span>{{ value ? df.format(toDate(value)) : \"Pick a date\" }}</span>\n <CalendarIcon class=\"ms-auto h-4 w-4 opacity-50\" />\n </Button>\n <input hidden>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent class=\"w-auto p-0\">\n <Calendar\n v-model:placeholder=\"placeholder\"\n v-model=\"value\"\n calendar-label=\"Date of birth\"\n initial-focus\n :min-value=\"new CalendarDate(1900, 1, 1)\"\n :max-value=\"today(getLocalTimeZone())\"\n @update:model-value=\"(v) => {\n if (v) {\n setFieldValue('dob', v.toString())\n }\n else {\n setFieldValue('dob', undefined)\n }\n }\"\n />\n </PopoverContent>\n </Popover>\n <FormDescription>\n Your date of birth is used to calculate your age.\n </FormDescription>\n <FormMessage />\n </FormItem>\n </FormField>\n <Button type=\"submit\">\n Submit\n </Button>\n </Form>\n</template>\n",
"type": "registry:example",
"target": "CalendarForm.vue"
}
]
}
}

View File

@ -5,16 +5,16 @@
"@vueuse/core"
],
"registryDependencies": [
"utils",
"calendar",
"select",
"utils"
"select"
],
"files": [
{
"path": "example/CalendarWithSelect.vue",
"content": "<script setup lang=\"ts\">\nimport { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading } from '@/registry/default/ui/calendar'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/registry/default/ui/select'\nimport { cn } from '@/lib/utils'\nimport { type DateValue, getLocalTimeZone, today } from '@internationalized/date'\nimport { useVModel } from '@vueuse/core'\nimport { CalendarRoot, type CalendarRootEmits, type CalendarRootProps, useDateFormatter, useForwardPropsEmits } from 'reka-ui'\nimport { createDecade, createYear, toDate } from 'reka-ui/date'\nimport { computed, type HTMLAttributes, type Ref } from 'vue'\n\nconst props = withDefaults(defineProps<CalendarRootProps & { class?: HTMLAttributes['class'] }>(), {\n modelValue: undefined,\n placeholder() {\n return today(getLocalTimeZone())\n },\n weekdayFormat: 'short',\n})\nconst emits = defineEmits<CalendarRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, placeholder: __, ...delegated } = props\n\n return delegated\n})\n\nconst placeholder = useVModel(props, 'modelValue', emits, {\n passive: true,\n defaultValue: today(getLocalTimeZone()),\n}) as Ref<DateValue>\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n\nconst formatter = useDateFormatter('en')\n</script>\n\n<template>\n <CalendarRoot\n v-slot=\"{ date, grid, weekDays }\"\n v-model:placeholder=\"placeholder\"\n v-bind=\"forwarded\"\n :class=\"cn('rounded-md border p-3', props.class)\"\n >\n <CalendarHeader>\n <CalendarHeading class=\"flex w-full items-center justify-between gap-2\">\n <Select\n :default-value=\"placeholder.month.toString()\"\n @update:model-value=\"(v) => {\n if (!v || !placeholder) return;\n if (Number(v) === placeholder?.month) return;\n placeholder = placeholder.set({\n month: Number(v),\n })\n }\"\n >\n <SelectTrigger aria-label=\"Select month\" class=\"w-[60%]\">\n <SelectValue placeholder=\"Select month\" />\n </SelectTrigger>\n <SelectContent class=\"max-h-[200px]\">\n <SelectItem\n v-for=\"month in createYear({ dateObj: date })\"\n :key=\"month.toString()\" :value=\"month.month.toString()\"\n >\n {{ formatter.custom(toDate(month), { month: 'long' }) }}\n </SelectItem>\n </SelectContent>\n </Select>\n\n <Select\n :default-value=\"placeholder.year.toString()\"\n @update:model-value=\"(v) => {\n if (!v || !placeholder) return;\n if (Number(v) === placeholder?.year) return;\n placeholder = placeholder.set({\n year: Number(v),\n })\n }\"\n >\n <SelectTrigger aria-label=\"Select year\" class=\"w-[40%]\">\n <SelectValue placeholder=\"Select year\" />\n </SelectTrigger>\n <SelectContent class=\"max-h-[200px]\">\n <SelectItem\n v-for=\"yearValue in createDecade({ dateObj: date, startIndex: -10, endIndex: 10 })\"\n :key=\"yearValue.toString()\" :value=\"yearValue.year.toString()\"\n >\n {{ yearValue.year }}\n </SelectItem>\n </SelectContent>\n </Select>\n </CalendarHeading>\n </CalendarHeader>\n\n <div class=\"flex flex-col space-y-4 pt-4 sm:flex-row sm:gap-x-4 sm:gap-y-0\">\n <CalendarGrid v-for=\"month in grid\" :key=\"month.value.toString()\">\n <CalendarGridHead>\n <CalendarGridRow>\n <CalendarHeadCell\n v-for=\"day in weekDays\" :key=\"day\"\n >\n {{ day }}\n </CalendarHeadCell>\n </CalendarGridRow>\n </CalendarGridHead>\n <CalendarGridBody class=\"grid\">\n <CalendarGridRow v-for=\"(weekDates, index) in month.rows\" :key=\"`weekDate-${index}`\" class=\"mt-2 w-full\">\n <CalendarCell\n v-for=\"weekDate in weekDates\"\n :key=\"weekDate.toString()\"\n :date=\"weekDate\"\n >\n <CalendarCellTrigger\n :day=\"weekDate\"\n :month=\"month.value\"\n />\n </CalendarCell>\n </CalendarGridRow>\n </CalendarGridBody>\n </CalendarGrid>\n </div>\n </CalendarRoot>\n</template>\n",
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading } from '@/registry/default/ui/calendar'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/registry/default/ui/select'\nimport { type DateValue, getLocalTimeZone, today } from '@internationalized/date'\nimport { useVModel } from '@vueuse/core'\nimport { CalendarRoot, type CalendarRootEmits, type CalendarRootProps, useDateFormatter, useForwardPropsEmits } from 'reka-ui'\nimport { createDecade, createYear, toDate } from 'reka-ui/date'\nimport { computed, type HTMLAttributes, type Ref } from 'vue'\n\nconst props = withDefaults(defineProps<CalendarRootProps & { class?: HTMLAttributes['class'] }>(), {\n modelValue: undefined,\n placeholder() {\n return today(getLocalTimeZone())\n },\n weekdayFormat: 'short',\n})\nconst emits = defineEmits<CalendarRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, placeholder: __, ...delegated } = props\n\n return delegated\n})\n\nconst placeholder = useVModel(props, 'modelValue', emits, {\n passive: true,\n defaultValue: today(getLocalTimeZone()),\n}) as Ref<DateValue>\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n\nconst formatter = useDateFormatter('en')\n</script>\n\n<template>\n <CalendarRoot\n v-slot=\"{ date, grid, weekDays }\"\n v-model:placeholder=\"placeholder\"\n v-bind=\"forwarded\"\n :class=\"cn('rounded-md border p-3', props.class)\"\n >\n <CalendarHeader>\n <CalendarHeading class=\"flex w-full items-center justify-between gap-2\">\n <Select\n :default-value=\"placeholder.month.toString()\"\n @update:model-value=\"(v) => {\n if (!v || !placeholder) return;\n if (Number(v) === placeholder?.month) return;\n placeholder = placeholder.set({\n month: Number(v),\n })\n }\"\n >\n <SelectTrigger aria-label=\"Select month\" class=\"w-[60%]\">\n <SelectValue placeholder=\"Select month\" />\n </SelectTrigger>\n <SelectContent class=\"max-h-[200px]\">\n <SelectItem\n v-for=\"month in createYear({ dateObj: date })\"\n :key=\"month.toString()\" :value=\"month.month.toString()\"\n >\n {{ formatter.custom(toDate(month), { month: 'long' }) }}\n </SelectItem>\n </SelectContent>\n </Select>\n\n <Select\n :default-value=\"placeholder.year.toString()\"\n @update:model-value=\"(v) => {\n if (!v || !placeholder) return;\n if (Number(v) === placeholder?.year) return;\n placeholder = placeholder.set({\n year: Number(v),\n })\n }\"\n >\n <SelectTrigger aria-label=\"Select year\" class=\"w-[40%]\">\n <SelectValue placeholder=\"Select year\" />\n </SelectTrigger>\n <SelectContent class=\"max-h-[200px]\">\n <SelectItem\n v-for=\"yearValue in createDecade({ dateObj: date, startIndex: -10, endIndex: 10 })\"\n :key=\"yearValue.toString()\" :value=\"yearValue.year.toString()\"\n >\n {{ yearValue.year }}\n </SelectItem>\n </SelectContent>\n </Select>\n </CalendarHeading>\n </CalendarHeader>\n\n <div class=\"flex flex-col space-y-4 pt-4 sm:flex-row sm:gap-x-4 sm:gap-y-0\">\n <CalendarGrid v-for=\"month in grid\" :key=\"month.value.toString()\">\n <CalendarGridHead>\n <CalendarGridRow>\n <CalendarHeadCell\n v-for=\"day in weekDays\" :key=\"day\"\n >\n {{ day }}\n </CalendarHeadCell>\n </CalendarGridRow>\n </CalendarGridHead>\n <CalendarGridBody class=\"grid\">\n <CalendarGridRow v-for=\"(weekDates, index) in month.rows\" :key=\"`weekDate-${index}`\" class=\"mt-2 w-full\">\n <CalendarCell\n v-for=\"weekDate in weekDates\"\n :key=\"weekDate.toString()\"\n :date=\"weekDate\"\n >\n <CalendarCellTrigger\n :day=\"weekDate\"\n :month=\"month.value\"\n />\n </CalendarCell>\n </CalendarGridRow>\n </CalendarGridBody>\n </CalendarGrid>\n </div>\n </CalendarRoot>\n</template>\n",
"type": "registry:example",
"target": "CalendarWithSelect.vue"
}
]
}
}

File diff suppressed because one or more lines are too long

View File

@ -3,17 +3,17 @@
"type": "registry:example",
"dependencies": [],
"registryDependencies": [
"utils",
"button",
"card",
"switch",
"utils"
"switch"
],
"files": [
{
"path": "example/CardDemo.vue",
"content": "<script setup lang=\"ts\">\nimport { Button } from '@/registry/default/ui/button'\n\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from '@/registry/default/ui/card'\nimport { Switch } from '@/registry/default/ui/switch'\nimport { cn } from '@/lib/utils'\nimport { BellRing, Check } from 'lucide-vue-next'\n\nconst notifications = [\n {\n title: 'Your call has been confirmed.',\n description: '1 hour ago',\n },\n {\n title: 'You have a new message!',\n description: '1 hour ago',\n },\n {\n title: 'Your subscription is expiring soon!',\n description: '2 hours ago',\n },\n]\n</script>\n\n<template>\n <Card :class=\"cn('w-[380px]', $attrs.class ?? '')\">\n <CardHeader>\n <CardTitle>Notifications</CardTitle>\n <CardDescription>You have 3 unread messages.</CardDescription>\n </CardHeader>\n <CardContent class=\"grid gap-4\">\n <div class=\" flex items-center space-x-4 rounded-md border p-4\">\n <BellRing />\n <div class=\"flex-1 space-y-1\">\n <p class=\"text-sm font-medium leading-none\">\n Push Notifications\n </p>\n <p class=\"text-sm text-muted-foreground\">\n Send notifications to device.\n </p>\n </div>\n <Switch />\n </div>\n <div>\n <div\n v-for=\"(notification, index) in notifications\" :key=\"index\"\n class=\"mb-4 grid grid-cols-[25px_minmax(0,1fr)] items-start pb-4 last:mb-0 last:pb-0\"\n >\n <span class=\"flex h-2 w-2 translate-y-1 rounded-full bg-sky-500\" />\n <div class=\"space-y-1\">\n <p class=\"text-sm font-medium leading-none\">\n {{ notification.title }}\n </p>\n <p class=\"text-sm text-muted-foreground\">\n {{ notification.description }}\n </p>\n </div>\n </div>\n </div>\n </CardContent>\n <CardFooter>\n <Button class=\"w-full\">\n <Check class=\"mr-2 h-4 w-4\" /> Mark all as read\n </Button>\n </CardFooter>\n </Card>\n</template>\n",
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\n\nimport { Button } from '@/registry/default/ui/button'\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from '@/registry/default/ui/card'\nimport { Switch } from '@/registry/default/ui/switch'\nimport { BellRing, Check } from 'lucide-vue-next'\n\nconst notifications = [\n {\n title: 'Your call has been confirmed.',\n description: '1 hour ago',\n },\n {\n title: 'You have a new message!',\n description: '1 hour ago',\n },\n {\n title: 'Your subscription is expiring soon!',\n description: '2 hours ago',\n },\n]\n</script>\n\n<template>\n <Card :class=\"cn('w-[380px]', $attrs.class ?? '')\">\n <CardHeader>\n <CardTitle>Notifications</CardTitle>\n <CardDescription>You have 3 unread messages.</CardDescription>\n </CardHeader>\n <CardContent class=\"grid gap-4\">\n <div class=\" flex items-center space-x-4 rounded-md border p-4\">\n <BellRing />\n <div class=\"flex-1 space-y-1\">\n <p class=\"text-sm font-medium leading-none\">\n Push Notifications\n </p>\n <p class=\"text-sm text-muted-foreground\">\n Send notifications to device.\n </p>\n </div>\n <Switch />\n </div>\n <div>\n <div\n v-for=\"(notification, index) in notifications\" :key=\"index\"\n class=\"mb-4 grid grid-cols-[25px_minmax(0,1fr)] items-start pb-4 last:mb-0 last:pb-0\"\n >\n <span class=\"flex h-2 w-2 translate-y-1 rounded-full bg-sky-500\" />\n <div class=\"space-y-1\">\n <p class=\"text-sm font-medium leading-none\">\n {{ notification.title }}\n </p>\n <p class=\"text-sm text-muted-foreground\">\n {{ notification.description }}\n </p>\n </div>\n </div>\n </div>\n </CardContent>\n <CardFooter>\n <Button class=\"w-full\">\n <Check class=\"mr-2 h-4 w-4\" /> Mark all as read\n </Button>\n </CardFooter>\n </Card>\n</template>\n",
"type": "registry:example",
"target": "CardDemo.vue"
}
]
}
}

View File

@ -17,4 +17,4 @@
"target": "CardFormDemo.vue"
}
]
}
}

View File

@ -18,4 +18,4 @@
"target": "CardStats.vue"
}
]
}
}

View File

@ -17,4 +17,4 @@
"target": "CardWithForm.vue"
}
]
}
}

View File

@ -16,4 +16,4 @@
"target": "CarouselApi.vue"
}
]
}
}

View File

@ -14,4 +14,4 @@
"target": "CarouselDemo.vue"
}
]
}
}

View File

@ -14,4 +14,4 @@
"target": "CarouselOrientation.vue"
}
]
}
}

View File

@ -14,4 +14,4 @@
"target": "CarouselPlugin.vue"
}
]
}
}

View File

@ -14,4 +14,4 @@
"target": "CarouselSize.vue"
}
]
}
}

View File

@ -14,4 +14,4 @@
"target": "CarouselSpacing.vue"
}
]
}
}

View File

@ -16,4 +16,4 @@
"target": "CarouselThumbnails.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "CheckboxDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "CheckboxDisabled.vue"
}
]
}
}

View File

@ -20,4 +20,4 @@
"target": "CheckboxFormMultiple.vue"
}
]
}
}

View File

@ -20,4 +20,4 @@
"target": "CheckboxFormSingle.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "CheckboxWithText.vue"
}
]
}
}

View File

@ -14,4 +14,4 @@
"target": "CollapsibleDemo.vue"
}
]
}
}

View File

@ -3,17 +3,17 @@
"type": "registry:example",
"dependencies": [],
"registryDependencies": [
"utils",
"button",
"command",
"popover",
"utils"
"popover"
],
"files": [
{
"path": "example/ComboboxDemo.vue",
"content": "<script setup lang=\"ts\">\nimport { Button } from '@/registry/default/ui/button'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/registry/default/ui/command'\n\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/registry/default/ui/popover'\nimport { cn } from '@/lib/utils'\nimport { Check, ChevronsUpDown } from 'lucide-vue-next'\nimport { ref } from 'vue'\n\nconst frameworks = [\n { value: 'next.js', label: 'Next.js' },\n { value: 'sveltekit', label: 'SvelteKit' },\n { value: 'nuxt', label: 'Nuxt' },\n { value: 'remix', label: 'Remix' },\n { value: 'astro', label: 'Astro' },\n]\n\nconst open = ref(false)\nconst value = ref('')\n</script>\n\n<template>\n <Popover v-model:open=\"open\">\n <PopoverTrigger as-child>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n :aria-expanded=\"open\"\n class=\"w-[200px] justify-between\"\n >\n {{ value\n ? frameworks.find((framework) => framework.value === value)?.label\n : \"Select framework...\" }}\n <ChevronsUpDown class=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"w-[200px] p-0\">\n <Command>\n <CommandInput class=\"h-9\" placeholder=\"Search framework...\" />\n <CommandEmpty>No framework found.</CommandEmpty>\n <CommandList>\n <CommandGroup>\n <CommandItem\n v-for=\"framework in frameworks\"\n :key=\"framework.value\"\n :value=\"framework.value\"\n @select=\"(ev) => {\n if (typeof ev.detail.value === 'string') {\n value = ev.detail.value\n }\n open = false\n }\"\n >\n {{ framework.label }}\n <Check\n :class=\"cn(\n 'ml-auto h-4 w-4',\n value === framework.value ? 'opacity-100' : 'opacity-0',\n )\"\n />\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n</template>\n",
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/registry/default/ui/button'\n\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/registry/default/ui/command'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/registry/default/ui/popover'\nimport { Check, ChevronsUpDown } from 'lucide-vue-next'\nimport { ref } from 'vue'\n\nconst frameworks = [\n { value: 'next.js', label: 'Next.js' },\n { value: 'sveltekit', label: 'SvelteKit' },\n { value: 'nuxt', label: 'Nuxt' },\n { value: 'remix', label: 'Remix' },\n { value: 'astro', label: 'Astro' },\n]\n\nconst open = ref(false)\nconst value = ref('')\n</script>\n\n<template>\n <Popover v-model:open=\"open\">\n <PopoverTrigger as-child>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n :aria-expanded=\"open\"\n class=\"w-[200px] justify-between\"\n >\n {{ value\n ? frameworks.find((framework) => framework.value === value)?.label\n : \"Select framework...\" }}\n <ChevronsUpDown class=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"w-[200px] p-0\">\n <Command>\n <CommandInput class=\"h-9\" placeholder=\"Search framework...\" />\n <CommandEmpty>No framework found.</CommandEmpty>\n <CommandList>\n <CommandGroup>\n <CommandItem\n v-for=\"framework in frameworks\"\n :key=\"framework.value\"\n :value=\"framework.value\"\n @select=\"(ev) => {\n if (typeof ev.detail.value === 'string') {\n value = ev.detail.value\n }\n open = false\n }\"\n >\n {{ framework.label }}\n <Check\n :class=\"cn(\n 'ml-auto h-4 w-4',\n value === framework.value ? 'opacity-100' : 'opacity-0',\n )\"\n />\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n</template>\n",
"type": "registry:example",
"target": "ComboboxDemo.vue"
}
]
}
}

View File

@ -15,4 +15,4 @@
"target": "ComboboxDropdownMenu.vue"
}
]
}
}

View File

@ -7,19 +7,19 @@
"zod"
],
"registryDependencies": [
"utils",
"button",
"command",
"form",
"popover",
"toast",
"utils"
"toast"
],
"files": [
{
"path": "example/ComboboxForm.vue",
"content": "<script setup lang=\"ts\">\nimport { Button } from '@/registry/default/ui/button'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/registry/default/ui/command'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/registry/default/ui/form'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/registry/default/ui/popover'\n\nimport { toast } from '@/registry/default/ui/toast'\nimport { cn } from '@/lib/utils'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport { Check, ChevronsUpDown } from 'lucide-vue-next'\nimport { useForm } from 'vee-validate'\nimport { h } from 'vue'\nimport * as z from 'zod'\n\nconst languages = [\n { label: 'English', value: 'en' },\n { label: 'French', value: 'fr' },\n { label: 'German', value: 'de' },\n { label: 'Spanish', value: 'es' },\n { label: 'Portuguese', value: 'pt' },\n { label: 'Russian', value: 'ru' },\n { label: 'Japanese', value: 'ja' },\n { label: 'Korean', value: 'ko' },\n { label: 'Chinese', value: 'zh' },\n]\n\nconst formSchema = toTypedSchema(z.object({\n language: z.string({\n required_error: 'Please select a language.',\n }),\n}))\n\nconst { handleSubmit, setFieldValue, values } = useForm({\n validationSchema: formSchema,\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"space-y-6\" @submit=\"onSubmit\">\n <FormField name=\"language\">\n <FormItem class=\"flex flex-col\">\n <FormLabel>Language</FormLabel>\n <Popover>\n <PopoverTrigger as-child>\n <FormControl>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n :class=\"cn('w-[200px] justify-between', !values.language && 'text-muted-foreground')\"\n >\n {{ values.language ? languages.find(\n (language) => language.value === values.language,\n )?.label : 'Select language...' }}\n <ChevronsUpDown class=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent class=\"w-[200px] p-0\">\n <Command>\n <CommandInput placeholder=\"Search language...\" />\n <CommandEmpty>Nothing found.</CommandEmpty>\n <CommandList>\n <CommandGroup>\n <CommandItem\n v-for=\"language in languages\"\n :key=\"language.value\"\n :value=\"language.label\"\n @select=\"() => {\n setFieldValue('language', language.value)\n }\"\n >\n <Check\n :class=\"cn('mr-2 h-4 w-4', language.value === values.language ? 'opacity-100' : 'opacity-0')\"\n />\n {{ language.label }}\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n <FormDescription>\n This is the language that will be used in the dashboard.\n </FormDescription>\n <FormMessage />\n </FormItem>\n </FormField>\n\n <Button type=\"submit\">\n Submit\n </Button>\n </form>\n</template>\n",
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/registry/default/ui/button'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/registry/default/ui/command'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/registry/default/ui/form'\n\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/registry/default/ui/popover'\nimport { toast } from '@/registry/default/ui/toast'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport { Check, ChevronsUpDown } from 'lucide-vue-next'\nimport { useForm } from 'vee-validate'\nimport { h } from 'vue'\nimport * as z from 'zod'\n\nconst languages = [\n { label: 'English', value: 'en' },\n { label: 'French', value: 'fr' },\n { label: 'German', value: 'de' },\n { label: 'Spanish', value: 'es' },\n { label: 'Portuguese', value: 'pt' },\n { label: 'Russian', value: 'ru' },\n { label: 'Japanese', value: 'ja' },\n { label: 'Korean', value: 'ko' },\n { label: 'Chinese', value: 'zh' },\n]\n\nconst formSchema = toTypedSchema(z.object({\n language: z.string({\n required_error: 'Please select a language.',\n }),\n}))\n\nconst { handleSubmit, setFieldValue, values } = useForm({\n validationSchema: formSchema,\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"space-y-6\" @submit=\"onSubmit\">\n <FormField name=\"language\">\n <FormItem class=\"flex flex-col\">\n <FormLabel>Language</FormLabel>\n <Popover>\n <PopoverTrigger as-child>\n <FormControl>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n :class=\"cn('w-[200px] justify-between', !values.language && 'text-muted-foreground')\"\n >\n {{ values.language ? languages.find(\n (language) => language.value === values.language,\n )?.label : 'Select language...' }}\n <ChevronsUpDown class=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent class=\"w-[200px] p-0\">\n <Command>\n <CommandInput placeholder=\"Search language...\" />\n <CommandEmpty>Nothing found.</CommandEmpty>\n <CommandList>\n <CommandGroup>\n <CommandItem\n v-for=\"language in languages\"\n :key=\"language.value\"\n :value=\"language.label\"\n @select=\"() => {\n setFieldValue('language', language.value)\n }\"\n >\n <Check\n :class=\"cn('mr-2 h-4 w-4', language.value === values.language ? 'opacity-100' : 'opacity-0')\"\n />\n {{ language.label }}\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n <FormDescription>\n This is the language that will be used in the dashboard.\n </FormDescription>\n <FormMessage />\n </FormItem>\n </FormField>\n\n <Button type=\"submit\">\n Submit\n </Button>\n </form>\n</template>\n",
"type": "registry:example",
"target": "ComboboxForm.vue"
}
]
}
}

View File

@ -3,17 +3,17 @@
"type": "registry:example",
"dependencies": [],
"registryDependencies": [
"utils",
"button",
"command",
"popover",
"utils"
"popover"
],
"files": [
{
"path": "example/ComboboxPopover.vue",
"content": "<script setup lang=\"ts\">\nimport type { Icon } from 'lucide-vue-next'\nimport { Button } from '@/registry/default/ui/button'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/registry/default/ui/command'\n\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/registry/default/ui/popover'\nimport { cn } from '@/lib/utils'\nimport {\n ArrowUpCircle,\n CheckCircle2,\n Circle,\n HelpCircle,\n XCircle,\n} from 'lucide-vue-next'\nimport { ref } from 'vue'\n\ninterface Status {\n value: string\n label: string\n icon: Icon\n}\n\nconst statuses: Status[] = [\n {\n value: 'backlog',\n label: 'Backlog',\n icon: HelpCircle,\n },\n {\n value: 'todo',\n label: 'Todo',\n icon: Circle,\n },\n {\n value: 'in progress',\n label: 'In Progress',\n icon: ArrowUpCircle,\n },\n {\n value: 'done',\n label: 'Done',\n icon: CheckCircle2,\n },\n {\n value: 'canceled',\n label: 'Canceled',\n icon: XCircle,\n },\n]\n\nconst open = ref(false)\n// const value = ref<typeof statuses[number]>()\n\nconst selectedStatus = ref<Status>()\n</script>\n\n<template>\n <div class=\"flex items-center space-x-4\">\n <p class=\"text-sm text-muted-foreground\">\n Status\n </p>\n <Popover v-model:open=\"open\">\n <PopoverTrigger as-child>\n <Button\n variant=\"outline\"\n size=\"sm\"\n class=\"w-[150px] justify-start\"\n >\n <template v-if=\"selectedStatus\">\n <component :is=\"selectedStatus?.icon\" class=\"mr-2 h-4 w-4 shrink-0\" />\n {{ selectedStatus?.label }}\n </template>\n <template v-else>\n + Set status\n </template>\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"p-0\" side=\"right\" align=\"start\">\n <Command>\n <CommandInput placeholder=\"Change status...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup>\n <CommandItem\n v-for=\"status in statuses\"\n :key=\"status.value\"\n :value=\"status.value\"\n @select=\"(value) => {\n selectedStatus = status\n open = false\n }\"\n >\n <component\n :is=\"status.icon\"\n :key=\"status.value\"\n :class=\"cn('mr-2 h-4 w-4', status.value === selectedStatus?.value ? 'opacity-100' : 'opacity-40',\n )\"\n />\n <span>{{ status.label }}</span>\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n </div>\n</template>\n",
"content": "<script setup lang=\"ts\">\nimport type { Icon } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/registry/default/ui/button'\n\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/registry/default/ui/command'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/registry/default/ui/popover'\nimport {\n ArrowUpCircle,\n CheckCircle2,\n Circle,\n HelpCircle,\n XCircle,\n} from 'lucide-vue-next'\nimport { ref } from 'vue'\n\ninterface Status {\n value: string\n label: string\n icon: Icon\n}\n\nconst statuses: Status[] = [\n {\n value: 'backlog',\n label: 'Backlog',\n icon: HelpCircle,\n },\n {\n value: 'todo',\n label: 'Todo',\n icon: Circle,\n },\n {\n value: 'in progress',\n label: 'In Progress',\n icon: ArrowUpCircle,\n },\n {\n value: 'done',\n label: 'Done',\n icon: CheckCircle2,\n },\n {\n value: 'canceled',\n label: 'Canceled',\n icon: XCircle,\n },\n]\n\nconst open = ref(false)\n// const value = ref<typeof statuses[number]>()\n\nconst selectedStatus = ref<Status>()\n</script>\n\n<template>\n <div class=\"flex items-center space-x-4\">\n <p class=\"text-sm text-muted-foreground\">\n Status\n </p>\n <Popover v-model:open=\"open\">\n <PopoverTrigger as-child>\n <Button\n variant=\"outline\"\n size=\"sm\"\n class=\"w-[150px] justify-start\"\n >\n <template v-if=\"selectedStatus\">\n <component :is=\"selectedStatus?.icon\" class=\"mr-2 h-4 w-4 shrink-0\" />\n {{ selectedStatus?.label }}\n </template>\n <template v-else>\n + Set status\n </template>\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"p-0\" side=\"right\" align=\"start\">\n <Command>\n <CommandInput placeholder=\"Change status...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup>\n <CommandItem\n v-for=\"status in statuses\"\n :key=\"status.value\"\n :value=\"status.value\"\n @select=\"(value) => {\n selectedStatus = status\n open = false\n }\"\n >\n <component\n :is=\"status.icon\"\n :key=\"status.value\"\n :class=\"cn('mr-2 h-4 w-4', status.value === selectedStatus?.value ? 'opacity-100' : 'opacity-40',\n )\"\n />\n <span>{{ status.label }}</span>\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n </div>\n</template>\n",
"type": "registry:example",
"target": "ComboboxPopover.vue"
}
]
}
}

View File

@ -18,4 +18,4 @@
"target": "ComboboxResponsive.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "CommandDemo.vue"
}
]
}
}

View File

@ -15,4 +15,4 @@
"target": "CommandDialogDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "ContextMenuDemo.vue"
}
]
}
}

View File

@ -13,4 +13,4 @@
"target": "CustomChartTooltip.vue"
}
]
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -14,4 +14,4 @@
"target": "DataTableDemoColumn.vue"
}
]
}
}

File diff suppressed because one or more lines are too long

View File

@ -3,17 +3,17 @@
"type": "registry:example",
"dependencies": [],
"registryDependencies": [
"utils",
"button",
"calendar",
"popover",
"utils"
"popover"
],
"files": [
{
"path": "example/DatePickerDemo.vue",
"content": "<script setup lang=\"ts\">\nimport { Button } from '@/registry/default/ui/button'\nimport { Calendar } from '@/registry/default/ui/calendar'\n\nimport { Popover, PopoverContent, PopoverTrigger } from '@/registry/default/ui/popover'\nimport { cn } from '@/lib/utils'\nimport {\n DateFormatter,\n type DateValue,\n getLocalTimeZone,\n} from '@internationalized/date'\nimport { Calendar as CalendarIcon } from 'lucide-vue-next'\nimport { ref } from 'vue'\n\nconst df = new DateFormatter('en-US', {\n dateStyle: 'long',\n})\n\nconst value = ref<DateValue>()\n</script>\n\n<template>\n <Popover>\n <PopoverTrigger as-child>\n <Button\n variant=\"outline\"\n :class=\"cn(\n 'w-[280px] justify-start text-left font-normal',\n !value && 'text-muted-foreground',\n )\"\n >\n <CalendarIcon class=\"mr-2 h-4 w-4\" />\n {{ value ? df.format(value.toDate(getLocalTimeZone())) : \"Pick a date\" }}\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"w-auto p-0\">\n <Calendar v-model=\"value\" initial-focus />\n </PopoverContent>\n </Popover>\n</template>\n",
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/registry/default/ui/button'\n\nimport { Calendar } from '@/registry/default/ui/calendar'\nimport { Popover, PopoverContent, PopoverTrigger } from '@/registry/default/ui/popover'\nimport {\n DateFormatter,\n type DateValue,\n getLocalTimeZone,\n} from '@internationalized/date'\nimport { Calendar as CalendarIcon } from 'lucide-vue-next'\nimport { ref } from 'vue'\n\nconst df = new DateFormatter('en-US', {\n dateStyle: 'long',\n})\n\nconst value = ref<DateValue>()\n</script>\n\n<template>\n <Popover>\n <PopoverTrigger as-child>\n <Button\n variant=\"outline\"\n :class=\"cn(\n 'w-[280px] justify-start text-left font-normal',\n !value && 'text-muted-foreground',\n )\"\n >\n <CalendarIcon class=\"mr-2 h-4 w-4\" />\n {{ value ? df.format(value.toDate(getLocalTimeZone())) : \"Pick a date\" }}\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"w-auto p-0\">\n <Calendar v-model=\"value\" initial-focus />\n </PopoverContent>\n </Popover>\n</template>\n",
"type": "registry:example",
"target": "DatePickerDemo.vue"
}
]
}
}

View File

@ -7,19 +7,19 @@
"zod"
],
"registryDependencies": [
"utils",
"button",
"calendar",
"form",
"popover",
"toast",
"utils"
"toast"
],
"files": [
{
"path": "example/DatePickerForm.vue",
"content": "<script setup lang=\"ts\">\nimport { Button } from '@/registry/default/ui/button'\nimport { Calendar } from '@/registry/default/ui/calendar'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/registry/default/ui/form'\nimport { Popover, PopoverContent, PopoverTrigger } from '@/registry/default/ui/popover'\nimport { toast } from '@/registry/default/ui/toast'\nimport { cn } from '@/lib/utils'\nimport { CalendarDate, DateFormatter, getLocalTimeZone, parseDate, today } from '@internationalized/date'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport { Calendar as CalendarIcon } from 'lucide-vue-next'\nimport { toDate } from 'reka-ui/date'\nimport { useForm } from 'vee-validate'\nimport { computed, h, ref } from 'vue'\nimport { z } from 'zod'\n\nconst df = new DateFormatter('en-US', {\n dateStyle: 'long',\n})\n\nconst formSchema = toTypedSchema(z.object({\n dob: z\n .string()\n .refine(v => v, { message: 'A date of birth is required.' }),\n}))\n\nconst placeholder = ref()\n\nconst { handleSubmit, setFieldValue, values } = useForm({\n validationSchema: formSchema,\n initialValues: {\n\n },\n})\n\nconst value = computed({\n get: () => values.dob ? parseDate(values.dob) : undefined,\n set: val => val,\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"space-y-8\" @submit=\"onSubmit\">\n <FormField name=\"dob\">\n <FormItem class=\"flex flex-col\">\n <FormLabel>Date of birth</FormLabel>\n <Popover>\n <PopoverTrigger as-child>\n <FormControl>\n <Button\n variant=\"outline\" :class=\"cn(\n 'w-[240px] ps-3 text-start font-normal',\n !value && 'text-muted-foreground',\n )\"\n >\n <span>{{ value ? df.format(toDate(value)) : \"Pick a date\" }}</span>\n <CalendarIcon class=\"ms-auto h-4 w-4 opacity-50\" />\n </Button>\n <input hidden>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent class=\"w-auto p-0\">\n <Calendar\n v-model:placeholder=\"placeholder\"\n v-model=\"value\"\n calendar-label=\"Date of birth\"\n initial-focus\n :min-value=\"new CalendarDate(1900, 1, 1)\"\n :max-value=\"today(getLocalTimeZone())\"\n @update:model-value=\"(v) => {\n if (v) {\n setFieldValue('dob', v.toString())\n }\n else {\n setFieldValue('dob', undefined)\n }\n\n }\"\n />\n </PopoverContent>\n </Popover>\n <FormDescription>\n Your date of birth is used to calculate your age.\n </FormDescription>\n <FormMessage />\n </FormItem>\n </FormField>\n <Button type=\"submit\">\n Submit\n </Button>\n </Form>\n</template>\n",
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/registry/default/ui/button'\nimport { Calendar } from '@/registry/default/ui/calendar'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/registry/default/ui/form'\nimport { Popover, PopoverContent, PopoverTrigger } from '@/registry/default/ui/popover'\nimport { toast } from '@/registry/default/ui/toast'\nimport { CalendarDate, DateFormatter, getLocalTimeZone, parseDate, today } from '@internationalized/date'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport { Calendar as CalendarIcon } from 'lucide-vue-next'\nimport { toDate } from 'reka-ui/date'\nimport { useForm } from 'vee-validate'\nimport { computed, h, ref } from 'vue'\nimport { z } from 'zod'\n\nconst df = new DateFormatter('en-US', {\n dateStyle: 'long',\n})\n\nconst formSchema = toTypedSchema(z.object({\n dob: z\n .string()\n .refine(v => v, { message: 'A date of birth is required.' }),\n}))\n\nconst placeholder = ref()\n\nconst { handleSubmit, setFieldValue, values } = useForm({\n validationSchema: formSchema,\n initialValues: {\n\n },\n})\n\nconst value = computed({\n get: () => values.dob ? parseDate(values.dob) : undefined,\n set: val => val,\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"space-y-8\" @submit=\"onSubmit\">\n <FormField name=\"dob\">\n <FormItem class=\"flex flex-col\">\n <FormLabel>Date of birth</FormLabel>\n <Popover>\n <PopoverTrigger as-child>\n <FormControl>\n <Button\n variant=\"outline\" :class=\"cn(\n 'w-[240px] ps-3 text-start font-normal',\n !value && 'text-muted-foreground',\n )\"\n >\n <span>{{ value ? df.format(toDate(value)) : \"Pick a date\" }}</span>\n <CalendarIcon class=\"ms-auto h-4 w-4 opacity-50\" />\n </Button>\n <input hidden>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent class=\"w-auto p-0\">\n <Calendar\n v-model:placeholder=\"placeholder\"\n v-model=\"value\"\n calendar-label=\"Date of birth\"\n initial-focus\n :min-value=\"new CalendarDate(1900, 1, 1)\"\n :max-value=\"today(getLocalTimeZone())\"\n @update:model-value=\"(v) => {\n if (v) {\n setFieldValue('dob', v.toString())\n }\n else {\n setFieldValue('dob', undefined)\n }\n\n }\"\n />\n </PopoverContent>\n </Popover>\n <FormDescription>\n Your date of birth is used to calculate your age.\n </FormDescription>\n <FormMessage />\n </FormItem>\n </FormField>\n <Button type=\"submit\">\n Submit\n </Button>\n </Form>\n</template>\n",
"type": "registry:example",
"target": "DatePickerForm.vue"
}
]
}
}

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More