@dinachi/cli 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/index.js +390 -13
  2. package/package.json +12 -5
  3. package/templates/accordion/accordion.tsx +8 -3
  4. package/templates/alert-dialog/alert-dialog.tsx +24 -25
  5. package/templates/alert-dialog/index.ts +1 -1
  6. package/templates/autocomplete/autocomplete.tsx +0 -1
  7. package/templates/avatar/avatar.tsx +1 -3
  8. package/templates/badge/badge.tsx +167 -0
  9. package/templates/badge/index.ts +2 -0
  10. package/templates/button/button.tsx +6 -6
  11. package/templates/button/index.ts +2 -2
  12. package/templates/card/card.tsx +78 -0
  13. package/templates/card/index.ts +1 -0
  14. package/templates/checkbox/checkbox.tsx +2 -3
  15. package/templates/checkbox-group/checkbox-group.tsx +1 -3
  16. package/templates/collapsible/collapsible.tsx +1 -2
  17. package/templates/combobox/combobox.tsx +0 -1
  18. package/templates/context-menu/context-menu.tsx +0 -1
  19. package/templates/dialog/dialog.tsx +1 -1
  20. package/templates/drawer/drawer.tsx +0 -1
  21. package/templates/field/field.tsx +69 -85
  22. package/templates/fieldset/fieldset.tsx +0 -1
  23. package/templates/form/form.tsx +36 -28
  24. package/templates/input/index.ts +1 -2
  25. package/templates/input/input.tsx +0 -1
  26. package/templates/menu/menu.tsx +0 -1
  27. package/templates/menubar/menubar.tsx +21 -22
  28. package/templates/meter/meter.tsx +0 -1
  29. package/templates/navigation-menu/index.ts +1 -13
  30. package/templates/navigation-menu/navigation-menu.tsx +1 -3
  31. package/templates/number-field/number-field.tsx +0 -1
  32. package/templates/popover/popover.tsx +0 -1
  33. package/templates/preview-card/preview-card.tsx +0 -1
  34. package/templates/progress/progress.tsx +0 -1
  35. package/templates/radio/radio.tsx +0 -1
  36. package/templates/scroll-area/scroll-area.tsx +0 -1
  37. package/templates/select/select.tsx +1 -4
  38. package/templates/separator/separator.tsx +0 -1
  39. package/templates/slider/index.ts +10 -0
  40. package/templates/slider/slider.tsx +1 -3
  41. package/templates/switch/switch.tsx +0 -1
  42. package/templates/tabs/index.ts +8 -0
  43. package/templates/tabs/tabs.tsx +8 -3
  44. package/templates/textarea/index.ts +2 -0
  45. package/templates/textarea/textarea.tsx +23 -0
  46. package/templates/toast/toast.tsx +3 -2
  47. package/templates/toggle/toggle.tsx +0 -1
  48. package/templates/toggle-group/toggle-group.tsx +0 -1
  49. package/templates/toolbar/toolbar.tsx +0 -1
  50. package/templates/tooltip/tooltip.tsx +0 -1
  51. package/templates/tsconfig.json +20 -0
  52. package/templates/utils/utils.ts +0 -1
  53. package/templates/utils/variants.ts +0 -1
package/dist/index.js CHANGED
@@ -102,6 +102,13 @@ function getComponentRegistry() {
102
102
  dependencies: ["@base-ui/react", "class-variance-authority"],
103
103
  utilityDependencies: ["cn"]
104
104
  },
