gradient-forge 1.0.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/.eslintrc.json +3 -0
- package/.github/FUNDING.yml +2 -0
- package/README.md +140 -0
- package/app/docs/page.tsx +417 -0
- package/app/gallery/page.tsx +398 -0
- package/app/globals.css +1155 -0
- package/app/layout.tsx +36 -0
- package/app/page.tsx +600 -0
- package/app/showcase/page.tsx +730 -0
- package/app/studio/page.tsx +1310 -0
- package/cli/index.mjs +1141 -0
- package/cli/templates/theme-context.tsx +120 -0
- package/cli/templates/theme-engine.ts +237 -0
- package/cli/templates/themes.css +512 -0
- package/components/site/component-showcase.tsx +623 -0
- package/components/site/site-data.ts +103 -0
- package/components/site/site-header.tsx +270 -0
- package/components/templates/blog.tsx +198 -0
- package/components/templates/components-showcase.tsx +298 -0
- package/components/templates/dashboard.tsx +246 -0
- package/components/templates/ecommerce.tsx +199 -0
- package/components/templates/mail.tsx +275 -0
- package/components/templates/saas-landing.tsx +169 -0
- package/components/theme/studio-code-panel.tsx +485 -0
- package/components/theme/theme-context.tsx +120 -0
- package/components/theme/theme-engine.ts +237 -0
- package/components/theme/theme-exporter.tsx +369 -0
- package/components/theme/theme-panel.tsx +268 -0
- package/components/theme/token-export-utils.ts +1211 -0
- package/components/ui/animated.tsx +55 -0
- package/components/ui/avatar.tsx +38 -0
- package/components/ui/badge.tsx +32 -0
- package/components/ui/button.tsx +65 -0
- package/components/ui/card.tsx +56 -0
- package/components/ui/checkbox.tsx +19 -0
- package/components/ui/command-palette.tsx +245 -0
- package/components/ui/gsap-animated.tsx +436 -0
- package/components/ui/input.tsx +17 -0
- package/components/ui/select.tsx +176 -0
- package/components/ui/skeleton.tsx +102 -0
- package/components/ui/switch.tsx +43 -0
- package/components/ui/tabs.tsx +115 -0
- package/components/ui/toast.tsx +119 -0
- package/gradient-forge/theme-context.tsx +119 -0
- package/gradient-forge/theme-engine.ts +236 -0
- package/gradient-forge/themes.css +556 -0
- package/lib/animations.ts +50 -0
- package/lib/gsap.ts +426 -0
- package/lib/utils.ts +6 -0
- package/next-env.d.ts +6 -0
- package/next.config.mjs +6 -0
- package/package.json +53 -0
- package/postcss.config.mjs +5 -0
- package/tailwind.config.ts +15 -0
- package/tsconfig.json +43 -0
- package/tsconfig.tsbuildinfo +1 -0
package/cli/index.mjs
ADDED
|
@@ -0,0 +1,1141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import readline from "node:readline";
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
const templateDir = path.join(__dirname, "templates");
|
|
10
|
+
|
|
11
|
+
const args = process.argv.slice(2);
|
|
12
|
+
const command = args[0] ?? "help";
|
|
13
|
+
|
|
14
|
+
const readArg = (flag, fallback) => {
|
|
15
|
+
const idx = args.indexOf(flag);
|
|
16
|
+
if (idx === -1) return fallback;
|
|
17
|
+
const next = args[idx + 1];
|
|
18
|
+
if (!next || next.startsWith("--")) return fallback;
|
|
19
|
+
return next;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const hasFlag = (flag) => args.includes(flag);
|
|
23
|
+
|
|
24
|
+
const log = (message) => process.stdout.write(`${message}\n`);
|
|
25
|
+
const logError = (message) => process.stderr.write(`${message}\n`);
|
|
26
|
+
const logSuccess = (message) => process.stdout.write(`✅ ${message}\n`);
|
|
27
|
+
const logInfo = (message) => process.stdout.write(`ℹ️ ${message}\n`);
|
|
28
|
+
|
|
29
|
+
const themes = [
|
|
30
|
+
{ id: "theme-nitro-mint-apple", label: "Mint Apple", preview: "linear-gradient(145deg, #2d8e74, #70c76a, #d5ef91)" },
|
|
31
|
+
{ id: "theme-nitro-citrus-sherbert", label: "Citrus Sherbert", preview: "linear-gradient(145deg, #e67d35, #f7bb54, #fff0a3)" },
|
|
32
|
+
{ id: "theme-nitro-retro-raincloud", label: "Retro Raincloud", preview: "linear-gradient(145deg, #4e6077, #6f86a0, #98aec3)" },
|
|
33
|
+
{ id: "theme-nitro-hanami", label: "Hanami", preview: "linear-gradient(145deg, #995382, #c77ca9, #f0b7ce)" },
|
|
34
|
+
{ id: "theme-nitro-sunrise", label: "Sunrise", preview: "linear-gradient(145deg, #e25263, #ef8a57, #ffd07a)" },
|
|
35
|
+
{ id: "theme-nitro-cotton-candy", label: "Cotton Candy", preview: "linear-gradient(145deg, #5aa2ff, #9b78f0, #f39bca)" },
|
|
36
|
+
{ id: "theme-nitro-lofi-vibes", label: "Lofi Vibes", preview: "linear-gradient(145deg, #3f476c, #59608f, #7a6f9f)" },
|
|
37
|
+
{ id: "theme-nitro-desert-khaki", label: "Desert Khaki", preview: "linear-gradient(145deg, #6d5c49, #8f7a5d, #b49f76)" },
|
|
38
|
+
{ id: "theme-nitro-sunset", label: "Sunset", preview: "linear-gradient(145deg, #3f1b4d, #8c335f, #f4874f)" },
|
|
39
|
+
{ id: "theme-nitro-chroma-glow", label: "Chroma Glow", preview: "linear-gradient(145deg, #2d3eff, #a726fa, #00c7ff)" },
|
|
40
|
+
{ id: "theme-nitro-forest", label: "Forest", preview: "linear-gradient(145deg, #163f2e, #246b49, #59a86c)" },
|
|
41
|
+
{ id: "theme-nitro-crimson", label: "Crimson", preview: "linear-gradient(145deg, #2d050f, #681126, #a82435)" },
|
|
42
|
+
{ id: "theme-nitro-midnight-blurple", label: "Midnight Blurple", preview: "linear-gradient(145deg, #0f1232, #25366f, #5757dc)" },
|
|
43
|
+
{ id: "theme-nitro-mars", label: "Mars", preview: "linear-gradient(145deg, #2e140f, #5e261d, #9c422f)" },
|
|
44
|
+
{ id: "theme-nitro-dusk", label: "Dusk", preview: "linear-gradient(145deg, #1b1632, #3b2d5b, #745495)" },
|
|
45
|
+
{ id: "theme-nitro-under-the-sea", label: "Under The Sea", preview: "linear-gradient(145deg, #0b2242, #0d4f69, #2b848e)" },
|
|
46
|
+
{ id: "theme-nitro-retro-storm", label: "Retro Storm", preview: "linear-gradient(145deg, #1d2b3a, #354657, #55667a)" },
|
|
47
|
+
{ id: "theme-nitro-neon-nights", label: "Neon Nights", preview: "linear-gradient(145deg, #05061a, #180f52, #00bde6)" },
|
|
48
|
+
{ id: "theme-nitro-strawberry-lemonade", label: "Strawberry Lemonade", preview: "linear-gradient(145deg, #8f1847, #cc3f5e, #efc141)" },
|
|
49
|
+
{ id: "theme-nitro-aurora", label: "Aurora", preview: "linear-gradient(145deg, #083142, #1b7e74, #5fbf75)" },
|
|
50
|
+
{ id: "theme-nitro-sepia", label: "Sepia", preview: "linear-gradient(145deg, #35261d, #5d4636, #927454)" },
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
const themeTokens = {
|
|
54
|
+
"theme-nitro-mint-apple": {
|
|
55
|
+
"--background": "160 45% 18%",
|
|
56
|
+
"--foreground": "150 40% 95%",
|
|
57
|
+
"--card": "160 40% 20%",
|
|
58
|
+
"--card-foreground": "150 40% 95%",
|
|
59
|
+
"--popover": "160 40% 20%",
|
|
60
|
+
"--popover-foreground": "150 40% 95%",
|
|
61
|
+
"--primary": "145 50% 55%",
|
|
62
|
+
"--primary-foreground": "160 40% 10%",
|
|
63
|
+
"--secondary": "100 45% 68%",
|
|
64
|
+
"--secondary-foreground": "160 40% 10%",
|
|
65
|
+
"--muted": "160 35% 25%",
|
|
66
|
+
"--muted-foreground": "150 30% 70%",
|
|
67
|
+
"--accent": "100 45% 68%",
|
|
68
|
+
"--accent-foreground": "160 40% 10%",
|
|
69
|
+
"--destructive": "0 84% 60%",
|
|
70
|
+
"--destructive-foreground": "0 0% 98%",
|
|
71
|
+
"--border": "160 30% 30%",
|
|
72
|
+
"--input": "160 30% 30%",
|
|
73
|
+
"--ring": "145 50% 55%",
|
|
74
|
+
"--app-gradient": "radial-gradient(1050px 560px at -10% -20%, hsl(156 58% 60% / 0.3), transparent 60%), radial-gradient(940px 520px at 114% 0%, hsl(96 64% 62% / 0.22), transparent 58%), linear-gradient(160deg, hsl(156 27% 13%) 0%, hsl(149 23% 13%) 50%, hsl(136 21% 10%) 100%)",
|
|
75
|
+
"--app-surface-tint": "hsl(145 50% 55% / 0.1)",
|
|
76
|
+
},
|
|
77
|
+
"theme-nitro-citrus-sherbert": {
|
|
78
|
+
"--background": "25 70% 15%",
|
|
79
|
+
"--foreground": "35 60% 95%",
|
|
80
|
+
"--card": "25 65% 18%",
|
|
81
|
+
"--card-foreground": "35 60% 95%",
|
|
82
|
+
"--popover": "25 65% 18%",
|
|
83
|
+
"--popover-foreground": "35 60% 95%",
|
|
84
|
+
"--primary": "25 80% 55%",
|
|
85
|
+
"--primary-foreground": "25 70% 10%",
|
|
86
|
+
"--secondary": "45 85% 65%",
|
|
87
|
+
"--secondary-foreground": "25 70% 10%",
|
|
88
|
+
"--muted": "25 50% 25%",
|
|
89
|
+
"--muted-foreground": "35 40% 70%",
|
|
90
|
+
"--accent": "55 90% 75%",
|
|
91
|
+
"--accent-foreground": "25 70% 10%",
|
|
92
|
+
"--destructive": "0 84% 60%",
|
|
93
|
+
"--destructive-foreground": "0 0% 98%",
|
|
94
|
+
"--border": "25 45% 30%",
|
|
95
|
+
"--input": "25 45% 30%",
|
|
96
|
+
"--ring": "25 80% 55%",
|
|
97
|
+
"--app-gradient": "radial-gradient(1060px 560px at -10% -20%, hsl(28 97% 66% / 0.3), transparent 58%), radial-gradient(920px 520px at 112% 4%, hsl(53 95% 68% / 0.22), transparent 58%), linear-gradient(160deg, hsl(34 29% 12%) 0%, hsl(32 24% 13%) 50%, hsl(27 21% 10%) 100%)",
|
|
98
|
+
"--app-surface-tint": "hsl(25 80% 55% / 0.1)",
|
|
99
|
+
},
|
|
100
|
+
"theme-nitro-retro-raincloud": {
|
|
101
|
+
"--background": "215 25% 20%",
|
|
102
|
+
"--foreground": "210 30% 95%",
|
|
103
|
+
"--card": "215 22% 23%",
|
|
104
|
+
"--card-foreground": "210 30% 95%",
|
|
105
|
+
"--popover": "215 22% 23%",
|
|
106
|
+
"--popover-foreground": "210 30% 95%",
|
|
107
|
+
"--primary": "210 25% 55%",
|
|
108
|
+
"--primary-foreground": "215 25% 15%",
|
|
109
|
+
"--secondary": "210 20% 65%",
|
|
110
|
+
"--secondary-foreground": "215 25% 15%",
|
|
111
|
+
"--muted": "215 20% 30%",
|
|
112
|
+
"--muted-foreground": "210 20% 70%",
|
|
113
|
+
"--accent": "210 20% 65%",
|
|
114
|
+
"--accent-foreground": "215 25% 15%",
|
|
115
|
+
"--destructive": "0 84% 60%",
|
|
116
|
+
"--destructive-foreground": "0 0% 98%",
|
|
117
|
+
"--border": "215 20% 35%",
|
|
118
|
+
"--input": "215 20% 35%",
|
|
119
|
+
"--ring": "210 25% 55%",
|
|
120
|
+
"--app-gradient": "radial-gradient(1080px 560px at -8% -20%, hsl(215 36% 66% / 0.28), transparent 60%), radial-gradient(940px 520px at 114% 2%, hsl(206 30% 64% / 0.2), transparent 58%), linear-gradient(160deg, hsl(217 21% 13%) 0%, hsl(214 18% 13%) 52%, hsl(211 16% 10%) 100%)",
|
|
121
|
+
"--app-surface-tint": "hsl(210 25% 55% / 0.1)",
|
|
122
|
+
},
|
|
123
|
+
"theme-nitro-hanami": {
|
|
124
|
+
"--background": "330 30% 20%",
|
|
125
|
+
"--foreground": "330 30% 95%",
|
|
126
|
+
"--card": "330 25% 23%",
|
|
127
|
+
"--card-foreground": "330 30% 95%",
|
|
128
|
+
"--popover": "330 25% 23%",
|
|
129
|
+
"--popover-foreground": "330 30% 95%",
|
|
130
|
+
"--primary": "330 40% 55%",
|
|
131
|
+
"--primary-foreground": "330 30% 10%",
|
|
132
|
+
"--secondary": "340 45% 65%",
|
|
133
|
+
"--secondary-foreground": "330 30% 10%",
|
|
134
|
+
"--muted": "330 20% 30%",
|
|
135
|
+
"--muted-foreground": "330 25% 70%",
|
|
136
|
+
"--accent": "350 50% 75%",
|
|
137
|
+
"--accent-foreground": "330 30% 10%",
|
|
138
|
+
"--destructive": "0 84% 60%",
|
|
139
|
+
"--destructive-foreground": "0 0% 98%",
|
|
140
|
+
"--border": "330 20% 35%",
|
|
141
|
+
"--input": "330 20% 35%",
|
|
142
|
+
"--ring": "330 40% 55%",
|
|
143
|
+
"--app-gradient": "radial-gradient(1040px 560px at -10% -20%, hsl(319 65% 69% / 0.3), transparent 58%), radial-gradient(920px 520px at 112% 2%, hsl(339 58% 75% / 0.22), transparent 58%), linear-gradient(160deg, hsl(323 27% 12%) 0%, hsl(315 23% 13%) 50%, hsl(304 19% 10%) 100%)",
|
|
144
|
+
"--app-surface-tint": "hsl(330 40% 55% / 0.1)",
|
|
145
|
+
},
|
|
146
|
+
"theme-nitro-sunrise": {
|
|
147
|
+
"--background": "350 50% 18%",
|
|
148
|
+
"--foreground": "30 60% 95%",
|
|
149
|
+
"--card": "350 45% 21%",
|
|
150
|
+
"--card-foreground": "30 60% 95%",
|
|
151
|
+
"--popover": "350 45% 21%",
|
|
152
|
+
"--popover-foreground": "30 60% 95%",
|
|
153
|
+
"--primary": "355 75% 60%",
|
|
154
|
+
"--primary-foreground": "350 50% 10%",
|
|
155
|
+
"--secondary": "25 85% 65%",
|
|
156
|
+
"--secondary-foreground": "350 50% 10%",
|
|
157
|
+
"--muted": "350 30% 28%",
|
|
158
|
+
"--muted-foreground": "30 40% 75%",
|
|
159
|
+
"--accent": "45 90% 73%",
|
|
160
|
+
"--accent-foreground": "350 50% 10%",
|
|
161
|
+
"--destructive": "0 84% 60%",
|
|
162
|
+
"--destructive-foreground": "0 0% 98%",
|
|
163
|
+
"--border": "350 25% 35%",
|
|
164
|
+
"--input": "350 25% 35%",
|
|
165
|
+
"--ring": "355 75% 60%",
|
|
166
|
+
"--app-gradient": "radial-gradient(1080px 560px at -12% -20%, hsl(2 88% 66% / 0.28), transparent 58%), radial-gradient(920px 520px at 114% 4%, hsl(35 96% 67% / 0.24), transparent 58%), linear-gradient(160deg, hsl(9 30% 12%) 0%, hsl(13 26% 13%) 50%, hsl(21 21% 10%) 100%)",
|
|
167
|
+
"--app-surface-tint": "hsl(355 75% 60% / 0.1)",
|
|
168
|
+
},
|
|
169
|
+
"theme-nitro-cotton-candy": {
|
|
170
|
+
"--background": "220 50% 20%",
|
|
171
|
+
"--foreground": "220 40% 95%",
|
|
172
|
+
"--card": "220 45% 23%",
|
|
173
|
+
"--card-foreground": "220 40% 95%",
|
|
174
|
+
"--popover": "220 45% 23%",
|
|
175
|
+
"--popover-foreground": "220 40% 95%",
|
|
176
|
+
"--primary": "220 70% 65%",
|
|
177
|
+
"--primary-foreground": "220 50% 10%",
|
|
178
|
+
"--secondary": "270 60% 70%",
|
|
179
|
+
"--secondary-foreground": "220 50% 10%",
|
|
180
|
+
"--muted": "220 30% 30%",
|
|
181
|
+
"--muted-foreground": "220 30% 75%",
|
|
182
|
+
"--accent": "330 65% 75%",
|
|
183
|
+
"--accent-foreground": "220 50% 10%",
|
|
184
|
+
"--destructive": "0 84% 60%",
|
|
185
|
+
"--destructive-foreground": "0 0% 98%",
|
|
186
|
+
"--border": "220 25% 35%",
|
|
187
|
+
"--input": "220 25% 35%",
|
|
188
|
+
"--ring": "220 70% 65%",
|
|
189
|
+
"--app-gradient": "radial-gradient(1040px 560px at -10% -20%, hsl(208 95% 74% / 0.28), transparent 58%), radial-gradient(940px 520px at 112% 4%, hsl(328 87% 73% / 0.24), transparent 58%), linear-gradient(160deg, hsl(247 30% 12%) 0%, hsl(258 26% 13%) 48%, hsl(286 20% 10%) 100%)",
|
|
190
|
+
"--app-surface-tint": "hsl(220 70% 65% / 0.1)",
|
|
191
|
+
},
|
|
192
|
+
"theme-nitro-lofi-vibes": {
|
|
193
|
+
"--background": "230 25% 18%",
|
|
194
|
+
"--foreground": "230 20% 95%",
|
|
195
|
+
"--card": "230 22% 21%",
|
|
196
|
+
"--card-foreground": "230 20% 95%",
|
|
197
|
+
"--popover": "230 22% 21%",
|
|
198
|
+
"--popover-foreground": "230 20% 95%",
|
|
199
|
+
"--primary": "230 25% 55%",
|
|
200
|
+
"--primary-foreground": "230 25% 10%",
|
|
201
|
+
"--secondary": "260 20% 60%",
|
|
202
|
+
"--secondary-foreground": "230 25% 10%",
|
|
203
|
+
"--muted": "230 15% 28%",
|
|
204
|
+
"--muted-foreground": "230 15% 70%",
|
|
205
|
+
"--accent": "280 20% 55%",
|
|
206
|
+
"--accent-foreground": "230 25% 10%",
|
|
207
|
+
"--destructive": "0 84% 60%",
|
|
208
|
+
"--destructive-foreground": "0 0% 98%",
|
|
209
|
+
"--border": "230 15% 33%",
|
|
210
|
+
"--input": "230 15% 33%",
|
|
211
|
+
"--ring": "230 25% 55%",
|
|
212
|
+
"--app-gradient": "radial-gradient(1060px 560px at -10% -20%, hsl(228 44% 63% / 0.26), transparent 60%), radial-gradient(940px 520px at 112% 2%, hsl(267 38% 64% / 0.2), transparent 58%), linear-gradient(160deg, hsl(236 26% 13%) 0%, hsl(232 22% 13%) 50%, hsl(258 16% 10%) 100%)",
|
|
213
|
+
"--app-surface-tint": "hsl(230 25% 55% / 0.1)",
|
|
214
|
+
},
|
|
215
|
+
"theme-nitro-desert-khaki": {
|
|
216
|
+
"--background": "35 25% 18%",
|
|
217
|
+
"--foreground": "35 30% 95%",
|
|
218
|
+
"--card": "35 22% 21%",
|
|
219
|
+
"--card-foreground": "35 30% 95%",
|
|
220
|
+
"--popover": "35 22% 21%",
|
|
221
|
+
"--popover-foreground": "35 30% 95%",
|
|
222
|
+
"--primary": "35 25% 50%",
|
|
223
|
+
"--primary-foreground": "35 25% 10%",
|
|
224
|
+
"--secondary": "40 20% 58%",
|
|
225
|
+
"--secondary-foreground": "35 25% 10%",
|
|
226
|
+
"--muted": "35 15% 28%",
|
|
227
|
+
"--muted-foreground": "35 20% 70%",
|
|
228
|
+
"--accent": "45 25% 60%",
|
|
229
|
+
"--accent-foreground": "35 25% 10%",
|
|
230
|
+
"--destructive": "0 84% 60%",
|
|
231
|
+
"--destructive-foreground": "0 0% 98%",
|
|
232
|
+
"--border": "35 15% 33%",
|
|
233
|
+
"--input": "35 15% 33%",
|
|
234
|
+
"--ring": "35 25% 50%",
|
|
235
|
+
"--app-gradient": "radial-gradient(1060px 560px at -10% -18%, hsl(34 44% 58% / 0.26), transparent 58%), radial-gradient(920px 520px at 112% 2%, hsl(48 33% 63% / 0.18), transparent 58%), linear-gradient(160deg, hsl(37 23% 13%) 0%, hsl(34 20% 13%) 52%, hsl(30 16% 10%) 100%)",
|
|
236
|
+
"--app-surface-tint": "hsl(35 25% 50% / 0.1)",
|
|
237
|
+
},
|
|
238
|
+
"theme-nitro-sunset": {
|
|
239
|
+
"--background": "320 40% 15%",
|
|
240
|
+
"--foreground": "25 60% 95%",
|
|
241
|
+
"--card": "320 35% 18%",
|
|
242
|
+
"--card-foreground": "25 60% 95%",
|
|
243
|
+
"--popover": "320 35% 18%",
|
|
244
|
+
"--popover-foreground": "25 60% 95%",
|
|
245
|
+
"--primary": "335 60% 50%",
|
|
246
|
+
"--primary-foreground": "320 40% 10%",
|
|
247
|
+
"--secondary": "20 70% 55%",
|
|
248
|
+
"--secondary-foreground": "320 40% 10%",
|
|
249
|
+
"--muted": "320 25% 25%",
|
|
250
|
+
"--muted-foreground": "25 40% 75%",
|
|
251
|
+
"--accent": "25 85% 62%",
|
|
252
|
+
"--accent-foreground": "320 40% 10%",
|
|
253
|
+
"--destructive": "0 84% 60%",
|
|
254
|
+
"--destructive-foreground": "0 0% 98%",
|
|
255
|
+
"--border": "320 20% 32%",
|
|
256
|
+
"--input": "320 20% 32%",
|
|
257
|
+
"--ring": "335 60% 50%",
|
|
258
|
+
"--app-gradient": "radial-gradient(1040px 560px at -12% -20%, hsl(325 84% 62% / 0.31), transparent 58%), radial-gradient(900px 520px at 112% 6%, hsl(24 97% 66% / 0.24), transparent 58%), linear-gradient(160deg, hsl(304 29% 12%) 0%, hsl(298 24% 13%) 50%, hsl(287 22% 10%) 100%)",
|
|
259
|
+
"--app-surface-tint": "hsl(335 60% 50% / 0.1)",
|
|
260
|
+
},
|
|
261
|
+
"theme-nitro-chroma-glow": {
|
|
262
|
+
"--background": "246 33% 11%",
|
|
263
|
+
"--foreground": "240 40% 95%",
|
|
264
|
+
"--card": "246 28% 13%",
|
|
265
|
+
"--card-foreground": "240 40% 95%",
|
|
266
|
+
"--popover": "246 28% 13%",
|
|
267
|
+
"--popover-foreground": "240 40% 95%",
|
|
268
|
+
"--primary": "286 94% 67%",
|
|
269
|
+
"--primary-foreground": "246 36% 10%",
|
|
270
|
+
"--secondary": "195 100% 61%",
|
|
271
|
+
"--secondary-foreground": "246 36% 10%",
|
|
272
|
+
"--muted": "246 30% 22%",
|
|
273
|
+
"--muted-foreground": "240 25% 75%",
|
|
274
|
+
"--accent": "195 100% 61%",
|
|
275
|
+
"--accent-foreground": "246 36% 10%",
|
|
276
|
+
"--destructive": "0 84% 60%",
|
|
277
|
+
"--destructive-foreground": "0 0% 98%",
|
|
278
|
+
"--border": "246 25% 28%",
|
|
279
|
+
"--input": "246 25% 28%",
|
|
280
|
+
"--ring": "286 94% 67%",
|
|
281
|
+
"--app-gradient": "radial-gradient(1020px 560px at -12% -18%, hsl(226 95% 63% / 0.32), transparent 58%), radial-gradient(940px 520px at 112% 2%, hsl(194 100% 62% / 0.28), transparent 58%), linear-gradient(160deg, hsl(246 36% 12%) 0%, hsl(272 30% 12%) 50%, hsl(305 24% 10%) 100%)",
|
|
282
|
+
"--app-surface-tint": "hsl(286 94% 67% / 0.1)",
|
|
283
|
+
},
|
|
284
|
+
"theme-nitro-forest": {
|
|
285
|
+
"--background": "150 40% 12%",
|
|
286
|
+
"--foreground": "140 30% 95%",
|
|
287
|
+
"--card": "150 35% 15%",
|
|
288
|
+
"--card-foreground": "140 30% 95%",
|
|
289
|
+
"--popover": "150 35% 15%",
|
|
290
|
+
"--popover-foreground": "140 30% 95%",
|
|
291
|
+
"--primary": "145 45% 45%",
|
|
292
|
+
"--primary-foreground": "150 40% 10%",
|
|
293
|
+
"--secondary": "100 40% 55%",
|
|
294
|
+
"--secondary-foreground": "150 40% 10%",
|
|
295
|
+
"--muted": "150 25% 22%",
|
|
296
|
+
"--muted-foreground": "140 20% 70%",
|
|
297
|
+
"--accent": "85 45% 52%",
|
|
298
|
+
"--accent-foreground": "150 40% 10%",
|
|
299
|
+
"--destructive": "0 84% 60%",
|
|
300
|
+
"--destructive-foreground": "0 0% 98%",
|
|
301
|
+
"--border": "150 20% 28%",
|
|
302
|
+
"--input": "150 20% 28%",
|
|
303
|
+
"--ring": "145 45% 45%",
|
|
304
|
+
"--app-gradient": "radial-gradient(1080px 560px at -10% -20%, hsl(145 62% 53% / 0.3), transparent 60%), radial-gradient(920px 520px at 112% 2%, hsl(170 48% 53% / 0.22), transparent 58%), linear-gradient(160deg, hsl(149 30% 12%) 0%, hsl(146 26% 12%) 52%, hsl(160 21% 10%) 100%)",
|
|
305
|
+
"--app-surface-tint": "hsl(145 45% 45% / 0.1)",
|
|
306
|
+
},
|
|
307
|
+
"theme-nitro-crimson": {
|
|
308
|
+
"--background": "345 60% 8%",
|
|
309
|
+
"--foreground": "345 40% 95%",
|
|
310
|
+
"--card": "345 55% 11%",
|
|
311
|
+
"--card-foreground": "345 40% 95%",
|
|
312
|
+
"--popover": "345 55% 11%",
|
|
313
|
+
"--popover-foreground": "345 40% 95%",
|
|
314
|
+
"--primary": "350 65% 45%",
|
|
315
|
+
"--primary-foreground": "345 60% 98%",
|
|
316
|
+
"--secondary": "350 50% 55%",
|
|
317
|
+
"--secondary-foreground": "345 60% 98%",
|
|
318
|
+
"--muted": "345 30% 18%",
|
|
319
|
+
"--muted-foreground": "345 25% 70%",
|
|
320
|
+
"--accent": "355 55% 60%",
|
|
321
|
+
"--accent-foreground": "345 60% 10%",
|
|
322
|
+
"--destructive": "0 84% 60%",
|
|
323
|
+
"--destructive-foreground": "0 0% 98%",
|
|
324
|
+
"--border": "345 25% 25%",
|
|
325
|
+
"--input": "345 25% 25%",
|
|
326
|
+
"--ring": "350 65% 45%",
|
|
327
|
+
"--app-gradient": "radial-gradient(1040px 560px at -12% -18%, hsl(352 85% 59% / 0.34), transparent 58%), radial-gradient(900px 520px at 112% 4%, hsl(9 84% 58% / 0.22), transparent 58%), linear-gradient(160deg, hsl(349 37% 11%) 0%, hsl(342 31% 12%) 50%, hsl(326 24% 10%) 100%)",
|
|
328
|
+
"--app-surface-tint": "hsl(350 65% 45% / 0.1)",
|
|
329
|
+
},
|
|
330
|
+
"theme-nitro-midnight-blurple": {
|
|
331
|
+
"--background": "235 26% 11%",
|
|
332
|
+
"--foreground": "235 30% 95%",
|
|
333
|
+
"--card": "235 22% 12%",
|
|
334
|
+
"--card-foreground": "235 30% 95%",
|
|
335
|
+
"--popover": "235 22% 12%",
|
|
336
|
+
"--popover-foreground": "235 30% 95%",
|
|
337
|
+
"--primary": "241 92% 70%",
|
|
338
|
+
"--primary-foreground": "235 26% 98%",
|
|
339
|
+
"--secondary": "210 92% 65%",
|
|
340
|
+
"--secondary-foreground": "235 26% 98%",
|
|
341
|
+
"--muted": "235 20% 20%",
|
|
342
|
+
"--muted-foreground": "235 20% 72%",
|
|
343
|
+
"--accent": "210 92% 65%",
|
|
344
|
+
"--accent-foreground": "235 26% 98%",
|
|
345
|
+
"--destructive": "0 84% 60%",
|
|
346
|
+
"--destructive-foreground": "0 0% 98%",
|
|
347
|
+
"--border": "235 18% 25%",
|
|
348
|
+
"--input": "235 18% 25%",
|
|
349
|
+
"--ring": "241 92% 70%",
|
|
350
|
+
"--app-gradient": "radial-gradient(1050px 560px at -10% -20%, hsl(246 92% 66% / 0.3), transparent 60%), radial-gradient(920px 520px at 112% 2%, hsl(201 92% 63% / 0.22), transparent 58%), linear-gradient(160deg, hsl(232 29% 12%) 0%, hsl(231 24% 12%) 50%, hsl(228 22% 10%) 100%)",
|
|
351
|
+
"--app-surface-tint": "hsl(241 92% 70% / 0.1)",
|
|
352
|
+
},
|
|
353
|
+
"theme-nitro-mars": {
|
|
354
|
+
"--background": "12 30% 10%",
|
|
355
|
+
"--foreground": "20 40% 95%",
|
|
356
|
+
"--card": "12 25% 12%",
|
|
357
|
+
"--card-foreground": "20 40% 95%",
|
|
358
|
+
"--popover": "12 25% 12%",
|
|
359
|
+
"--popover-foreground": "20 40% 95%",
|
|
360
|
+
"--primary": "14 74% 61%",
|
|
361
|
+
"--primary-foreground": "12 30% 10%",
|
|
362
|
+
"--secondary": "22 78% 62%",
|
|
363
|
+
"--secondary-foreground": "12 30% 10%",
|
|
364
|
+
"--muted": "12 25% 20%",
|
|
365
|
+
"--muted-foreground": "20 25% 72%",
|
|
366
|
+
"--accent": "22 78% 62%",
|
|
367
|
+
"--accent-foreground": "12 30% 10%",
|
|
368
|
+
"--destructive": "0 84% 60%",
|
|
369
|
+
"--destructive-foreground": "0 0% 98%",
|
|
370
|
+
"--border": "12 20% 25%",
|
|
371
|
+
"--input": "12 20% 25%",
|
|
372
|
+
"--ring": "14 74% 61%",
|
|
373
|
+
"--app-gradient": "radial-gradient(1040px 560px at -10% -20%, hsl(12 78% 62% / 0.3), transparent 60%), radial-gradient(920px 520px at 112% 2%, hsl(22 78% 60% / 0.22), transparent 58%), linear-gradient(160deg, hsl(13 29% 11%) 0%, hsl(11 25% 11%) 52%, hsl(8 21% 9%) 100%)",
|
|
374
|
+
"--app-surface-tint": "hsl(14 74% 61% / 0.1)",
|
|
375
|
+
},
|
|
376
|
+
"theme-nitro-dusk": {
|
|
377
|
+
"--background": "256 23% 11%",
|
|
378
|
+
"--foreground": "256 30% 95%",
|
|
379
|
+
"--card": "256 20% 13%",
|
|
380
|
+
"--card-foreground": "256 30% 95%",
|
|
381
|
+
"--popover": "256 20% 13%",
|
|
382
|
+
"--popover-foreground": "256 30% 95%",
|
|
383
|
+
"--primary": "263 53% 67%",
|
|
384
|
+
"--primary-foreground": "256 23% 10%",
|
|
385
|
+
"--secondary": "299 44% 64%",
|
|
386
|
+
"--secondary-foreground": "256 23% 10%",
|
|
387
|
+
"--muted": "256 20% 22%",
|
|
388
|
+
"--muted-foreground": "256 20% 72%",
|
|
389
|
+
"--accent": "299 44% 64%",
|
|
390
|
+
"--accent-foreground": "256 23% 10%",
|
|
391
|
+
"--destructive": "0 84% 60%",
|
|
392
|
+
"--destructive-foreground": "0 0% 98%",
|
|
393
|
+
"--border": "256 15% 28%",
|
|
394
|
+
"--input": "256 15% 28%",
|
|
395
|
+
"--ring": "263 53% 67%",
|
|
396
|
+
"--app-gradient": "radial-gradient(1020px 560px at -10% -20%, hsl(262 60% 62% / 0.28), transparent 58%), radial-gradient(920px 520px at 112% 2%, hsl(298 48% 60% / 0.2), transparent 58%), linear-gradient(160deg, hsl(256 26% 12%) 0%, hsl(256 23% 12%) 50%, hsl(258 20% 10%) 100%)",
|
|
397
|
+
"--app-surface-tint": "hsl(263 53% 67% / 0.1)",
|
|
398
|
+
},
|
|
399
|
+
"theme-nitro-under-the-sea": {
|
|
400
|
+
"--background": "205 33% 10%",
|
|
401
|
+
"--foreground": "190 40% 95%",
|
|
402
|
+
"--card": "205 28% 12%",
|
|
403
|
+
"--card-foreground": "190 40% 95%",
|
|
404
|
+
"--popover": "205 28% 12%",
|
|
405
|
+
"--popover-foreground": "190 40% 95%",
|
|
406
|
+
"--primary": "186 70% 58%",
|
|
407
|
+
"--primary-foreground": "205 33% 10%",
|
|
408
|
+
"--secondary": "197 74% 55%",
|
|
409
|
+
"--secondary-foreground": "205 33% 10%",
|
|
410
|
+
"--muted": "205 28% 20%",
|
|
411
|
+
"--muted-foreground": "190 25% 72%",
|
|
412
|
+
"--accent": "197 74% 55%",
|
|
413
|
+
"--accent-foreground": "205 33% 10%",
|
|
414
|
+
"--destructive": "0 84% 60%",
|
|
415
|
+
"--destructive-foreground": "0 0% 98%",
|
|
416
|
+
"--border": "205 22% 25%",
|
|
417
|
+
"--input": "205 22% 25%",
|
|
418
|
+
"--ring": "186 70% 58%",
|
|
419
|
+
"--app-gradient": "radial-gradient(1040px 560px at -10% -20%, hsl(186 75% 58% / 0.3), transparent 58%), radial-gradient(920px 520px at 112% 2%, hsl(197 76% 55% / 0.22), transparent 58%), linear-gradient(160deg, hsl(204 30% 11%) 0%, hsl(205 26% 11%) 50%, hsl(206 22% 9%) 100%)",
|
|
420
|
+
"--app-surface-tint": "hsl(186 70% 58% / 0.1)",
|
|
421
|
+
},
|
|
422
|
+
"theme-nitro-retro-storm": {
|
|
423
|
+
"--background": "216 20% 11%",
|
|
424
|
+
"--foreground": "216 20% 95%",
|
|
425
|
+
"--card": "216 18% 13%",
|
|
426
|
+
"--card-foreground": "216 20% 95%",
|
|
427
|
+
"--popover": "216 18% 13%",
|
|
428
|
+
"--popover-foreground": "216 20% 95%",
|
|
429
|
+
"--primary": "213 33% 66%",
|
|
430
|
+
"--primary-foreground": "216 20% 10%",
|
|
431
|
+
"--secondary": "214 26% 62%",
|
|
432
|
+
"--secondary-foreground": "216 20% 10%",
|
|
433
|
+
"--muted": "216 18% 22%",
|
|
434
|
+
"--muted-foreground": "216 15% 70%",
|
|
435
|
+
"--accent": "214 26% 62%",
|
|
436
|
+
"--accent-foreground": "216 20% 10%",
|
|
437
|
+
"--destructive": "0 84% 60%",
|
|
438
|
+
"--destructive-foreground": "0 0% 98%",
|
|
439
|
+
"--border": "216 15% 28%",
|
|
440
|
+
"--input": "216 15% 28%",
|
|
441
|
+
"--ring": "213 33% 66%",
|
|
442
|
+
"--app-gradient": "radial-gradient(1040px 560px at -10% -20%, hsl(213 35% 64% / 0.26), transparent 58%), radial-gradient(920px 520px at 112% 2%, hsl(214 27% 62% / 0.2), transparent 58%), linear-gradient(160deg, hsl(216 24% 11%) 0%, hsl(215 20% 11%) 50%, hsl(214 18% 9%) 100%)",
|
|
443
|
+
"--app-surface-tint": "hsl(213 33% 66% / 0.1)",
|
|
444
|
+
},
|
|
445
|
+
"theme-nitro-neon-nights": {
|
|
446
|
+
"--background": "245 36% 10%",
|
|
447
|
+
"--foreground": "260 40% 95%",
|
|
448
|
+
"--card": "245 31% 12%",
|
|
449
|
+
"--card-foreground": "260 40% 95%",
|
|
450
|
+
"--popover": "245 31% 12%",
|
|
451
|
+
"--popover-foreground": "260 40% 95%",
|
|
452
|
+
"--primary": "292 96% 66%",
|
|
453
|
+
"--primary-foreground": "245 36% 10%",
|
|
454
|
+
"--secondary": "190 94% 56%",
|
|
455
|
+
"--secondary-foreground": "245 36% 10%",
|
|
456
|
+
"--muted": "245 30% 18%",
|
|
457
|
+
"--muted-foreground": "260 25% 75%",
|
|
458
|
+
"--accent": "190 94% 56%",
|
|
459
|
+
"--accent-foreground": "245 36% 10%",
|
|
460
|
+
"--destructive": "0 84% 60%",
|
|
461
|
+
"--destructive-foreground": "0 0% 98%",
|
|
462
|
+
"--border": "245 25% 25%",
|
|
463
|
+
"--input": "245 25% 25%",
|
|
464
|
+
"--ring": "292 96% 66%",
|
|
465
|
+
"--app-gradient": "radial-gradient(1040px 560px at -10% -20%, hsl(280 92% 62% / 0.28), transparent 58%), radial-gradient(920px 520px at 112% 2%, hsl(191 94% 56% / 0.24), transparent 58%), linear-gradient(160deg, hsl(233 36% 10%) 0%, hsl(229 32% 9%) 50%, hsl(227 28% 8%) 100%)",
|
|
466
|
+
"--app-surface-tint": "hsl(292 96% 66% / 0.1)",
|
|
467
|
+
},
|
|
468
|
+
"theme-nitro-strawberry-lemonade": {
|
|
469
|
+
"--background": "334 31% 10%",
|
|
470
|
+
"--foreground": "40 70% 95%",
|
|
471
|
+
"--card": "334 27% 12%",
|
|
472
|
+
"--card-foreground": "40 70% 95%",
|
|
473
|
+
"--popover": "334 27% 12%",
|
|
474
|
+
"--popover-foreground": "40 70% 95%",
|
|
475
|
+
"--primary": "342 83% 67%",
|
|
476
|
+
"--primary-foreground": "334 31% 10%",
|
|
477
|
+
"--secondary": "46 89% 63%",
|
|
478
|
+
"--secondary-foreground": "334 31% 10%",
|
|
479
|
+
"--muted": "334 27% 20%",
|
|
480
|
+
"--muted-foreground": "40 40% 75%",
|
|
481
|
+
"--accent": "46 89% 63%",
|
|
482
|
+
"--accent-foreground": "334 31% 10%",
|
|
483
|
+
"--destructive": "0 84% 60%",
|
|
484
|
+
"--destructive-foreground": "0 0% 98%",
|
|
485
|
+
"--border": "334 22% 28%",
|
|
486
|
+
"--input": "334 22% 28%",
|
|
487
|
+
"--ring": "342 83% 67%",
|
|
488
|
+
"--app-gradient": "radial-gradient(1040px 560px at -10% -20%, hsl(342 86% 64% / 0.3), transparent 58%), radial-gradient(920px 520px at 112% 2%, hsl(46 90% 62% / 0.24), transparent 58%), linear-gradient(160deg, hsl(334 30% 11%) 0%, hsl(333 26% 11%) 50%, hsl(331 22% 9%) 100%)",
|
|
489
|
+
"--app-surface-tint": "hsl(342 83% 67% / 0.1)",
|
|
490
|
+
},
|
|
491
|
+
"theme-nitro-aurora": {
|
|
492
|
+
"--background": "174 25% 10%",
|
|
493
|
+
"--foreground": "160 50% 95%",
|
|
494
|
+
"--card": "174 22% 12%",
|
|
495
|
+
"--card-foreground": "160 50% 95%",
|
|
496
|
+
"--popover": "174 22% 12%",
|
|
497
|
+
"--popover-foreground": "160 50% 95%",
|
|
498
|
+
"--primary": "164 63% 57%",
|
|
499
|
+
"--primary-foreground": "174 25% 10%",
|
|
500
|
+
"--secondary": "145 62% 58%",
|
|
501
|
+
"--secondary-foreground": "174 25% 10%",
|
|
502
|
+
"--muted": "174 22% 20%",
|
|
503
|
+
"--muted-foreground": "160 30% 72%",
|
|
504
|
+
"--accent": "145 62% 58%",
|
|
505
|
+
"--accent-foreground": "174 25% 10%",
|
|
506
|
+
"--destructive": "0 84% 60%",
|
|
507
|
+
"--destructive-foreground": "0 0% 98%",
|
|
508
|
+
"--border": "174 18% 25%",
|
|
509
|
+
"--input": "174 18% 25%",
|
|
510
|
+
"--ring": "164 63% 57%",
|
|
511
|
+
"--app-gradient": "radial-gradient(1040px 560px at -10% -20%, hsl(164 66% 56% / 0.28), transparent 58%), radial-gradient(920px 520px at 112% 2%, hsl(145 64% 56% / 0.22), transparent 58%), linear-gradient(160deg, hsl(176 28% 11%) 0%, hsl(172 24% 11%) 50%, hsl(169 20% 9%) 100%)",
|
|
512
|
+
"--app-surface-tint": "hsl(164 63% 57% / 0.1)",
|
|
513
|
+
},
|
|
514
|
+
"theme-nitro-sepia": {
|
|
515
|
+
"--background": "27 24% 11%",
|
|
516
|
+
"--foreground": "35 30% 95%",
|
|
517
|
+
"--card": "27 21% 13%",
|
|
518
|
+
"--card-foreground": "35 30% 95%",
|
|
519
|
+
"--popover": "27 21% 13%",
|
|
520
|
+
"--popover-foreground": "35 30% 95%",
|
|
521
|
+
"--primary": "28 44% 62%",
|
|
522
|
+
"--primary-foreground": "27 24% 10%",
|
|
523
|
+
"--secondary": "36 39% 62%",
|
|
524
|
+
"--secondary-foreground": "27 24% 10%",
|
|
525
|
+
"--muted": "27 18% 20%",
|
|
526
|
+
"--muted-foreground": "35 20% 70%",
|
|
527
|
+
"--accent": "36 39% 62%",
|
|
528
|
+
"--accent-foreground": "27 24% 10%",
|
|
529
|
+
"--destructive": "0 84% 60%",
|
|
530
|
+
"--destructive-foreground": "0 0% 98%",
|
|
531
|
+
"--border": "27 15% 25%",
|
|
532
|
+
"--input": "27 15% 25%",
|
|
533
|
+
"--ring": "28 44% 62%",
|
|
534
|
+
"--app-gradient": "radial-gradient(1040px 560px at -10% -20%, hsl(28 45% 60% / 0.26), transparent 58%), radial-gradient(920px 520px at 112% 2%, hsl(36 40% 60% / 0.2), transparent 58%), linear-gradient(160deg, hsl(27 25% 12%) 0%, hsl(26 22% 12%) 50%, hsl(24 19% 10%) 100%)",
|
|
535
|
+
"--app-surface-tint": "hsl(28 44% 62% / 0.1)",
|
|
536
|
+
},
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
const getThemeTokens = (themeId) => {
|
|
540
|
+
return themeTokens[themeId] || themeTokens["theme-nitro-midnight-blurple"];
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
const ensureDir = (dir) => {
|
|
544
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
const copyTemplate = (name, dest, force) => {
|
|
548
|
+
const src = path.join(templateDir, name);
|
|
549
|
+
if (!fs.existsSync(src)) {
|
|
550
|
+
throw new Error(`Missing template: ${name}`);
|
|
551
|
+
}
|
|
552
|
+
if (fs.existsSync(dest) && !force) {
|
|
553
|
+
return { skipped: true, dest };
|
|
554
|
+
}
|
|
555
|
+
fs.copyFileSync(src, dest);
|
|
556
|
+
return { skipped: false, dest };
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
const DEFAULT_THEME = "theme-nitro-midnight-blurple";
|
|
560
|
+
const DEFAULT_MODE = "dark";
|
|
561
|
+
|
|
562
|
+
const promptSelect = async (title, items, defaultIndex = 0) => {
|
|
563
|
+
return new Promise((resolve) => {
|
|
564
|
+
if (!process.stdin.isTTY) {
|
|
565
|
+
resolve(items[defaultIndex]);
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
let index = defaultIndex;
|
|
570
|
+
let isFirstRender = true;
|
|
571
|
+
|
|
572
|
+
const render = () => {
|
|
573
|
+
if (isFirstRender) {
|
|
574
|
+
process.stdout.write("\x1b[s");
|
|
575
|
+
isFirstRender = false;
|
|
576
|
+
} else {
|
|
577
|
+
process.stdout.write("\x1b[u");
|
|
578
|
+
process.stdout.write("\x1b[0J");
|
|
579
|
+
}
|
|
580
|
+
log(title);
|
|
581
|
+
log("");
|
|
582
|
+
items.forEach((item, i) => {
|
|
583
|
+
const prefix = i === index ? ">" : " ";
|
|
584
|
+
log(`${prefix} ${i + 1}. ${item.label ?? item}`);
|
|
585
|
+
});
|
|
586
|
+
log("");
|
|
587
|
+
log("Use up/down arrows and press Enter.");
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
const onKey = (data) => {
|
|
591
|
+
const key = data.toString();
|
|
592
|
+
if (key === "\u0003") {
|
|
593
|
+
process.stdin.setRawMode(false);
|
|
594
|
+
process.stdin.pause();
|
|
595
|
+
process.exit(1);
|
|
596
|
+
}
|
|
597
|
+
if (key === "\r") {
|
|
598
|
+
process.stdin.setRawMode(false);
|
|
599
|
+
process.stdin.pause();
|
|
600
|
+
process.stdin.removeListener("data", onKey);
|
|
601
|
+
process.stdout.write("\x1b[?25h");
|
|
602
|
+
resolve(items[index]);
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
if (key === "\u001b[A") {
|
|
606
|
+
index = (index - 1 + items.length) % items.length;
|
|
607
|
+
render();
|
|
608
|
+
}
|
|
609
|
+
if (key === "\u001b[B") {
|
|
610
|
+
index = (index + 1) % items.length;
|
|
611
|
+
render();
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
process.stdin.setRawMode(true);
|
|
616
|
+
process.stdin.resume();
|
|
617
|
+
process.stdin.on("data", onKey);
|
|
618
|
+
process.stdout.write("\x1b[?25l");
|
|
619
|
+
render();
|
|
620
|
+
});
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
const promptYesNo = async (title, defaultYes = true) => {
|
|
624
|
+
const items = defaultYes ? ["Yes", "No"] : ["No", "Yes"];
|
|
625
|
+
const choice = await promptSelect(title, items, defaultYes ? 0 : 1);
|
|
626
|
+
return choice === "Yes";
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
const generateCSSVariables = (themeId, mode) => {
|
|
630
|
+
const tokens = getThemeTokens(themeId);
|
|
631
|
+
const theme = themes.find((t) => t.id === themeId);
|
|
632
|
+
|
|
633
|
+
let css = `/* Gradient Forge Theme: ${theme?.label ?? themeId} */\n`;
|
|
634
|
+
css += `/* Color Mode: ${mode} */\n\n`;
|
|
635
|
+
|
|
636
|
+
css += `.${themeId} {\n`;
|
|
637
|
+
Object.entries(tokens).forEach(([key, value]) => {
|
|
638
|
+
if (key !== "--app-gradient") {
|
|
639
|
+
css += ` ${key}: ${value};\n`;
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
css += ` --app-gradient: ${tokens["--app-gradient"]};\n`;
|
|
643
|
+
css += `}\n\n`;
|
|
644
|
+
|
|
645
|
+
css += `/* Surface Layer Styles */\n`;
|
|
646
|
+
css += `.bg-card,\n.bg-popover,\n.bg-sidebar {\n`;
|
|
647
|
+
css += ` background-color: hsl(var(--background) / 0.34);\n`;
|
|
648
|
+
css += ` background-image: linear-gradient(var(--app-surface-tint), var(--app-surface-tint));\n`;
|
|
649
|
+
css += ` backdrop-filter: blur(16px);\n`;
|
|
650
|
+
css += `}\n`;
|
|
651
|
+
|
|
652
|
+
return css;
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
const generateThemeEngine = (themeId, mode) => {
|
|
656
|
+
return `export const NITRO_PUBLIC_THEMES = [
|
|
657
|
+
${themes.map(t => `{
|
|
658
|
+
id: "${t.id}",
|
|
659
|
+
label: "${t.label}",
|
|
660
|
+
preview: "${t.preview}",
|
|
661
|
+
}`).join(",\n ")},
|
|
662
|
+
] as const;
|
|
663
|
+
|
|
664
|
+
export type ThemeId = typeof NITRO_PUBLIC_THEMES[number]["id"];
|
|
665
|
+
export type ColorMode = "dark" | "light";
|
|
666
|
+
|
|
667
|
+
const DEFAULT_THEME: ThemeId = "${themeId}";
|
|
668
|
+
const DEFAULT_COLOR_MODE: ColorMode = "${mode}";
|
|
669
|
+
|
|
670
|
+
export const defaultTheme = DEFAULT_THEME;
|
|
671
|
+
export const defaultColorMode = DEFAULT_COLOR_MODE;
|
|
672
|
+
`;
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
const generateThemeContext = (themeId, mode) => {
|
|
676
|
+
return `"use client";
|
|
677
|
+
|
|
678
|
+
import { createContext, useContext, useEffect, useState, type ReactNode } from "react";
|
|
679
|
+
|
|
680
|
+
export type ThemeId = "${themeId}";
|
|
681
|
+
export type ColorMode = "${mode}";
|
|
682
|
+
|
|
683
|
+
type ThemeContextValue = {
|
|
684
|
+
themeId: ThemeId;
|
|
685
|
+
colorMode: ColorMode;
|
|
686
|
+
setThemeId: (themeId: ThemeId) => void;
|
|
687
|
+
setColorMode: (mode: ColorMode) => void;
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
const ThemeContext = createContext<ThemeContextValue | null>(null);
|
|
691
|
+
|
|
692
|
+
export const ThemeProvider = ({ children }: { children: ReactNode }) => {
|
|
693
|
+
const [themeId, setThemeId] = useState<ThemeId>("${themeId}");
|
|
694
|
+
const [colorMode, setColorMode] = useState<ColorMode>("${mode}");
|
|
695
|
+
|
|
696
|
+
useEffect(() => {
|
|
697
|
+
const root = document.documentElement;
|
|
698
|
+
root.classList.remove("dark", "light");
|
|
699
|
+
root.classList.remove(${themes.map(t => `"${t.id}"`).join(", ")});
|
|
700
|
+
|
|
701
|
+
root.classList.add(colorMode, themeId);
|
|
702
|
+
root.setAttribute("data-theme", themeId);
|
|
703
|
+
root.setAttribute("data-color-mode", colorMode);
|
|
704
|
+
|
|
705
|
+
localStorage.setItem("gradient-forge.theme", themeId);
|
|
706
|
+
localStorage.setItem("gradient-forge.color-mode", colorMode);
|
|
707
|
+
}, [themeId, colorMode]);
|
|
708
|
+
|
|
709
|
+
return (
|
|
710
|
+
<ThemeContext.Provider value={{ themeId, colorMode, setThemeId, setColorMode }}>
|
|
711
|
+
{children}
|
|
712
|
+
</ThemeContext.Provider>
|
|
713
|
+
);
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
export const useTheme = () => {
|
|
717
|
+
const ctx = useContext(ThemeContext);
|
|
718
|
+
if (!ctx) throw new Error("useTheme must be used within ThemeProvider");
|
|
719
|
+
return ctx;
|
|
720
|
+
};
|
|
721
|
+
`;
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
const generateSetupInstructions = (projectRoot, themeId, mode, themeLabel) => {
|
|
725
|
+
return `# Gradient Forge Setup Complete! 🎨
|
|
726
|
+
|
|
727
|
+
Theme: ${themeLabel}
|
|
728
|
+
Mode: ${mode}
|
|
729
|
+
|
|
730
|
+
## What was created:
|
|
731
|
+
- components/theme/theme-engine.ts - Theme definitions
|
|
732
|
+
- components/theme/theme-context.tsx - React context provider
|
|
733
|
+
- app/gradient-forge.css - Theme CSS variables
|
|
734
|
+
|
|
735
|
+
## Next steps:
|
|
736
|
+
|
|
737
|
+
1. Import the CSS in your layout:
|
|
738
|
+
import "./app/gradient-forge.css";
|
|
739
|
+
|
|
740
|
+
2. Wrap your app with ThemeProvider:
|
|
741
|
+
import { ThemeProvider } from "./components/theme/theme-context";
|
|
742
|
+
|
|
743
|
+
export default function RootLayout({ children }) {
|
|
744
|
+
return (
|
|
745
|
+
<html lang="en" className="${mode} ${themeId}" data-theme="${themeId}" data-color-mode="${mode}">
|
|
746
|
+
<body>
|
|
747
|
+
<ThemeProvider>{children}</ThemeProvider>
|
|
748
|
+
</body>
|
|
749
|
+
</html>
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
3. Use the theme in your components:
|
|
754
|
+
import { useTheme } from "./components/theme/theme-context";
|
|
755
|
+
|
|
756
|
+
function MyComponent() {
|
|
757
|
+
const { themeId, colorMode } = useTheme();
|
|
758
|
+
// ...
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
## For more themes, visit: https://gradient-forge.vercel.app
|
|
762
|
+
`;
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
const init = async () => {
|
|
766
|
+
log("");
|
|
767
|
+
log("🎨 Gradient Forge CLI - Initialize Theme");
|
|
768
|
+
log("======================================");
|
|
769
|
+
log("");
|
|
770
|
+
|
|
771
|
+
const projectRoot = readArg("--path", process.cwd());
|
|
772
|
+
const force = hasFlag("--force");
|
|
773
|
+
const skipInject = hasFlag("--no-inject");
|
|
774
|
+
|
|
775
|
+
logInfo(`Project root: ${projectRoot}`);
|
|
776
|
+
log("");
|
|
777
|
+
|
|
778
|
+
// Check if it's a Next.js project
|
|
779
|
+
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
780
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
781
|
+
logError("Error: Not a valid Node.js project. No package.json found.");
|
|
782
|
+
process.exit(1);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// Select theme
|
|
786
|
+
log("Select a theme:");
|
|
787
|
+
log("");
|
|
788
|
+
const selectedTheme = await promptSelect("Choose your theme:", themes, 12); // Default: Midnight Blurple
|
|
789
|
+
log(`\n✓ Selected: ${selectedTheme.label}`);
|
|
790
|
+
|
|
791
|
+
// Select mode
|
|
792
|
+
log("");
|
|
793
|
+
const modeOptions = [
|
|
794
|
+
{ id: "dark", label: "Dark Mode" },
|
|
795
|
+
{ id: "light", label: "Light Mode" },
|
|
796
|
+
];
|
|
797
|
+
log("Select color mode:");
|
|
798
|
+
const selectedMode = await promptSelect("Choose color mode:", modeOptions, 0);
|
|
799
|
+
log(`\n✓ Selected: ${selectedMode.label}`);
|
|
800
|
+
|
|
801
|
+
const themeId = selectedTheme.id;
|
|
802
|
+
const mode = selectedMode.id;
|
|
803
|
+
|
|
804
|
+
log("");
|
|
805
|
+
logInfo("Generating theme files...");
|
|
806
|
+
log("");
|
|
807
|
+
|
|
808
|
+
// Create directories
|
|
809
|
+
const themeDir = path.join(projectRoot, "components", "theme");
|
|
810
|
+
const appDir = path.join(projectRoot, "app");
|
|
811
|
+
|
|
812
|
+
ensureDir(themeDir);
|
|
813
|
+
ensureDir(appDir);
|
|
814
|
+
|
|
815
|
+
// Generate and write files
|
|
816
|
+
const cssContent = generateCSSVariables(themeId, mode);
|
|
817
|
+
const cssPath = path.join(appDir, "gradient-forge.css");
|
|
818
|
+
fs.writeFileSync(cssPath, cssContent);
|
|
819
|
+
logSuccess(`Created: ${path.relative(projectRoot, cssPath)}`);
|
|
820
|
+
|
|
821
|
+
const engineContent = generateThemeEngine(themeId, mode);
|
|
822
|
+
const enginePath = path.join(themeDir, "theme-engine.ts");
|
|
823
|
+
fs.writeFileSync(enginePath, engineContent);
|
|
824
|
+
logSuccess(`Created: ${path.relative(projectRoot, enginePath)}`);
|
|
825
|
+
|
|
826
|
+
const contextContent = generateThemeContext(themeId, mode);
|
|
827
|
+
const contextPath = path.join(themeDir, "theme-context.tsx");
|
|
828
|
+
fs.writeFileSync(contextPath, contextContent);
|
|
829
|
+
logSuccess(`Created: ${path.relative(projectRoot, contextPath)}`);
|
|
830
|
+
|
|
831
|
+
// Inject into globals.css if it exists and not skipped
|
|
832
|
+
const globalsPath = path.join(appDir, "globals.css");
|
|
833
|
+
if (!skipInject && fs.existsSync(globalsPath)) {
|
|
834
|
+
const marker = "/* gradient-forge */";
|
|
835
|
+
const existing = fs.readFileSync(globalsPath, "utf8");
|
|
836
|
+
|
|
837
|
+
if (!existing.includes(marker)) {
|
|
838
|
+
const importStatement = '@import "./gradient-forge.css";';
|
|
839
|
+
fs.writeFileSync(globalsPath, `${importStatement}\n${existing}`);
|
|
840
|
+
logSuccess(`Injected theme import into: ${path.relative(projectRoot, globalsPath)}`);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
// Generate setup instructions
|
|
845
|
+
const instructions = generateSetupInstructions(projectRoot, themeId, mode, selectedTheme.label);
|
|
846
|
+
const readmePath = path.join(projectRoot, "GRADIENT_FORGE_SETUP.md");
|
|
847
|
+
fs.writeFileSync(readmePath, instructions);
|
|
848
|
+
logSuccess(`Created setup guide: ${path.relative(projectRoot, readmePath)}`);
|
|
849
|
+
|
|
850
|
+
log("");
|
|
851
|
+
log("======================================");
|
|
852
|
+
logSuccess("Theme setup complete! 🎉");
|
|
853
|
+
log("");
|
|
854
|
+
log(instructions);
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
const exportCommand = async () => {
|
|
858
|
+
const themeId = readArg("--theme", DEFAULT_THEME);
|
|
859
|
+
const mode = readArg("--mode", DEFAULT_MODE);
|
|
860
|
+
const format = readArg("--format", "css");
|
|
861
|
+
const output = readArg("--output", process.cwd());
|
|
862
|
+
|
|
863
|
+
const generator = exportGenerators[format];
|
|
864
|
+
if (!generator) {
|
|
865
|
+
logError(`Unknown format: ${format}`);
|
|
866
|
+
log("Available formats: css, scss, json, tailwind, w3c-tokens, figma-tokens, css-variables, html-root, all");
|
|
867
|
+
process.exit(1);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
const result = generator(themeId, mode);
|
|
871
|
+
|
|
872
|
+
ensureDir(output);
|
|
873
|
+
const outputPath = path.join(output, result.filename);
|
|
874
|
+
fs.writeFileSync(outputPath, result.content);
|
|
875
|
+
|
|
876
|
+
logSuccess(`Exported: ${outputPath}`);
|
|
877
|
+
};
|
|
878
|
+
|
|
879
|
+
const exportGenerators = {
|
|
880
|
+
css: (themeId, mode) => {
|
|
881
|
+
const tokens = getThemeTokens(themeId);
|
|
882
|
+
const theme = themes.find((t) => t.id === themeId);
|
|
883
|
+
|
|
884
|
+
let css = `/* Gradient Forge Theme: ${theme?.label ?? themeId} */\n`;
|
|
885
|
+
css += `/* Color Mode: ${mode} */\n\n`;
|
|
886
|
+
css += `.${themeId} {\n`;
|
|
887
|
+
Object.entries(tokens).forEach(([key, value]) => {
|
|
888
|
+
if (key !== "--app-gradient") {
|
|
889
|
+
css += ` ${key}: ${value};\n`;
|
|
890
|
+
}
|
|
891
|
+
});
|
|
892
|
+
css += ` --app-gradient: ${tokens["--app-gradient"]};\n`;
|
|
893
|
+
css += `}\n\n`;
|
|
894
|
+
css += `.bg-card, .bg-popover, .bg-sidebar {\n`;
|
|
895
|
+
css += ` background-color: hsl(var(--background) / 0.34);\n`;
|
|
896
|
+
css += ` background-image: linear-gradient(var(--app-surface-tint), var(--app-surface-tint));\n`;
|
|
897
|
+
css += ` backdrop-filter: blur(16px);\n`;
|
|
898
|
+
css += `}\n`;
|
|
899
|
+
|
|
900
|
+
return { filename: `${themeId}-theme.css`, content: css };
|
|
901
|
+
},
|
|
902
|
+
|
|
903
|
+
scss: (themeId, mode) => {
|
|
904
|
+
const tokens = getThemeTokens(themeId);
|
|
905
|
+
const theme = themes.find((t) => t.id === themeId);
|
|
906
|
+
|
|
907
|
+
let scss = `// Gradient Forge Theme: ${theme?.label ?? themeId}\n`;
|
|
908
|
+
scss += `// Color Mode: ${mode}\n\n`;
|
|
909
|
+
|
|
910
|
+
Object.entries(tokens).forEach(([key, value]) => {
|
|
911
|
+
if (key !== "--app-gradient") {
|
|
912
|
+
scss += `$${key.replace("--", "")}: ${value};\n`;
|
|
913
|
+
}
|
|
914
|
+
});
|
|
915
|
+
scss += `$app-gradient: ${tokens["--app-gradient"]};\n`;
|
|
916
|
+
|
|
917
|
+
return { filename: `${themeId}-theme.scss`, content: scss };
|
|
918
|
+
},
|
|
919
|
+
|
|
920
|
+
json: (themeId, mode) => {
|
|
921
|
+
const tokens = getThemeTokens(themeId);
|
|
922
|
+
const theme = themes.find((t) => t.id === themeId);
|
|
923
|
+
|
|
924
|
+
const colorTokens = {};
|
|
925
|
+
Object.entries(tokens).forEach(([key, value]) => {
|
|
926
|
+
colorTokens[key.replace("--", "")] = key === "--app-surface-tint" ? value : `hsl(${value})`;
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
const data = {
|
|
930
|
+
name: theme?.label ?? themeId,
|
|
931
|
+
id: themeId,
|
|
932
|
+
colorMode: mode,
|
|
933
|
+
version: "1.0.0",
|
|
934
|
+
generatedAt: new Date().toISOString(),
|
|
935
|
+
colors: colorTokens,
|
|
936
|
+
};
|
|
937
|
+
|
|
938
|
+
return { filename: `${themeId}-tokens.json`, content: JSON.stringify(data, null, 2) };
|
|
939
|
+
},
|
|
940
|
+
|
|
941
|
+
tailwind: (themeId, mode) => {
|
|
942
|
+
const tokens = getThemeTokens(themeId);
|
|
943
|
+
const theme = themes.find((t) => t.id === themeId);
|
|
944
|
+
|
|
945
|
+
const colors = {};
|
|
946
|
+
Object.entries(tokens).forEach(([key, value]) => {
|
|
947
|
+
if (key !== "--app-gradient" && key !== "--app-surface-tint") {
|
|
948
|
+
colors[key.replace("--", "")] = `"hsl(var(${key}))"`;
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
|
|
952
|
+
const content = `// Gradient Forge Theme: ${theme?.label ?? themeId}
|
|
953
|
+
// Color Mode: ${mode}
|
|
954
|
+
|
|
955
|
+
import type { Config } from "tailwindcss";
|
|
956
|
+
|
|
957
|
+
const config: Config = {
|
|
958
|
+
theme: {
|
|
959
|
+
extend: {
|
|
960
|
+
colors: ${JSON.stringify(colors, null, 6).replace(/"/g, "'")},
|
|
961
|
+
backgroundImage: {
|
|
962
|
+
"app-gradient": "var(--app-gradient)",
|
|
963
|
+
},
|
|
964
|
+
},
|
|
965
|
+
},
|
|
966
|
+
};
|
|
967
|
+
|
|
968
|
+
export default config;
|
|
969
|
+
`;
|
|
970
|
+
|
|
971
|
+
return { filename: `${themeId}-tailwind.ts`, content };
|
|
972
|
+
},
|
|
973
|
+
|
|
974
|
+
"w3c-tokens": (themeId, mode) => {
|
|
975
|
+
const tokens = getThemeTokens(themeId);
|
|
976
|
+
const theme = themes.find((t) => t.id === themeId);
|
|
977
|
+
|
|
978
|
+
const colorTokens = {};
|
|
979
|
+
Object.entries(tokens).forEach(([key, value]) => {
|
|
980
|
+
const tokenName = key.replace("--", "").replace(/-/g, ".");
|
|
981
|
+
colorTokens[tokenName] = {
|
|
982
|
+
$type: "color",
|
|
983
|
+
$value: key === "--app-surface-tint" ? value : `hsl(${value})`,
|
|
984
|
+
};
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
const data = {
|
|
988
|
+
$schema: "https://design-tokens.github.io/schema/format.json",
|
|
989
|
+
name: theme?.label ?? themeId,
|
|
990
|
+
id: themeId,
|
|
991
|
+
colorMode: mode,
|
|
992
|
+
version: "1.0.0",
|
|
993
|
+
generatedAt: new Date().toISOString(),
|
|
994
|
+
colors: colorTokens,
|
|
995
|
+
};
|
|
996
|
+
|
|
997
|
+
return { filename: `${themeId}-w3c-tokens.json`, content: JSON.stringify(data, null, 2) };
|
|
998
|
+
},
|
|
999
|
+
|
|
1000
|
+
"figma-tokens": (themeId, mode) => {
|
|
1001
|
+
const tokens = getThemeTokens(themeId);
|
|
1002
|
+
const theme = themes.find((t) => t.id === themeId);
|
|
1003
|
+
|
|
1004
|
+
const colorTokens = {};
|
|
1005
|
+
Object.entries(tokens).forEach(([key, value]) => {
|
|
1006
|
+
colorTokens[key.replace("--", "")] = {
|
|
1007
|
+
value: key === "--app-surface-tint" ? value : `hsl(${value})`,
|
|
1008
|
+
type: "color",
|
|
1009
|
+
};
|
|
1010
|
+
});
|
|
1011
|
+
|
|
1012
|
+
const data = {
|
|
1013
|
+
GradientForge: {
|
|
1014
|
+
[theme?.label ?? themeId]: { colors: colorTokens },
|
|
1015
|
+
},
|
|
1016
|
+
};
|
|
1017
|
+
|
|
1018
|
+
return { filename: `${themeId}-figma-tokens.json`, content: JSON.stringify(data, null, 2) };
|
|
1019
|
+
},
|
|
1020
|
+
|
|
1021
|
+
"css-variables": (themeId, mode) => {
|
|
1022
|
+
const tokens = getThemeTokens(themeId);
|
|
1023
|
+
const theme = themes.find((t) => t.id === themeId);
|
|
1024
|
+
|
|
1025
|
+
let css = `/* Gradient Forge Theme: ${theme?.label ?? themeId} */\n`;
|
|
1026
|
+
css += `/* Color Mode: ${mode} */\n`;
|
|
1027
|
+
css += `/* Paste these into your :root or theme class */\n\n`;
|
|
1028
|
+
|
|
1029
|
+
Object.entries(tokens).forEach(([key, value]) => {
|
|
1030
|
+
if (key !== "--app-gradient") {
|
|
1031
|
+
css += `${key}: ${value};\n`;
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
css += `--app-gradient: ${tokens["--app-gradient"]};\n`;
|
|
1035
|
+
|
|
1036
|
+
return { filename: `${themeId}-variables.css`, content: css };
|
|
1037
|
+
},
|
|
1038
|
+
|
|
1039
|
+
"html-root": (themeId, mode) => {
|
|
1040
|
+
const theme = themes.find((t) => t.id === themeId);
|
|
1041
|
+
|
|
1042
|
+
const content = `<!-- Gradient Forge Theme: ${theme?.label ?? themeId} -->
|
|
1043
|
+
<!-- Add these attributes to your <html> element -->
|
|
1044
|
+
|
|
1045
|
+
<html
|
|
1046
|
+
lang="en"
|
|
1047
|
+
class="${mode} ${themeId}"
|
|
1048
|
+
data-theme="${themeId}"
|
|
1049
|
+
data-color-mode="${mode}"
|
|
1050
|
+
suppressHydrationWarning
|
|
1051
|
+
>
|
|
1052
|
+
<!-- Your app content -->
|
|
1053
|
+
</html>`;
|
|
1054
|
+
|
|
1055
|
+
return { filename: `${themeId}-html-root.html`, content };
|
|
1056
|
+
},
|
|
1057
|
+
|
|
1058
|
+
all: (themeId, mode) => {
|
|
1059
|
+
const allContent = Object.keys(exportGenerators)
|
|
1060
|
+
.filter(f => f !== "all")
|
|
1061
|
+
.map(format => {
|
|
1062
|
+
const gen = exportGenerators[format];
|
|
1063
|
+
const result = gen(themeId, mode);
|
|
1064
|
+
return `/* ===== ${result.filename} ===== */\n\n${result.content}`;
|
|
1065
|
+
})
|
|
1066
|
+
.join("\n\n\n");
|
|
1067
|
+
|
|
1068
|
+
return { filename: `${themeId}-all-formats.txt`, content: allContent };
|
|
1069
|
+
},
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1072
|
+
const usage = () => {
|
|
1073
|
+
log("🎨 Gradient Forge CLI");
|
|
1074
|
+
log("");
|
|
1075
|
+
log("Usage:");
|
|
1076
|
+
log(" gradient-forge init [--path <project-root>] [--inject|--no-inject] [--force]");
|
|
1077
|
+
log(" gradient-forge export --theme <theme-id> --format <format> [--output <path>]");
|
|
1078
|
+
log(" gradient-forge list");
|
|
1079
|
+
log(" gradient-forge help");
|
|
1080
|
+
log("");
|
|
1081
|
+
log("Commands:");
|
|
1082
|
+
log(" init Initialize gradient-forge in a project (-interactive)");
|
|
1083
|
+
log(" export Export theme tokens in various formats");
|
|
1084
|
+
log(" list List all available themes");
|
|
1085
|
+
log(" help Show this help message");
|
|
1086
|
+
log("");
|
|
1087
|
+
log("Init Options:");
|
|
1088
|
+
log(" --path Target project root (default: current directory)");
|
|
1089
|
+
log(" --inject Append theme CSS to app/globals.css (default)");
|
|
1090
|
+
log(" --no-inject Skip CSS injection");
|
|
1091
|
+
log(" --force Overwrite existing files");
|
|
1092
|
+
log("");
|
|
1093
|
+
log("Export Options:");
|
|
1094
|
+
log(" --theme Theme ID to export (default: theme-nitro-midnight-blurple)");
|
|
1095
|
+
log(" --format Export format: css, scss, json, tailwind, w3c-tokens, figma-tokens, css-variables, html-root, all");
|
|
1096
|
+
log(" --output Output directory (default: current directory)");
|
|
1097
|
+
log(" --mode Color mode: dark, light (default: dark)");
|
|
1098
|
+
log("");
|
|
1099
|
+
log("Examples:");
|
|
1100
|
+
log(" gradient-forge init --path my-app");
|
|
1101
|
+
log(" gradient-forge export --theme theme-nitro-midnight-blurple --format css");
|
|
1102
|
+
log(" gradient-forge export --theme theme-nitro-aurora --format tailwind --output ./themes");
|
|
1103
|
+
log("");
|
|
1104
|
+
log("Available Themes:");
|
|
1105
|
+
themes.forEach((t, i) => {
|
|
1106
|
+
log(` ${String(i + 1).padStart(2, " ")}. ${t.label}`);
|
|
1107
|
+
});
|
|
1108
|
+
};
|
|
1109
|
+
|
|
1110
|
+
const listThemes = () => {
|
|
1111
|
+
log("🎨 Available Themes:");
|
|
1112
|
+
log("");
|
|
1113
|
+
themes.forEach((t, i) => {
|
|
1114
|
+
log(` ${String(i + 1).padStart(2, " ")}. ${t.id}`);
|
|
1115
|
+
log(` ${t.label}`);
|
|
1116
|
+
});
|
|
1117
|
+
};
|
|
1118
|
+
|
|
1119
|
+
switch (command) {
|
|
1120
|
+
case "init":
|
|
1121
|
+
init().catch((error) => {
|
|
1122
|
+
logError(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
1123
|
+
process.exit(1);
|
|
1124
|
+
});
|
|
1125
|
+
break;
|
|
1126
|
+
case "export":
|
|
1127
|
+
exportCommand().catch((error) => {
|
|
1128
|
+
logError(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
1129
|
+
process.exit(1);
|
|
1130
|
+
});
|
|
1131
|
+
break;
|
|
1132
|
+
case "list":
|
|
1133
|
+
listThemes();
|
|
1134
|
+
break;
|
|
1135
|
+
case "help":
|
|
1136
|
+
case "--help":
|
|
1137
|
+
case "-h":
|
|
1138
|
+
default:
|
|
1139
|
+
usage();
|
|
1140
|
+
break;
|
|
1141
|
+
}
|