bdsg-cli 0.1.0
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.
- package/README.md +277 -0
- package/dist/commands/generate.d.ts +3 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +176 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +125 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/validate.d.ts +3 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +63 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/files.d.ts +12 -0
- package/dist/utils/files.d.ts.map +1 -0
- package/dist/utils/files.js +190 -0
- package/dist/utils/files.js.map +1 -0
- package/package.json +25 -0
- package/src/commands/generate.ts +236 -0
- package/src/commands/init.ts +132 -0
- package/src/commands/validate.ts +89 -0
- package/src/index.ts +18 -0
- package/src/utils/files.ts +249 -0
- package/tsconfig.json +12 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import {
|
|
2
|
+
generatePalette,
|
|
3
|
+
generateShadows,
|
|
4
|
+
generateSpacingScale,
|
|
5
|
+
generateTypographyScale,
|
|
6
|
+
} from "bdsg";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import { Command } from "commander";
|
|
9
|
+
import inquirer from "inquirer";
|
|
10
|
+
import ora from "ora";
|
|
11
|
+
import { writeTokensToFile } from "../utils/files.js";
|
|
12
|
+
|
|
13
|
+
export const initCommand = new Command("init")
|
|
14
|
+
.description("Initialize a new design system")
|
|
15
|
+
.option("-o, --output <dir>", "Output directory", "./tokens")
|
|
16
|
+
.action(async (options) => {
|
|
17
|
+
console.log(chalk.bold("\n BDSG - Design System Generator\n"));
|
|
18
|
+
|
|
19
|
+
const answers = await inquirer.prompt([
|
|
20
|
+
{
|
|
21
|
+
type: "input",
|
|
22
|
+
name: "projectName",
|
|
23
|
+
message: "Project name:",
|
|
24
|
+
default: "my-design-system",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
type: "input",
|
|
28
|
+
name: "primaryColor",
|
|
29
|
+
message: "Primary color (hex):",
|
|
30
|
+
default: "#3B82F6",
|
|
31
|
+
validate: (input: string) => {
|
|
32
|
+
if (/^#[0-9A-Fa-f]{6}$/.test(input)) return true;
|
|
33
|
+
return "Please enter a valid hex color (e.g., #3B82F6)";
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
type: "list",
|
|
38
|
+
name: "typographyRatio",
|
|
39
|
+
message: "Typography scale ratio:",
|
|
40
|
+
choices: [
|
|
41
|
+
{ name: "Minor Second (1.067)", value: "minor-second" },
|
|
42
|
+
{ name: "Major Second (1.125)", value: "major-second" },
|
|
43
|
+
{ name: "Minor Third (1.2)", value: "minor-third" },
|
|
44
|
+
{ name: "Major Third (1.25)", value: "major-third" },
|
|
45
|
+
{ name: "Perfect Fourth (1.333)", value: "perfect-fourth" },
|
|
46
|
+
{ name: "Perfect Fifth (1.5)", value: "perfect-fifth" },
|
|
47
|
+
{ name: "Golden Ratio (1.618)", value: "golden-ratio" },
|
|
48
|
+
],
|
|
49
|
+
default: "perfect-fourth",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
type: "list",
|
|
53
|
+
name: "spacingMethod",
|
|
54
|
+
message: "Spacing method:",
|
|
55
|
+
choices: [
|
|
56
|
+
{ name: "Fibonacci (natural progression)", value: "fibonacci" },
|
|
57
|
+
{ name: "Linear (consistent increments)", value: "linear" },
|
|
58
|
+
{ name: "T-shirt sizes (semantic)", value: "t-shirt" },
|
|
59
|
+
],
|
|
60
|
+
default: "fibonacci",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
type: "list",
|
|
64
|
+
name: "shadowStyle",
|
|
65
|
+
message: "Shadow style:",
|
|
66
|
+
choices: [
|
|
67
|
+
{ name: "Material Design", value: "material" },
|
|
68
|
+
{ name: "Soft", value: "soft" },
|
|
69
|
+
{ name: "Hard", value: "hard" },
|
|
70
|
+
],
|
|
71
|
+
default: "material",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
type: "list",
|
|
75
|
+
name: "outputFormat",
|
|
76
|
+
message: "Output format:",
|
|
77
|
+
choices: [
|
|
78
|
+
{ name: "CSS Variables", value: "css" },
|
|
79
|
+
{ name: "JSON Tokens", value: "json" },
|
|
80
|
+
{ name: "Tailwind v4 (@theme)", value: "tailwind-v4" },
|
|
81
|
+
{ name: "Shadcn/ui (with dark mode)", value: "shadcn" },
|
|
82
|
+
],
|
|
83
|
+
default: "css",
|
|
84
|
+
},
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
const spinner = ora("Generating design tokens...").start();
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
// Generate tokens using bdsg
|
|
91
|
+
const palette = generatePalette(answers.primaryColor, "primary");
|
|
92
|
+
const typography = generateTypographyScale({
|
|
93
|
+
ratio: answers.typographyRatio,
|
|
94
|
+
});
|
|
95
|
+
const spacing = generateSpacingScale({
|
|
96
|
+
method: answers.spacingMethod,
|
|
97
|
+
});
|
|
98
|
+
const shadows = generateShadows({
|
|
99
|
+
style: answers.shadowStyle,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Write to files
|
|
103
|
+
await writeTokensToFile({
|
|
104
|
+
palette,
|
|
105
|
+
typography,
|
|
106
|
+
spacing,
|
|
107
|
+
shadows,
|
|
108
|
+
format: answers.outputFormat,
|
|
109
|
+
outputDir: options.output,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
spinner.succeed(chalk.green("Design tokens generated!"));
|
|
113
|
+
|
|
114
|
+
console.log(chalk.dim("\nFiles created:"));
|
|
115
|
+
if (answers.outputFormat === "shadcn") {
|
|
116
|
+
console.log(chalk.dim(` ${options.output}/globals.css`));
|
|
117
|
+
} else if (answers.outputFormat === "tailwind-v4") {
|
|
118
|
+
console.log(chalk.dim(` ${options.output}/theme.css`));
|
|
119
|
+
} else {
|
|
120
|
+
const ext = answers.outputFormat === "json" ? "json" : "css";
|
|
121
|
+
console.log(chalk.dim(` ${options.output}/colors.${ext}`));
|
|
122
|
+
console.log(chalk.dim(` ${options.output}/typography.${ext}`));
|
|
123
|
+
console.log(chalk.dim(` ${options.output}/spacing.${ext}`));
|
|
124
|
+
console.log(chalk.dim(` ${options.output}/shadows.${ext}`));
|
|
125
|
+
}
|
|
126
|
+
console.log();
|
|
127
|
+
} catch (error) {
|
|
128
|
+
spinner.fail(chalk.red("Failed to generate tokens"));
|
|
129
|
+
console.error(error);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { adjustColorForContrast, calculateContrast, meetsWCAG } from "bdsg";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
|
|
5
|
+
export const validateCommand = new Command("validate")
|
|
6
|
+
.description("Validate WCAG contrast between colors")
|
|
7
|
+
.argument("<foreground>", "Foreground color in hex format")
|
|
8
|
+
.argument("<background>", "Background color in hex format")
|
|
9
|
+
.option("-l, --level <level>", "Target WCAG level (AA, AAA)", "AA")
|
|
10
|
+
.option("-s, --size <size>", "Text size (normal, large)", "normal")
|
|
11
|
+
.action((foreground, background, options) => {
|
|
12
|
+
console.log(chalk.bold("\n Contrast Analysis\n"));
|
|
13
|
+
|
|
14
|
+
// Calculate contrast
|
|
15
|
+
const ratio = calculateContrast(foreground, background);
|
|
16
|
+
|
|
17
|
+
// Check each combination
|
|
18
|
+
const AANormal = meetsWCAG(ratio, "AA", "normal");
|
|
19
|
+
const AALarge = meetsWCAG(ratio, "AA", "large");
|
|
20
|
+
const AAANormal = meetsWCAG(ratio, "AAA", "normal");
|
|
21
|
+
const AAALarge = meetsWCAG(ratio, "AAA", "large");
|
|
22
|
+
|
|
23
|
+
// Display colors
|
|
24
|
+
console.log(chalk.dim("Colors"));
|
|
25
|
+
console.log(chalk.dim("──────────────────"));
|
|
26
|
+
console.log(` Foreground: ${chalk.hex(foreground)(foreground)}`);
|
|
27
|
+
console.log(` Background: ${chalk.hex(background)("████")} ${background}`);
|
|
28
|
+
console.log(` Ratio: ${chalk.bold(ratio.toFixed(2))}:1`);
|
|
29
|
+
console.log();
|
|
30
|
+
|
|
31
|
+
// WCAG Results
|
|
32
|
+
console.log(chalk.dim("WCAG Results"));
|
|
33
|
+
console.log(chalk.dim("──────────────────"));
|
|
34
|
+
|
|
35
|
+
const passSymbol = chalk.green("✓ Pass");
|
|
36
|
+
const failSymbol = chalk.red("✗ Fail");
|
|
37
|
+
|
|
38
|
+
console.log(
|
|
39
|
+
` AA Normal Text: ${AANormal ? passSymbol : failSymbol} (needs 4.5:1)`,
|
|
40
|
+
);
|
|
41
|
+
console.log(
|
|
42
|
+
` AA Large Text: ${AALarge ? passSymbol : failSymbol} (needs 3.0:1)`,
|
|
43
|
+
);
|
|
44
|
+
console.log(
|
|
45
|
+
` AAA Normal Text: ${AAANormal ? passSymbol : failSymbol} (needs 7.0:1)`,
|
|
46
|
+
);
|
|
47
|
+
console.log(
|
|
48
|
+
` AAA Large Text: ${AAALarge ? passSymbol : failSymbol} (needs 4.5:1)`,
|
|
49
|
+
);
|
|
50
|
+
console.log();
|
|
51
|
+
|
|
52
|
+
// Suggest fix if failing target level
|
|
53
|
+
const targetLevel = options.level as "AA" | "AAA";
|
|
54
|
+
const textSize = options.size as "normal" | "large";
|
|
55
|
+
const targetMet = meetsWCAG(ratio, targetLevel, textSize);
|
|
56
|
+
|
|
57
|
+
if (!targetMet) {
|
|
58
|
+
console.log(chalk.dim("Suggestion"));
|
|
59
|
+
console.log(chalk.dim("──────────────────"));
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const adjusted = adjustColorForContrast(
|
|
63
|
+
foreground,
|
|
64
|
+
background,
|
|
65
|
+
targetLevel,
|
|
66
|
+
textSize,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (adjusted.adjusted !== foreground) {
|
|
70
|
+
console.log(` For ${targetLevel} ${textSize} text compliance:`);
|
|
71
|
+
console.log(
|
|
72
|
+
` Try: ${chalk.hex(adjusted.adjusted)(adjusted.adjusted)} (ratio: ${adjusted.ratio.toFixed(2)}:1)`,
|
|
73
|
+
);
|
|
74
|
+
console.log(` Strategy: ${adjusted.strategy}`);
|
|
75
|
+
} else {
|
|
76
|
+
console.log(chalk.yellow(" Could not find a suitable adjustment."));
|
|
77
|
+
}
|
|
78
|
+
} catch {
|
|
79
|
+
console.log(chalk.yellow(" Could not calculate adjustment."));
|
|
80
|
+
}
|
|
81
|
+
console.log();
|
|
82
|
+
} else {
|
|
83
|
+
console.log(
|
|
84
|
+
chalk.green(
|
|
85
|
+
`✓ Colors meet ${targetLevel} ${textSize} text requirements!\n`,
|
|
86
|
+
),
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { generateCommand } from "./commands/generate.js";
|
|
4
|
+
import { initCommand } from "./commands/init.js";
|
|
5
|
+
import { validateCommand } from "./commands/validate.js";
|
|
6
|
+
|
|
7
|
+
const program = new Command();
|
|
8
|
+
|
|
9
|
+
program
|
|
10
|
+
.name("bdsg")
|
|
11
|
+
.description("Design system generation CLI")
|
|
12
|
+
.version("0.1.0");
|
|
13
|
+
|
|
14
|
+
program.addCommand(initCommand);
|
|
15
|
+
program.addCommand(generateCommand);
|
|
16
|
+
program.addCommand(validateCommand);
|
|
17
|
+
|
|
18
|
+
program.parse();
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import type {
|
|
4
|
+
ColorPalette,
|
|
5
|
+
ShadowScale,
|
|
6
|
+
SpacingScale,
|
|
7
|
+
TypographyScale,
|
|
8
|
+
} from "bdsg";
|
|
9
|
+
|
|
10
|
+
interface TokensToWrite {
|
|
11
|
+
palette: ColorPalette;
|
|
12
|
+
typography: TypographyScale;
|
|
13
|
+
spacing: SpacingScale;
|
|
14
|
+
shadows: ShadowScale;
|
|
15
|
+
format: "css" | "json" | "tailwind-v4" | "shadcn";
|
|
16
|
+
outputDir: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function writeTokensToFile(tokens: TokensToWrite): Promise<void> {
|
|
20
|
+
await mkdir(tokens.outputDir, { recursive: true });
|
|
21
|
+
|
|
22
|
+
if (tokens.format === "json") {
|
|
23
|
+
await writeJsonTokens(tokens);
|
|
24
|
+
} else if (tokens.format === "tailwind-v4") {
|
|
25
|
+
await writeTailwindV4Tokens(tokens);
|
|
26
|
+
} else if (tokens.format === "shadcn") {
|
|
27
|
+
await writeShadcnTokens(tokens);
|
|
28
|
+
} else {
|
|
29
|
+
await writeCssTokens(tokens);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function writeCssTokens(tokens: TokensToWrite): Promise<void> {
|
|
34
|
+
// Colors CSS
|
|
35
|
+
const colorsContent = generateColorsCss(tokens.palette);
|
|
36
|
+
await writeFile(join(tokens.outputDir, "colors.css"), colorsContent);
|
|
37
|
+
|
|
38
|
+
// Typography CSS
|
|
39
|
+
await writeFile(
|
|
40
|
+
join(tokens.outputDir, "typography.css"),
|
|
41
|
+
tokens.typography.cssVariables,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
// Spacing CSS
|
|
45
|
+
await writeFile(
|
|
46
|
+
join(tokens.outputDir, "spacing.css"),
|
|
47
|
+
tokens.spacing.cssVariables,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
// Shadows CSS
|
|
51
|
+
await writeFile(
|
|
52
|
+
join(tokens.outputDir, "shadows.css"),
|
|
53
|
+
tokens.shadows.cssVariables,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function writeJsonTokens(tokens: TokensToWrite): Promise<void> {
|
|
58
|
+
// Colors JSON
|
|
59
|
+
const colors: Record<string, string> = {};
|
|
60
|
+
for (const [shade, data] of Object.entries(tokens.palette.shades)) {
|
|
61
|
+
colors[`primary-${shade}`] = data.value;
|
|
62
|
+
}
|
|
63
|
+
await writeFile(
|
|
64
|
+
join(tokens.outputDir, "colors.json"),
|
|
65
|
+
JSON.stringify({ colors }, null, 2),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// Typography JSON
|
|
69
|
+
const typography: Record<string, unknown> = {};
|
|
70
|
+
for (const token of tokens.typography.tokens) {
|
|
71
|
+
typography[token.name] = {
|
|
72
|
+
fontSize: token.fontSize,
|
|
73
|
+
lineHeight: token.lineHeight,
|
|
74
|
+
letterSpacing: token.letterSpacing,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
await writeFile(
|
|
78
|
+
join(tokens.outputDir, "typography.json"),
|
|
79
|
+
JSON.stringify({ typography }, null, 2),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Spacing JSON
|
|
83
|
+
const spacing: Record<string, unknown> = {};
|
|
84
|
+
for (const token of tokens.spacing.tokens) {
|
|
85
|
+
spacing[token.name] = {
|
|
86
|
+
value: token.formatted,
|
|
87
|
+
px: token.value,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
await writeFile(
|
|
91
|
+
join(tokens.outputDir, "spacing.json"),
|
|
92
|
+
JSON.stringify({ spacing }, null, 2),
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// Shadows JSON
|
|
96
|
+
const shadows: Record<string, string> = {};
|
|
97
|
+
for (const token of tokens.shadows.tokens) {
|
|
98
|
+
shadows[token.name] = token.value;
|
|
99
|
+
}
|
|
100
|
+
await writeFile(
|
|
101
|
+
join(tokens.outputDir, "shadows.json"),
|
|
102
|
+
JSON.stringify({ shadows }, null, 2),
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function writeTailwindV4Tokens(tokens: TokensToWrite): Promise<void> {
|
|
107
|
+
let content = '@import "tailwindcss";\n\n@theme {\n';
|
|
108
|
+
|
|
109
|
+
// Colors
|
|
110
|
+
for (const [shade, data] of Object.entries(tokens.palette.shades)) {
|
|
111
|
+
content += ` --color-primary-${shade}: ${data.value};\n`;
|
|
112
|
+
}
|
|
113
|
+
content += "\n";
|
|
114
|
+
|
|
115
|
+
// Typography
|
|
116
|
+
for (const token of tokens.typography.tokens) {
|
|
117
|
+
const remValue = token.fontSize / 16;
|
|
118
|
+
content += ` --font-size-${token.name}: ${remValue}rem;\n`;
|
|
119
|
+
}
|
|
120
|
+
content += "\n";
|
|
121
|
+
|
|
122
|
+
// Spacing
|
|
123
|
+
for (const token of tokens.spacing.tokens) {
|
|
124
|
+
content += ` --spacing-${token.name}: ${token.formatted};\n`;
|
|
125
|
+
}
|
|
126
|
+
content += "\n";
|
|
127
|
+
|
|
128
|
+
// Shadows
|
|
129
|
+
for (const token of tokens.shadows.tokens) {
|
|
130
|
+
content += ` --shadow-${token.name}: ${token.value};\n`;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
content += "}\n";
|
|
134
|
+
|
|
135
|
+
await writeFile(join(tokens.outputDir, "theme.css"), content);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function generateColorsCss(palette: ColorPalette): string {
|
|
139
|
+
let css = ":root {\n";
|
|
140
|
+
for (const [shade, data] of Object.entries(palette.shades)) {
|
|
141
|
+
css += ` --color-primary-${shade}: ${data.value};\n`;
|
|
142
|
+
}
|
|
143
|
+
css += "}\n";
|
|
144
|
+
return css;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function writeShadcnTokens(tokens: TokensToWrite): Promise<void> {
|
|
148
|
+
const shades = tokens.palette.shades;
|
|
149
|
+
|
|
150
|
+
// Light mode tokens (using palette shades)
|
|
151
|
+
const lightTokens = {
|
|
152
|
+
background: "#ffffff",
|
|
153
|
+
foreground: shades[900].value,
|
|
154
|
+
card: "#ffffff",
|
|
155
|
+
"card-foreground": shades[900].value,
|
|
156
|
+
popover: "#ffffff",
|
|
157
|
+
"popover-foreground": shades[900].value,
|
|
158
|
+
primary: shades[500].value,
|
|
159
|
+
"primary-foreground": shades[50].value,
|
|
160
|
+
secondary: shades[100].value,
|
|
161
|
+
"secondary-foreground": shades[900].value,
|
|
162
|
+
muted: shades[100].value,
|
|
163
|
+
"muted-foreground": shades[500].value,
|
|
164
|
+
accent: shades[100].value,
|
|
165
|
+
"accent-foreground": shades[900].value,
|
|
166
|
+
destructive: "#ef4444",
|
|
167
|
+
border: shades[200].value,
|
|
168
|
+
input: shades[200].value,
|
|
169
|
+
ring: shades[500].value,
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// Dark mode tokens (inverted)
|
|
173
|
+
const darkTokens = {
|
|
174
|
+
background: shades[900].value,
|
|
175
|
+
foreground: shades[50].value,
|
|
176
|
+
card: shades[800].value,
|
|
177
|
+
"card-foreground": shades[50].value,
|
|
178
|
+
popover: shades[800].value,
|
|
179
|
+
"popover-foreground": shades[50].value,
|
|
180
|
+
primary: shades[400].value,
|
|
181
|
+
"primary-foreground": shades[900].value,
|
|
182
|
+
secondary: shades[700].value,
|
|
183
|
+
"secondary-foreground": shades[50].value,
|
|
184
|
+
muted: shades[700].value,
|
|
185
|
+
"muted-foreground": shades[400].value,
|
|
186
|
+
accent: shades[700].value,
|
|
187
|
+
"accent-foreground": shades[50].value,
|
|
188
|
+
destructive: "#dc2626",
|
|
189
|
+
border: shades[700].value,
|
|
190
|
+
input: shades[700].value,
|
|
191
|
+
ring: shades[400].value,
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
let content = '@import "tailwindcss";\n\n';
|
|
195
|
+
|
|
196
|
+
// @theme block for Tailwind v4 mapping
|
|
197
|
+
content += "@custom-variant dark (&:is(.dark *));\n\n";
|
|
198
|
+
content += "@theme inline {\n";
|
|
199
|
+
content += " --color-background: var(--background);\n";
|
|
200
|
+
content += " --color-foreground: var(--foreground);\n";
|
|
201
|
+
content += " --color-card: var(--card);\n";
|
|
202
|
+
content += " --color-card-foreground: var(--card-foreground);\n";
|
|
203
|
+
content += " --color-popover: var(--popover);\n";
|
|
204
|
+
content += " --color-popover-foreground: var(--popover-foreground);\n";
|
|
205
|
+
content += " --color-primary: var(--primary);\n";
|
|
206
|
+
content += " --color-primary-foreground: var(--primary-foreground);\n";
|
|
207
|
+
content += " --color-secondary: var(--secondary);\n";
|
|
208
|
+
content += " --color-secondary-foreground: var(--secondary-foreground);\n";
|
|
209
|
+
content += " --color-muted: var(--muted);\n";
|
|
210
|
+
content += " --color-muted-foreground: var(--muted-foreground);\n";
|
|
211
|
+
content += " --color-accent: var(--accent);\n";
|
|
212
|
+
content += " --color-accent-foreground: var(--accent-foreground);\n";
|
|
213
|
+
content += " --color-destructive: var(--destructive);\n";
|
|
214
|
+
content += " --color-border: var(--border);\n";
|
|
215
|
+
content += " --color-input: var(--input);\n";
|
|
216
|
+
content += " --color-ring: var(--ring);\n";
|
|
217
|
+
content += " --radius-sm: calc(var(--radius) - 4px);\n";
|
|
218
|
+
content += " --radius-md: calc(var(--radius) - 2px);\n";
|
|
219
|
+
content += " --radius-lg: var(--radius);\n";
|
|
220
|
+
content += " --radius-xl: calc(var(--radius) + 4px);\n";
|
|
221
|
+
content += "}\n\n";
|
|
222
|
+
|
|
223
|
+
// :root with light mode tokens
|
|
224
|
+
content += ":root {\n";
|
|
225
|
+
content += " --radius: 0.625rem;\n";
|
|
226
|
+
for (const [name, value] of Object.entries(lightTokens)) {
|
|
227
|
+
content += ` --${name}: ${value};\n`;
|
|
228
|
+
}
|
|
229
|
+
content += "}\n\n";
|
|
230
|
+
|
|
231
|
+
// .dark with dark mode tokens
|
|
232
|
+
content += ".dark {\n";
|
|
233
|
+
for (const [name, value] of Object.entries(darkTokens)) {
|
|
234
|
+
content += ` --${name}: ${value};\n`;
|
|
235
|
+
}
|
|
236
|
+
content += "}\n\n";
|
|
237
|
+
|
|
238
|
+
// Base layer
|
|
239
|
+
content += "@layer base {\n";
|
|
240
|
+
content += " * {\n";
|
|
241
|
+
content += " @apply border-border outline-ring/50;\n";
|
|
242
|
+
content += " }\n";
|
|
243
|
+
content += " body {\n";
|
|
244
|
+
content += " @apply bg-background text-foreground;\n";
|
|
245
|
+
content += " }\n";
|
|
246
|
+
content += "}\n";
|
|
247
|
+
|
|
248
|
+
await writeFile(join(tokens.outputDir, "globals.css"), content);
|
|
249
|
+
}
|
package/tsconfig.json
ADDED