105
+ badge: {
106
+ name: "badge",
107
+ description: "A small status indicator for highlighting information.",
108
+ files: [{ name: "badge.tsx" }, { name: "index.ts" }],
109
+ dependencies: ["@base-ui/react", "class-variance-authority"],
110
+ utilityDependencies: ["cn"]
111
+ },
105
112
  button: {
106
113
  name: "button",
107
114
  description: "A customizable button component with multiple variants.",
@@ -109,6 +116,13 @@ function getComponentRegistry() {
109
116
  dependencies: ["@base-ui/react", "class-variance-authority"],
110
117
  utilityDependencies: ["cn", "variants"]
111
118
  },
119
+ card: {
120
+ name: "card",
121
+ description: "A container for grouping related content with header, body, and footer sections.",
122
+ files: [{ name: "card.tsx" }, { name: "index.ts" }],
123
+ dependencies: [],
124
+ utilityDependencies: ["cn"]
125
+ },
112
126
  checkbox: {
113
127
  name: "checkbox",
114
128
  description: "A control that allows the user to select one or more options from a set.",
@@ -292,6 +306,13 @@ function getComponentRegistry() {
292
306
  dependencies: ["@base-ui/react"],
293
307
  utilityDependencies: ["cn"]
294
308
  },
309
+ textarea: {
310
+ name: "textarea",
311
+ description: "A multi-line text input for longer form content.",
312
+ files: [{ name: "textarea.tsx" }, { name: "index.ts" }],
313
+ dependencies: [],
314
+ utilityDependencies: ["cn"]
315
+ },
295
316
  toast: {
296
317
  name: "toast",
297
318
  description: "Generates toast notifications with support for different types, promises, actions, and global management.",
@@ -647,6 +668,45 @@ ${withTrailingComma}
647
668
  `;
648
669
  return next;
649
670
  }
671
+ function detectTailwindMajorVersion(projectRoot) {
672
+ const packageJsonPath = path3.join(projectRoot, "package.json");
673
+ if (!fs3.existsSync(packageJsonPath)) return 4;
674
+ try {
675
+ const raw = fs3.readFileSync(packageJsonPath, "utf-8");
676
+ const packageJson = JSON.parse(raw);
677
+ const deps = { ...packageJson.dependencies ?? {}, ...packageJson.devDependencies ?? {} };
678
+ const twVersion = deps.tailwindcss;
679
+ if (!twVersion) return 4;
680
+ const match = twVersion.match(/(\d+)/);
681
+ return match ? parseInt(match[1], 10) : 4;
682
+ } catch {
683
+ return 4;
684
+ }
685
+ }
686
+ async function ensureTW4Plugin(deps, cssFilePath) {
687
+ if (!deps.includes("tailwindcss-animate")) {
688
+ return null;
689
+ }
690
+ if (!fs3.existsSync(cssFilePath)) {
691
+ return { skipped: true, path: cssFilePath };
692
+ }
693
+ const content = await fs3.readFile(cssFilePath, "utf-8");
694
+ if (content.includes("tailwindcss-animate")) {
695
+ return { exists: true, path: cssFilePath };
696
+ }
697
+ const pluginLine = '@plugin "tailwindcss-animate";';
698
+ const importMatch = content.match(/^@import\s+["']tailwindcss["'];?\s*$/m);
699
+ let updated;
700
+ if (importMatch) {
701
+ updated = content.replace(importMatch[0], `${importMatch[0].trimEnd()}
702
+ ${pluginLine}`);
703
+ } else {
704
+ updated = `${pluginLine}
705
+ ${content}`;
706
+ }
707
+ await fs3.writeFile(cssFilePath, updated);
708
+ return { updated: true, path: cssFilePath };
709
+ }
650
710
  async function ensureTailwindConfig(deps, projectRoot, configuredFileName) {
651
711
  if (!deps.includes("tailwindcss-animate")) {
652
712
  return null;
@@ -740,8 +800,8 @@ ${linesToAppend.join("\n")}
740
800
  await fs3.writeFile(targetPath, updatedContent);
741
801
  allFilesAdded.push({ name: "index.ts", path: path3.join(targetDir, "index.ts") });
742
802
  }
743
- var addCommand = new Command("add").description("Add a component to your project").argument("[component]", "Name of the component (optional when using --all)").option("-y, --yes", "Skip confirmation prompts").option("-o, --overwrite", "Overwrite existing files").option("-a, --all", "Install all available components").option("--skip-install", "Skip package installation").action(
744
- async (componentName, options) => {
803
+ var addCommand = new Command("add").description("Add a component to your project").argument("[components...]", "Names of the components to add (optional when using --all)").option("-y, --yes", "Skip confirmation prompts").option("-o, --overwrite", "Overwrite existing files").option("-a, --all", "Install all available components").option("--skip-install", "Skip package installation").action(
804
+ async (componentNames, options) => {
745
805
  const spinner = ora("Adding component...").start();
746
806
  try {
747
807
  const config = await getConfig();
@@ -764,7 +824,7 @@ var addCommand = new Command("add").description("Add a component to your project
764
824
  }
765
825
  componentsToInstall = Array.from(allComponentsWithDeps);
766
826
  } else {
767
- if (!componentName) {
827
+ if (componentNames.length === 0) {
768
828
  spinner.fail("\u274C Component name is required when not using --all flag.");
769
829
  console.log("Available components:");
770
830
  Object.keys(registry).forEach((name) => {
@@ -772,16 +832,23 @@ var addCommand = new Command("add").description("Add a component to your project
772
832
  });
773
833
  process.exit(1);
774
834
  }
775
- const component = registry[componentName];
776
- if (!component) {
777
- spinner.fail(`\u274C Component "${componentName}" not found.`);
778
- console.log("Available components:");
779
- Object.keys(registry).forEach((name) => {
780
- console.log(` ${chalk.cyan(name)}`);
781
- });
782
- process.exit(1);
835
+ for (const name of componentNames) {
836
+ if (!registry[name]) {
837
+ spinner.fail(`\u274C Component "${name}" not found.`);
838
+ console.log("Available components:");
839
+ Object.keys(registry).forEach((n) => {
840
+ console.log(` ${chalk.cyan(n)}`);
841
+ });
842
+ process.exit(1);
843
+ }
783
844
  }
784
- componentsToInstall = [componentName, ...getComponentDependencies(componentName)];
845
+ const allWithDeps = /* @__PURE__ */ new Set();
846
+ for (const name of componentNames) {
847
+ allWithDeps.add(name);
848
+ const deps = getComponentDependencies(name);
849
+ deps.forEach((dep) => allWithDeps.add(dep));
850
+ }
851
+ componentsToInstall = Array.from(allWithDeps);
785
852
  }
786
853
  if (!options.all) {
787
854
  spinner.text = `Installing ${componentsToInstall.join(", ")}...`;
@@ -847,7 +914,11 @@ var addCommand = new Command("add").description("Add a component to your project
847
914
  }
848
915
  }
849
916
  spinner.text = "Updating Tailwind configuration...";
850
- const tailwindConfigInfo = await ensureTailwindConfig(
917
+ const tailwindMajor = detectTailwindMajorVersion(projectRoot);
918
+ const tailwindConfigInfo = tailwindMajor >= 4 ? await ensureTW4Plugin(
919
+ allDepsInstalled,
920
+ path3.resolve(projectRoot, config.tailwind?.css || "src/index.css")
921
+ ) : await ensureTailwindConfig(
851
922
  allDepsInstalled,
852
923
  projectRoot,
853
924
  config.tailwind?.config || "tailwind.config.js"
@@ -946,6 +1017,287 @@ export function cn(...inputs: ClassValue[]) {
946
1017
  }
947
1018
  `;
948
1019
  }
1020
+ function detectTailwindMajorVersion2(projectRoot) {
1021
+ const packageJsonPath = path4.join(projectRoot, "package.json");
1022
+ if (!fs4.existsSync(packageJsonPath)) return 4;
1023
+ try {
1024
+ const raw = fs4.readFileSync(packageJsonPath, "utf-8");
1025
+ const packageJson = JSON.parse(raw);
1026
+ const deps = { ...packageJson.dependencies ?? {}, ...packageJson.devDependencies ?? {} };
1027
+ const twVersion = deps.tailwindcss;
1028
+ if (!twVersion) return 4;
1029
+ const match = twVersion.match(/(\d+)/);
1030
+ return match ? parseInt(match[1], 10) : 4;
1031
+ } catch {
1032
+ return 4;
1033
+ }
1034
+ }
1035
+ function getThemeCSS(tailwindMajor, mode) {
1036
+ const lightVars = `:root {
1037
+ --background: oklch(0.986 0.0034 145.5499);
1038
+ --foreground: oklch(0.1459 0.0497 142.4953);
1039
+ --card: oklch(0.9781 0.0017 145.5621);
1040
+ --card-foreground: oklch(0.1459 0.0497 142.4953);
1041
+ --popover: oklch(1 0 0);
1042
+ --popover-foreground: oklch(0.1324 0.0033 145.3864);
1043
+ --primary: oklch(0.1324 0.0033 145.3864);
1044
+ --primary-foreground: oklch(0.9729 0.0101 145.4971);
1045
+ --secondary: oklch(0.9248 0.0051 145.5339);
1046
+ --secondary-foreground: oklch(0.1324 0.0033 145.3864);
1047
+ --muted: oklch(0.9631 0.0017 145.5619);
1048
+ --muted-foreground: oklch(0.1849 0.0629 142.4953);
1049
+ --accent: oklch(0.9248 0.0051 145.5339);
1050
+ --accent-foreground: oklch(0.1459 0.0497 142.4953);
1051
+ --destructive: oklch(0.5248 0.1368 20.8317);
1052
+ --destructive-foreground: oklch(1 0 0);
1053
+ --border: oklch(0.9239 0.0017 145.5613);
1054
+ --input: oklch(0.8481 0.0105 145.4823);
1055
+ --ring: oklch(0.1459 0.0497 142.4953);
1056
+ --radius: 0.625rem;
1057
+ }`;
1058
+ const darkVars = `.dark {
1059
+ --background: oklch(0.1149 0 0);
1060
+ --foreground: oklch(0.7999 0.0218 134.1191);
1061
+ --card: oklch(0.133 0.0021 196.9098);
1062
+ --card-foreground: oklch(0.7996 0.023 132.5769);
1063
+ --popover: oklch(0.1663 0.0138 135.2766);
1064
+ --popover-foreground: oklch(0.9742 0.0101 131.3574);
1065
+ --primary: oklch(0.9729 0.0101 145.4971);
1066
+ --primary-foreground: oklch(0.1324 0.0033 145.3864);
1067
+ --secondary: oklch(0.1844 0.0062 122.0354);
1068
+ --secondary-foreground: oklch(0.8009 0.0399 133.2927);
1069
+ --muted: oklch(0.1579 0.0017 196.9874);
1070
+ --muted-foreground: oklch(0.7897 0.0171 133.8518);
1071
+ --accent: oklch(0.1391 0.0113 136.9894);
1072
+ --accent-foreground: oklch(0.9742 0.0101 131.3574);
1073
+ --destructive: oklch(0.2258 0.0524 12.6119);
1074
+ --destructive-foreground: oklch(1 0 0);
1075
+ --border: oklch(0.1811 0.0128 129.2819);
1076
+ --input: oklch(0.2213 0.0193 135.2915);
1077
+ --ring: oklch(0.9248 0.0051 145.5339);
1078
+ }`;
1079
+ const parts = [];
1080
+ if (tailwindMajor >= 4) {
1081
+ if (mode === "full") {
1082
+ parts.push('@import "tailwindcss";');
1083
+ }
1084
+ parts.push(lightVars, darkVars);
1085
+ parts.push(`@theme inline {
1086
+ --color-background: var(--background);
1087
+ --color-foreground: var(--foreground);
1088
+ --color-card: var(--card);
1089
+ --color-card-foreground: var(--card-foreground);
1090
+ --color-popover: var(--popover);
1091
+ --color-popover-foreground: var(--popover-foreground);
1092
+ --color-primary: var(--primary);
1093
+ --color-primary-foreground: var(--primary-foreground);
1094
+ --color-secondary: var(--secondary);
1095
+ --color-secondary-foreground: var(--secondary-foreground);
1096
+ --color-muted: var(--muted);
1097
+ --color-muted-foreground: var(--muted-foreground);
1098
+ --color-accent: var(--accent);
1099
+ --color-accent-foreground: var(--accent-foreground);
1100
+ --color-destructive: var(--destructive);
1101
+ --color-destructive-foreground: var(--destructive-foreground);
1102
+ --color-border: var(--border);
1103
+ --color-input: var(--input);
1104
+ --color-ring: var(--ring);
1105
+ --radius-sm: calc(var(--radius) - 4px);
1106
+ --radius-md: calc(var(--radius) - 2px);
1107
+ --radius-lg: var(--radius);
1108
+ --radius-xl: calc(var(--radius) + 4px);
1109
+ }`);
1110
+ parts.push(`@layer base {
1111
+ * {
1112
+ @apply border-border outline-ring/50;
1113
+ }
1114
+ body {
1115
+ @apply bg-background text-foreground;
1116
+ }
1117
+ }`);
1118
+ } else {
1119
+ if (mode === "full") {
1120
+ parts.push("@tailwind base;\n@tailwind components;\n@tailwind utilities;");
1121
+ }
1122
+ parts.push(lightVars, darkVars);
1123
+ parts.push(`@layer base {
1124
+ * {
1125
+ @apply border-border;
1126
+ }
1127
+ body {
1128
+ @apply bg-background text-foreground;
1129
+ }
1130
+ }`);
1131
+ }
1132
+ return parts.join("\n\n") + "\n";
1133
+ }
1134
+ function stripConflictingCSS(css) {
1135
+ let result = css;
1136
+ result = result.replace(/@media\s*\(\s*prefers-color-scheme\s*:\s*dark\s*\)\s*\{[\s\S]*?\n\}/g, "");
1137
+ result = result.replace(/:root\s*\{[^}]*\}/g, "");
1138
+ result = result.replace(/\.dark\s*\{[^}]*\}/g, "");
1139
+ result = result.replace(/@theme\s+inline\s*\{[^}]*\}/g, "");
1140
+ result = result.replace(/(?:^|\n)body\s*\{[^}]*\}/g, "");
1141
+ result = result.replace(/\n{3,}/g, "\n\n");
1142
+ return result.trim();
1143
+ }
1144
+ async function injectThemeCSS(cssFilePath, tailwindMajor) {
1145
+ await fs4.ensureDir(path4.dirname(cssFilePath));
1146
+ if (fs4.existsSync(cssFilePath)) {
1147
+ const existing = await fs4.readFile(cssFilePath, "utf-8");
1148
+ if (existing.includes("--primary:")) {
1149
+ return { path: cssFilePath, skipped: true };
1150
+ }
1151
+ const cleaned = stripConflictingCSS(existing);
1152
+ const theme2 = getThemeCSS(tailwindMajor, "append");
1153
+ const result = cleaned.length > 0 ? cleaned + "\n\n" + theme2 : getThemeCSS(tailwindMajor, "full");
1154
+ await fs4.writeFile(cssFilePath, result);
1155
+ return { path: cssFilePath, updated: true };
1156
+ }
1157
+ const theme = getThemeCSS(tailwindMajor, "full");
1158
+ await fs4.writeFile(cssFilePath, theme);
1159
+ return { path: cssFilePath, created: true };
1160
+ }
1161
+ function getTW3ColorExtend() {
1162
+ return `colors: {
1163
+ border: "var(--border)",
1164
+ input: "var(--input)",
1165
+ ring: "var(--ring)",
1166
+ background: "var(--background)",
1167
+ foreground: "var(--foreground)",
1168
+ primary: {
1169
+ DEFAULT: "var(--primary)",
1170
+ foreground: "var(--primary-foreground)",
1171
+ },
1172
+ secondary: {
1173
+ DEFAULT: "var(--secondary)",
1174
+ foreground: "var(--secondary-foreground)",
1175
+ },
1176
+ destructive: {
1177
+ DEFAULT: "var(--destructive)",
1178
+ foreground: "var(--destructive-foreground)",
1179
+ },
1180
+ muted: {
1181
+ DEFAULT: "var(--muted)",
1182
+ foreground: "var(--muted-foreground)",
1183
+ },
1184
+ accent: {
1185
+ DEFAULT: "var(--accent)",
1186
+ foreground: "var(--accent-foreground)",
1187
+ },
1188
+ popover: {
1189
+ DEFAULT: "var(--popover)",
1190
+ foreground: "var(--popover-foreground)",
1191
+ },
1192
+ card: {
1193
+ DEFAULT: "var(--card)",
1194
+ foreground: "var(--card-foreground)",
1195
+ },
1196
+ },
1197
+ borderRadius: {
1198
+ lg: "var(--radius)",
1199
+ md: "calc(var(--radius) - 2px)",
1200
+ sm: "calc(var(--radius) - 4px)",
1201
+ },`;
1202
+ }
1203
+ function createTW3Config(isCjs) {
1204
+ const colorExtend = getTW3ColorExtend();
1205
+ if (isCjs) {
1206
+ return `/** @type {import('tailwindcss').Config} */
1207
+ module.exports = {
1208
+ content: [
1209
+ "./src/**/*.{js,ts,jsx,tsx}",
1210
+ "./app/**/*.{js,ts,jsx,tsx}",
1211
+ "./components/**/*.{js,ts,jsx,tsx}",
1212
+ ],
1213
+ theme: {
1214
+ extend: {
1215
+ ${colorExtend}
1216
+ },
1217
+ },
1218
+ plugins: [],
1219
+ }
1220
+ `;
1221
+ }
1222
+ return `/** @type {import('tailwindcss').Config} */
1223
+ export default {
1224
+ content: [
1225
+ "./src/**/*.{js,ts,jsx,tsx}",
1226
+ "./app/**/*.{js,ts,jsx,tsx}",
1227
+ "./components/**/*.{js,ts,jsx,tsx}",
1228
+ ],
1229
+ theme: {
1230
+ extend: {
1231
+ ${colorExtend}
1232
+ },
1233
+ },
1234
+ plugins: [],
1235
+ }
1236
+ `;
1237
+ }
1238
+ async function ensureTW3ColorConfig(projectRoot, configFileName) {
1239
+ const candidates = [
1240
+ configFileName,
1241
+ "tailwind.config.ts",
1242
+ "tailwind.config.js",
1243
+ "tailwind.config.mjs",
1244
+ "tailwind.config.cjs"
1245
+ ];
1246
+ let configPath = null;
1247
+ for (const candidate of candidates) {
1248
+ const candidatePath = path4.join(projectRoot, candidate);
1249
+ if (fs4.existsSync(candidatePath)) {
1250
+ configPath = candidatePath;
1251
+ break;
1252
+ }
1253
+ }
1254
+ if (!configPath) {
1255
+ configPath = path4.join(projectRoot, configFileName);
1256
+ const ext = path4.extname(configPath);
1257
+ const isCjs = ext === ".cjs";
1258
+ await fs4.writeFile(configPath, createTW3Config(isCjs));
1259
+ return { path: configPath, created: true };
1260
+ }
1261
+ const content = await fs4.readFile(configPath, "utf-8");
1262
+ if (content.includes('"var(--primary)"') || content.includes("'var(--primary)'")) {
1263
+ return { path: configPath, skipped: true };
1264
+ }
1265
+ const colorExtend = getTW3ColorExtend();
1266
+ const extendMatch = content.match(/extend\s*:\s*\{/);
1267
+ if (extendMatch && extendMatch.index !== void 0) {
1268
+ const insertPos = extendMatch.index + extendMatch[0].length;
1269
+ const updated = content.slice(0, insertPos) + "\n " + colorExtend + content.slice(insertPos);
1270
+ await fs4.writeFile(configPath, updated);
1271
+ return { path: configPath, updated: true };
1272
+ }
1273
+ const themeMatch = content.match(/theme\s*:\s*\{/);
1274
+ if (themeMatch && themeMatch.index !== void 0) {
1275
+ const insertPos = themeMatch.index + themeMatch[0].length;
1276
+ const extendBlock = `
1277
+ extend: {
1278
+ ${colorExtend}
1279
+ },`;
1280
+ const updated = content.slice(0, insertPos) + extendBlock + content.slice(insertPos);
1281
+ await fs4.writeFile(configPath, updated);
1282
+ return { path: configPath, updated: true };
1283
+ }
1284
+ const closingBrace = content.lastIndexOf("}");
1285
+ if (closingBrace !== -1) {
1286
+ const before = content.slice(0, closingBrace).trimEnd();
1287
+ const needsComma = !before.endsWith(",") && !before.endsWith("{");
1288
+ const themeBlock = `${needsComma ? "," : ""}
1289
+ theme: {
1290
+ extend: {
1291
+ ${colorExtend}
1292
+ },
1293
+ },
1294
+ `;
1295
+ const updated = before + themeBlock + content.slice(closingBrace);
1296
+ await fs4.writeFile(configPath, updated);
1297
+ return { path: configPath, updated: true };
1298
+ }
1299
+ return { path: configPath, skipped: true };
1300
+ }
949
1301
  function readJsonConfig(filePath) {
950
1302
  try {
951
1303
  const content = fs4.readFileSync(filePath, "utf-8");
@@ -1041,6 +1393,15 @@ var initCommand = new Command2("init").description("Initialize Dinachi UI in you
1041
1393
  await fs4.ensureDir(utilsDirPath);
1042
1394
  const utilsContent = createUtilsFileContent();
1043
1395
  await fs4.writeFile(utilsFilePath, utilsContent);
1396
+ spinner.text = "Setting up color theme...";
1397
+ const tailwindMajor = detectTailwindMajorVersion2(projectRoot);
1398
+ const cssFilePath = path4.resolve(projectRoot, projectConfig.cssPath);
1399
+ const themeCSSResult = await injectThemeCSS(cssFilePath, tailwindMajor);
1400
+ let twColorConfigResult = null;
1401
+ if (tailwindMajor < 4) {
1402
+ spinner.text = "Configuring Tailwind color mappings...";
1403
+ twColorConfigResult = await ensureTW3ColorConfig(projectRoot, projectConfig.tailwindConfig);
1404
+ }
1044
1405
  spinner.text = "Installing dependencies...";
1045
1406
  const deps = ["class-variance-authority", "clsx", "tailwind-merge"];
1046
1407
  if (!options.skipInstall) {
@@ -1091,6 +1452,22 @@ var initCommand = new Command2("init").description("Initialize Dinachi UI in you
1091
1452
  ` ${chalk2.yellow("!")} Could not update ${aliasConfigUpdate.path}. Configure @/* manually if you use alias imports.`
1092
1453
  );
1093
1454
  }
1455
+ if (themeCSSResult.created) {
1456
+ console.log(` ${chalk2.green("+")} Created ${projectConfig.cssPath} with color theme (light + dark)`);
1457
+ } else if (themeCSSResult.updated) {
1458
+ console.log(` ${chalk2.blue("~")} Updated ${projectConfig.cssPath} with color theme (light + dark)`);
1459
+ } else if (themeCSSResult.skipped) {
1460
+ console.log(` ${chalk2.gray("-")} Color theme already configured in ${projectConfig.cssPath}`);
1461
+ }
1462
+ if (twColorConfigResult) {
1463
+ if (twColorConfigResult.created) {
1464
+ console.log(` ${chalk2.green("+")} Created ${projectConfig.tailwindConfig} with color mappings`);
1465
+ } else if (twColorConfigResult.updated) {
1466
+ console.log(` ${chalk2.blue("~")} Updated ${projectConfig.tailwindConfig} with color mappings`);
1467
+ } else if (twColorConfigResult.skipped) {
1468
+ console.log(` ${chalk2.gray("-")} Color mappings already in ${projectConfig.tailwindConfig}`);
1469
+ }
1470
+ }
1094
1471
  if (!projectConfig.isTypeScript) {
1095
1472
  console.log();
1096
1473
  console.log(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dinachi/cli",
3
- "version": "0.5.1",
3
+ "version": "0.6.1",
4
4
  "description": "CLI for adding Dinachi UI components to your project",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -27,18 +27,25 @@
27
27
  "templates"
28
28
  ],
29
29
  "dependencies": {
30
- "commander": "^14.0.2",
31
30
  "chalk": "^5.3.0",
32
- "ora": "^9.0.0",
33
- "prompts": "^2.4.2",
31
+ "commander": "^14.0.2",
32
+ "execa": "^9.6.1",
34
33
  "fs-extra": "^11.2.0",
35
34
  "node-fetch": "^3.3.2",
36
- "execa": "^9.6.1",
35
+ "ora": "^9.0.0",
36
+ "prompts": "^2.4.2",
37
37
  "ts-morph": "^27.0.2"
38
38
  },
39
39
  "devDependencies": {
40
+ "@base-ui/react": "1.2.0",
40
41
  "@types/fs-extra": "^11.0.4",
41
42
  "@types/prompts": "^2.4.9",
43
+ "@types/react": "^19.2.14",
44
+ "class-variance-authority": "^0.7.1",
45
+ "clsx": "^2.1.1",
46
+ "lucide-react": "0.552.0",
47
+ "react": "19.2.4",
48
+ "tailwind-merge": "^3.5.0",
42
49
  "tsup": "^8.0.1",
43
50
  "typescript": "^5.5.3"
44
51
  },
@@ -1,10 +1,15 @@
1
- // @ts-nocheck
2
1
  import * as React from "react";
3
2
  import { Accordion as BaseAccordion } from "@base-ui/react/accordion";
4
- import { cn } from "@/lib/utils"
3
+ import { cn } from "@/lib/utils";
5
4
  import { ChevronDown } from "lucide-react";
6
5
 
7
- const Accordion = BaseAccordion.Root;
6
+ const Accordion = React.forwardRef<
7
+ React.ComponentRef<typeof BaseAccordion.Root>,
8
+ React.ComponentProps<typeof BaseAccordion.Root>
9
+ >(({ className, ...props }, ref) => (
10
+ <BaseAccordion.Root ref={ref} className={cn(className)} {...props} />
11
+ ));
12
+ Accordion.displayName = "Accordion";
8
13
 
9
14
  const AccordionItem = React.forwardRef<
10
15
  HTMLDivElement,
@@ -1,9 +1,8 @@
1
- // @ts-nocheck
2
- import * as React from "react"
3
- import { AlertDialog as BaseAlertDialog } from "@base-ui/react"
4
- import { cn } from "@/lib/utils"
1
+ import * as React from "react";
2
+ import { AlertDialog as BaseAlertDialog } from "@base-ui/react";
3
+ import { cn } from "@/lib/utils";
5
4
 
6
- const AlertDialog = BaseAlertDialog.Root
5
+ const AlertDialog = BaseAlertDialog.Root;
7
6
 
8
7
  const AlertDialogTrigger = React.forwardRef<
9
8
  HTMLButtonElement,
@@ -21,10 +20,10 @@ const AlertDialogTrigger = React.forwardRef<
21
20
  )}
22
21
  {...props}
23
22
  />
24
- ))
25
- AlertDialogTrigger.displayName = "AlertDialogTrigger"
23
+ ));
24
+ AlertDialogTrigger.displayName = "AlertDialogTrigger";
26
25
 
