@gilav21/shadcn-angular 0.0.5 → 0.0.7

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.
@@ -55,7 +55,7 @@ export async function add(components, options) {
55
55
  const config = await getConfig(cwd);
56
56
  if (!config) {
57
57
  console.log(chalk.red('Error: components.json not found.'));
58
- console.log(chalk.dim('Run `npx shadcn-angular init` first.'));
58
+ console.log(chalk.dim('Run `npx @gilav21/shadcn-angular init` first.'));
59
59
  process.exit(1);
60
60
  }
61
61
  // Get components to add
@@ -75,7 +75,7 @@ export async function init(options) {
75
75
  {
76
76
  type: 'text',
77
77
  name: 'globalCss',
78
- message: 'Where is your global CSS file?',
78
+ message: 'Where is your global styles file?',
79
79
  initial: 'src/styles.scss',
80
80
  },
81
81
  ]);
@@ -111,14 +111,23 @@ export async function init(options) {
111
111
  await fs.ensureDir(utilsDir);
112
112
  await fs.writeFile(path.join(cwd, utilsPathResolved + '.ts'), getUtilsTemplate());
113
113
  spinner.text = 'Created utils.ts';
114
- // Create/update styles file
115
- const stylesPath = path.join(cwd, config.tailwind.css);
116
- const existingStyles = await fs.pathExists(stylesPath)
117
- ? await fs.readFile(stylesPath, 'utf-8')
114
+ // Create tailwind.css file in the same directory as the global styles
115
+ const stylesDir = path.dirname(path.join(cwd, config.tailwind.css));
116
+ const tailwindCssPath = path.join(stylesDir, 'tailwind.css');
117
+ // Write the tailwind.css file with all Tailwind directives
118
+ await fs.writeFile(tailwindCssPath, getStylesTemplate(config.tailwind.baseColor));
119
+ spinner.text = 'Created tailwind.css';
120
+ // Add import to the user's global styles file if not already present
121
+ const userStylesPath = path.join(cwd, config.tailwind.css);
122
+ let userStyles = await fs.pathExists(userStylesPath)
123
+ ? await fs.readFile(userStylesPath, 'utf-8')
118
124
  : '';
119
- if (!existingStyles.includes('--background:')) {
120
- await fs.writeFile(stylesPath, getStylesTemplate(config.tailwind.baseColor) + '\n' + existingStyles);
121
- spinner.text = 'Updated styles with theme variables';
125
+ const tailwindImport = '@import "./tailwind.css";';
126
+ if (!userStyles.includes('tailwind.css')) {
127
+ // Add import at the top of the file
128
+ userStyles = tailwindImport + '\n\n' + userStyles;
129
+ await fs.writeFile(userStylesPath, userStyles);
130
+ spinner.text = 'Added tailwind.css import to styles';
122
131
  }
123
132
  // Create components/ui directory
124
133
  const uiPathResolved = config.aliases.ui.replace('@/', 'src/');
@@ -131,54 +140,26 @@ export async function init(options) {
131
140
  'clsx',
132
141
  'tailwind-merge',
133
142
  'class-variance-authority',
134
- '@angular/cdk',
135
143
  'lucide-angular',
136
144
  'tailwindcss',
137
145
  'postcss',
138
146
  '@tailwindcss/postcss'
139
147
  ];
140
148
  await execa('npm', ['install', ...dependencies], { cwd });
141
- // Setup PostCSS
149
+ // Setup PostCSS - create .postcssrc.json which is the preferred format for Angular
142
150
  spinner.text = 'Configuring PostCSS...';
143
- const postcssConfigPath = path.join(cwd, 'postcss.config.js');
144
- const postcssConfigMjsPath = path.join(cwd, 'postcss.config.mjs');
145
- if (await fs.pathExists(postcssConfigMjsPath)) {
146
- // Check mjs config
147
- const content = await fs.readFile(postcssConfigMjsPath, 'utf-8');
148
- if (!content.includes('@tailwindcss/postcss')) {
149
- // Very basic append attempt for mjs, safest is to warn or skip complex types
150
- // But user asked to try.
151
- // If it's a simple export default { plugins: {} }, we can try to inject.
152
- // For now, let's just log a warning if we can't safely inject
153
- console.log(chalk.yellow('\nComputed postcss.config.mjs found. Please manually add "@tailwindcss/postcss" to your plugins.'));
154
- }
155
- }
156
- else if (await fs.pathExists(postcssConfigPath)) {
157
- let content = await fs.readFile(postcssConfigPath, 'utf-8');
158
- if (!content.includes('@tailwindcss/postcss')) {
159
- // Try to inject into plugins object
160
- if (content.includes('plugins: {')) {
161
- content = content.replace('plugins: {', 'plugins: {\n \'@tailwindcss/postcss\': {},');
162
- await fs.writeFile(postcssConfigPath, content);
163
- }
164
- else {
165
- console.log(chalk.yellow('\nExisting postcss.config.js found but structure not recognized. Please manually add "@tailwindcss/postcss" to your plugins.'));
151
+ const postcssrcPath = path.join(cwd, '.postcssrc.json');
152
+ if (!await fs.pathExists(postcssrcPath)) {
153
+ const configContent = {
154
+ plugins: {
155
+ '@tailwindcss/postcss': {}
166
156
  }
167
- }
168
- }
169
- else {
170
- // Create new config
171
- const configContent = `module.exports = {
172
- plugins: {
173
- '@tailwindcss/postcss': {},
174
- },
175
- }
176
- `;
177
- await fs.writeFile(postcssConfigPath, configContent);
157
+ };
158
+ await fs.writeJson(postcssrcPath, configContent, { spaces: 4 });
178
159
  }
179
160
  spinner.succeed(chalk.green('Project initialized successfully!'));
180
161
  console.log('\n' + chalk.bold('Next steps:'));
181
- console.log(chalk.dim(' 1. Add components: ') + chalk.cyan('npx shadcn-angular add button'));
162
+ console.log(chalk.dim(' 1. Add components: ') + chalk.cyan('npx @gilav21/shadcn-angular add button'));
182
163
  console.log(chalk.dim(' 2. Import and use in your templates'));
183
164
  console.log(chalk.dim(' 3. Update your ') + chalk.bold('tsconfig.json') + chalk.dim(' paths:'));
184
165
  console.log(chalk.dim(' "compilerOptions": {'));
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ const program = new Command();
6
6
  program
7
7
  .name('shadcn-angular')
8
8
  .description('CLI for adding shadcn-angular components to your Angular project')
9
- .version('0.0.1');
9
+ .version('0.0.6');
10
10
  program
11
11
  .command('init')
12
12
  .description('Initialize shadcn-angular in your project')
@@ -38,10 +38,12 @@ export const registry = {
38
38
  'button-group': {
39
39
  name: 'button-group',
40
40
  files: ['button-group.component.ts'],
41
+ dependencies: ['button']
41
42
  },
42
43
  calendar: {
43
44
  name: 'calendar',
44
- files: ['calendar.component.ts'],
45
+ files: ['calendar.component.ts', 'calendar-locales.ts'],
46
+ dependencies: ['button', 'select'],
45
47
  },
46
48
  card: {
47
49
  name: 'card',
@@ -213,4 +215,9 @@ export const registry = {
213
215
  name: 'tooltip',
214
216
  files: ['tooltip.component.ts'],
215
217
  },
218
+ 'speed-dial': {
219
+ name: 'speed-dial',
220
+ files: ['speed-dial.component.ts'],
221
+ dependencies: ['button']
222
+ },
216
223
  };
@@ -219,6 +219,10 @@ export function getStylesTemplate(baseColor = 'neutral') {
219
219
  const colors = baseColors[baseColor];
220
220
  return `@import "tailwindcss";
221
221
 
222
+ /* Tell Tailwind v4 where to scan for classes */
223
+ @source "../src/**/*.ts";
224
+ @source "../src/**/*.html";
225
+
222
226
  @custom-variant dark (&:is(.dark *));
223
227
 
224
228
  :root {
@@ -257,7 +261,7 @@ ${generateCssVars(colors.dark)}
257
261
  }
258
262
 
259
263
  @theme inline {
260
- --font-sans: system-ui, sans-serif;
264
+ --font-sans: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
261
265
  --color-background: var(--background);
262
266
  --color-foreground: var(--foreground);
263
267
  --color-card: var(--card);
@@ -300,13 +304,16 @@ ${generateCssVars(colors.dark)}
300
304
 
301
305
  @layer base {
302
306
  * {
303
- @apply border-border outline-ring/50;
307
+ border-color: var(--border);
308
+ outline-color: color-mix(in oklch, var(--ring) 50%, transparent);
304
309
  }
305
310
  body {
306
- @apply font-sans bg-background text-foreground;
311
+ font-family: var(--font-sans);
312
+ background-color: var(--background);
313
+ color: var(--foreground);
307
314
  }
308
315
  html {
309
- @apply font-sans;
316
+ font-family: var(--font-sans);
310
317
  }
311
318
  button:not(:disabled),
312
319
  [role="button"]:not(:disabled) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gilav21/shadcn-angular",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "CLI for adding shadcn-angular components to your project",
5
5
  "bin": {
6
6
  "shadcn-angular": "./dist/index.js"
@@ -32,4 +32,4 @@
32
32
  "@types/prompts": "^2.4.9",
33
33
  "typescript": "^5.5.0"
34
34
  }
35
- }
35
+ }
@@ -70,7 +70,7 @@ export async function add(components: string[], options: AddOptions) {
70
70
  const config = await getConfig(cwd);
71
71
  if (!config) {
72
72
  console.log(chalk.red('Error: components.json not found.'));
73
- console.log(chalk.dim('Run `npx shadcn-angular init` first.'));
73
+ console.log(chalk.dim('Run `npx @gilav21/shadcn-angular init` first.'));
74
74
  process.exit(1);
75
75
  }
76
76
 
@@ -85,7 +85,7 @@ export async function init(options: InitOptions) {
85
85
  {
86
86
  type: 'text',
87
87
  name: 'globalCss',
88
- message: 'Where is your global CSS file?',
88
+ message: 'Where is your global styles file?',
89
89
  initial: 'src/styles.scss',
90
90
  },
91
91
  ]);
@@ -128,15 +128,26 @@ export async function init(options: InitOptions) {
128
128
  await fs.writeFile(path.join(cwd, utilsPathResolved + '.ts'), getUtilsTemplate());
129
129
  spinner.text = 'Created utils.ts';
130
130
 
131
- // Create/update styles file
132
- const stylesPath = path.join(cwd, config.tailwind.css);
133
- const existingStyles = await fs.pathExists(stylesPath)
134
- ? await fs.readFile(stylesPath, 'utf-8')
131
+ // Create tailwind.css file in the same directory as the global styles
132
+ const stylesDir = path.dirname(path.join(cwd, config.tailwind.css));
133
+ const tailwindCssPath = path.join(stylesDir, 'tailwind.css');
134
+
135
+ // Write the tailwind.css file with all Tailwind directives
136
+ await fs.writeFile(tailwindCssPath, getStylesTemplate(config.tailwind.baseColor));
137
+ spinner.text = 'Created tailwind.css';
138
+
139
+ // Add import to the user's global styles file if not already present
140
+ const userStylesPath = path.join(cwd, config.tailwind.css);
141
+ let userStyles = await fs.pathExists(userStylesPath)
142
+ ? await fs.readFile(userStylesPath, 'utf-8')
135
143
  : '';
136
144
 
137
- if (!existingStyles.includes('--background:')) {
138
- await fs.writeFile(stylesPath, getStylesTemplate(config.tailwind.baseColor) + '\n' + existingStyles);
139
- spinner.text = 'Updated styles with theme variables';
145
+ const tailwindImport = '@import "./tailwind.css";';
146
+ if (!userStyles.includes('tailwind.css')) {
147
+ // Add import at the top of the file
148
+ userStyles = tailwindImport + '\n\n' + userStyles;
149
+ await fs.writeFile(userStylesPath, userStyles);
150
+ spinner.text = 'Added tailwind.css import to styles';
140
151
  }
141
152
 
142
153
  // Create components/ui directory
@@ -151,7 +162,6 @@ export async function init(options: InitOptions) {
151
162
  'clsx',
152
163
  'tailwind-merge',
153
164
  'class-variance-authority',
154
- '@angular/cdk',
155
165
  'lucide-angular',
156
166
  'tailwindcss',
157
167
  'postcss',
@@ -159,47 +169,23 @@ export async function init(options: InitOptions) {
159
169
  ];
160
170
  await execa('npm', ['install', ...dependencies], { cwd });
161
171
 
162
- // Setup PostCSS
172
+ // Setup PostCSS - create .postcssrc.json which is the preferred format for Angular
163
173
  spinner.text = 'Configuring PostCSS...';
164
- const postcssConfigPath = path.join(cwd, 'postcss.config.js');
165
- const postcssConfigMjsPath = path.join(cwd, 'postcss.config.mjs');
166
-
167
- if (await fs.pathExists(postcssConfigMjsPath)) {
168
- // Check mjs config
169
- const content = await fs.readFile(postcssConfigMjsPath, 'utf-8');
170
- if (!content.includes('@tailwindcss/postcss')) {
171
- // Very basic append attempt for mjs, safest is to warn or skip complex types
172
- // But user asked to try.
173
- // If it's a simple export default { plugins: {} }, we can try to inject.
174
- // For now, let's just log a warning if we can't safely inject
175
- console.log(chalk.yellow('\nComputed postcss.config.mjs found. Please manually add "@tailwindcss/postcss" to your plugins.'));
176
- }
177
- } else if (await fs.pathExists(postcssConfigPath)) {
178
- let content = await fs.readFile(postcssConfigPath, 'utf-8');
179
- if (!content.includes('@tailwindcss/postcss')) {
180
- // Try to inject into plugins object
181
- if (content.includes('plugins: {')) {
182
- content = content.replace('plugins: {', 'plugins: {\n \'@tailwindcss/postcss\': {},');
183
- await fs.writeFile(postcssConfigPath, content);
184
- } else {
185
- console.log(chalk.yellow('\nExisting postcss.config.js found but structure not recognized. Please manually add "@tailwindcss/postcss" to your plugins.'));
174
+ const postcssrcPath = path.join(cwd, '.postcssrc.json');
175
+
176
+ if (!await fs.pathExists(postcssrcPath)) {
177
+ const configContent = {
178
+ plugins: {
179
+ '@tailwindcss/postcss': {}
186
180
  }
187
- }
188
- } else {
189
- // Create new config
190
- const configContent = `module.exports = {
191
- plugins: {
192
- '@tailwindcss/postcss': {},
193
- },
194
- }
195
- `;
196
- await fs.writeFile(postcssConfigPath, configContent);
181
+ };
182
+ await fs.writeJson(postcssrcPath, configContent, { spaces: 4 });
197
183
  }
198
184
 
199
185
  spinner.succeed(chalk.green('Project initialized successfully!'));
200
186
 
201
187
  console.log('\n' + chalk.bold('Next steps:'));
202
- console.log(chalk.dim(' 1. Add components: ') + chalk.cyan('npx shadcn-angular add button'));
188
+ console.log(chalk.dim(' 1. Add components: ') + chalk.cyan('npx @gilav21/shadcn-angular add button'));
203
189
  console.log(chalk.dim(' 2. Import and use in your templates'));
204
190
  console.log(chalk.dim(' 3. Update your ') + chalk.bold('tsconfig.json') + chalk.dim(' paths:'));
205
191
  console.log(chalk.dim(' "compilerOptions": {'));
package/src/index.ts CHANGED
@@ -8,7 +8,7 @@ const program = new Command();
8
8
  program
9
9
  .name('shadcn-angular')
10
10
  .description('CLI for adding shadcn-angular components to your Angular project')
11
- .version('0.0.1');
11
+ .version('0.0.6');
12
12
 
13
13
  program
14
14
  .command('init')
@@ -47,10 +47,12 @@ export const registry: Record<string, ComponentDefinition> = {
47
47
  'button-group': {
48
48
  name: 'button-group',
49
49
  files: ['button-group.component.ts'],
50
+ dependencies: ['button']
50
51
  },
51
52
  calendar: {
52
53
  name: 'calendar',
53
- files: ['calendar.component.ts'],
54
+ files: ['calendar.component.ts', 'calendar-locales.ts'],
55
+ dependencies: ['button', 'select'],
54
56
  },
55
57
  card: {
56
58
  name: 'card',
@@ -222,4 +224,9 @@ export const registry: Record<string, ComponentDefinition> = {
222
224
  name: 'tooltip',
223
225
  files: ['tooltip.component.ts'],
224
226
  },
227
+ 'speed-dial': {
228
+ name: 'speed-dial',
229
+ files: ['speed-dial.component.ts'],
230
+ dependencies: ['button']
231
+ },
225
232
  };
@@ -1,228 +1,232 @@
1
1
  type BaseColor = 'neutral' | 'slate' | 'stone' | 'gray' | 'zinc';
2
2
 
3
3
  const baseColors: Record<BaseColor, { light: Record<string, string>; dark: Record<string, string> }> = {
4
- neutral: {
5
- light: {
6
- '--background': 'oklch(1 0 0)',
7
- '--foreground': 'oklch(0.145 0 0)',
8
- '--card': 'oklch(1 0 0)',
9
- '--card-foreground': 'oklch(0.145 0 0)',
10
- '--popover': 'oklch(1 0 0)',
11
- '--popover-foreground': 'oklch(0.145 0 0)',
12
- '--primary': 'oklch(0.205 0 0)',
13
- '--primary-foreground': 'oklch(0.985 0 0)',
14
- '--secondary': 'oklch(0.97 0 0)',
15
- '--secondary-foreground': 'oklch(0.205 0 0)',
16
- '--muted': 'oklch(0.97 0 0)',
17
- '--muted-foreground': 'oklch(0.556 0 0)',
18
- '--accent': 'oklch(0.97 0 0)',
19
- '--accent-foreground': 'oklch(0.205 0 0)',
20
- '--destructive': 'oklch(0.577 0.245 27.325)',
21
- '--border': 'oklch(0.922 0 0)',
22
- '--input': 'oklch(0.922 0 0)',
23
- '--ring': 'oklch(0.708 0 0)',
24
- },
25
- dark: {
26
- '--background': 'oklch(0.145 0 0)',
27
- '--foreground': 'oklch(0.985 0 0)',
28
- '--card': 'oklch(0.205 0 0)',
29
- '--card-foreground': 'oklch(0.985 0 0)',
30
- '--popover': 'oklch(0.269 0 0)',
31
- '--popover-foreground': 'oklch(0.985 0 0)',
32
- '--primary': 'oklch(0.922 0 0)',
33
- '--primary-foreground': 'oklch(0.205 0 0)',
34
- '--secondary': 'oklch(0.269 0 0)',
35
- '--secondary-foreground': 'oklch(0.985 0 0)',
36
- '--muted': 'oklch(0.269 0 0)',
37
- '--muted-foreground': 'oklch(0.708 0 0)',
38
- '--accent': 'oklch(0.371 0 0)',
39
- '--accent-foreground': 'oklch(0.985 0 0)',
40
- '--destructive': 'oklch(0.704 0.191 22.216)',
41
- '--border': 'oklch(1 0 0 / 10%)',
42
- '--input': 'oklch(1 0 0 / 15%)',
43
- '--ring': 'oklch(0.556 0 0)',
44
- },
4
+ neutral: {
5
+ light: {
6
+ '--background': 'oklch(1 0 0)',
7
+ '--foreground': 'oklch(0.145 0 0)',
8
+ '--card': 'oklch(1 0 0)',
9
+ '--card-foreground': 'oklch(0.145 0 0)',
10
+ '--popover': 'oklch(1 0 0)',
11
+ '--popover-foreground': 'oklch(0.145 0 0)',
12
+ '--primary': 'oklch(0.205 0 0)',
13
+ '--primary-foreground': 'oklch(0.985 0 0)',
14
+ '--secondary': 'oklch(0.97 0 0)',
15
+ '--secondary-foreground': 'oklch(0.205 0 0)',
16
+ '--muted': 'oklch(0.97 0 0)',
17
+ '--muted-foreground': 'oklch(0.556 0 0)',
18
+ '--accent': 'oklch(0.97 0 0)',
19
+ '--accent-foreground': 'oklch(0.205 0 0)',
20
+ '--destructive': 'oklch(0.577 0.245 27.325)',
21
+ '--border': 'oklch(0.922 0 0)',
22
+ '--input': 'oklch(0.922 0 0)',
23
+ '--ring': 'oklch(0.708 0 0)',
45
24
  },
46
- slate: {
47
- light: {
48
- '--background': 'oklch(1 0 0)',
49
- '--foreground': 'oklch(0.129 0.042 264.695)',
50
- '--card': 'oklch(1 0 0)',
51
- '--card-foreground': 'oklch(0.129 0.042 264.695)',
52
- '--popover': 'oklch(1 0 0)',
53
- '--popover-foreground': 'oklch(0.129 0.042 264.695)',
54
- '--primary': 'oklch(0.208 0.042 265.755)',
55
- '--primary-foreground': 'oklch(0.984 0.003 247.858)',
56
- '--secondary': 'oklch(0.968 0.007 247.896)',
57
- '--secondary-foreground': 'oklch(0.208 0.042 265.755)',
58
- '--muted': 'oklch(0.968 0.007 247.896)',
59
- '--muted-foreground': 'oklch(0.554 0.046 257.417)',
60
- '--accent': 'oklch(0.968 0.007 247.896)',
61
- '--accent-foreground': 'oklch(0.208 0.042 265.755)',
62
- '--destructive': 'oklch(0.577 0.245 27.325)',
63
- '--border': 'oklch(0.929 0.013 255.508)',
64
- '--input': 'oklch(0.929 0.013 255.508)',
65
- '--ring': 'oklch(0.704 0.04 256.788)',
66
- },
67
- dark: {
68
- '--background': 'oklch(0.129 0.042 264.695)',
69
- '--foreground': 'oklch(0.984 0.003 247.858)',
70
- '--card': 'oklch(0.208 0.042 265.755)',
71
- '--card-foreground': 'oklch(0.984 0.003 247.858)',
72
- '--popover': 'oklch(0.269 0.04 260.031)',
73
- '--popover-foreground': 'oklch(0.984 0.003 247.858)',
74
- '--primary': 'oklch(0.929 0.013 255.508)',
75
- '--primary-foreground': 'oklch(0.208 0.042 265.755)',
76
- '--secondary': 'oklch(0.269 0.04 260.031)',
77
- '--secondary-foreground': 'oklch(0.984 0.003 247.858)',
78
- '--muted': 'oklch(0.269 0.04 260.031)',
79
- '--muted-foreground': 'oklch(0.704 0.04 256.788)',
80
- '--accent': 'oklch(0.372 0.044 257.287)',
81
- '--accent-foreground': 'oklch(0.984 0.003 247.858)',
82
- '--destructive': 'oklch(0.704 0.191 22.216)',
83
- '--border': 'oklch(1 0 0 / 10%)',
84
- '--input': 'oklch(1 0 0 / 15%)',
85
- '--ring': 'oklch(0.554 0.046 257.417)',
86
- },
25
+ dark: {
26
+ '--background': 'oklch(0.145 0 0)',
27
+ '--foreground': 'oklch(0.985 0 0)',
28
+ '--card': 'oklch(0.205 0 0)',
29
+ '--card-foreground': 'oklch(0.985 0 0)',
30
+ '--popover': 'oklch(0.269 0 0)',
31
+ '--popover-foreground': 'oklch(0.985 0 0)',
32
+ '--primary': 'oklch(0.922 0 0)',
33
+ '--primary-foreground': 'oklch(0.205 0 0)',
34
+ '--secondary': 'oklch(0.269 0 0)',
35
+ '--secondary-foreground': 'oklch(0.985 0 0)',
36
+ '--muted': 'oklch(0.269 0 0)',
37
+ '--muted-foreground': 'oklch(0.708 0 0)',
38
+ '--accent': 'oklch(0.371 0 0)',
39
+ '--accent-foreground': 'oklch(0.985 0 0)',
40
+ '--destructive': 'oklch(0.704 0.191 22.216)',
41
+ '--border': 'oklch(1 0 0 / 10%)',
42
+ '--input': 'oklch(1 0 0 / 15%)',
43
+ '--ring': 'oklch(0.556 0 0)',
87
44
  },
88
- stone: {
89
- light: {
90
- '--background': 'oklch(1 0 0)',
91
- '--foreground': 'oklch(0.147 0.004 49.25)',
92
- '--card': 'oklch(1 0 0)',
93
- '--card-foreground': 'oklch(0.147 0.004 49.25)',
94
- '--popover': 'oklch(1 0 0)',
95
- '--popover-foreground': 'oklch(0.147 0.004 49.25)',
96
- '--primary': 'oklch(0.216 0.006 56.043)',
97
- '--primary-foreground': 'oklch(0.985 0.001 106.423)',
98
- '--secondary': 'oklch(0.97 0.001 106.424)',
99
- '--secondary-foreground': 'oklch(0.216 0.006 56.043)',
100
- '--muted': 'oklch(0.97 0.001 106.424)',
101
- '--muted-foreground': 'oklch(0.553 0.013 58.071)',
102
- '--accent': 'oklch(0.97 0.001 106.424)',
103
- '--accent-foreground': 'oklch(0.216 0.006 56.043)',
104
- '--destructive': 'oklch(0.577 0.245 27.325)',
105
- '--border': 'oklch(0.923 0.003 48.717)',
106
- '--input': 'oklch(0.923 0.003 48.717)',
107
- '--ring': 'oklch(0.709 0.01 56.259)',
108
- },
109
- dark: {
110
- '--background': 'oklch(0.147 0.004 49.25)',
111
- '--foreground': 'oklch(0.985 0.001 106.423)',
112
- '--card': 'oklch(0.216 0.006 56.043)',
113
- '--card-foreground': 'oklch(0.985 0.001 106.423)',
114
- '--popover': 'oklch(0.268 0.007 34.298)',
115
- '--popover-foreground': 'oklch(0.985 0.001 106.423)',
116
- '--primary': 'oklch(0.923 0.003 48.717)',
117
- '--primary-foreground': 'oklch(0.216 0.006 56.043)',
118
- '--secondary': 'oklch(0.268 0.007 34.298)',
119
- '--secondary-foreground': 'oklch(0.985 0.001 106.423)',
120
- '--muted': 'oklch(0.268 0.007 34.298)',
121
- '--muted-foreground': 'oklch(0.709 0.01 56.259)',
122
- '--accent': 'oklch(0.374 0.01 67.558)',
123
- '--accent-foreground': 'oklch(0.985 0.001 106.423)',
124
- '--destructive': 'oklch(0.704 0.191 22.216)',
125
- '--border': 'oklch(1 0 0 / 10%)',
126
- '--input': 'oklch(1 0 0 / 15%)',
127
- '--ring': 'oklch(0.553 0.013 58.071)',
128
- },
45
+ },
46
+ slate: {
47
+ light: {
48
+ '--background': 'oklch(1 0 0)',
49
+ '--foreground': 'oklch(0.129 0.042 264.695)',
50
+ '--card': 'oklch(1 0 0)',
51
+ '--card-foreground': 'oklch(0.129 0.042 264.695)',
52
+ '--popover': 'oklch(1 0 0)',
53
+ '--popover-foreground': 'oklch(0.129 0.042 264.695)',
54
+ '--primary': 'oklch(0.208 0.042 265.755)',
55
+ '--primary-foreground': 'oklch(0.984 0.003 247.858)',
56
+ '--secondary': 'oklch(0.968 0.007 247.896)',
57
+ '--secondary-foreground': 'oklch(0.208 0.042 265.755)',
58
+ '--muted': 'oklch(0.968 0.007 247.896)',
59
+ '--muted-foreground': 'oklch(0.554 0.046 257.417)',
60
+ '--accent': 'oklch(0.968 0.007 247.896)',
61
+ '--accent-foreground': 'oklch(0.208 0.042 265.755)',
62
+ '--destructive': 'oklch(0.577 0.245 27.325)',
63
+ '--border': 'oklch(0.929 0.013 255.508)',
64
+ '--input': 'oklch(0.929 0.013 255.508)',
65
+ '--ring': 'oklch(0.704 0.04 256.788)',
129
66
  },
130
- gray: {
131
- light: {
132
- '--background': 'oklch(1 0 0)',
133
- '--foreground': 'oklch(0.13 0.028 261.692)',
134
- '--card': 'oklch(1 0 0)',
135
- '--card-foreground': 'oklch(0.13 0.028 261.692)',
136
- '--popover': 'oklch(1 0 0)',
137
- '--popover-foreground': 'oklch(0.13 0.028 261.692)',
138
- '--primary': 'oklch(0.21 0.028 264.532)',
139
- '--primary-foreground': 'oklch(0.985 0.002 247.839)',
140
- '--secondary': 'oklch(0.967 0.003 264.542)',
141
- '--secondary-foreground': 'oklch(0.21 0.028 264.532)',
142
- '--muted': 'oklch(0.967 0.003 264.542)',
143
- '--muted-foreground': 'oklch(0.551 0.027 264.364)',
144
- '--accent': 'oklch(0.967 0.003 264.542)',
145
- '--accent-foreground': 'oklch(0.21 0.028 264.532)',
146
- '--destructive': 'oklch(0.577 0.245 27.325)',
147
- '--border': 'oklch(0.928 0.006 264.531)',
148
- '--input': 'oklch(0.928 0.006 264.531)',
149
- '--ring': 'oklch(0.707 0.022 264.436)',
150
- },
151
- dark: {
152
- '--background': 'oklch(0.13 0.028 261.692)',
153
- '--foreground': 'oklch(0.985 0.002 247.839)',
154
- '--card': 'oklch(0.21 0.028 264.532)',
155
- '--card-foreground': 'oklch(0.985 0.002 247.839)',
156
- '--popover': 'oklch(0.274 0.029 256.848)',
157
- '--popover-foreground': 'oklch(0.985 0.002 247.839)',
158
- '--primary': 'oklch(0.928 0.006 264.531)',
159
- '--primary-foreground': 'oklch(0.21 0.028 264.532)',
160
- '--secondary': 'oklch(0.274 0.029 256.848)',
161
- '--secondary-foreground': 'oklch(0.985 0.002 247.839)',
162
- '--muted': 'oklch(0.274 0.029 256.848)',
163
- '--muted-foreground': 'oklch(0.707 0.022 264.436)',
164
- '--accent': 'oklch(0.37 0.029 259.733)',
165
- '--accent-foreground': 'oklch(0.985 0.002 247.839)',
166
- '--destructive': 'oklch(0.704 0.191 22.216)',
167
- '--border': 'oklch(1 0 0 / 10%)',
168
- '--input': 'oklch(1 0 0 / 15%)',
169
- '--ring': 'oklch(0.551 0.027 264.364)',
170
- },
67
+ dark: {
68
+ '--background': 'oklch(0.129 0.042 264.695)',
69
+ '--foreground': 'oklch(0.984 0.003 247.858)',
70
+ '--card': 'oklch(0.208 0.042 265.755)',
71
+ '--card-foreground': 'oklch(0.984 0.003 247.858)',
72
+ '--popover': 'oklch(0.269 0.04 260.031)',
73
+ '--popover-foreground': 'oklch(0.984 0.003 247.858)',
74
+ '--primary': 'oklch(0.929 0.013 255.508)',
75
+ '--primary-foreground': 'oklch(0.208 0.042 265.755)',
76
+ '--secondary': 'oklch(0.269 0.04 260.031)',
77
+ '--secondary-foreground': 'oklch(0.984 0.003 247.858)',
78
+ '--muted': 'oklch(0.269 0.04 260.031)',
79
+ '--muted-foreground': 'oklch(0.704 0.04 256.788)',
80
+ '--accent': 'oklch(0.372 0.044 257.287)',
81
+ '--accent-foreground': 'oklch(0.984 0.003 247.858)',
82
+ '--destructive': 'oklch(0.704 0.191 22.216)',
83
+ '--border': 'oklch(1 0 0 / 10%)',
84
+ '--input': 'oklch(1 0 0 / 15%)',
85
+ '--ring': 'oklch(0.554 0.046 257.417)',
171
86
  },
172
- zinc: {
173
- light: {
174
- '--background': 'oklch(1 0 0)',
175
- '--foreground': 'oklch(0.141 0.005 285.823)',
176
- '--card': 'oklch(1 0 0)',
177
- '--card-foreground': 'oklch(0.141 0.005 285.823)',
178
- '--popover': 'oklch(1 0 0)',
179
- '--popover-foreground': 'oklch(0.141 0.005 285.823)',
180
- '--primary': 'oklch(0.21 0.006 285.885)',
181
- '--primary-foreground': 'oklch(0.985 0 0)',
182
- '--secondary': 'oklch(0.967 0.001 286.375)',
183
- '--secondary-foreground': 'oklch(0.21 0.006 285.885)',
184
- '--muted': 'oklch(0.967 0.001 286.375)',
185
- '--muted-foreground': 'oklch(0.552 0.016 285.938)',
186
- '--accent': 'oklch(0.967 0.001 286.375)',
187
- '--accent-foreground': 'oklch(0.21 0.006 285.885)',
188
- '--destructive': 'oklch(0.577 0.245 27.325)',
189
- '--border': 'oklch(0.92 0.004 286.32)',
190
- '--input': 'oklch(0.92 0.004 286.32)',
191
- '--ring': 'oklch(0.705 0.015 286.067)',
192
- },
193
- dark: {
194
- '--background': 'oklch(0.141 0.005 285.823)',
195
- '--foreground': 'oklch(0.985 0 0)',
196
- '--card': 'oklch(0.21 0.006 285.885)',
197
- '--card-foreground': 'oklch(0.985 0 0)',
198
- '--popover': 'oklch(0.274 0.006 286.033)',
199
- '--popover-foreground': 'oklch(0.985 0 0)',
200
- '--primary': 'oklch(0.92 0.004 286.32)',
201
- '--primary-foreground': 'oklch(0.21 0.006 285.885)',
202
- '--secondary': 'oklch(0.274 0.006 286.033)',
203
- '--secondary-foreground': 'oklch(0.985 0 0)',
204
- '--muted': 'oklch(0.274 0.006 286.033)',
205
- '--muted-foreground': 'oklch(0.705 0.015 286.067)',
206
- '--accent': 'oklch(0.37 0.013 285.805)',
207
- '--accent-foreground': 'oklch(0.985 0 0)',
208
- '--destructive': 'oklch(0.704 0.191 22.216)',
209
- '--border': 'oklch(1 0 0 / 10%)',
210
- '--input': 'oklch(1 0 0 / 15%)',
211
- '--ring': 'oklch(0.552 0.016 285.938)',
212
- },
87
+ },
88
+ stone: {
89
+ light: {
90
+ '--background': 'oklch(1 0 0)',
91
+ '--foreground': 'oklch(0.147 0.004 49.25)',
92
+ '--card': 'oklch(1 0 0)',
93
+ '--card-foreground': 'oklch(0.147 0.004 49.25)',
94
+ '--popover': 'oklch(1 0 0)',
95
+ '--popover-foreground': 'oklch(0.147 0.004 49.25)',
96
+ '--primary': 'oklch(0.216 0.006 56.043)',
97
+ '--primary-foreground': 'oklch(0.985 0.001 106.423)',
98
+ '--secondary': 'oklch(0.97 0.001 106.424)',
99
+ '--secondary-foreground': 'oklch(0.216 0.006 56.043)',
100
+ '--muted': 'oklch(0.97 0.001 106.424)',
101
+ '--muted-foreground': 'oklch(0.553 0.013 58.071)',
102
+ '--accent': 'oklch(0.97 0.001 106.424)',
103
+ '--accent-foreground': 'oklch(0.216 0.006 56.043)',
104
+ '--destructive': 'oklch(0.577 0.245 27.325)',
105
+ '--border': 'oklch(0.923 0.003 48.717)',
106
+ '--input': 'oklch(0.923 0.003 48.717)',
107
+ '--ring': 'oklch(0.709 0.01 56.259)',
213
108
  },
109
+ dark: {
110
+ '--background': 'oklch(0.147 0.004 49.25)',
111
+ '--foreground': 'oklch(0.985 0.001 106.423)',
112
+ '--card': 'oklch(0.216 0.006 56.043)',
113
+ '--card-foreground': 'oklch(0.985 0.001 106.423)',
114
+ '--popover': 'oklch(0.268 0.007 34.298)',
115
+ '--popover-foreground': 'oklch(0.985 0.001 106.423)',
116
+ '--primary': 'oklch(0.923 0.003 48.717)',
117
+ '--primary-foreground': 'oklch(0.216 0.006 56.043)',
118
+ '--secondary': 'oklch(0.268 0.007 34.298)',
119
+ '--secondary-foreground': 'oklch(0.985 0.001 106.423)',
120
+ '--muted': 'oklch(0.268 0.007 34.298)',
121
+ '--muted-foreground': 'oklch(0.709 0.01 56.259)',
122
+ '--accent': 'oklch(0.374 0.01 67.558)',
123
+ '--accent-foreground': 'oklch(0.985 0.001 106.423)',
124
+ '--destructive': 'oklch(0.704 0.191 22.216)',
125
+ '--border': 'oklch(1 0 0 / 10%)',
126
+ '--input': 'oklch(1 0 0 / 15%)',
127
+ '--ring': 'oklch(0.553 0.013 58.071)',
128
+ },
129
+ },
130
+ gray: {
131
+ light: {
132
+ '--background': 'oklch(1 0 0)',
133
+ '--foreground': 'oklch(0.13 0.028 261.692)',
134
+ '--card': 'oklch(1 0 0)',
135
+ '--card-foreground': 'oklch(0.13 0.028 261.692)',
136
+ '--popover': 'oklch(1 0 0)',
137
+ '--popover-foreground': 'oklch(0.13 0.028 261.692)',
138
+ '--primary': 'oklch(0.21 0.028 264.532)',
139
+ '--primary-foreground': 'oklch(0.985 0.002 247.839)',
140
+ '--secondary': 'oklch(0.967 0.003 264.542)',
141
+ '--secondary-foreground': 'oklch(0.21 0.028 264.532)',
142
+ '--muted': 'oklch(0.967 0.003 264.542)',
143
+ '--muted-foreground': 'oklch(0.551 0.027 264.364)',
144
+ '--accent': 'oklch(0.967 0.003 264.542)',
145
+ '--accent-foreground': 'oklch(0.21 0.028 264.532)',
146
+ '--destructive': 'oklch(0.577 0.245 27.325)',
147
+ '--border': 'oklch(0.928 0.006 264.531)',
148
+ '--input': 'oklch(0.928 0.006 264.531)',
149
+ '--ring': 'oklch(0.707 0.022 264.436)',
150
+ },
151
+ dark: {
152
+ '--background': 'oklch(0.13 0.028 261.692)',
153
+ '--foreground': 'oklch(0.985 0.002 247.839)',
154
+ '--card': 'oklch(0.21 0.028 264.532)',
155
+ '--card-foreground': 'oklch(0.985 0.002 247.839)',
156
+ '--popover': 'oklch(0.274 0.029 256.848)',
157
+ '--popover-foreground': 'oklch(0.985 0.002 247.839)',
158
+ '--primary': 'oklch(0.928 0.006 264.531)',
159
+ '--primary-foreground': 'oklch(0.21 0.028 264.532)',
160
+ '--secondary': 'oklch(0.274 0.029 256.848)',
161
+ '--secondary-foreground': 'oklch(0.985 0.002 247.839)',
162
+ '--muted': 'oklch(0.274 0.029 256.848)',
163
+ '--muted-foreground': 'oklch(0.707 0.022 264.436)',
164
+ '--accent': 'oklch(0.37 0.029 259.733)',
165
+ '--accent-foreground': 'oklch(0.985 0.002 247.839)',
166
+ '--destructive': 'oklch(0.704 0.191 22.216)',
167
+ '--border': 'oklch(1 0 0 / 10%)',
168
+ '--input': 'oklch(1 0 0 / 15%)',
169
+ '--ring': 'oklch(0.551 0.027 264.364)',
170
+ },
171
+ },
172
+ zinc: {
173
+ light: {
174
+ '--background': 'oklch(1 0 0)',
175
+ '--foreground': 'oklch(0.141 0.005 285.823)',
176
+ '--card': 'oklch(1 0 0)',
177
+ '--card-foreground': 'oklch(0.141 0.005 285.823)',
178
+ '--popover': 'oklch(1 0 0)',
179
+ '--popover-foreground': 'oklch(0.141 0.005 285.823)',
180
+ '--primary': 'oklch(0.21 0.006 285.885)',
181
+ '--primary-foreground': 'oklch(0.985 0 0)',
182
+ '--secondary': 'oklch(0.967 0.001 286.375)',
183
+ '--secondary-foreground': 'oklch(0.21 0.006 285.885)',
184
+ '--muted': 'oklch(0.967 0.001 286.375)',
185
+ '--muted-foreground': 'oklch(0.552 0.016 285.938)',
186
+ '--accent': 'oklch(0.967 0.001 286.375)',
187
+ '--accent-foreground': 'oklch(0.21 0.006 285.885)',
188
+ '--destructive': 'oklch(0.577 0.245 27.325)',
189
+ '--border': 'oklch(0.92 0.004 286.32)',
190
+ '--input': 'oklch(0.92 0.004 286.32)',
191
+ '--ring': 'oklch(0.705 0.015 286.067)',
192
+ },
193
+ dark: {
194
+ '--background': 'oklch(0.141 0.005 285.823)',
195
+ '--foreground': 'oklch(0.985 0 0)',
196
+ '--card': 'oklch(0.21 0.006 285.885)',
197
+ '--card-foreground': 'oklch(0.985 0 0)',
198
+ '--popover': 'oklch(0.274 0.006 286.033)',
199
+ '--popover-foreground': 'oklch(0.985 0 0)',
200
+ '--primary': 'oklch(0.92 0.004 286.32)',
201
+ '--primary-foreground': 'oklch(0.21 0.006 285.885)',
202
+ '--secondary': 'oklch(0.274 0.006 286.033)',
203
+ '--secondary-foreground': 'oklch(0.985 0 0)',
204
+ '--muted': 'oklch(0.274 0.006 286.033)',
205
+ '--muted-foreground': 'oklch(0.705 0.015 286.067)',
206
+ '--accent': 'oklch(0.37 0.013 285.805)',
207
+ '--accent-foreground': 'oklch(0.985 0 0)',
208
+ '--destructive': 'oklch(0.704 0.191 22.216)',
209
+ '--border': 'oklch(1 0 0 / 10%)',
210
+ '--input': 'oklch(1 0 0 / 15%)',
211
+ '--ring': 'oklch(0.552 0.016 285.938)',
212
+ },
213
+ },
214
214
  };
215
215
 
216
216
  function generateCssVars(vars: Record<string, string>, indent: string = ' '): string {
217
- return Object.entries(vars)
218
- .map(([key, value]) => `${indent}${key}: ${value};`)
219
- .join('\n');
217
+ return Object.entries(vars)
218
+ .map(([key, value]) => `${indent}${key}: ${value};`)
219
+ .join('\n');
220
220
  }
221
221
 
222
222
  export function getStylesTemplate(baseColor: BaseColor = 'neutral'): string {
223
- const colors = baseColors[baseColor];
223
+ const colors = baseColors[baseColor];
224
+
225
+ return `@import "tailwindcss";
224
226
 
225
- return `@import "tailwindcss";
227
+ /* Tell Tailwind v4 where to scan for classes */
228
+ @source "../src/**/*.ts";
229
+ @source "../src/**/*.html";
226
230
 
227
231
  @custom-variant dark (&:is(.dark *));
228
232
 
@@ -262,7 +266,7 @@ ${generateCssVars(colors.dark)}
262
266
  }
263
267
 
264
268
  @theme inline {
265
- --font-sans: system-ui, sans-serif;
269
+ --font-sans: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
266
270
  --color-background: var(--background);
267
271
  --color-foreground: var(--foreground);
268
272
  --color-card: var(--card);
@@ -305,13 +309,16 @@ ${generateCssVars(colors.dark)}
305
309
 
306
310
  @layer base {
307
311
  * {
308
- @apply border-border outline-ring/50;
312
+ border-color: var(--border);
313
+ outline-color: color-mix(in oklch, var(--ring) 50%, transparent);
309
314
  }
310
315
  body {
311
- @apply font-sans bg-background text-foreground;
316
+ font-family: var(--font-sans);
317
+ background-color: var(--background);
318
+ color: var(--foreground);
312
319
  }
313
320
  html {
314
- @apply font-sans;
321
+ font-family: var(--font-sans);
315
322
  }
316
323
  button:not(:disabled),
317
324
  [role="button"]:not(:disabled) {