feat: add v0 handling

This commit is contained in:
shadcn
2024-08-29 22:52:35 +04:00
parent ab10b70a90
commit bfcf2b2de9
5 changed files with 47 additions and 2 deletions

View File

@@ -8,6 +8,7 @@ import { handleError } from "@/src/utils/handle-error"
import { highlighter } from "@/src/utils/highlighter"
import { logger } from "@/src/utils/logger"
import { getRegistryIndex } from "@/src/utils/registry"
import { updateAppIndex } from "@/src/utils/update-app-index"
import { Command } from "commander"
import prompts from "prompts"
import { z } from "zod"
@@ -102,6 +103,7 @@ export const add = new Command()
})
}
let shouldUpdateAppIndex = false
if (errors[ERRORS.MISSING_DIR_OR_EMPTY_PROJECT]) {
const { projectPath } = await createProject({
cwd: options.cwd,
@@ -122,6 +124,10 @@ export const add = new Command()
silent: true,
isNewProject: true,
})
shouldUpdateAppIndex =
options.components?.length === 1 &&
!!options.components[0].match(/\/chat\/b\//)
}
if (!config) {
@@ -131,6 +137,12 @@ export const add = new Command()
}
await addComponents(options.components, config, options)
// If we're adding a single component and it's from the v0 registry,
// let's update the app/page.tsx file to import the component.
if (shouldUpdateAppIndex) {
await updateAppIndex(options.components[0], config)
}
} catch (error) {
logger.break()
handleError(error)

View File

@@ -71,7 +71,9 @@ export async function createProject(
process.exit(1)
}
const createSpinner = spinner(`Creating a new Next.js project.`).start()
const createSpinner = spinner(
`Creating a new Next.js project. This may take a few minutes.`
).start()
// Note: pnpm fails here. Fallback to npx with --use-PACKAGE-MANAGER.
const args = [
@@ -100,7 +102,7 @@ export async function createProject(
process.exit(1)
}
createSpinner?.succeed()
createSpinner?.succeed("Creating a new Next.js project.")
return {
projectPath,

View File

@@ -364,6 +364,12 @@ export async function registryGetTheme(name: string, config: Config) {
function getRegistryUrl(path: string) {
if (isUrl(path)) {
// If the url contains /chat/b/, we assume it's the v0 registry.
// We need to add the /json suffix if it's missing.
if (path.match(/\/chat\/b\//) && !path.endsWith("/json")) {
path = `${path}/json`
}
return path
}

View File

@@ -45,6 +45,7 @@ export const registryItemSchema = z.object({
files: z.array(registryItemFileSchema).optional(),
tailwind: registryItemTailwindSchema.optional(),
cssVars: registryItemCssVarsSchema.optional(),
meta: z.record(z.string(), z.any()).optional(),
})
export type RegistryItem = z.infer<typeof registryItemSchema>

View File

@@ -0,0 +1,24 @@
import fs from "fs/promises"
import path from "path"
import { Config } from "@/src/utils/get-config"
import { getRegistryItem } from "@/src/utils/registry"
export async function updateAppIndex(component: string, config: Config) {
const indexPath = path.join(config.resolvedPaths.cwd, "app/page.tsx")
if (!(await fs.stat(indexPath)).isFile()) {
return
}
const registryItem = await getRegistryItem(component, config.style)
if (
!registryItem?.meta?.importSpecifier ||
!registryItem?.meta?.moduleSpecifier
) {
return
}
// Overwrite the index file with the new import.
const content = `import { ${registryItem?.meta?.importSpecifier} } from "${registryItem.meta.moduleSpecifier}"\n\nexport default function Page() {\n return <${registryItem?.meta?.importSpecifier} />\n}`
await fs.writeFile(indexPath, content, "utf8")
}