27
- const AlertDialogPortal = BaseAlertDialog.Portal
26
+ const AlertDialogPortal = BaseAlertDialog.Portal;
28
27
 
29
28
  const AlertDialogBackdrop = React.forwardRef<
30
29
  HTMLDivElement,
@@ -40,8 +39,8 @@ const AlertDialogBackdrop = React.forwardRef<
40
39
  )}
41
40
  {...props}
42
41
  />
43
- ))
44
- AlertDialogBackdrop.displayName = "AlertDialogBackdrop"
42
+ ));
43
+ AlertDialogBackdrop.displayName = "AlertDialogBackdrop";
45
44
 
46
45
  const AlertDialogPopup = React.forwardRef<
47
46
  HTMLDivElement,
@@ -58,8 +57,8 @@ const AlertDialogPopup = React.forwardRef<
58
57
  )}
59
58
  {...props}
60
59
  />
61
- ))
62
- AlertDialogPopup.displayName = "AlertDialogPopup"
60
+ ));
61
+ AlertDialogPopup.displayName = "AlertDialogPopup";
63
62
 
64
63
  const AlertDialogTitle = React.forwardRef<
65
64
  HTMLHeadingElement,
@@ -70,8 +69,8 @@ const AlertDialogTitle = React.forwardRef<
70
69
  className={cn("text-lg font-semibold", className)}
