diff --git a/packages/cli/src/commands/add.ts b/packages/cli/src/commands/add.ts index 2ad23e8a93..706e3da78b 100644 --- a/packages/cli/src/commands/add.ts +++ b/packages/cli/src/commands/add.ts @@ -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) diff --git a/packages/cli/src/utils/create-project.ts b/packages/cli/src/utils/create-project.ts index 6de9bf7679..92706e7845 100644 --- a/packages/cli/src/utils/create-project.ts +++ b/packages/cli/src/utils/create-project.ts @@ -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, diff --git a/packages/cli/src/utils/registry/index.ts b/packages/cli/src/utils/registry/index.ts index abe8830ffe..61bae19677 100644 --- a/packages/cli/src/utils/registry/index.ts +++ b/packages/cli/src/utils/registry/index.ts @@ -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 } diff --git a/packages/cli/src/utils/registry/schema.ts b/packages/cli/src/utils/registry/schema.ts index 76c09fc3d3..3809654f73 100644 --- a/packages/cli/src/utils/registry/schema.ts +++ b/packages/cli/src/utils/registry/schema.ts @@ -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 diff --git a/packages/cli/src/utils/update-app-index.ts b/packages/cli/src/utils/update-app-index.ts new file mode 100644 index 0000000000..c1adfdc0a9 --- /dev/null +++ b/packages/cli/src/utils/update-app-index.ts @@ -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") +}