galaxy-design 0.2.73 → 0.2.74

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 (50) hide show
  1. package/README.md +113 -95
  2. package/dist/bin.js +17 -1
  3. package/dist/bin.js.map +1 -1
  4. package/dist/commands/add.js +59 -99
  5. package/dist/commands/add.js.map +1 -1
  6. package/dist/commands/init.js +120 -611
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/migrate-tailwind.js +90 -0
  9. package/dist/commands/migrate-tailwind.js.map +1 -0
  10. package/dist/index.js +6 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/registries/registry-angular.json +145 -537
  13. package/dist/registry-angular.json +145 -537
  14. package/dist/schemas/components-schema.json +66 -11
  15. package/dist/schemas/registry-framework-schema.json +17 -7
  16. package/dist/utils/angular-provider-manager.js +1 -1
  17. package/dist/utils/angular-provider-manager.js.map +1 -1
  18. package/dist/utils/component-copier.js +102 -62
  19. package/dist/utils/component-copier.js.map +1 -1
  20. package/dist/utils/component-transformer.js +86 -16
  21. package/dist/utils/component-transformer.js.map +1 -1
  22. package/dist/utils/config-schema.js +160 -9
  23. package/dist/utils/config-schema.js.map +1 -1
  24. package/dist/utils/framework-registry-service.js +181 -0
  25. package/dist/utils/framework-registry-service.js.map +1 -0
  26. package/dist/utils/framework-registry.js +1 -138
  27. package/dist/utils/framework-registry.js.map +1 -1
  28. package/dist/utils/github-fetcher.js +55 -27
  29. package/dist/utils/github-fetcher.js.map +1 -1
  30. package/dist/utils/index.js +4 -3
  31. package/dist/utils/index.js.map +1 -1
  32. package/dist/utils/init-runtime.js +477 -0
  33. package/dist/utils/init-runtime.js.map +1 -0
  34. package/dist/utils/init-scaffold.js +115 -0
  35. package/dist/utils/init-scaffold.js.map +1 -0
  36. package/dist/utils/init-workflow.js +189 -0
  37. package/dist/utils/init-workflow.js.map +1 -0
  38. package/dist/utils/package-manager.js +77 -2
  39. package/dist/utils/package-manager.js.map +1 -1
  40. package/dist/utils/platform-detector.js +12 -8
  41. package/dist/utils/platform-detector.js.map +1 -1
  42. package/dist/utils/registry-loader.js +20 -41
  43. package/dist/utils/registry-loader.js.map +1 -1
  44. package/dist/utils/tailwind-detector.js +162 -0
  45. package/dist/utils/tailwind-detector.js.map +1 -0
  46. package/dist/utils/tailwind-migration.js +401 -0
  47. package/dist/utils/tailwind-migration.js.map +1 -0
  48. package/dist/utils/tailwind-scaffold.js +398 -0
  49. package/dist/utils/tailwind-scaffold.js.map +1 -0
  50. package/package.json +20 -2
@@ -1,14 +1,12 @@
1
- import { _ as _extends } from "@swc/helpers/_/_extends";
2
1
  import prompts from 'prompts';
3
2
  import chalk from 'chalk';
4
3
  import ora from 'ora';
5
- import { detectFramework, detectPackageManager, hasSrcDirectory } from '../utils/detect.js';
6
- import { createComponentsConfig, hasComponentsConfig } from '../utils/components-config.js';
7
- import { getDefaultConfig } from '../utils/config-schema.js';
8
- import { writeFile, ensureDir } from '../utils/files.js';
4
+ import { applyInitPromptAnswers, detectExpoProject, ensureInitDirectories, getInitPromptQuestions, resolveInitProjectContext } from '../utils/init-workflow.js';
5
+ import { hasComponentsConfig, saveComponentsConfig } from '../utils/components-config.js';
9
6
  import { installDependencies } from '../utils/package-manager.js';
10
- import { resolve } from 'path';
11
- import { existsSync, readFileSync, writeFileSync } from 'fs';
7
+ import { configureProjectAliases, getUtilsTemplate, writeInitUtilityFile } from '../utils/init-scaffold.js';
8
+ import { scaffoldInitFrameworkRuntime } from '../utils/init-runtime.js';
9
+ import { getTailwindDevDependencies } from '../utils/tailwind-scaffold.js';
12
10
  export async function initCommand(options) {
13
11
  console.log(chalk.bold.cyan('\n🌌 Galaxy UI CLI - Multi-Framework Edition\n'));
14
12
  const cwd = options.cwd;
@@ -26,171 +24,42 @@ export async function initCommand(options) {
26
24
  return;
27
25
  }
28
26
  }