71
70
  {...props}
72
71
  />
73
- ))
74
- AlertDialogTitle.displayName = "AlertDialogTitle"
72
+ ));
73
+ AlertDialogTitle.displayName = "AlertDialogTitle";
75
74
 
76
75
  const AlertDialogDescription = React.forwardRef<
77
76
  HTMLParagraphElement,
@@ -82,8 +81,8 @@ const AlertDialogDescription = React.forwardRef<
82
81
  className={cn("text-sm text-muted-foreground", className)}
83
82
  {...props}
84
83
  />
85
- ))
86
- AlertDialogDescription.displayName = "AlertDialogDescription"
84
+ ));
85
+ AlertDialogDescription.displayName = "AlertDialogDescription";
87
86
 
88
87
  const AlertDialogAction = React.forwardRef<
89
88
  HTMLButtonElement,
@@ -99,8 +98,8 @@ const AlertDialogAction = React.forwardRef<
99
98
  )}
100
99
  {...props}
101
100
  />
102
- ))
103
- AlertDialogAction.displayName = "AlertDialogAction"
101
+ ));
102
+ AlertDialogAction.displayName = "AlertDialogAction";
104
103
 
105
104
  const AlertDialogCancel = React.forwardRef<
106
105
  HTMLButtonElement,
@@ -116,8 +115,8 @@ const AlertDialogCancel = React.forwardRef<
116
115
  )}
