@bison-lab/create-theme 0.1.0 → 0.3.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/dist/index.mjs +309 -104
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as p from "@clack/prompts";
|
|
3
3
|
import pc from "picocolors";
|
|
4
|
+
import { execSync } from "child_process";
|
|
4
5
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
5
|
-
import { resolve } from "path";
|
|
6
|
+
import { join, resolve } from "path";
|
|
7
|
+
import { GREY_SCALES, hexToHSL, hslToString } from "@bison-lab/tokens";
|
|
6
8
|
//#region src/preview.ts
|
|
7
9
|
function hexToRgb(hex) {
|
|
8
10
|
hex = hex.replace("#", "");
|
|
@@ -23,7 +25,7 @@ function isValidHex(hex) {
|
|
|
23
25
|
}
|
|
24
26
|
async function runPrompts(existing) {
|
|
25
27
|
p.log.info(pc.bold("Brand Colors"));
|
|
26
|
-
if (existing) p.log.message(`Current: Primary ${previewHexColor(existing.brandPrimary)} Secondary ${previewHexColor(existing.brandSecondary)} Accent ${previewHexColor(existing.brandAccent)}`);
|
|
28
|
+
if (existing) p.log.message(`Current: Primary ${previewHexColor(existing.brandPrimary)} Secondary ${previewHexColor(existing.brandSecondary)} Accent ${previewHexColor(existing.brandAccent)} Highlight ${previewHexColor(existing.brandHighlight)}`);
|
|
27
29
|
const brandPrimary = await p.text({
|
|
28
30
|
message: "Primary brand color (hex)",
|
|
29
31
|
placeholder: "#1e3a5f",
|
|
@@ -41,13 +43,54 @@ async function runPrompts(existing) {
|
|
|
41
43
|
if (p.isCancel(brandSecondary)) return null;
|
|
42
44
|
p.log.message(` ${previewHexColor(brandSecondary)} Secondary`);
|
|
43
45
|
const brandAccent = await p.text({
|
|
44
|
-
message: "Accent
|
|
46
|
+
message: "Accent color (hex)",
|
|
45
47
|
placeholder: "#e89b20",
|
|
46
48
|
...existing?.brandAccent && { defaultValue: existing.brandAccent },
|
|
47
49
|
validate: (v) => !isValidHex(v) ? "Enter a valid hex color (e.g. #e89b20)" : void 0
|
|
48
50
|
});
|
|
49
51
|
if (p.isCancel(brandAccent)) return null;
|
|
50
52
|
p.log.message(` ${previewHexColor(brandAccent)} Accent`);
|
|
53
|
+
const brandHighlight = await p.text({
|
|
54
|
+
message: "Highlight color (hex)",
|
|
55
|
+
placeholder: "#7c3aed",
|
|
56
|
+
...existing?.brandHighlight && { defaultValue: existing.brandHighlight },
|
|
57
|
+
validate: (v) => !isValidHex(v) ? "Enter a valid hex color (e.g. #7c3aed)" : void 0
|
|
58
|
+
});
|
|
59
|
+
if (p.isCancel(brandHighlight)) return null;
|
|
60
|
+
p.log.message(` ${previewHexColor(brandHighlight)} Highlight`);
|
|
61
|
+
p.log.info(pc.bold("Grey Scale"));
|
|
62
|
+
const greyScale = await p.select({
|
|
63
|
+
message: "Grey palette for borders, text, backgrounds",
|
|
64
|
+
initialValue: existing?.greyScale ?? "slate",
|
|
65
|
+
options: [
|
|
66
|
+
{
|
|
67
|
+
value: "slate",
|
|
68
|
+
label: "Slate",
|
|
69
|
+
hint: "Cool blue-grey — modern, tech-forward"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
value: "gray",
|
|
73
|
+
label: "Gray",
|
|
74
|
+
hint: "Balanced blue-grey — neutral default"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
value: "zinc",
|
|
78
|
+
label: "Zinc",
|
|
79
|
+
hint: "Cool desaturated — minimal, sharp"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
value: "neutral",
|
|
83
|
+
label: "Neutral",
|
|
84
|
+
hint: "Pure grey — zero hue bias"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
value: "stone",
|
|
88
|
+
label: "Stone",
|
|
89
|
+
hint: "Warm earthy grey — organic, approachable"
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
});
|
|
93
|
+
if (p.isCancel(greyScale)) return null;
|
|
51
94
|
const radius = await p.select({
|
|
52
95
|
message: "Border radius preset",
|
|
53
96
|
initialValue: existing?.radius ?? "rounded",
|
|
@@ -142,12 +185,27 @@ async function runPrompts(existing) {
|
|
|
142
185
|
});
|
|
143
186
|
if (p.isCancel(density)) return null;
|
|
144
187
|
p.log.info(pc.bold("Typography"));
|
|
145
|
-
const
|
|
146
|
-
message: "
|
|
188
|
+
const fontBody = await p.text({
|
|
189
|
+
message: "Body font family",
|
|
147
190
|
placeholder: "Inter",
|
|
148
|
-
defaultValue: existing?.
|
|
191
|
+
defaultValue: existing?.fontBody ?? "Inter"
|
|
149
192
|
});
|
|
150
|
-
if (p.isCancel(
|
|
193
|
+
if (p.isCancel(fontBody)) return null;
|
|
194
|
+
const wantsHeading = await p.confirm({
|
|
195
|
+
message: "Use a separate display/heading font?",
|
|
196
|
+
initialValue: existing?.fontHeading != null
|
|
197
|
+
});
|
|
198
|
+
if (p.isCancel(wantsHeading)) return null;
|
|
199
|
+
let fontHeading = null;
|
|
200
|
+
if (wantsHeading) {
|
|
201
|
+
const heading = await p.text({
|
|
202
|
+
message: "Heading font family",
|
|
203
|
+
placeholder: "Playfair Display",
|
|
204
|
+
...existing?.fontHeading && { defaultValue: existing.fontHeading }
|
|
205
|
+
});
|
|
206
|
+
if (p.isCancel(heading)) return null;
|
|
207
|
+
fontHeading = heading;
|
|
208
|
+
}
|
|
151
209
|
const customizeWeights = await p.confirm({
|
|
152
210
|
message: "Customize font weights? (default: 400/500/600/700)",
|
|
153
211
|
initialValue: false
|
|
@@ -195,118 +253,117 @@ async function runPrompts(existing) {
|
|
|
195
253
|
brandPrimary,
|
|
196
254
|
brandSecondary,
|
|
197
255
|
brandAccent,
|
|
256
|
+
brandHighlight,
|
|
257
|
+
greyScale,
|
|
198
258
|
radius,
|
|
199
259
|
shadow,
|
|
200
260
|
motion,
|
|
201
261
|
density,
|
|
202
|
-
|
|
262
|
+
fontBody,
|
|
263
|
+
fontHeading,
|
|
203
264
|
fontWeights
|
|
204
265
|
};
|
|
205
266
|
}
|
|
206
267
|
//#endregion
|
|
207
268
|
//#region src/generate.ts
|
|
208
|
-
function hexToHSL(hex) {
|
|
209
|
-
hex = hex.replace("#", "");
|
|
210
|
-
const r = parseInt(hex.substring(0, 2), 16) / 255;
|
|
211
|
-
const g = parseInt(hex.substring(2, 4), 16) / 255;
|
|
212
|
-
const b = parseInt(hex.substring(4, 6), 16) / 255;
|
|
213
|
-
const max = Math.max(r, g, b);
|
|
214
|
-
const min = Math.min(r, g, b);
|
|
215
|
-
const l = (max + min) / 2;
|
|
216
|
-
let h = 0;
|
|
217
|
-
let s = 0;
|
|
218
|
-
if (max !== min) {
|
|
219
|
-
const d = max - min;
|
|
220
|
-
s = l > .5 ? d / (2 - max - min) : d / (max + min);
|
|
221
|
-
switch (max) {
|
|
222
|
-
case r:
|
|
223
|
-
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
224
|
-
break;
|
|
225
|
-
case g:
|
|
226
|
-
h = ((b - r) / d + 2) / 6;
|
|
227
|
-
break;
|
|
228
|
-
case b:
|
|
229
|
-
h = ((r - g) / d + 4) / 6;
|
|
230
|
-
break;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return {
|
|
234
|
-
h: Math.round(h * 360),
|
|
235
|
-
s: Math.round(s * 100),
|
|
236
|
-
l: Math.round(l * 100)
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
function hsl(h, s, l) {
|
|
240
|
-
return `${h} ${s}% ${l}%`;
|
|
241
|
-
}
|
|
242
269
|
function clamp(v, min, max) {
|
|
243
270
|
return Math.min(Math.max(v, min), max);
|
|
244
271
|
}
|
|
245
|
-
function
|
|
272
|
+
function contrastForeground(color) {
|
|
273
|
+
return color.l > 55 ? hslToString({
|
|
274
|
+
h: color.h,
|
|
275
|
+
s: clamp(color.s - 20, 0, 100),
|
|
276
|
+
l: 10
|
|
277
|
+
}) : hslToString({
|
|
278
|
+
h: color.h,
|
|
279
|
+
s: clamp(color.s - 25, 0, 100),
|
|
280
|
+
l: 98
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
function boostForDark(color) {
|
|
284
|
+
if (color.l < 40) return {
|
|
285
|
+
...color,
|
|
286
|
+
l: clamp(color.l + 25, 0, 100)
|
|
287
|
+
};
|
|
288
|
+
return color;
|
|
289
|
+
}
|
|
290
|
+
function deriveLight(primary, secondary, accent, highlight, grey) {
|
|
246
291
|
return {
|
|
247
|
-
background:
|
|
248
|
-
foreground:
|
|
249
|
-
card:
|
|
250
|
-
"card-foreground":
|
|
251
|
-
popover:
|
|
252
|
-
"popover-foreground":
|
|
253
|
-
primary:
|
|
254
|
-
"primary-foreground":
|
|
255
|
-
secondary:
|
|
256
|
-
"secondary-foreground":
|
|
257
|
-
accent:
|
|
258
|
-
"accent-foreground":
|
|
259
|
-
|
|
260
|
-
"
|
|
292
|
+
background: grey["50"],
|
|
293
|
+
foreground: grey["950"],
|
|
294
|
+
card: grey["50"],
|
|
295
|
+
"card-foreground": grey["950"],
|
|
296
|
+
popover: grey["50"],
|
|
297
|
+
"popover-foreground": grey["950"],
|
|
298
|
+
primary: hslToString(primary),
|
|
299
|
+
"primary-foreground": contrastForeground(primary),
|
|
300
|
+
secondary: hslToString(secondary),
|
|
301
|
+
"secondary-foreground": contrastForeground(secondary),
|
|
302
|
+
accent: grey["100"],
|
|
303
|
+
"accent-foreground": grey["950"],
|
|
304
|
+
"brand-accent": hslToString(accent),
|
|
305
|
+
"brand-accent-foreground": contrastForeground(accent),
|
|
306
|
+
highlight: hslToString(highlight),
|
|
307
|
+
"highlight-foreground": contrastForeground(highlight),
|
|
308
|
+
muted: grey["100"],
|
|
309
|
+
"muted-foreground": grey["500"],
|
|
261
310
|
destructive: "0 84% 60%",
|
|
262
311
|
"destructive-foreground": "0 0% 98%",
|
|
263
|
-
border:
|
|
264
|
-
input:
|
|
265
|
-
ring:
|
|
312
|
+
border: grey["200"],
|
|
313
|
+
input: grey["200"],
|
|
314
|
+
ring: hslToString(primary)
|
|
266
315
|
};
|
|
267
316
|
}
|
|
268
|
-
function deriveDark(primary, secondary, accent) {
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
317
|
+
function deriveDark(primary, secondary, accent, highlight, grey) {
|
|
318
|
+
const dp = boostForDark(primary);
|
|
319
|
+
const ds = boostForDark(secondary);
|
|
320
|
+
const da = boostForDark(accent);
|
|
321
|
+
const dh = boostForDark(highlight);
|
|
273
322
|
return {
|
|
274
|
-
background:
|
|
275
|
-
foreground:
|
|
276
|
-
card:
|
|
277
|
-
"card-foreground":
|
|
278
|
-
popover:
|
|
279
|
-
"popover-foreground":
|
|
280
|
-
primary:
|
|
281
|
-
"primary-foreground":
|
|
282
|
-
secondary:
|
|
283
|
-
"secondary-foreground":
|
|
284
|
-
accent:
|
|
285
|
-
"accent-foreground":
|
|
286
|
-
|
|
287
|
-
"
|
|
323
|
+
background: grey["950"],
|
|
324
|
+
foreground: grey["50"],
|
|
325
|
+
card: grey["900"],
|
|
326
|
+
"card-foreground": grey["50"],
|
|
327
|
+
popover: grey["900"],
|
|
328
|
+
"popover-foreground": grey["50"],
|
|
329
|
+
primary: hslToString(dp),
|
|
330
|
+
"primary-foreground": contrastForeground(dp),
|
|
331
|
+
secondary: hslToString(ds),
|
|
332
|
+
"secondary-foreground": contrastForeground(ds),
|
|
333
|
+
accent: grey["800"],
|
|
334
|
+
"accent-foreground": grey["50"],
|
|
335
|
+
"brand-accent": hslToString(da),
|
|
336
|
+
"brand-accent-foreground": contrastForeground(da),
|
|
337
|
+
highlight: hslToString(dh),
|
|
338
|
+
"highlight-foreground": contrastForeground(dh),
|
|
339
|
+
muted: grey["800"],
|
|
340
|
+
"muted-foreground": grey["400"],
|
|
288
341
|
destructive: "0 62% 30%",
|
|
289
342
|
"destructive-foreground": "0 0% 98%",
|
|
290
|
-
border:
|
|
291
|
-
input:
|
|
292
|
-
ring:
|
|
343
|
+
border: grey["800"],
|
|
344
|
+
input: grey["800"],
|
|
345
|
+
ring: hslToString(dp)
|
|
293
346
|
};
|
|
294
347
|
}
|
|
295
348
|
function generateThemeCSS(config) {
|
|
296
349
|
const primary = hexToHSL(config.brandPrimary);
|
|
297
350
|
const secondary = hexToHSL(config.brandSecondary);
|
|
298
351
|
const accent = hexToHSL(config.brandAccent);
|
|
299
|
-
const
|
|
300
|
-
const
|
|
352
|
+
const highlight = hexToHSL(config.brandHighlight);
|
|
353
|
+
const grey = GREY_SCALES[config.greyScale];
|
|
354
|
+
const light = deriveLight(primary, secondary, accent, highlight, grey);
|
|
355
|
+
const dark = deriveDark(primary, secondary, accent, highlight, grey);
|
|
301
356
|
return [
|
|
302
357
|
`/* Bison Lab Theme — Generated by @bison-lab/create-theme */`,
|
|
303
|
-
`/* Brand: ${config.brandPrimary} / ${config.brandSecondary} / ${config.brandAccent} */`,
|
|
358
|
+
`/* Brand: ${config.brandPrimary} / ${config.brandSecondary} / ${config.brandAccent} / ${config.brandHighlight} */`,
|
|
359
|
+
`/* Grey: ${config.greyScale} */`,
|
|
304
360
|
``,
|
|
305
361
|
`:root {`,
|
|
306
362
|
...Object.entries(light).map(([k, v]) => ` --${k}: ${v};`),
|
|
307
363
|
``,
|
|
308
364
|
` /* Typography */`,
|
|
309
|
-
` --font-
|
|
365
|
+
` --font-body: '${config.fontBody}', ui-sans-serif, system-ui, sans-serif;`,
|
|
366
|
+
` --font-heading: '${config.fontHeading ?? config.fontBody}', ui-sans-serif, system-ui, sans-serif;`,
|
|
310
367
|
` --font-weight-normal: ${config.fontWeights.normal};`,
|
|
311
368
|
` --font-weight-medium: ${config.fontWeights.medium};`,
|
|
312
369
|
` --font-weight-semibold: ${config.fontWeights.semibold};`,
|
|
@@ -333,8 +390,87 @@ function generateTailwindConfig(config) {
|
|
|
333
390
|
`};`
|
|
334
391
|
].join("\n");
|
|
335
392
|
}
|
|
393
|
+
function generateImports(config, themeFile) {
|
|
394
|
+
return [
|
|
395
|
+
`import '@bison-lab/tokens/css/globals.css';`,
|
|
396
|
+
`import '@bison-lab/tokens/css/themes/radius-${config.radius}.css';`,
|
|
397
|
+
`import '@bison-lab/tokens/css/themes/shadow-${config.shadow}.css';`,
|
|
398
|
+
`import '@bison-lab/tokens/css/themes/motion-${config.motion}.css';`,
|
|
399
|
+
`import '@bison-lab/tokens/css/themes/density-${config.density}.css';`,
|
|
400
|
+
`import './${themeFile}';`
|
|
401
|
+
].join("\n");
|
|
402
|
+
}
|
|
336
403
|
//#endregion
|
|
337
404
|
//#region src/index.ts
|
|
405
|
+
const BISON_PACKAGES = [
|
|
406
|
+
"@bison-lab/tokens",
|
|
407
|
+
"@bison-lab/ui",
|
|
408
|
+
"@bison-lab/tailwind-preset"
|
|
409
|
+
];
|
|
410
|
+
function copyToClipboard(text) {
|
|
411
|
+
try {
|
|
412
|
+
const platform = process.platform;
|
|
413
|
+
if (platform === "darwin") execSync("pbcopy", { input: text });
|
|
414
|
+
else if (platform === "linux") execSync("xclip -selection clipboard", { input: text });
|
|
415
|
+
else if (platform === "win32") execSync("clip", { input: text });
|
|
416
|
+
else return false;
|
|
417
|
+
return true;
|
|
418
|
+
} catch {
|
|
419
|
+
return false;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
function detectPackageManager() {
|
|
423
|
+
const cwd = process.cwd();
|
|
424
|
+
if (existsSync(join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
425
|
+
if (existsSync(join(cwd, "bun.lockb")) || existsSync(join(cwd, "bun.lock"))) return "bun";
|
|
426
|
+
if (existsSync(join(cwd, "yarn.lock"))) return "yarn";
|
|
427
|
+
return "npm";
|
|
428
|
+
}
|
|
429
|
+
function installCommand(pm) {
|
|
430
|
+
const pkgs = BISON_PACKAGES.join(" ");
|
|
431
|
+
switch (pm) {
|
|
432
|
+
case "pnpm": return `pnpm add ${pkgs}`;
|
|
433
|
+
case "yarn": return `yarn add ${pkgs}`;
|
|
434
|
+
case "bun": return `bun add ${pkgs}`;
|
|
435
|
+
default: return `npm install ${pkgs}`;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function areBisonPackagesInstalled() {
|
|
439
|
+
return BISON_PACKAGES.every((pkg) => {
|
|
440
|
+
try {
|
|
441
|
+
return existsSync(join(process.cwd(), "node_modules", pkg, "package.json"));
|
|
442
|
+
} catch {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
function findLayoutFile() {
|
|
448
|
+
for (const candidate of [
|
|
449
|
+
"app/layout.tsx",
|
|
450
|
+
"app/layout.jsx",
|
|
451
|
+
"src/app/layout.tsx",
|
|
452
|
+
"src/app/layout.jsx"
|
|
453
|
+
]) {
|
|
454
|
+
const full = resolve(process.cwd(), candidate);
|
|
455
|
+
if (existsSync(full)) return full;
|
|
456
|
+
}
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
function injectImportsIntoLayout(layoutPath, imports) {
|
|
460
|
+
const content = readFileSync(layoutPath, "utf-8");
|
|
461
|
+
if (content.includes("@bison-lab/tokens/css/globals.css")) return false;
|
|
462
|
+
const importRegex = /^import\s[\s\S]*?from\s+['"][^'"]+['"];?\s*$/gm;
|
|
463
|
+
let lastMatchEnd = -1;
|
|
464
|
+
let match;
|
|
465
|
+
while ((match = importRegex.exec(content)) !== null) lastMatchEnd = match.index + match[0].length;
|
|
466
|
+
if (lastMatchEnd === -1) writeFileSync(layoutPath, imports + "\n\n" + content, "utf-8");
|
|
467
|
+
else {
|
|
468
|
+
const before = content.slice(0, lastMatchEnd);
|
|
469
|
+
const after = content.slice(lastMatchEnd);
|
|
470
|
+
writeFileSync(layoutPath, before + "\n\n" + imports + after, "utf-8");
|
|
471
|
+
}
|
|
472
|
+
return true;
|
|
473
|
+
}
|
|
338
474
|
const CONFIG_FILE = "bison.config.json";
|
|
339
475
|
const THEME_FILE = "bison-theme.css";
|
|
340
476
|
async function main() {
|
|
@@ -366,30 +502,99 @@ async function main() {
|
|
|
366
502
|
p.cancel("Cancelled.");
|
|
367
503
|
process.exit(0);
|
|
368
504
|
}
|
|
505
|
+
if (!areBisonPackagesInstalled()) {
|
|
506
|
+
const pm = detectPackageManager();
|
|
507
|
+
const cmd = installCommand(pm);
|
|
508
|
+
const shouldInstall = await p.confirm({
|
|
509
|
+
message: `Install Bison Lab packages? (${pc.dim(cmd)})`,
|
|
510
|
+
initialValue: true
|
|
511
|
+
});
|
|
512
|
+
if (p.isCancel(shouldInstall)) {
|
|
513
|
+
p.cancel("Cancelled.");
|
|
514
|
+
process.exit(0);
|
|
515
|
+
}
|
|
516
|
+
if (shouldInstall) {
|
|
517
|
+
const s = p.spinner();
|
|
518
|
+
s.start(`Installing packages with ${pm}...`);
|
|
519
|
+
try {
|
|
520
|
+
execSync(cmd, {
|
|
521
|
+
cwd: process.cwd(),
|
|
522
|
+
stdio: "pipe"
|
|
523
|
+
});
|
|
524
|
+
s.stop("Packages installed!");
|
|
525
|
+
} catch (err) {
|
|
526
|
+
s.stop("Package installation failed.");
|
|
527
|
+
p.log.warning(`Run manually: ${pc.cyan(cmd)}`);
|
|
528
|
+
}
|
|
529
|
+
} else p.log.warning(`Skipped. Run manually: ${pc.cyan(installCommand(pm))}`);
|
|
530
|
+
} else p.log.success("Bison Lab packages already installed.");
|
|
369
531
|
const s = p.spinner();
|
|
370
532
|
s.start("Generating theme files...");
|
|
371
533
|
const themeCSS = generateThemeCSS(config);
|
|
372
534
|
writeFileSync(resolve(process.cwd(), THEME_FILE), themeCSS, "utf-8");
|
|
373
535
|
writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
374
|
-
const tailwindSnippet = generateTailwindConfig(config);
|
|
375
536
|
s.stop("Theme files generated!");
|
|
376
|
-
p.
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
""
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
""
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
537
|
+
p.log.success(`${pc.green("Created:")} ${THEME_FILE}`);
|
|
538
|
+
p.log.success(`${pc.green("Created:")} ${CONFIG_FILE}`);
|
|
539
|
+
const tailwindSnippet = generateTailwindConfig(config);
|
|
540
|
+
const tailwindPath = resolve(process.cwd(), "tailwind.config.ts");
|
|
541
|
+
if (!existsSync(tailwindPath)) {
|
|
542
|
+
writeFileSync(tailwindPath, tailwindSnippet, "utf-8");
|
|
543
|
+
p.log.success(`${pc.green("Created:")} tailwind.config.ts`);
|
|
544
|
+
} else if (readFileSync(tailwindPath, "utf-8").includes("@bison-lab/tailwind-preset")) p.log.success("tailwind.config.ts already includes Bison Lab preset.");
|
|
545
|
+
else {
|
|
546
|
+
p.note(tailwindSnippet, "tailwind.config.ts");
|
|
547
|
+
const action = await p.select({
|
|
548
|
+
message: "tailwind.config.ts already exists. How should we handle it?",
|
|
549
|
+
options: [
|
|
550
|
+
{
|
|
551
|
+
value: "overwrite",
|
|
552
|
+
label: "Overwrite",
|
|
553
|
+
hint: "Replace with Bison Lab config"
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
value: "copy",
|
|
557
|
+
label: "Copy to clipboard",
|
|
558
|
+
hint: "Paste manually"
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
value: "skip",
|
|
562
|
+
label: "Skip",
|
|
563
|
+
hint: "I'll handle it"
|
|
564
|
+
}
|
|
565
|
+
]
|
|
566
|
+
});
|
|
567
|
+
if (p.isCancel(action)) {
|
|
568
|
+
p.cancel("Cancelled.");
|
|
569
|
+
process.exit(0);
|
|
570
|
+
}
|
|
571
|
+
if (action === "overwrite") {
|
|
572
|
+
writeFileSync(tailwindPath, tailwindSnippet, "utf-8");
|
|
573
|
+
p.log.success("tailwind.config.ts overwritten.");
|
|
574
|
+
} else if (action === "copy") if (copyToClipboard(tailwindSnippet)) p.log.success("Copied tailwind config to clipboard!");
|
|
575
|
+
else p.log.warning("Could not access clipboard — copy manually from above.");
|
|
576
|
+
}
|
|
577
|
+
const importsSnippet = generateImports(config, THEME_FILE);
|
|
578
|
+
const layoutPath = findLayoutFile();
|
|
579
|
+
if (layoutPath) if (injectImportsIntoLayout(layoutPath, importsSnippet)) {
|
|
580
|
+
const relative = layoutPath.replace(process.cwd() + "/", "");
|
|
581
|
+
p.log.success(`${pc.green("Updated:")} ${relative} with Bison Lab imports.`);
|
|
582
|
+
} else p.log.success("Layout file already includes Bison Lab imports.");
|
|
583
|
+
else {
|
|
584
|
+
p.note(importsSnippet, "app/layout.tsx imports");
|
|
585
|
+
const action = await p.select({
|
|
586
|
+
message: "No layout file found. Copy imports to clipboard?",
|
|
587
|
+
options: [{
|
|
588
|
+
value: "copy",
|
|
589
|
+
label: "Copy to clipboard"
|
|
590
|
+
}, {
|
|
591
|
+
value: "skip",
|
|
592
|
+
label: "Skip"
|
|
593
|
+
}]
|
|
594
|
+
});
|
|
595
|
+
if (!p.isCancel(action) && action === "copy") if (copyToClipboard(importsSnippet)) p.log.success("Copied CSS imports to clipboard!");
|
|
596
|
+
else p.log.warning("Could not access clipboard — copy manually from above.");
|
|
597
|
+
}
|
|
393
598
|
p.outro(pc.green("Done! Your Bison Lab theme is ready."));
|
|
394
599
|
}
|
|
395
600
|
main().catch(console.error);
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/preview.ts","../src/prompts.ts","../src/generate.ts","../src/index.ts"],"sourcesContent":["import pc from \"picocolors\";\n\nexport function hexToRgb(hex: string): [number, number, number] {\n hex = hex.replace(\"#\", \"\");\n return [\n parseInt(hex.substring(0, 2), 16),\n parseInt(hex.substring(2, 4), 16),\n parseInt(hex.substring(4, 6), 16),\n ];\n}\n\nexport function previewHexColor(hex: string): string {\n const [r, g, b] = hexToRgb(hex);\n // Use ANSI 24-bit color for background\n return `\\x1b[48;2;${r};${g};${b}m \\x1b[0m ${pc.dim(hex)}`;\n}\n","import * as p from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { previewHexColor } from \"./preview\";\n\nexport interface ThemeConfig {\n brandPrimary: string;\n brandSecondary: string;\n brandAccent: string;\n radius: \"sharp\" | \"subtle\" | \"rounded\" | \"pill\";\n shadow: \"flat\" | \"subtle\" | \"elevated\";\n motion: \"snappy\" | \"smooth\" | \"minimal\";\n density: \"compact\" | \"default\" | \"spacious\";\n fontFamily: string;\n fontWeights: {\n normal: number;\n medium: number;\n semibold: number;\n bold: number;\n };\n}\n\nfunction isValidHex(hex: string | undefined): boolean {\n return hex != null && /^#[0-9A-Fa-f]{6}$/.test(hex);\n}\n\nexport async function runPrompts(existing?: ThemeConfig): Promise<ThemeConfig | null> {\n // Brand colors\n p.log.info(pc.bold(\"Brand Colors\"));\n\n if (existing) {\n p.log.message(\n `Current: Primary ${previewHexColor(existing.brandPrimary)} Secondary ${previewHexColor(existing.brandSecondary)} Accent ${previewHexColor(existing.brandAccent)}`\n );\n }\n\n const brandPrimary = await p.text({\n message: \"Primary brand color (hex)\",\n placeholder: \"#1e3a5f\",\n ...(existing?.brandPrimary && { defaultValue: existing.brandPrimary }),\n validate: (v) => (!isValidHex(v) ? \"Enter a valid hex color (e.g. #1e3a5f)\" : undefined),\n });\n if (p.isCancel(brandPrimary)) return null;\n\n p.log.message(` ${previewHexColor(brandPrimary as string)} Primary`);\n\n const brandSecondary = await p.text({\n message: \"Secondary brand color (hex)\",\n placeholder: \"#2d9d6e\",\n ...(existing?.brandSecondary && { defaultValue: existing.brandSecondary }),\n validate: (v) => (!isValidHex(v) ? \"Enter a valid hex color (e.g. #2d9d6e)\" : undefined),\n });\n if (p.isCancel(brandSecondary)) return null;\n\n p.log.message(` ${previewHexColor(brandSecondary as string)} Secondary`);\n\n const brandAccent = await p.text({\n message: \"Accent brand color (hex)\",\n placeholder: \"#e89b20\",\n ...(existing?.brandAccent && { defaultValue: existing.brandAccent }),\n validate: (v) => (!isValidHex(v) ? \"Enter a valid hex color (e.g. #e89b20)\" : undefined),\n });\n if (p.isCancel(brandAccent)) return null;\n\n p.log.message(` ${previewHexColor(brandAccent as string)} Accent`);\n\n // Radius\n const radius = await p.select({\n message: \"Border radius preset\",\n initialValue: existing?.radius ?? \"rounded\",\n options: [\n { value: \"sharp\" as const, label: \"Sharp\", hint: \"0px — square corners\" },\n { value: \"subtle\" as const, label: \"Subtle\", hint: \"6px — barely rounded\" },\n { value: \"rounded\" as const, label: \"Rounded\", hint: \"8px — balanced (default)\" },\n { value: \"pill\" as const, label: \"Pill\", hint: \"12px — soft, bubbly\" },\n ],\n });\n if (p.isCancel(radius)) return null;\n\n // Shadow\n const shadow = await p.select({\n message: \"Shadow preset\",\n initialValue: existing?.shadow ?? \"subtle\",\n options: [\n { value: \"flat\" as const, label: \"Flat\", hint: \"No shadows — clean, modern\" },\n { value: \"subtle\" as const, label: \"Subtle\", hint: \"Soft low-opacity shadows (default)\" },\n { value: \"elevated\" as const, label: \"Elevated\", hint: \"Prominent layered shadows\" },\n ],\n });\n if (p.isCancel(shadow)) return null;\n\n // Motion\n const motion = await p.select({\n message: \"Motion preset\",\n initialValue: existing?.motion ?? \"smooth\",\n options: [\n { value: \"snappy\" as const, label: \"Snappy\", hint: \"Fast, spring-like (150ms)\" },\n { value: \"smooth\" as const, label: \"Smooth\", hint: \"Balanced ease-out (200ms, default)\" },\n { value: \"minimal\" as const, label: \"Minimal\", hint: \"Barely-there, linear (100ms)\" },\n ],\n });\n if (p.isCancel(motion)) return null;\n\n // Density\n const density = await p.select({\n message: \"Component density\",\n initialValue: existing?.density ?? \"default\",\n options: [\n { value: \"compact\" as const, label: \"Compact\", hint: \"Tight padding, smaller components\" },\n { value: \"default\" as const, label: \"Default\", hint: \"Balanced spacing\" },\n { value: \"spacious\" as const, label: \"Spacious\", hint: \"Generous padding, larger components\" },\n ],\n });\n if (p.isCancel(density)) return null;\n\n // Font\n p.log.info(pc.bold(\"Typography\"));\n\n const fontFamily = await p.text({\n message: \"Font family name\",\n placeholder: \"Inter\",\n defaultValue: existing?.fontFamily ?? \"Inter\",\n });\n if (p.isCancel(fontFamily)) return null;\n\n // Font weights\n const customizeWeights = await p.confirm({\n message: \"Customize font weights? (default: 400/500/600/700)\",\n initialValue: false,\n });\n if (p.isCancel(customizeWeights)) return null;\n\n let fontWeights = existing?.fontWeights ?? { normal: 400, medium: 500, semibold: 600, bold: 700 };\n\n if (customizeWeights) {\n const normal = await p.text({\n message: \"Normal weight\",\n defaultValue: String(fontWeights.normal),\n validate: (v) => (isNaN(Number(v)) ? \"Must be a number\" : undefined),\n });\n if (p.isCancel(normal)) return null;\n\n const medium = await p.text({\n message: \"Medium weight\",\n defaultValue: String(fontWeights.medium),\n validate: (v) => (isNaN(Number(v)) ? \"Must be a number\" : undefined),\n });\n if (p.isCancel(medium)) return null;\n\n const semibold = await p.text({\n message: \"Semibold weight\",\n defaultValue: String(fontWeights.semibold),\n validate: (v) => (isNaN(Number(v)) ? \"Must be a number\" : undefined),\n });\n if (p.isCancel(semibold)) return null;\n\n const bold = await p.text({\n message: \"Bold weight\",\n defaultValue: String(fontWeights.bold),\n validate: (v) => (isNaN(Number(v)) ? \"Must be a number\" : undefined),\n });\n if (p.isCancel(bold)) return null;\n\n fontWeights = {\n normal: Number(normal),\n medium: Number(medium),\n semibold: Number(semibold),\n bold: Number(bold),\n };\n }\n\n return {\n brandPrimary: brandPrimary as string,\n brandSecondary: brandSecondary as string,\n brandAccent: brandAccent as string,\n radius: radius as ThemeConfig[\"radius\"],\n shadow: shadow as ThemeConfig[\"shadow\"],\n motion: motion as ThemeConfig[\"motion\"],\n density: density as ThemeConfig[\"density\"],\n fontFamily: fontFamily as string,\n fontWeights,\n };\n}\n","import type { ThemeConfig } from \"./prompts\";\n\nfunction hexToHSL(hex: string): { h: number; s: number; l: number } {\n hex = hex.replace(\"#\", \"\");\n const r = parseInt(hex.substring(0, 2), 16) / 255;\n const g = parseInt(hex.substring(2, 4), 16) / 255;\n const b = parseInt(hex.substring(4, 6), 16) / 255;\n\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const l = (max + min) / 2;\n let h = 0;\n let s = 0;\n\n if (max !== min) {\n const d = max - min;\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n switch (max) {\n case r:\n h = ((g - b) / d + (g < b ? 6 : 0)) / 6;\n break;\n case g:\n h = ((b - r) / d + 2) / 6;\n break;\n case b:\n h = ((r - g) / d + 4) / 6;\n break;\n }\n }\n\n return {\n h: Math.round(h * 360),\n s: Math.round(s * 100),\n l: Math.round(l * 100),\n };\n}\n\nfunction hsl(h: number, s: number, l: number): string {\n return `${h} ${s}% ${l}%`;\n}\n\nfunction clamp(v: number, min: number, max: number): number {\n return Math.min(Math.max(v, min), max);\n}\n\ninterface HSL {\n h: number;\n s: number;\n l: number;\n}\n\nfunction deriveLight(primary: HSL, secondary: HSL, accent: HSL): Record<string, string> {\n return {\n background: hsl(primary.h, clamp(primary.s - 30, 0, 100), 100),\n foreground: hsl(primary.h, clamp(primary.s - 20, 0, 100), 10),\n card: hsl(primary.h, clamp(primary.s - 30, 0, 100), 100),\n \"card-foreground\": hsl(primary.h, clamp(primary.s - 20, 0, 100), 10),\n popover: hsl(primary.h, clamp(primary.s - 30, 0, 100), 100),\n \"popover-foreground\": hsl(primary.h, clamp(primary.s - 20, 0, 100), 10),\n primary: hsl(primary.h, primary.s, primary.l),\n \"primary-foreground\": hsl(primary.h, clamp(primary.s - 30, 0, 100), primary.l > 50 ? 10 : 98),\n secondary: hsl(secondary.h, clamp(secondary.s - 30, 0, 100), clamp(secondary.l + 40, 0, 100)),\n \"secondary-foreground\": hsl(secondary.h, secondary.s, clamp(secondary.l - 30, 0, 100)),\n accent: hsl(accent.h, accent.s, clamp(accent.l + 10, 0, 100)),\n \"accent-foreground\": hsl(accent.h, accent.s, clamp(accent.l - 60, 0, 100)),\n muted: hsl(primary.h, clamp(primary.s - 30, 0, 100), 96),\n \"muted-foreground\": hsl(primary.h, clamp(primary.s - 25, 0, 100), 45),\n destructive: \"0 84% 60%\",\n \"destructive-foreground\": \"0 0% 98%\",\n border: hsl(primary.h, clamp(primary.s - 25, 0, 100), 91),\n input: hsl(primary.h, clamp(primary.s - 25, 0, 100), 91),\n ring: hsl(primary.h, primary.s, primary.l),\n };\n}\n\nfunction deriveDark(primary: HSL, secondary: HSL, accent: HSL): Record<string, string> {\n const darkPrimary = { ...primary, l: primary.l < 50 ? primary.l + 20 : primary.l };\n\n return {\n background: hsl(primary.h, clamp(primary.s - 25, 0, 100), 7),\n foreground: hsl(primary.h, clamp(primary.s - 30, 0, 100), 98),\n card: hsl(primary.h, clamp(primary.s - 25, 0, 100), 10),\n \"card-foreground\": hsl(primary.h, clamp(primary.s - 30, 0, 100), 98),\n popover: hsl(primary.h, clamp(primary.s - 25, 0, 100), 10),\n \"popover-foreground\": hsl(primary.h, clamp(primary.s - 30, 0, 100), 98),\n primary: hsl(darkPrimary.h, darkPrimary.s, darkPrimary.l),\n \"primary-foreground\": hsl(primary.h, clamp(primary.s - 30, 0, 100), darkPrimary.l > 50 ? 10 : 98),\n secondary: hsl(secondary.h, clamp(secondary.s - 20, 0, 100), 18),\n \"secondary-foreground\": hsl(secondary.h, secondary.s, clamp(secondary.l + 30, 0, 100)),\n accent: hsl(accent.h, clamp(accent.s - 10, 0, 100), 20),\n \"accent-foreground\": hsl(accent.h, accent.s, clamp(accent.l + 40, 0, 100)),\n muted: hsl(primary.h, clamp(primary.s - 25, 0, 100), 18),\n \"muted-foreground\": hsl(primary.h, clamp(primary.s - 20, 0, 100), 65),\n destructive: \"0 62% 30%\",\n \"destructive-foreground\": \"0 0% 98%\",\n border: hsl(primary.h, clamp(primary.s - 25, 0, 100), 18),\n input: hsl(primary.h, clamp(primary.s - 25, 0, 100), 18),\n ring: hsl(darkPrimary.h, darkPrimary.s, darkPrimary.l),\n };\n}\n\nexport function generateThemeCSS(config: ThemeConfig): string {\n const primary = hexToHSL(config.brandPrimary);\n const secondary = hexToHSL(config.brandSecondary);\n const accent = hexToHSL(config.brandAccent);\n\n const light = deriveLight(primary, secondary, accent);\n const dark = deriveDark(primary, secondary, accent);\n\n const lines: string[] = [\n `/* Bison Lab Theme — Generated by @bison-lab/create-theme */`,\n `/* Brand: ${config.brandPrimary} / ${config.brandSecondary} / ${config.brandAccent} */`,\n ``,\n `:root {`,\n ...Object.entries(light).map(([k, v]) => ` --${k}: ${v};`),\n ``,\n ` /* Typography */`,\n ` --font-sans: '${config.fontFamily}', ui-sans-serif, system-ui, sans-serif;`,\n ` --font-weight-normal: ${config.fontWeights.normal};`,\n ` --font-weight-medium: ${config.fontWeights.medium};`,\n ` --font-weight-semibold: ${config.fontWeights.semibold};`,\n ` --font-weight-bold: ${config.fontWeights.bold};`,\n `}`,\n ``,\n `.dark {`,\n ...Object.entries(dark).map(([k, v]) => ` --${k}: ${v};`),\n `}`,\n ``,\n ];\n\n return lines.join(\"\\n\");\n}\n\nexport function generateTailwindConfig(config: ThemeConfig): string {\n return [\n `import bisonPreset from '@bison-lab/tailwind-preset';`,\n ``,\n `export default {`,\n ` presets: [bisonPreset],`,\n ` content: [`,\n ` './app/**/*.{ts,tsx}',`,\n ` './components/**/*.{ts,tsx}',`,\n ` './node_modules/@bison-lab/ui/dist/**/*.js',`,\n ` ],`,\n `};`,\n ].join(\"\\n\");\n}\n","import * as p from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { existsSync, readFileSync, writeFileSync } from \"fs\";\nimport { resolve } from \"path\";\nimport { runPrompts, type ThemeConfig } from \"./prompts\";\nimport { generateThemeCSS, generateTailwindConfig } from \"./generate\";\n\nconst CONFIG_FILE = \"bison.config.json\";\nconst THEME_FILE = \"bison-theme.css\";\n\nasync function main() {\n p.intro(pc.bgCyan(pc.black(\" Bison Lab Theme Generator \")));\n\n const configPath = resolve(process.cwd(), CONFIG_FILE);\n let existingConfig: ThemeConfig | undefined;\n\n if (existsSync(configPath)) {\n const raw = JSON.parse(readFileSync(configPath, \"utf-8\")) as ThemeConfig;\n existingConfig = raw;\n\n const mode = await p.select({\n message: \"An existing theme was found. What would you like to do?\",\n options: [\n { value: \"update\", label: \"Update existing theme\", hint: \"Modify individual properties\" },\n { value: \"fresh\", label: \"Start fresh\", hint: \"Overwrite everything\" },\n ],\n });\n\n if (p.isCancel(mode)) {\n p.cancel(\"Cancelled.\");\n process.exit(0);\n }\n\n if (mode === \"fresh\") {\n existingConfig = undefined;\n }\n }\n\n const config = await runPrompts(existingConfig);\n\n if (!config) {\n p.cancel(\"Cancelled.\");\n process.exit(0);\n }\n\n const s = p.spinner();\n s.start(\"Generating theme files...\");\n\n const themeCSS = generateThemeCSS(config);\n const themePath = resolve(process.cwd(), THEME_FILE);\n writeFileSync(themePath, themeCSS, \"utf-8\");\n\n writeFileSync(configPath, JSON.stringify(config, null, 2), \"utf-8\");\n\n const tailwindSnippet = generateTailwindConfig(config);\n\n s.stop(\"Theme files generated!\");\n\n p.note(\n [\n `${pc.green(\"Created:\")} ${THEME_FILE}`,\n `${pc.green(\"Created:\")} ${CONFIG_FILE}`,\n \"\",\n `${pc.bold(\"Add to your tailwind.config.ts:\")}`,\n \"\",\n tailwindSnippet,\n \"\",\n `${pc.bold(\"Import in your app/layout.tsx:\")}`,\n \"\",\n `import '@bison-lab/tokens/css/globals.css';`,\n `import '@bison-lab/tokens/css/themes/radius-${config.radius}.css';`,\n `import '@bison-lab/tokens/css/themes/shadow-${config.shadow}.css';`,\n `import '@bison-lab/tokens/css/themes/motion-${config.motion}.css';`,\n `import '@bison-lab/tokens/css/themes/density-${config.density}.css';`,\n `import './${THEME_FILE}';`,\n ].join(\"\\n\"),\n \"Next steps\"\n );\n\n p.outro(pc.green(\"Done! Your Bison Lab theme is ready.\"));\n}\n\nmain().catch(console.error);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/preview.ts","../src/prompts.ts","../src/generate.ts","../src/index.ts"],"sourcesContent":["import pc from \"picocolors\";\n\nexport function hexToRgb(hex: string): [number, number, number] {\n hex = hex.replace(\"#\", \"\");\n return [\n parseInt(hex.substring(0, 2), 16),\n parseInt(hex.substring(2, 4), 16),\n parseInt(hex.substring(4, 6), 16),\n ];\n}\n\nexport function previewHexColor(hex: string): string {\n const [r, g, b] = hexToRgb(hex);\n // Use ANSI 24-bit color for background\n return `\\x1b[48;2;${r};${g};${b}m \\x1b[0m ${pc.dim(hex)}`;\n}\n","import * as p from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { previewHexColor } from \"./preview\";\n\nexport type GreyScale = \"slate\" | \"gray\" | \"zinc\" | \"neutral\" | \"stone\";\n\nexport interface ThemeConfig {\n brandPrimary: string;\n brandSecondary: string;\n brandAccent: string;\n brandHighlight: string;\n greyScale: GreyScale;\n radius: \"sharp\" | \"subtle\" | \"rounded\" | \"pill\";\n shadow: \"flat\" | \"subtle\" | \"elevated\";\n motion: \"snappy\" | \"smooth\" | \"minimal\";\n density: \"compact\" | \"default\" | \"spacious\";\n fontBody: string;\n fontHeading: string | null;\n fontWeights: {\n normal: number;\n medium: number;\n semibold: number;\n bold: number;\n };\n}\n\nfunction isValidHex(hex: string | undefined): boolean {\n return hex != null && /^#[0-9A-Fa-f]{6}$/.test(hex);\n}\n\nexport async function runPrompts(existing?: ThemeConfig): Promise<ThemeConfig | null> {\n // Brand colors\n p.log.info(pc.bold(\"Brand Colors\"));\n\n if (existing) {\n p.log.message(\n `Current: Primary ${previewHexColor(existing.brandPrimary)} Secondary ${previewHexColor(existing.brandSecondary)} Accent ${previewHexColor(existing.brandAccent)} Highlight ${previewHexColor(existing.brandHighlight)}`\n );\n }\n\n const brandPrimary = await p.text({\n message: \"Primary brand color (hex)\",\n placeholder: \"#1e3a5f\",\n ...(existing?.brandPrimary && { defaultValue: existing.brandPrimary }),\n validate: (v) => (!isValidHex(v) ? \"Enter a valid hex color (e.g. #1e3a5f)\" : undefined),\n });\n if (p.isCancel(brandPrimary)) return null;\n\n p.log.message(` ${previewHexColor(brandPrimary as string)} Primary`);\n\n const brandSecondary = await p.text({\n message: \"Secondary brand color (hex)\",\n placeholder: \"#2d9d6e\",\n ...(existing?.brandSecondary && { defaultValue: existing.brandSecondary }),\n validate: (v) => (!isValidHex(v) ? \"Enter a valid hex color (e.g. #2d9d6e)\" : undefined),\n });\n if (p.isCancel(brandSecondary)) return null;\n\n p.log.message(` ${previewHexColor(brandSecondary as string)} Secondary`);\n\n const brandAccent = await p.text({\n message: \"Accent color (hex)\",\n placeholder: \"#e89b20\",\n ...(existing?.brandAccent && { defaultValue: existing.brandAccent }),\n validate: (v) => (!isValidHex(v) ? \"Enter a valid hex color (e.g. #e89b20)\" : undefined),\n });\n if (p.isCancel(brandAccent)) return null;\n\n p.log.message(` ${previewHexColor(brandAccent as string)} Accent`);\n\n const brandHighlight = await p.text({\n message: \"Highlight color (hex)\",\n placeholder: \"#7c3aed\",\n ...(existing?.brandHighlight && { defaultValue: existing.brandHighlight }),\n validate: (v) => (!isValidHex(v) ? \"Enter a valid hex color (e.g. #7c3aed)\" : undefined),\n });\n if (p.isCancel(brandHighlight)) return null;\n\n p.log.message(` ${previewHexColor(brandHighlight as string)} Highlight`);\n\n // Grey scale\n p.log.info(pc.bold(\"Grey Scale\"));\n\n const greyScale = await p.select({\n message: \"Grey palette for borders, text, backgrounds\",\n initialValue: existing?.greyScale ?? \"slate\",\n options: [\n { value: \"slate\" as const, label: \"Slate\", hint: \"Cool blue-grey — modern, tech-forward\" },\n { value: \"gray\" as const, label: \"Gray\", hint: \"Balanced blue-grey — neutral default\" },\n { value: \"zinc\" as const, label: \"Zinc\", hint: \"Cool desaturated — minimal, sharp\" },\n { value: \"neutral\" as const, label: \"Neutral\", hint: \"Pure grey — zero hue bias\" },\n { value: \"stone\" as const, label: \"Stone\", hint: \"Warm earthy grey — organic, approachable\" },\n ],\n });\n if (p.isCancel(greyScale)) return null;\n\n // Radius\n const radius = await p.select({\n message: \"Border radius preset\",\n initialValue: existing?.radius ?? \"rounded\",\n options: [\n { value: \"sharp\" as const, label: \"Sharp\", hint: \"0px — square corners\" },\n { value: \"subtle\" as const, label: \"Subtle\", hint: \"6px — barely rounded\" },\n { value: \"rounded\" as const, label: \"Rounded\", hint: \"8px — balanced (default)\" },\n { value: \"pill\" as const, label: \"Pill\", hint: \"12px — soft, bubbly\" },\n ],\n });\n if (p.isCancel(radius)) return null;\n\n // Shadow\n const shadow = await p.select({\n message: \"Shadow preset\",\n initialValue: existing?.shadow ?? \"subtle\",\n options: [\n { value: \"flat\" as const, label: \"Flat\", hint: \"No shadows — clean, modern\" },\n { value: \"subtle\" as const, label: \"Subtle\", hint: \"Soft low-opacity shadows (default)\" },\n { value: \"elevated\" as const, label: \"Elevated\", hint: \"Prominent layered shadows\" },\n ],\n });\n if (p.isCancel(shadow)) return null;\n\n // Motion\n const motion = await p.select({\n message: \"Motion preset\",\n initialValue: existing?.motion ?? \"smooth\",\n options: [\n { value: \"snappy\" as const, label: \"Snappy\", hint: \"Fast, spring-like (150ms)\" },\n { value: \"smooth\" as const, label: \"Smooth\", hint: \"Balanced ease-out (200ms, default)\" },\n { value: \"minimal\" as const, label: \"Minimal\", hint: \"Barely-there, linear (100ms)\" },\n ],\n });\n if (p.isCancel(motion)) return null;\n\n // Density\n const density = await p.select({\n message: \"Component density\",\n initialValue: existing?.density ?? \"default\",\n options: [\n { value: \"compact\" as const, label: \"Compact\", hint: \"Tight padding, smaller components\" },\n { value: \"default\" as const, label: \"Default\", hint: \"Balanced spacing\" },\n { value: \"spacious\" as const, label: \"Spacious\", hint: \"Generous padding, larger components\" },\n ],\n });\n if (p.isCancel(density)) return null;\n\n // Font\n p.log.info(pc.bold(\"Typography\"));\n\n const fontBody = await p.text({\n message: \"Body font family\",\n placeholder: \"Inter\",\n defaultValue: existing?.fontBody ?? \"Inter\",\n });\n if (p.isCancel(fontBody)) return null;\n\n const wantsHeading = await p.confirm({\n message: \"Use a separate display/heading font?\",\n initialValue: existing?.fontHeading != null,\n });\n if (p.isCancel(wantsHeading)) return null;\n\n let fontHeading: string | null = null;\n if (wantsHeading) {\n const heading = await p.text({\n message: \"Heading font family\",\n placeholder: \"Playfair Display\",\n ...(existing?.fontHeading && { defaultValue: existing.fontHeading }),\n });\n if (p.isCancel(heading)) return null;\n fontHeading = heading as string;\n }\n\n // Font weights\n const customizeWeights = await p.confirm({\n message: \"Customize font weights? (default: 400/500/600/700)\",\n initialValue: false,\n });\n if (p.isCancel(customizeWeights)) return null;\n\n let fontWeights = existing?.fontWeights ?? { normal: 400, medium: 500, semibold: 600, bold: 700 };\n\n if (customizeWeights) {\n const normal = await p.text({\n message: \"Normal weight\",\n defaultValue: String(fontWeights.normal),\n validate: (v) => (isNaN(Number(v)) ? \"Must be a number\" : undefined),\n });\n if (p.isCancel(normal)) return null;\n\n const medium = await p.text({\n message: \"Medium weight\",\n defaultValue: String(fontWeights.medium),\n validate: (v) => (isNaN(Number(v)) ? \"Must be a number\" : undefined),\n });\n if (p.isCancel(medium)) return null;\n\n const semibold = await p.text({\n message: \"Semibold weight\",\n defaultValue: String(fontWeights.semibold),\n validate: (v) => (isNaN(Number(v)) ? \"Must be a number\" : undefined),\n });\n if (p.isCancel(semibold)) return null;\n\n const bold = await p.text({\n message: \"Bold weight\",\n defaultValue: String(fontWeights.bold),\n validate: (v) => (isNaN(Number(v)) ? \"Must be a number\" : undefined),\n });\n if (p.isCancel(bold)) return null;\n\n fontWeights = {\n normal: Number(normal),\n medium: Number(medium),\n semibold: Number(semibold),\n bold: Number(bold),\n };\n }\n\n return {\n brandPrimary: brandPrimary as string,\n brandSecondary: brandSecondary as string,\n brandAccent: brandAccent as string,\n brandHighlight: brandHighlight as string,\n greyScale: greyScale as GreyScale,\n radius: radius as ThemeConfig[\"radius\"],\n shadow: shadow as ThemeConfig[\"shadow\"],\n motion: motion as ThemeConfig[\"motion\"],\n density: density as ThemeConfig[\"density\"],\n fontBody: fontBody as string,\n fontHeading,\n fontWeights,\n };\n}\n","import type { ThemeConfig } from \"./prompts\";\nimport {\n hexToHSL,\n hslToString,\n GREY_SCALES,\n type GreyScale,\n} from \"@bison-lab/tokens\";\n\n// --- Local HSL utilities (not exported from tokens) ---\n\nfunction clamp(v: number, min: number, max: number): number {\n return Math.min(Math.max(v, min), max);\n}\n\nfunction contrastForeground(color: { h: number; s: number; l: number }): string {\n return color.l > 55\n ? hslToString({ h: color.h, s: clamp(color.s - 20, 0, 100), l: 10 })\n : hslToString({ h: color.h, s: clamp(color.s - 25, 0, 100), l: 98 });\n}\n\nfunction boostForDark(color: { h: number; s: number; l: number }): { h: number; s: number; l: number } {\n if (color.l < 40) {\n return { ...color, l: clamp(color.l + 25, 0, 100) };\n }\n return color;\n}\n\n// --- Palette derivation ---\n\ntype GreyShade = \"50\" | \"100\" | \"200\" | \"300\" | \"400\" | \"500\" | \"600\" | \"700\" | \"800\" | \"900\" | \"950\";\n\nfunction deriveLight(\n primary: { h: number; s: number; l: number },\n secondary: { h: number; s: number; l: number },\n accent: { h: number; s: number; l: number },\n highlight: { h: number; s: number; l: number },\n grey: Record<GreyShade, string>,\n): Record<string, string> {\n return {\n background: grey[\"50\"],\n foreground: grey[\"950\"],\n card: grey[\"50\"],\n \"card-foreground\": grey[\"950\"],\n popover: grey[\"50\"],\n \"popover-foreground\": grey[\"950\"],\n primary: hslToString(primary),\n \"primary-foreground\": contrastForeground(primary),\n secondary: hslToString(secondary),\n \"secondary-foreground\": contrastForeground(secondary),\n accent: grey[\"100\"],\n \"accent-foreground\": grey[\"950\"],\n \"brand-accent\": hslToString(accent),\n \"brand-accent-foreground\": contrastForeground(accent),\n highlight: hslToString(highlight),\n \"highlight-foreground\": contrastForeground(highlight),\n muted: grey[\"100\"],\n \"muted-foreground\": grey[\"500\"],\n destructive: \"0 84% 60%\",\n \"destructive-foreground\": \"0 0% 98%\",\n border: grey[\"200\"],\n input: grey[\"200\"],\n ring: hslToString(primary),\n };\n}\n\nfunction deriveDark(\n primary: { h: number; s: number; l: number },\n secondary: { h: number; s: number; l: number },\n accent: { h: number; s: number; l: number },\n highlight: { h: number; s: number; l: number },\n grey: Record<GreyShade, string>,\n): Record<string, string> {\n const dp = boostForDark(primary);\n const ds = boostForDark(secondary);\n const da = boostForDark(accent);\n const dh = boostForDark(highlight);\n\n return {\n background: grey[\"950\"],\n foreground: grey[\"50\"],\n card: grey[\"900\"],\n \"card-foreground\": grey[\"50\"],\n popover: grey[\"900\"],\n \"popover-foreground\": grey[\"50\"],\n primary: hslToString(dp),\n \"primary-foreground\": contrastForeground(dp),\n secondary: hslToString(ds),\n \"secondary-foreground\": contrastForeground(ds),\n accent: grey[\"800\"],\n \"accent-foreground\": grey[\"50\"],\n \"brand-accent\": hslToString(da),\n \"brand-accent-foreground\": contrastForeground(da),\n highlight: hslToString(dh),\n \"highlight-foreground\": contrastForeground(dh),\n muted: grey[\"800\"],\n \"muted-foreground\": grey[\"400\"],\n destructive: \"0 62% 30%\",\n \"destructive-foreground\": \"0 0% 98%\",\n border: grey[\"800\"],\n input: grey[\"800\"],\n ring: hslToString(dp),\n };\n}\n\n// --- Public generators ---\n\nexport function generateThemeCSS(config: ThemeConfig): string {\n const primary = hexToHSL(config.brandPrimary);\n const secondary = hexToHSL(config.brandSecondary);\n const accent = hexToHSL(config.brandAccent);\n const highlight = hexToHSL(config.brandHighlight);\n const grey = GREY_SCALES[config.greyScale as GreyScale];\n\n const light = deriveLight(primary, secondary, accent, highlight, grey);\n const dark = deriveDark(primary, secondary, accent, highlight, grey);\n\n const lines: string[] = [\n `/* Bison Lab Theme — Generated by @bison-lab/create-theme */`,\n `/* Brand: ${config.brandPrimary} / ${config.brandSecondary} / ${config.brandAccent} / ${config.brandHighlight} */`,\n `/* Grey: ${config.greyScale} */`,\n ``,\n `:root {`,\n ...Object.entries(light).map(([k, v]) => ` --${k}: ${v};`),\n ``,\n ` /* Typography */`,\n ` --font-body: '${config.fontBody}', ui-sans-serif, system-ui, sans-serif;`,\n ` --font-heading: '${config.fontHeading ?? config.fontBody}', ui-sans-serif, system-ui, sans-serif;`,\n ` --font-weight-normal: ${config.fontWeights.normal};`,\n ` --font-weight-medium: ${config.fontWeights.medium};`,\n ` --font-weight-semibold: ${config.fontWeights.semibold};`,\n ` --font-weight-bold: ${config.fontWeights.bold};`,\n `}`,\n ``,\n `.dark {`,\n ...Object.entries(dark).map(([k, v]) => ` --${k}: ${v};`),\n `}`,\n ``,\n ];\n\n return lines.join(\"\\n\");\n}\n\nexport function generateTailwindConfig(config: ThemeConfig): string {\n return [\n `import bisonPreset from '@bison-lab/tailwind-preset';`,\n ``,\n `export default {`,\n ` presets: [bisonPreset],`,\n ` content: [`,\n ` './app/**/*.{ts,tsx}',`,\n ` './components/**/*.{ts,tsx}',`,\n ` './node_modules/@bison-lab/ui/dist/**/*.js',`,\n ` ],`,\n `};`,\n ].join(\"\\n\");\n}\n\nexport function generateImports(config: ThemeConfig, themeFile: string): string {\n return [\n `import '@bison-lab/tokens/css/globals.css';`,\n `import '@bison-lab/tokens/css/themes/radius-${config.radius}.css';`,\n `import '@bison-lab/tokens/css/themes/shadow-${config.shadow}.css';`,\n `import '@bison-lab/tokens/css/themes/motion-${config.motion}.css';`,\n `import '@bison-lab/tokens/css/themes/density-${config.density}.css';`,\n `import './${themeFile}';`,\n ].join(\"\\n\");\n}\n","import * as p from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { execSync } from \"child_process\";\nimport { existsSync, readFileSync, writeFileSync } from \"fs\";\nimport { resolve, join } from \"path\";\nimport { runPrompts, type ThemeConfig } from \"./prompts\";\nimport { generateThemeCSS, generateTailwindConfig, generateImports } from \"./generate\";\n\nconst BISON_PACKAGES = [\n \"@bison-lab/tokens\",\n \"@bison-lab/ui\",\n \"@bison-lab/tailwind-preset\",\n];\n\nfunction copyToClipboard(text: string): boolean {\n try {\n const platform = process.platform;\n if (platform === \"darwin\") {\n execSync(\"pbcopy\", { input: text });\n } else if (platform === \"linux\") {\n execSync(\"xclip -selection clipboard\", { input: text });\n } else if (platform === \"win32\") {\n execSync(\"clip\", { input: text });\n } else {\n return false;\n }\n return true;\n } catch {\n return false;\n }\n}\n\nfunction detectPackageManager(): \"pnpm\" | \"npm\" | \"yarn\" | \"bun\" {\n const cwd = process.cwd();\n if (existsSync(join(cwd, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (existsSync(join(cwd, \"bun.lockb\")) || existsSync(join(cwd, \"bun.lock\"))) return \"bun\";\n if (existsSync(join(cwd, \"yarn.lock\"))) return \"yarn\";\n return \"npm\";\n}\n\nfunction installCommand(pm: \"pnpm\" | \"npm\" | \"yarn\" | \"bun\"): string {\n const pkgs = BISON_PACKAGES.join(\" \");\n switch (pm) {\n case \"pnpm\": return `pnpm add ${pkgs}`;\n case \"yarn\": return `yarn add ${pkgs}`;\n case \"bun\": return `bun add ${pkgs}`;\n default: return `npm install ${pkgs}`;\n }\n}\n\nfunction areBisonPackagesInstalled(): boolean {\n return BISON_PACKAGES.every((pkg) => {\n try {\n const pkgJsonPath = join(process.cwd(), \"node_modules\", pkg, \"package.json\");\n return existsSync(pkgJsonPath);\n } catch {\n return false;\n }\n });\n}\n\nfunction findLayoutFile(): string | null {\n const candidates = [\n \"app/layout.tsx\",\n \"app/layout.jsx\",\n \"src/app/layout.tsx\",\n \"src/app/layout.jsx\",\n ];\n for (const candidate of candidates) {\n const full = resolve(process.cwd(), candidate);\n if (existsSync(full)) return full;\n }\n return null;\n}\n\nfunction injectImportsIntoLayout(layoutPath: string, imports: string): boolean {\n const content = readFileSync(layoutPath, \"utf-8\");\n\n // Check if already injected\n if (content.includes(\"@bison-lab/tokens/css/globals.css\")) {\n return false;\n }\n\n // Match all import statements including multiline ones (e.g. import { \\n Foo,\\n } from \"bar\";)\n const importRegex = /^import\\s[\\s\\S]*?from\\s+['\"][^'\"]+['\"];?\\s*$/gm;\n let lastMatchEnd = -1;\n let match: RegExpExecArray | null;\n\n while ((match = importRegex.exec(content)) !== null) {\n lastMatchEnd = match.index + match[0].length;\n }\n\n if (lastMatchEnd === -1) {\n // No imports found, prepend to file\n writeFileSync(layoutPath, imports + \"\\n\\n\" + content, \"utf-8\");\n } else {\n // Insert after the last import statement\n const before = content.slice(0, lastMatchEnd);\n const after = content.slice(lastMatchEnd);\n writeFileSync(layoutPath, before + \"\\n\\n\" + imports + after, \"utf-8\");\n }\n\n return true;\n}\n\nconst CONFIG_FILE = \"bison.config.json\";\nconst THEME_FILE = \"bison-theme.css\";\n\nasync function main() {\n p.intro(pc.bgCyan(pc.black(\" Bison Lab Theme Generator \")));\n\n const configPath = resolve(process.cwd(), CONFIG_FILE);\n let existingConfig: ThemeConfig | undefined;\n\n if (existsSync(configPath)) {\n const raw = JSON.parse(readFileSync(configPath, \"utf-8\")) as ThemeConfig;\n existingConfig = raw;\n\n const mode = await p.select({\n message: \"An existing theme was found. What would you like to do?\",\n options: [\n { value: \"update\", label: \"Update existing theme\", hint: \"Modify individual properties\" },\n { value: \"fresh\", label: \"Start fresh\", hint: \"Overwrite everything\" },\n ],\n });\n\n if (p.isCancel(mode)) {\n p.cancel(\"Cancelled.\");\n process.exit(0);\n }\n\n if (mode === \"fresh\") {\n existingConfig = undefined;\n }\n }\n\n const config = await runPrompts(existingConfig);\n\n if (!config) {\n p.cancel(\"Cancelled.\");\n process.exit(0);\n }\n\n // --- Install dependencies ---\n if (!areBisonPackagesInstalled()) {\n const pm = detectPackageManager();\n const cmd = installCommand(pm);\n\n const shouldInstall = await p.confirm({\n message: `Install Bison Lab packages? (${pc.dim(cmd)})`,\n initialValue: true,\n });\n\n if (p.isCancel(shouldInstall)) {\n p.cancel(\"Cancelled.\");\n process.exit(0);\n }\n\n if (shouldInstall) {\n const s = p.spinner();\n s.start(`Installing packages with ${pm}...`);\n try {\n execSync(cmd, { cwd: process.cwd(), stdio: \"pipe\" });\n s.stop(\"Packages installed!\");\n } catch (err) {\n s.stop(\"Package installation failed.\");\n p.log.warning(`Run manually: ${pc.cyan(cmd)}`);\n }\n } else {\n p.log.warning(`Skipped. Run manually: ${pc.cyan(installCommand(pm))}`);\n }\n } else {\n p.log.success(\"Bison Lab packages already installed.\");\n }\n\n // --- Generate theme files ---\n const s = p.spinner();\n s.start(\"Generating theme files...\");\n\n const themeCSS = generateThemeCSS(config);\n const themePath = resolve(process.cwd(), THEME_FILE);\n writeFileSync(themePath, themeCSS, \"utf-8\");\n writeFileSync(configPath, JSON.stringify(config, null, 2), \"utf-8\");\n\n s.stop(\"Theme files generated!\");\n\n p.log.success(`${pc.green(\"Created:\")} ${THEME_FILE}`);\n p.log.success(`${pc.green(\"Created:\")} ${CONFIG_FILE}`);\n\n // --- Tailwind config ---\n const tailwindSnippet = generateTailwindConfig(config);\n const tailwindPath = resolve(process.cwd(), \"tailwind.config.ts\");\n\n if (!existsSync(tailwindPath)) {\n writeFileSync(tailwindPath, tailwindSnippet, \"utf-8\");\n p.log.success(`${pc.green(\"Created:\")} tailwind.config.ts`);\n } else {\n const existing = readFileSync(tailwindPath, \"utf-8\");\n if (existing.includes(\"@bison-lab/tailwind-preset\")) {\n p.log.success(\"tailwind.config.ts already includes Bison Lab preset.\");\n } else {\n p.note(tailwindSnippet, \"tailwind.config.ts\");\n\n const action = await p.select({\n message: \"tailwind.config.ts already exists. How should we handle it?\",\n options: [\n { value: \"overwrite\", label: \"Overwrite\", hint: \"Replace with Bison Lab config\" },\n { value: \"copy\", label: \"Copy to clipboard\", hint: \"Paste manually\" },\n { value: \"skip\", label: \"Skip\", hint: \"I'll handle it\" },\n ],\n });\n\n if (p.isCancel(action)) {\n p.cancel(\"Cancelled.\");\n process.exit(0);\n }\n\n if (action === \"overwrite\") {\n writeFileSync(tailwindPath, tailwindSnippet, \"utf-8\");\n p.log.success(\"tailwind.config.ts overwritten.\");\n } else if (action === \"copy\") {\n if (copyToClipboard(tailwindSnippet)) {\n p.log.success(\"Copied tailwind config to clipboard!\");\n } else {\n p.log.warning(\"Could not access clipboard — copy manually from above.\");\n }\n }\n }\n }\n\n // --- Layout imports ---\n const importsSnippet = generateImports(config, THEME_FILE);\n const layoutPath = findLayoutFile();\n\n if (layoutPath) {\n const injected = injectImportsIntoLayout(layoutPath, importsSnippet);\n if (injected) {\n const relative = layoutPath.replace(process.cwd() + \"/\", \"\");\n p.log.success(`${pc.green(\"Updated:\")} ${relative} with Bison Lab imports.`);\n } else {\n p.log.success(\"Layout file already includes Bison Lab imports.\");\n }\n } else {\n p.note(importsSnippet, \"app/layout.tsx imports\");\n\n const action = await p.select({\n message: \"No layout file found. Copy imports to clipboard?\",\n options: [\n { value: \"copy\", label: \"Copy to clipboard\" },\n { value: \"skip\", label: \"Skip\" },\n ],\n });\n\n if (!p.isCancel(action) && action === \"copy\") {\n if (copyToClipboard(importsSnippet)) {\n p.log.success(\"Copied CSS imports to clipboard!\");\n } else {\n p.log.warning(\"Could not access clipboard — copy manually from above.\");\n }\n }\n }\n\n p.outro(pc.green(\"Done! Your Bison Lab theme is ready.\"));\n}\n\nmain().catch(console.error);\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bison-lab/create-theme",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Interactive CLI for generating and updating Bison Lab theme files",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
],
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@clack/prompts": "^1.1.0",
|
|
14
|
-
"picocolors": "^1.1.1"
|
|
14
|
+
"picocolors": "^1.1.1",
|
|
15
|
+
"@bison-lab/tokens": "0.3.0"
|
|
15
16
|
},
|
|
16
17
|
"devDependencies": {
|
|
17
18
|
"@types/node": "^25.5.0",
|