29
- // Detect framework
30
- const detectedFramework = detectFramework(cwd);
31
- if (detectedFramework === 'unknown') {
32
- console.log(chalk.red('āŒ Could not detect framework. Please ensure you are in a valid Angular, React, Vue, Next.js, Nuxt.js, React Native, or Flutter project.'));
27
+ let initContext;
28
+ try {
29
+ initContext = resolveInitProjectContext(cwd);
30
+ } catch (error) {
31
+ console.log(chalk.red(`āŒ ${error instanceof Error ? error.message : 'Failed to inspect project.'}`));
33
32
  return;
34
33
  }
34
+ const { detectedFramework, framework, packageManager, usesSrcDir, isExpoProject, tailwindDetection, tailwindMode } = initContext;
35
+ let config = initContext.config;
35
36
  console.log(chalk.green(`āœ“ Detected ${chalk.bold(detectedFramework)} framework`));
36
- // Map detected framework to Framework type
37
- const frameworkMap = {
38
- angular: 'angular',
39
- react: 'react',
40
- vue: 'vue',
41
- 'react-native': 'react-native',
42
- flutter: 'flutter',
43
- nextjs: 'nextjs',
44
- nuxtjs: 'nuxtjs',
45
- unknown: null
46
- };
47
- const framework = frameworkMap[detectedFramework];
48
- if (!framework) {
49
- console.log(chalk.red('āŒ Unsupported framework detected.'));
50
- return;
51
- }
52
- // Detect package manager
53
- const packageManager = detectPackageManager(cwd);
54
37
  console.log(chalk.green(`āœ“ Using ${chalk.bold(packageManager)} package manager`));
55
- // Get configuration from user (or use defaults with --yes)
56
- let config = getDefaultConfig(framework);
57
- // Detect if project uses src/ directory and adjust paths accordingly
58
- const usesSrcDir = hasSrcDirectory(cwd);
59
38
  if (usesSrcDir) {
60
39
  console.log(chalk.green(`āœ“ Detected ${chalk.bold('src/')} directory structure`));
61
40
  }
41
+ if (framework !== 'flutter') {
42
+ const tailwindSourceLabel = tailwindDetection.source === 'unknown' ? 'default' : tailwindDetection.source;
43
+ console.log(chalk.green(`āœ“ Tailwind mode: ${chalk.bold(tailwindMode)} ${chalk.gray(`(${tailwindSourceLabel})`)}`));
44
+ }
62
45
  if (!options.yes) {
63
46
  console.log(chalk.cyan('\nšŸ“ Configuration\n'));
64
- // Build prompts based on framework
65
- const promptQuestions = [];
66
- // TypeScript prompt (not for Flutter)
67
- if (framework !== 'flutter') {
68
- promptQuestions.push({
69
- type: 'toggle',
70
- name: 'typescript',
71
- message: 'Would you like to use TypeScript?',
72
- initial: true,
73
- active: 'yes',
74
- inactive: 'no'
75
- });
76
- }
77
- // Base color prompt (for all frameworks)
78
- promptQuestions.push({
79
- type: 'select',
80
- name: 'baseColor',
81
- message: 'Which base color would you like to use?',
82
- choices: [
83
- {
84
- title: 'Slate',
85
- value: 'slate'
86
- },
87
- {
88
- title: 'Gray',
89
- value: 'gray'
90
- },
91
- {
92
- title: 'Zinc',
93
- value: 'zinc'
94
- },
95
- {
96
- title: 'Neutral',
97
- value: 'neutral'
98
- },
99
- {
100
- title: 'Stone',
101
- value: 'stone'
102
- }
103
- ],
104
- initial: 0
105
- });
106
- // Icon library prompt (not for Flutter - uses built-in icons)
107
- if (framework !== 'flutter') {
108
- promptQuestions.push({
109
- type: 'select',
110
- name: 'iconLibrary',
111
- message: 'Which icon library would you like to use?',
112
- choices: [
113
- {
114
- title: 'Lucide (Recommended)',
115
- value: 'lucide'
116
- },
117
- {
118
- title: 'Heroicons',
119
- value: 'heroicons'
120
- },
121
- {
122
- title: 'Radix Icons',
123
- value: 'radix-icons'
124
- }
125
- ],
126
- initial: 0
127
- });
128
- }
129
- // CSS file prompt (only for web frameworks and React Native)
130
- if (framework !== 'flutter' && config.tailwind.css) {
131
- promptQuestions.push({
132
- type: 'text',
133
- name: 'cssFile',
134
- message: framework === 'react-native' ? 'Where is your global CSS file (for NativeWind)?' : 'Where is your global CSS file?',
135
- initial: config.tailwind.css
136
- });
137
- }
138
- const answers = await prompts(promptQuestions);
47
+ const answers = await prompts(getInitPromptQuestions(framework, config));
139
48
  if (Object.keys(answers).length === 0) {
140
49
  console.log(chalk.gray('Initialization cancelled.'));
141
50
  return;
142
51
  }
143
- var _answers_typescript, _answers_iconLibrary, _answers_baseColor, _answers_cssFile;
144
- // Update config with user choices
145
- config = _extends({}, config, {
146
- typescript: (_answers_typescript = answers.typescript) != null ? _answers_typescript : config.typescript,
147
- iconLibrary: (_answers_iconLibrary = answers.iconLibrary) != null ? _answers_iconLibrary : config.iconLibrary,
148
- tailwind: _extends({}, config.tailwind, {
149
- baseColor: (_answers_baseColor = answers.baseColor) != null ? _answers_baseColor : config.tailwind.baseColor,
150
- css: (_answers_cssFile = answers.cssFile) != null ? _answers_cssFile : config.tailwind.css
151
- })
152
- });
52
+ config = applyInitPromptAnswers(config, answers);
153
53
  }
154
54
  console.log(chalk.cyan('\nšŸ“¦ Installing dependencies...\n'));
155
55
  // Install dependencies
156
56
  const spinner = ora('Installing dependencies...').start();
157
- const dependencies = [];
158
- const devDependencies = [];
159
- // Common dependencies
160
- dependencies.push('clsx', 'tailwind-merge');
161
- // Framework-specific dependencies
162
- switch(framework){
163
- case 'vue':
164
- case 'nuxtjs':
165
- dependencies.push('radix-vue');
166
- devDependencies.push('tailwindcss@3.4.0', 'autoprefixer', 'postcss');
167
- if (config.iconLibrary === 'lucide') {
168
- dependencies.push('lucide-vue-next');
169
- }
170
- if (config.typescript) {
171
- devDependencies.push('@types/node');
172
- }
173
- break;
174
- case 'react':
175
- case 'nextjs':
176
- dependencies.push('@radix-ui/react-slot');
177
- devDependencies.push('tailwindcss@3.4.0', 'autoprefixer', 'postcss');
178
- if (config.iconLibrary === 'lucide') {
179
- dependencies.push('lucide-react');
180
- }
181
- if (config.typescript) {
182
- devDependencies.push('@types/react', '@types/react-dom', '@types/node');
183
- }
184
- break;
185
- case 'angular':
186
- // Angular components use Radix NG primitives
187
- dependencies.push('@radix-ng/primitives');
188
- devDependencies.push('tailwindcss@3.4.0', 'autoprefixer', 'postcss');
189
- if (config.iconLibrary === 'lucide') {
190
- dependencies.push('lucide-angular');
191
- }
192
- break;
193
- }
57
+ const { dependencies, devDependencies } = getInitDependencyPlan({
58
+ framework,
59
+ iconLibrary: config.iconLibrary,
60
+ typescript: config.typescript,
61
+ tailwindMode
62
+ });
194
63
  try {
195
64
  // Install dependencies
196
65
  if (dependencies.length > 0) {
@@ -216,26 +85,28 @@ export async function initCommand(options) {
216
85
  // Create directories
217
86
  const dirSpinner = ora('Creating directories...').start();
218
87
  try {
219
- const baseDir = usesSrcDir ? 'src/' : '';
220
- const componentsPath = resolve(cwd, baseDir + config.aliases.components.replace('@/', ''));
221
- const utilsPath = resolve(cwd, baseDir + config.aliases.utils.replace('@/', ''));
222
- await ensureDir(componentsPath);
223
- await ensureDir(resolve(componentsPath, 'ui'));
224
- await ensureDir(utilsPath.replace('/utils', '')); // Create lib dir
88
+ ensureInitDirectories(cwd, config, usesSrcDir);
225
89
  dirSpinner.succeed('Directories created');
226
90
  } catch (error) {
227
91
  dirSpinner.fail('Failed to create directories');
228
92
  console.error(chalk.red(error));
229
93
  return;
230
94
  }
231
- // Create utils file
232
- const utilsSpinner = ora('Creating utility functions...').start();
95
+ // Create utils file when the framework templates expect one
96
+ const utilsSpinner = ora('Preparing utility functions...').start();
233
97
  try {
234
- const baseDir = usesSrcDir ? 'src/' : '';
235
- const utilsPath = resolve(cwd, baseDir + config.aliases.utils.replace('@/', '') + '.ts');
236
- const utilsContent = getUtilsContent();
237
- writeFile(utilsPath, utilsContent);
238
- utilsSpinner.succeed('Utility functions created');
98
+ const didWriteUtils = writeInitUtilityFile({
99
+ cwd,
100
+ framework,
101
+ typescript: config.typescript,
102
+ usesSrcDir,
103
+ utilsAlias: config.aliases.utils
104
+ });
105
+ if (didWriteUtils) {
106
+ utilsSpinner.succeed('Utility functions created');
107
+ } else {
108
+ utilsSpinner.succeed('No utility file required for this framework');
109
+ }
239
110
  } catch (error) {
240
111
  utilsSpinner.fail('Failed to create utility functions');
241
112
  console.error(chalk.red(error));
@@ -244,41 +115,30 @@ export async function initCommand(options) {
244
115
  // Save components.json
245
116
  const configSpinner = ora('Creating components.json...').start();
246
117
  try {
247
- createComponentsConfig(cwd, framework);
118
+ saveComponentsConfig(cwd, config);
248
119
  configSpinner.succeed('components.json created');
249
120
  } catch (error) {
250
121
  configSpinner.fail('Failed to create components.json');
251
122
  console.error(chalk.red(error));
252
123
  return;
253
124
  }
254
- // Create Tailwind CSS configuration files (only for frameworks that use Tailwind)
255
125
  if (framework !== 'flutter') {
256
- const tailwindSpinner = ora('Creating Tailwind CSS configuration...').start();
257
- try {
258
- // Create tailwind.config.js
259
- const tailwindConfigPath = resolve(cwd, config.tailwind.config);
260
- const tailwindConfigContent = getTailwindConfigContent(framework);
261
- writeFile(tailwindConfigPath, tailwindConfigContent);
262
- // Create postcss.config.js
263
- const postcssConfigPath = resolve(cwd, 'postcss.config.js');
264
- const postcssConfigContent = getPostCSSConfigContent(framework);
265
- writeFile(postcssConfigPath, postcssConfigContent);
266
- tailwindSpinner.succeed('Tailwind CSS configuration created');
267
- } catch (error) {
268
- tailwindSpinner.fail('Failed to create Tailwind CSS configuration');
269
- console.error(chalk.red(error));
270
- return;
271
- }
272
- // Create or update CSS file with Tailwind directives
273
- const cssSpinner = ora('Setting up CSS file...').start();
126
+ const runtimeLabel = framework === 'react-native' ? 'Configuring React Native runtime...' : 'Creating Tailwind CSS configuration...';
127
+ const runtimeSpinner = ora(runtimeLabel).start();
274
128
  try {
275
- const baseDir = usesSrcDir ? 'src/' : '';
276
- const cssPath = resolve(cwd, baseDir + config.tailwind.css.replace('src/', ''));
277
- const cssContent = getCSSContent(config.tailwind.baseColor);
278
- writeFile(cssPath, cssContent);
279
- cssSpinner.succeed('CSS file configured');
129
+ const scaffoldResult = scaffoldInitFrameworkRuntime({
130
+ cwd,
131
+ framework,
132
+ tailwindMode,
133
+ cssPath: config.tailwind.css,
134
+ tailwindConfigPath: config.tailwind.config || 'tailwind.config.js',
135
+ baseColor: config.tailwind.baseColor,
136
+ usesSrcDir,
137
+ isExpoProject
138
+ });
139
+ runtimeSpinner.succeed(framework === 'react-native' ? `React Native runtime configured (${(scaffoldResult == null ? void 0 : scaffoldResult.written.length) || 0} written, ${(scaffoldResult == null ? void 0 : scaffoldResult.skipped.length) || 0} kept)` : `Tailwind CSS configuration created (${(scaffoldResult == null ? void 0 : scaffoldResult.written.length) || 0} written, ${(scaffoldResult == null ? void 0 : scaffoldResult.skipped.length) || 0} kept)`);
280
140
  } catch (error) {
281
- cssSpinner.fail('Failed to configure CSS file');
141
+ runtimeSpinner.fail(framework === 'react-native' ? 'Failed to configure React Native runtime' : 'Failed to create Tailwind CSS configuration');
282
142
  console.error(chalk.red(error));
283
143
  return;
284
144
  }
@@ -287,19 +147,12 @@ export async function initCommand(options) {
287
147
  if (config.typescript && framework !== 'flutter') {
288
148
  const aliasSpinner = ora('Configuring path aliases...').start();
289
149
  try {
290
- // Configure TypeScript path aliases
291
- if (framework === 'react' || framework === 'angular' || framework === 'vue') {
292
- // Vite React, Angular, and Vue use tsconfig.app.json
293
- configureTypeScriptAliases(cwd, 'tsconfig.app.json', usesSrcDir);
294
- } else if (framework === 'nextjs') {
295
- // Next.js uses tsconfig.json
296
- configureTypeScriptAliases(cwd, 'tsconfig.json', usesSrcDir);
297
- }
298
- // Configure bundler path aliases (only for Vite projects, not Next.js/Nuxt)
299
- if (framework === 'react' || framework === 'vue') {
300
- // Both React and Vue Vite projects use vite.config.ts
301
- configureViteAliases(cwd, 'vite.config.ts');
302
- }
150
+ configureProjectAliases({
151
+ cwd,
152
+ framework,
153
+ typescript: config.typescript,
154
+ usesSrcDir
155
+ });
303
156
  aliasSpinner.succeed('Path aliases configured');
304
157
  } catch (error) {
305
158
  aliasSpinner.fail('Failed to configure path aliases');
@@ -307,418 +160,74 @@ export async function initCommand(options) {
307
160
  // Don't return - this is not critical
308
161
  }
309
162
  }
310
- // Success message
311
163
  console.log(chalk.green('\n✨ Success! Galaxy UI has been initialized.\n'));
312
164
  console.log(chalk.cyan('Next steps:\n'));
313
- console.log(chalk.white(` 1. Add components:`));
314
- console.log(chalk.gray(` galaxy-design add button`));
315
- console.log(chalk.gray(` galaxy-design add input card`));
316
- console.log(chalk.gray(` galaxy-design add --all\n`));
165
+ console.log(chalk.white(' 1. Add components:'));
166
+ console.log(chalk.gray(' galaxy-design add button'));
167
+ console.log(chalk.gray(' galaxy-design add input card'));
168
+ console.log(chalk.gray(' galaxy-design add --all\n'));
169
+ if (framework === 'react-native') {
170
+ console.log(chalk.white(' 2. Confirm your React Native entry file keeps the generated global stylesheet import.'));
171
+ }
172
+ if (framework === 'flutter') {
173
+ console.log(chalk.white(' 2. Run `flutter pub get` if your project has pending Dart dependencies.'));
174
+ }
317
175
  console.log(chalk.cyan('Learn more:'));
318
176
  console.log(chalk.white(' Documentation: https://galaxy-design.vercel.app'));
319
177
  console.log(chalk.white(' GitHub: https://github.com/buikevin/galaxy-design\n'));
320
178
  }
321
- /**
322
- * Get utils.ts content
323
- */ function getUtilsContent() {
324
- return `import { clsx, type ClassValue } from 'clsx';
325
- import { twMerge } from 'tailwind-merge';
326
-
327
- /**
328
- * Merge Tailwind CSS classes
329
- */
330
- export function cn(...inputs: ClassValue[]) {
331
- return twMerge(clsx(inputs));
332
- }
333
- `;
334
- }
335
- /**
336
- * Get tailwind.config.js content
337
- */ function getTailwindConfigContent(framework) {
338
- const contentPaths = framework === 'react' || framework === 'nextjs' ? `[
339
- "./index.html",
340
- "./src/**/*.{js,ts,jsx,tsx}",
341
- ]` : framework === 'vue' || framework === 'nuxtjs' ? `[
342
- "./index.html",
343
- "./src/**/*.{vue,js,ts,jsx,tsx}",
344
- ]` : framework === 'angular' ? `[
345
- "./src/**/*.{html,ts}",
346
- "./src/components/**/*.{html,ts}",
347
- ]` : `[
348
- "./src/**/*.{js,ts,jsx,tsx,mdx}",
349
- ]`;
350
- // Angular uses CommonJS, other frameworks use ES modules
351
- const exportStatement = framework === 'angular' ? 'module.exports = ' : 'export default ';
352
- return `/** @type {import('tailwindcss').Config} */
353
- ${exportStatement}{
354
- darkMode: ["class"],
355
- content: ${contentPaths},
356
- theme: {
357
- extend: {
358
- colors: {
359
- border: "hsl(var(--border))",
360
- input: "hsl(var(--input))",
361
- ring: "hsl(var(--ring))",
362
- background: "hsl(var(--background))",
363
- foreground: "hsl(var(--foreground))",
364
- primary: {
365
- DEFAULT: "hsl(var(--primary))",
366
- foreground: "hsl(var(--primary-foreground))",
367
- },
368
- secondary: {
369
- DEFAULT: "hsl(var(--secondary))",
370
- foreground: "hsl(var(--secondary-foreground))",
371
- },
372
- destructive: {
373
- DEFAULT: "hsl(var(--destructive))",
374
- foreground: "hsl(var(--destructive-foreground))",
375
- },
376
- muted: {
377
- DEFAULT: "hsl(var(--muted))",
378
- foreground: "hsl(var(--muted-foreground))",
379
- },
380
- accent: {
381
- DEFAULT: "hsl(var(--accent))",
382
- foreground: "hsl(var(--accent-foreground))",
383
- },
384
- popover: {
385
- DEFAULT: "hsl(var(--popover))",
386
- foreground: "hsl(var(--popover-foreground))",
387
- },
388
- card: {
389
- DEFAULT: "hsl(var(--card))",
390
- foreground: "hsl(var(--card-foreground))",
391
- },
392
- },
393
- borderRadius: {
394
- lg: "var(--radius)",
395
- md: "calc(var(--radius) - 2px)",
396
- sm: "calc(var(--radius) - 4px)",
397
- },
398
- },
399
- },
400
- plugins: [],
401
- }
402
- `;
403
- }
404
- /**
405
- * Get postcss.config.js content
406
- */ function getPostCSSConfigContent(framework) {
407
- // Angular uses CommonJS, other frameworks use ES modules
408
- if (framework === 'angular') {
409
- return `module.exports = {
410
- plugins: {
411
- tailwindcss: {},
412
- autoprefixer: {},
413
- },
414
- }
415
- `;
179
+ export function getInitDependencyPlan(options) {
180
+ const { framework, iconLibrary, typescript, tailwindMode } = options;
181
+ const dependencies = [];
182
+ const devDependencies = [];
183
+ switch(framework){
184
+ case 'vue':
185
+ case 'nuxtjs':
186
+ dependencies.push('clsx', 'tailwind-merge', 'radix-vue');
187
+ devDependencies.push(...getTailwindDevDependencies(tailwindMode || 'v4'));
188
+ if (iconLibrary === 'lucide') {
189
+ dependencies.push('lucide-vue-next');
190
+ }
191
+ if (typescript) {
192
+ devDependencies.push('@types/node');
193
+ }
194
+ break;
195
+ case 'react':
196
+ case 'nextjs':
197
+ dependencies.push('clsx', 'tailwind-merge', '@radix-ui/react-slot');
198
+ devDependencies.push(...getTailwindDevDependencies(tailwindMode || 'v4'));
199
+ if (iconLibrary === 'lucide') {
200
+ dependencies.push('lucide-react');
201
+ }
202
+ if (typescript) {
203
+ devDependencies.push('@types/react', '@types/react-dom', '@types/node');
204
+ }
205
+ break;
206
+ case 'angular':
207
+ dependencies.push('clsx', 'tailwind-merge', '@radix-ng/primitives');
208
+ devDependencies.push(...getTailwindDevDependencies(tailwindMode || 'v4'));
209
+ if (iconLibrary === 'lucide') {
210
+ dependencies.push('lucide-angular');
211
+ }
212
+ break;
213
+ case 'react-native':
214
+ dependencies.push('clsx', 'class-variance-authority', 'nativewind');
215
+ devDependencies.push('tailwindcss@^3.4.0', 'babel-plugin-module-resolver');
216
+ break;
217
+ case 'flutter':
218
+ break;
416
219
  }
417
- return `export default {
418
- plugins: {
419
- tailwindcss: {},
420
- autoprefixer: {},
421
- },
422
- }
423
- `;
424
- }
425
- /**
426
- * Get CSS file content with Tailwind directives and CSS variables
427
- */ function getCSSContent(baseColor) {
428
- // CSS variables based on base color
429
- const colorVariables = {
430
- slate: {
431
- light: `--background: 0 0% 100%;
432
- --foreground: 222.2 84% 4.9%;
433
- --card: 0 0% 100%;
434
- --card-foreground: 222.2 84% 4.9%;
435
- --popover: 0 0% 100%;
436
- --popover-foreground: 222.2 84% 4.9%;
437
- --primary: 222.2 47.4% 11.2%;
438
- --primary-foreground: 210 40% 98%;
439
- --secondary: 210 40% 96.1%;
440
- --secondary-foreground: 222.2 47.4% 11.2%;
441
- --muted: 210 40% 96.1%;
442
- --muted-foreground: 215.4 16.3% 46.9%;
443
- --accent: 210 40% 96.1%;
444
- --accent-foreground: 222.2 47.4% 11.2%;
445
- --destructive: 0 84.2% 60.2%;
446
- --destructive-foreground: 210 40% 98%;
447
- --border: 214.3 31.8% 91.4%;
448
- --input: 214.3 31.8% 91.4%;
449
- --ring: 222.2 84% 4.9%;
450
- --radius: 0.5rem;`,
451
- dark: `--background: 222.2 84% 4.9%;
452
- --foreground: 210 40% 98%;
453
- --card: 222.2 84% 4.9%;
454
- --card-foreground: 210 40% 98%;
455
- --popover: 222.2 84% 4.9%;
456
- --popover-foreground: 210 40% 98%;
457
- --primary: 210 40% 98%;
458
- --primary-foreground: 222.2 47.4% 11.2%;
459
- --secondary: 217.2 32.6% 17.5%;
460
- --secondary-foreground: 210 40% 98%;
461
- --muted: 217.2 32.6% 17.5%;
462
- --muted-foreground: 215 20.2% 65.1%;
463
- --accent: 217.2 32.6% 17.5%;
464
- --accent-foreground: 210 40% 98%;
465
- --destructive: 0 62.8% 30.6%;
466
- --destructive-foreground: 210 40% 98%;
467
- --border: 217.2 32.6% 17.5%;
468
- --input: 217.2 32.6% 17.5%;
469
- --ring: 212.7 26.8% 83.9%;`
470
- },
471
- gray: {
472
- light: `--background: 0 0% 100%;
473
- --foreground: 224 71.4% 4.1%;
474
- --card: 0 0% 100%;
475
- --card-foreground: 224 71.4% 4.1%;
476
- --popover: 0 0% 100%;
477
- --popover-foreground: 224 71.4% 4.1%;
478
- --primary: 220.9 39.3% 11%;
479
- --primary-foreground: 210 20% 98%;
480
- --secondary: 220 14.3% 95.9%;
481
- --secondary-foreground: 220.9 39.3% 11%;
482
- --muted: 220 14.3% 95.9%;
483
- --muted-foreground: 220 8.9% 46.1%;
484
- --accent: 220 14.3% 95.9%;
485
- --accent-foreground: 220.9 39.3% 11%;
486
- --destructive: 0 84.2% 60.2%;
487
- --destructive-foreground: 210 20% 98%;
488
- --border: 220 13% 91%;
489
- --input: 220 13% 91%;
490
- --ring: 224 71.4% 4.1%;
491
- --radius: 0.5rem;`,
492
- dark: `--background: 224 71.4% 4.1%;
493
- --foreground: 210 20% 98%;
494
- --card: 224 71.4% 4.1%;
495
- --card-foreground: 210 20% 98%;
496
- --popover: 224 71.4% 4.1%;
497
- --popover-foreground: 210 20% 98%;
498
- --primary: 210 20% 98%;
499
- --primary-foreground: 220.9 39.3% 11%;
500
- --secondary: 215 27.9% 16.9%;
501
- --secondary-foreground: 210 20% 98%;
502
- --muted: 215 27.9% 16.9%;
503
- --muted-foreground: 217.9 10.6% 64.9%;
504
- --accent: 215 27.9% 16.9%;
505
- --accent-foreground: 210 20% 98%;
506
- --destructive: 0 62.8% 30.6%;
507
- --destructive-foreground: 210 20% 98%;
508
- --border: 215 27.9% 16.9%;
509
- --input: 215 27.9% 16.9%;
510
- --ring: 216 12.2% 83.9%;`
511
- },
512
- zinc: {
513
- light: `--background: 0 0% 100%;
514
- --foreground: 240 10% 3.9%;
515
- --card: 0 0% 100%;
516
- --card-foreground: 240 10% 3.9%;
517
- --popover: 0 0% 100%;
518
- --popover-foreground: 240 10% 3.9%;
519
- --primary: 240 5.9% 10%;
520
- --primary-foreground: 0 0% 98%;
521
- --secondary: 240 4.8% 95.9%;
522
- --secondary-foreground: 240 5.9% 10%;
523
- --muted: 240 4.8% 95.9%;
524
- --muted-foreground: 240 3.8% 46.1%;
525
- --accent: 240 4.8% 95.9%;
526
- --accent-foreground: 240 5.9% 10%;
527
- --destructive: 0 84.2% 60.2%;
528
- --destructive-foreground: 0 0% 98%;
529
- --border: 240 5.9% 90%;
530
- --input: 240 5.9% 90%;
531
- --ring: 240 10% 3.9%;
532
- --radius: 0.5rem;`,
533
- dark: `--background: 240 10% 3.9%;
534
- --foreground: 0 0% 98%;
535
- --card: 240 10% 3.9%;
536
- --card-foreground: 0 0% 98%;
537
- --popover: 240 10% 3.9%;
538
- --popover-foreground: 0 0% 98%;
539
- --primary: 0 0% 98%;
540
- --primary-foreground: 240 5.9% 10%;
541
- --secondary: 240 3.7% 15.9%;
542
- --secondary-foreground: 0 0% 98%;
543
- --muted: 240 3.7% 15.9%;
544
- --muted-foreground: 240 5% 64.9%;
545
- --accent: 240 3.7% 15.9%;
546
- --accent-foreground: 0 0% 98%;
547
- --destructive: 0 62.8% 30.6%;
548
- --destructive-foreground: 0 0% 98%;
549
- --border: 240 3.7% 15.9%;
550
- --input: 240 3.7% 15.9%;
551
- --ring: 240 4.9% 83.9%;`
552
- },
553
- neutral: {
554
- light: `--background: 0 0% 100%;
555
- --foreground: 0 0% 3.9%;
556
- --card: 0 0% 100%;
557
- --card-foreground: 0 0% 3.9%;
558
- --popover: 0 0% 100%;
559
- --popover-foreground: 0 0% 3.9%;
560
- --primary: 0 0% 9%;
561
- --primary-foreground: 0 0% 98%;
562
- --secondary: 0 0% 96.1%;
563
- --secondary-foreground: 0 0% 9%;
564
- --muted: 0 0% 96.1%;
565
- --muted-foreground: 0 0% 45.1%;
566
- --accent: 0 0% 96.1%;
567
- --accent-foreground: 0 0% 9%;
568
- --destructive: 0 84.2% 60.2%;
569
- --destructive-foreground: 0 0% 98%;
570
- --border: 0 0% 89.8%;
571
- --input: 0 0% 89.8%;
572
- --ring: 0 0% 3.9%;
573
- --radius: 0.5rem;`,
574
- dark: `--background: 0 0% 3.9%;
575
- --foreground: 0 0% 98%;
576
- --card: 0 0% 3.9%;
577
- --card-foreground: 0 0% 98%;
578
- --popover: 0 0% 3.9%;
579
- --popover-foreground: 0 0% 98%;
580
- --primary: 0 0% 98%;
581
- --primary-foreground: 0 0% 9%;
582
- --secondary: 0 0% 14.9%;
583
- --secondary-foreground: 0 0% 98%;
584
- --muted: 0 0% 14.9%;
585
- --muted-foreground: 0 0% 63.9%;
586
- --accent: 0 0% 14.9%;
587
- --accent-foreground: 0 0% 98%;
588
- --destructive: 0 62.8% 30.6%;
589
- --destructive-foreground: 0 0% 98%;
590
- --border: 0 0% 14.9%;
591
- --input: 0 0% 14.9%;
592
- --ring: 0 0% 83.1%;`
593
- },
594
- stone: {
595
- light: `--background: 0 0% 100%;
596
- --foreground: 20 14.3% 4.1%;
597
- --card: 0 0% 100%;
598
- --card-foreground: 20 14.3% 4.1%;
599
- --popover: 0 0% 100%;
600
- --popover-foreground: 20 14.3% 4.1%;
601
- --primary: 24 9.8% 10%;
602
- --primary-foreground: 60 9.1% 97.8%;
603
- --secondary: 60 4.8% 95.9%;
604
- --secondary-foreground: 24 9.8% 10%;
605
- --muted: 60 4.8% 95.9%;
606
- --muted-foreground: 25 5.3% 44.7%;
607
- --accent: 60 4.8% 95.9%;
608
- --accent-foreground: 24 9.8% 10%;
609
- --destructive: 0 84.2% 60.2%;
610
- --destructive-foreground: 60 9.1% 97.8%;
611
- --border: 20 5.9% 90%;
612
- --input: 20 5.9% 90%;
613
- --ring: 20 14.3% 4.1%;
614
- --radius: 0.5rem;`,
615
- dark: `--background: 20 14.3% 4.1%;
616
- --foreground: 60 9.1% 97.8%;
617
- --card: 20 14.3% 4.1%;
618
- --card-foreground: 60 9.1% 97.8%;
619
- --popover: 20 14.3% 4.1%;
620
- --popover-foreground: 60 9.1% 97.8%;
621
- --primary: 60 9.1% 97.8%;
622
- --primary-foreground: 24 9.8% 10%;
623
- --secondary: 12 6.5% 15.1%;
624
- --secondary-foreground: 60 9.1% 97.8%;
625
- --muted: 12 6.5% 15.1%;
626
- --muted-foreground: 24 5.4% 63.9%;
627
- --accent: 12 6.5% 15.1%;
628
- --accent-foreground: 60 9.1% 97.8%;
629
- --destructive: 0 62.8% 30.6%;
630
- --destructive-foreground: 60 9.1% 97.8%;
631
- --border: 12 6.5% 15.1%;
632
- --input: 12 6.5% 15.1%;
633
- --ring: 24 5.7% 82.9%;`
634
- }
220
+ return {
221
+ dependencies: [
222
+ ...new Set(dependencies)
223
+ ],
224
+ devDependencies: [
225
+ ...new Set(devDependencies)
226
+ ]
635
227
  };
636
- const colors = colorVariables[baseColor];
637
- return `@tailwind base;
638
- @tailwind components;
639
- @tailwind utilities;
640
-
641
- @layer base {
642
- :root {
643
- ${colors.light}
644
- }
645
-
646
- .dark {
647
- ${colors.dark}
648
- }
649
- }
650
-
651
- @layer base {
652
- * {
653
- @apply border-border;
654
- }
655
- body {
656
- @apply bg-background text-foreground;
657
- }
658
- }
659
- `;
660
- }
661
- /**
662
- * Configure TypeScript path aliases in tsconfig
663
- */ function configureTypeScriptAliases(cwd, tsconfigFile, usesSrcDir) {
664
- const tsconfigPath = resolve(cwd, tsconfigFile);
665
- if (!existsSync(tsconfigPath)) {
666
- return;
667
- }
668
- try {
669
- let content = readFileSync(tsconfigPath, 'utf-8');
670
- // Determine the correct path based on project structure
671
- const pathMapping = usesSrcDir ? './src/*' : './*';
672
- // Simple check: if "paths" already exists anywhere in the file, skip
673
- // This prevents duplicates for frameworks like Next.js that pre-configure paths
674
- if (content.includes('"paths"')) {
675
- return; // Paths already configured, skip to avoid duplicates
676
- }
677
- // Find the position to insert path aliases
678
- const compilerOptionsMatch = content.match(/"compilerOptions"\s*:\s*{/);
679
- if (!compilerOptionsMatch) {
680
- throw new Error('compilerOptions not found');
681
- }
682
- // Strategy: Insert before the closing } of compilerOptions
683
- // Match the closing brace of compilerOptions followed by next root property
684
- const insertPattern = /(\n)(\s*)(}\s*,?\s*\n\s*"(?:include|exclude|files|references))/;
685
- const match = content.match(insertPattern);
686
- if (match) {
687
- // Detect indent level from the closing brace
688
- const baseIndent = match[2] || ' ';
689
- const propertyIndent = baseIndent + ' ';
690
- // Insert path config before the closing brace
691
- const pathConfig = `,${match[1]}${propertyIndent}/* Path Aliases */${match[1]}${propertyIndent}"baseUrl": ".",${match[1]}${propertyIndent}"paths": {${match[1]}${propertyIndent} "@/*": ["${pathMapping}"]${match[1]}${propertyIndent}}`;
692
- content = content.replace(insertPattern, `${pathConfig}${match[1]}${match[2]}${match[3]}`);
693
- writeFileSync(tsconfigPath, content, 'utf-8');
694
- }
695
- } catch (error) {
696
- // Silently fail - path aliases are not critical
697
- }
698
- }
699
- /**
700
- * Configure Vite path aliases in vite.config
701
- */ function configureViteAliases(cwd, viteConfigFile) {
702
- const viteConfigPath = resolve(cwd, viteConfigFile);
703
- if (!existsSync(viteConfigPath)) {
704
- return;
705
- }
706
- try {
707
- let content = readFileSync(viteConfigPath, 'utf-8');
708
- // Check if path is already imported
709
- if (!content.includes("import path from 'path'") && !content.includes('import path from "path"')) {
710
- // Add path import after the first import line
711
- content = content.replace(/(import .+ from .+\n)/, "$1import path from 'path'\n");
712
- }
713
- // Check if resolve.alias is already configured
714
- if (!content.includes('resolve:') && !content.includes('@:')) {
715
- // Add resolve.alias configuration
716
- content = content.replace(RegExp("(plugins: \\[.+\\],?)", "s"), `$1\n resolve: {\n alias: {\n '@': path.resolve(__dirname, './src'),\n },\n },`);
717
- }
718
- writeFileSync(viteConfigPath, content, 'utf-8');
719
- } catch (error) {
720
- console.error(chalk.yellow(`Warning: Could not update ${viteConfigFile}`));
721
- }
722
228
  }
229
+ export { detectExpoProject };
230
+ export { configureReactNativeRuntime } from '../utils/init-runtime.js';
231
+ export { getUtilsTemplate };
723
232
 
724
233
  //# sourceMappingURL=init.js.map