117
116
  {...props}
118
117
  />
119
- ))
120
- AlertDialogCancel.displayName = "AlertDialogCancel"
118
+ ));
119
+ AlertDialogCancel.displayName = "AlertDialogCancel";
121
120
 
122
121
  const AlertDialogHeader = ({
123
122
  className,
@@ -130,8 +129,8 @@ const AlertDialogHeader = ({
130
129
  )}
131
130
  {...props}
132
131
  />
133
- )
134
- AlertDialogHeader.displayName = "AlertDialogHeader"
132
+ );
133
+ AlertDialogHeader.displayName = "AlertDialogHeader";
135
134
 
136
135
  const AlertDialogFooter = ({
137
136
  className,
@@ -144,8 +143,8 @@ const AlertDialogFooter = ({
144
143
  )}
145
144
  {...props}
146
145
  />
147
- )
148
- AlertDialogFooter.displayName = "AlertDialogFooter"
146
+ );
147
+ AlertDialogFooter.displayName = "AlertDialogFooter";
149
148
 
150
149
  export {
151
150
  AlertDialog,
@@ -159,4 +158,4 @@ export {
159
158
  AlertDialogCancel,
160
159
  AlertDialogHeader,
161
160
  AlertDialogFooter,
162
- }
161
+ };
@@ -10,4 +10,4 @@ export {
10
10
  AlertDialogCancel,
11
11
  AlertDialogHeader,
12
12
  AlertDialogFooter,
13
- } from "./alert-dialog"
13
+ } from "./alert-dialog";
@@ -1,4 +1,3 @@
1
- // @ts-nocheck
2
1
  "use client"
3
2
 
4
3
  import * as React from "react"
@@ -1,9 +1,7 @@
1
- // @ts-nocheck
2
1
  import * as React from "react";
3
2
  import { Avatar as BaseAvatar } from "@base-ui/react";
4
3
  import { cva, type VariantProps } from "class-variance-authority";
5
- import { cn } from "@/lib/utils"
6
-
4
+ import { cn } from "@/lib/utils";
7
5
 
8
6
  const avatarVariants = cva(
9
7
  "relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",