From 525775fb3675402b70c65c53e69fe3bb8e8602e0 Mon Sep 17 00:00:00 2001 From: shadcn Date: Sat, 14 Feb 2026 18:36:56 +0400 Subject: [PATCH] feat --- packages/shadcn/src/commands/add.ts | 15 - packages/shadcn/src/commands/create.ts | 31 +- packages/shadcn/src/commands/init.ts | 396 ++++++++---------- packages/shadcn/src/registry/resolver.test.ts | 6 +- packages/shadcn/src/registry/resolver.ts | 2 +- .../shadcn/src/templates/create-template.ts | 46 ++ .../shadcn/src/{utils => }/templates/index.ts | 9 +- .../shadcn/src/templates/next-monorepo.ts | 213 ++++++++++ .../next-monorepo.ts => templates/next.ts} | 50 +-- .../shadcn/src/{utils => }/templates/start.ts | 12 +- .../shadcn/src/{utils => }/templates/vite.ts | 12 +- packages/shadcn/src/utils/add-components.ts | 19 +- .../shadcn/src/utils/create-project.test.ts | 41 +- packages/shadcn/src/utils/create-project.ts | 38 +- packages/shadcn/src/utils/init-monorepo.ts | 116 ----- .../src/utils/templates/create-template.ts | 23 - packages/shadcn/src/utils/templates/next.ts | 75 ---- packages/tests/src/tests/init.test.ts | 209 +++++---- templates/monorepo-next/.vscode/settings.json | 3 - templates/monorepo-next/apps/web/app/page.tsx | 9 - .../apps/web/components/providers.tsx | 18 - templates/next-app/.gitignore | 36 ++ templates/next-app/.prettierrc | 11 + templates/next-app/README.md | 21 + .../apps/web => next-app}/app/favicon.ico | Bin templates/next-app/app/globals.css | 1 + templates/next-app/app/layout.tsx | 32 ++ templates/next-app/app/page.tsx | 7 + .../apps/web => next-app}/components/.gitkeep | 0 .../next-app/components/theme-provider.tsx | 71 ++++ templates/next-app/eslint.config.mjs | 18 + .../apps/web => next-app}/hooks/.gitkeep | 0 .../apps/web => next-app}/lib/.gitkeep | 0 templates/next-app/next.config.mjs | 4 + templates/next-app/package.json | 34 ++ templates/next-app/postcss.config.mjs | 8 + .../components => next-app/public}/.gitkeep | 0 templates/next-app/tsconfig.json | 34 ++ .../.eslintrc.js | 0 .../.gitignore | 0 .../{monorepo-next => next-monorepo}/.npmrc | 0 templates/next-monorepo/.prettierrc | 11 + .../README.md | 14 +- .../next-monorepo/apps/web/app/favicon.ico | Bin 0 -> 25931 bytes .../apps/web/app/layout.tsx | 14 +- templates/next-monorepo/apps/web/app/page.tsx | 7 + .../apps/web/components.json | 0 .../apps/web/components}/.gitkeep | 0 .../apps/web/components/theme-provider.tsx | 71 ++++ .../apps/web/eslint.config.js | 0 .../apps/web/hooks}/.gitkeep | 0 templates/next-monorepo/apps/web/lib/.gitkeep | 0 .../apps/web/next-env.d.ts | 2 +- .../apps/web/next.config.mjs | 0 .../apps/web/package.json | 4 +- .../apps/web/postcss.config.mjs | 0 .../apps/web/tsconfig.json | 0 .../package.json | 8 +- .../packages/eslint-config/README.md | 0 .../packages/eslint-config/base.js | 0 .../packages/eslint-config/next.js | 0 .../packages/eslint-config/package.json | 0 .../packages/eslint-config/react-internal.js | 0 .../packages/typescript-config/README.md | 0 .../packages/typescript-config/base.json | 0 .../packages/typescript-config/nextjs.json | 0 .../packages/typescript-config/package.json | 0 .../typescript-config/react-library.json | 0 .../packages/ui/components.json | 0 .../packages/ui/eslint.config.js | 0 .../packages/ui/package.json | 4 +- .../packages/ui/postcss.config.mjs | 0 .../packages/ui/src/components/.gitkeep | 0 .../packages/ui/src/hooks/.gitkeep | 0 .../packages/ui/src/lib/.gitkeep | 0 .../packages/ui/src/styles/globals.css | 0 .../packages/ui/tsconfig.json | 0 .../packages/ui/tsconfig.lint.json | 0 .../pnpm-lock.yaml | 0 .../pnpm-workspace.yaml | 0 .../tsconfig.json | 0 .../turbo.json | 7 +- templates/start-app/.cta.json | 2 +- templates/start-app/.gitignore | 1 + templates/start-app/.prettierrc | 11 + templates/start-app/README.md | 18 + templates/start-app/eslint.config.js | 2 +- templates/start-app/package.json | 7 +- templates/start-app/prettier.config.js | 10 - templates/start-app/src/lib/utils.ts | 7 + templates/start-app/src/routeTree.gen.ts | 36 +- templates/start-app/src/router.tsx | 19 +- templates/start-app/src/routes/__root.tsx | 26 +- templates/start-app/src/routes/index.tsx | 10 +- templates/start-app/tsconfig.json | 5 +- templates/start-app/vite.config.ts | 16 +- templates/vite-app/.prettierrc | 11 + templates/vite-app/README.md | 18 + templates/vite-app/package.json | 6 +- templates/vite-app/src/App.tsx | 4 +- .../src/components/theme-provider.tsx | 230 ++++++++++ templates/vite-app/src/main.tsx | 5 +- 102 files changed, 1353 insertions(+), 853 deletions(-) create mode 100644 packages/shadcn/src/templates/create-template.ts rename packages/shadcn/src/{utils => }/templates/index.ts (77%) create mode 100644 packages/shadcn/src/templates/next-monorepo.ts rename packages/shadcn/src/{utils/templates/next-monorepo.ts => templates/next.ts} (67%) rename packages/shadcn/src/{utils => }/templates/start.ts (89%) rename packages/shadcn/src/{utils => }/templates/vite.ts (89%) delete mode 100644 packages/shadcn/src/utils/init-monorepo.ts delete mode 100644 packages/shadcn/src/utils/templates/create-template.ts delete mode 100644 packages/shadcn/src/utils/templates/next.ts delete mode 100644 templates/monorepo-next/.vscode/settings.json delete mode 100644 templates/monorepo-next/apps/web/app/page.tsx delete mode 100644 templates/monorepo-next/apps/web/components/providers.tsx create mode 100644 templates/next-app/.gitignore create mode 100644 templates/next-app/.prettierrc create mode 100644 templates/next-app/README.md rename templates/{monorepo-next/apps/web => next-app}/app/favicon.ico (100%) create mode 100644 templates/next-app/app/globals.css create mode 100644 templates/next-app/app/layout.tsx create mode 100644 templates/next-app/app/page.tsx rename templates/{monorepo-next/apps/web => next-app}/components/.gitkeep (100%) create mode 100644 templates/next-app/components/theme-provider.tsx create mode 100644 templates/next-app/eslint.config.mjs rename templates/{monorepo-next/apps/web => next-app}/hooks/.gitkeep (100%) rename templates/{monorepo-next/apps/web => next-app}/lib/.gitkeep (100%) create mode 100644 templates/next-app/next.config.mjs create mode 100644 templates/next-app/package.json create mode 100644 templates/next-app/postcss.config.mjs rename templates/{monorepo-next/packages/ui/src/components => next-app/public}/.gitkeep (100%) create mode 100644 templates/next-app/tsconfig.json rename templates/{monorepo-next => next-monorepo}/.eslintrc.js (100%) rename templates/{monorepo-next => next-monorepo}/.gitignore (100%) rename templates/{monorepo-next => next-monorepo}/.npmrc (100%) create mode 100644 templates/next-monorepo/.prettierrc rename templates/{monorepo-next => next-monorepo}/README.md (57%) create mode 100644 templates/next-monorepo/apps/web/app/favicon.ico rename templates/{monorepo-next => next-monorepo}/apps/web/app/layout.tsx (59%) create mode 100644 templates/next-monorepo/apps/web/app/page.tsx rename templates/{monorepo-next => next-monorepo}/apps/web/components.json (100%) rename templates/{monorepo-next/packages/ui/src/hooks => next-monorepo/apps/web/components}/.gitkeep (100%) create mode 100644 templates/next-monorepo/apps/web/components/theme-provider.tsx rename templates/{monorepo-next => next-monorepo}/apps/web/eslint.config.js (100%) rename templates/{monorepo-next/packages/ui/src/lib => next-monorepo/apps/web/hooks}/.gitkeep (100%) create mode 100644 templates/next-monorepo/apps/web/lib/.gitkeep rename templates/{monorepo-next => next-monorepo}/apps/web/next-env.d.ts (84%) rename templates/{monorepo-next => next-monorepo}/apps/web/next.config.mjs (100%) rename templates/{monorepo-next => next-monorepo}/apps/web/package.json (90%) rename templates/{monorepo-next => next-monorepo}/apps/web/postcss.config.mjs (100%) rename templates/{monorepo-next => next-monorepo}/apps/web/tsconfig.json (100%) rename templates/{monorepo-next => next-monorepo}/package.json (71%) rename templates/{monorepo-next => next-monorepo}/packages/eslint-config/README.md (100%) rename templates/{monorepo-next => next-monorepo}/packages/eslint-config/base.js (100%) rename templates/{monorepo-next => next-monorepo}/packages/eslint-config/next.js (100%) rename templates/{monorepo-next => next-monorepo}/packages/eslint-config/package.json (100%) rename templates/{monorepo-next => next-monorepo}/packages/eslint-config/react-internal.js (100%) rename templates/{monorepo-next => next-monorepo}/packages/typescript-config/README.md (100%) rename templates/{monorepo-next => next-monorepo}/packages/typescript-config/base.json (100%) rename templates/{monorepo-next => next-monorepo}/packages/typescript-config/nextjs.json (100%) rename templates/{monorepo-next => next-monorepo}/packages/typescript-config/package.json (100%) rename templates/{monorepo-next => next-monorepo}/packages/typescript-config/react-library.json (100%) rename templates/{monorepo-next => next-monorepo}/packages/ui/components.json (100%) rename templates/{monorepo-next => next-monorepo}/packages/ui/eslint.config.js (100%) rename templates/{monorepo-next => next-monorepo}/packages/ui/package.json (88%) rename templates/{monorepo-next => next-monorepo}/packages/ui/postcss.config.mjs (100%) create mode 100644 templates/next-monorepo/packages/ui/src/components/.gitkeep create mode 100644 templates/next-monorepo/packages/ui/src/hooks/.gitkeep create mode 100644 templates/next-monorepo/packages/ui/src/lib/.gitkeep rename templates/{monorepo-next => next-monorepo}/packages/ui/src/styles/globals.css (100%) rename templates/{monorepo-next => next-monorepo}/packages/ui/tsconfig.json (100%) rename templates/{monorepo-next => next-monorepo}/packages/ui/tsconfig.lint.json (100%) rename templates/{monorepo-next => next-monorepo}/pnpm-lock.yaml (100%) rename templates/{monorepo-next => next-monorepo}/pnpm-workspace.yaml (100%) rename templates/{monorepo-next => next-monorepo}/tsconfig.json (100%) rename templates/{monorepo-next => next-monorepo}/turbo.json (76%) create mode 100644 templates/start-app/.prettierrc delete mode 100644 templates/start-app/prettier.config.js create mode 100644 templates/start-app/src/lib/utils.ts create mode 100644 templates/vite-app/.prettierrc create mode 100644 templates/vite-app/src/components/theme-provider.tsx diff --git a/packages/shadcn/src/commands/add.ts b/packages/shadcn/src/commands/add.ts index e2cc919418..08726092e2 100644 --- a/packages/shadcn/src/commands/add.ts +++ b/packages/shadcn/src/commands/add.ts @@ -29,7 +29,6 @@ export const addOptionsSchema = z.object({ all: z.boolean(), path: z.string().optional(), silent: z.boolean(), - srcDir: z.boolean().optional(), cssVariables: z.boolean(), }) @@ -47,15 +46,6 @@ export const add = new Command() .option("-a, --all", "add all available components", false) .option("-p, --path ", "the path to add the component to.") .option("-s, --silent", "mute output.", false) - .option( - "--src-dir", - "use the src directory when creating a new project.", - false - ) - .option( - "--no-src-dir", - "do not use the src directory when creating a new project." - ) .option("--css-variables", "use css variables for theming.", true) .option("--no-css-variables", "do not use css variables for theming.") .action(async (components, opts) => { @@ -177,10 +167,8 @@ export const add = new Command() skipPreflight: false, silent: options.silent && !hasNewRegistries, isNewProject: false, - srcDir: options.srcDir, cssVariables: options.cssVariables, installStyleIndex: shouldInstallStyleIndex, - baseColor: shouldInstallStyleIndex ? undefined : "neutral", components: options.components, }) initHasRun = true @@ -192,7 +180,6 @@ export const add = new Command() const { projectPath, template } = await createProject({ cwd: options.cwd, force: options.overwrite, - srcDir: options.srcDir, components: options.components, }) if (!projectPath) { @@ -213,10 +200,8 @@ export const add = new Command() skipPreflight: true, silent: !hasNewRegistries && options.silent, isNewProject: true, - srcDir: options.srcDir, cssVariables: options.cssVariables, installStyleIndex: shouldInstallStyleIndex, - baseColor: shouldInstallStyleIndex ? undefined : "neutral", components: options.components, }) initHasRun = true diff --git a/packages/shadcn/src/commands/create.ts b/packages/shadcn/src/commands/create.ts index 7a1a6e6cb0..5b00f71e4a 100644 --- a/packages/shadcn/src/commands/create.ts +++ b/packages/shadcn/src/commands/create.ts @@ -2,6 +2,7 @@ import path from "path" import { getRegistryItems } from "@/src/registry/api" import { configWithDefaults } from "@/src/registry/config" import { clearRegistryContext } from "@/src/registry/context" +import { templates } from "@/src/templates/index" import { addComponents } from "@/src/utils/add-components" import { handleError } from "@/src/utils/handle-error" import { highlighter } from "@/src/utils/highlighter" @@ -12,7 +13,6 @@ import { handlePresetOption, } from "@/src/utils/presets" import { ensureRegistriesInConfig } from "@/src/utils/registries" -import { templates } from "@/src/utils/templates/index" import { updateFiles } from "@/src/utils/updaters/update-files" import { Command } from "commander" import open from "open" @@ -35,15 +35,6 @@ export const create = new Command() "the working directory. defaults to the current directory.", process.cwd() ) - .option( - "--src-dir", - "use the src directory when creating a new project.", - false - ) - .option( - "--no-src-dir", - "do not use the src directory when creating a new project." - ) .option("-y, --yes", "skip confirmation prompt.", true) .option("--rtl", "enable RTL support.", false) .action(async (name, opts) => { @@ -146,9 +137,8 @@ export const create = new Command() process.exit(0) } - // Determine initUrl and baseColor based on preset type. + // Determine initUrl based on preset type. let initUrl: string - let baseColor: string if ("_isUrl" in presetResult) { // User provided a URL directly. @@ -157,11 +147,9 @@ export const create = new Command() url.searchParams.set("rtl", "true") } initUrl = url.toString() - baseColor = url.searchParams.get("baseColor") ?? "neutral" } else { // User selected a preset by name. initUrl = buildInitUrl(presetResult, opts.rtl) - baseColor = presetResult.baseColor } // Fetch the registry:base item to get its config. @@ -192,11 +180,9 @@ export const create = new Command() force: false, silent: false, isNewProject: true, - srcDir: opts.srcDir, cssVariables: true, rtl: opts.rtl, template, - baseColor, installStyleIndex: false, registryBaseConfig, skipPreflight: false, @@ -215,10 +201,11 @@ export const create = new Command() overwrite: true, }) - const templateFiles = - templates[template as keyof typeof templates]?.files ?? [] - if (templateFiles.length > 0) { - await updateFiles(templateFiles, config, { + const selectedTemplate = + templates[template as keyof typeof templates] + + if (selectedTemplate?.files?.length) { + await updateFiles(selectedTemplate.files, config, { overwrite: true, silent: true, }) @@ -226,9 +213,7 @@ export const create = new Command() } logger.log( - `${highlighter.success( - "Success!" - )} Project initialization completed.\nYou may now add components.` + `Project initialization completed.\nYou may now add components.` ) logger.break() } catch (error) { diff --git a/packages/shadcn/src/commands/init.ts b/packages/shadcn/src/commands/init.ts index 4f63dfcf0e..d0ab72ee33 100644 --- a/packages/shadcn/src/commands/init.ts +++ b/packages/shadcn/src/commands/init.ts @@ -8,9 +8,10 @@ import { } from "@/src/registry/api" import { buildUrlAndHeadersForRegistryItem } from "@/src/registry/builder" import { configWithDefaults } from "@/src/registry/config" -import { BASE_COLORS, BUILTIN_REGISTRIES } from "@/src/registry/constants" +import { BUILTIN_REGISTRIES } from "@/src/registry/constants" import { clearRegistryContext } from "@/src/registry/context" import { rawConfigSchema } from "@/src/schema" +import { templates } from "@/src/templates/index" import { addComponents } from "@/src/utils/add-components" import { createProject } from "@/src/utils/create-project" import { loadEnvFiles } from "@/src/utils/env-loader" @@ -38,7 +39,6 @@ import { } from "@/src/utils/get-project-info" import { handleError } from "@/src/utils/handle-error" import { highlighter } from "@/src/utils/highlighter" -import { initMonorepoProject } from "@/src/utils/init-monorepo" import { logger } from "@/src/utils/logger" import { buildInitUrl, @@ -47,8 +47,6 @@ import { } from "@/src/utils/presets" import { ensureRegistriesInConfig } from "@/src/utils/registries" import { spinner } from "@/src/utils/spinner" -import { templates } from "@/src/utils/templates/index" -import { updateTailwindContent } from "@/src/utils/updaters/update-tailwind-content" import { Command } from "commander" import deepmerge from "deepmerge" import fsExtra from "fs-extra" @@ -78,7 +76,6 @@ export const initOptionsSchema = z.object({ force: z.boolean(), silent: z.boolean(), isNewProject: z.boolean(), - srcDir: z.boolean().optional(), cssVariables: z.boolean(), rtl: z.boolean().optional(), template: z @@ -96,23 +93,6 @@ export const initOptionsSchema = z.object({ "Invalid template. Please use 'next', 'vite', 'start' or 'next-monorepo'.", } ), - baseColor: z - .string() - .optional() - .refine( - (val) => { - if (val) { - return BASE_COLORS.find((color) => color.name === val) - } - - return true - }, - { - message: `Invalid base color. Please use '${BASE_COLORS.map( - (color) => color.name - ).join("', '")}'`, - } - ), installStyleIndex: z.boolean(), // Config from registry:base item to merge into components.json. registryBaseConfig: rawConfigSchema.deepPartial().optional(), @@ -126,40 +106,47 @@ export const init = new Command() "-t, --template