@bison-lab/create-theme 0.3.0 → 0.4.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 CHANGED
@@ -3,7 +3,7 @@ import * as p from "@clack/prompts";
3
3
  import pc from "picocolors";
4
4
  import { execSync } from "child_process";
5
5
  import { existsSync, readFileSync, writeFileSync } from "fs";
6
- import { join, resolve } from "path";
6
+ import { dirname, join, relative, resolve } from "path";
7
7
  import { GREY_SCALES, hexToHSL, hslToString } from "@bison-lab/tokens";
8
8
  //#region src/preview.ts
9
9
  function hexToRgb(hex) {
@@ -91,6 +91,28 @@ async function runPrompts(existing) {
91
91
  ]
92
92
  });
93
93
  if (p.isCancel(greyScale)) return null;
94
+ const darkSelector = await p.select({
95
+ message: "Dark mode CSS selector",
96
+ initialValue: existing?.darkSelector ?? "[data-theme=\"dark\"]",
97
+ options: [
98
+ {
99
+ value: "[data-theme=\"dark\"]",
100
+ label: "[data-theme=\"dark\"]",
101
+ hint: "Attribute selector — works with class & attribute strategies (recommended)"
102
+ },
103
+ {
104
+ value: ".dark",
105
+ label: ".dark",
106
+ hint: "Class selector — Tailwind default"
107
+ },
108
+ {
109
+ value: "@media",
110
+ label: "@media (prefers-color-scheme: dark)",
111
+ hint: "System preference — no JS needed"
112
+ }
113
+ ]
114
+ });
115
+ if (p.isCancel(darkSelector)) return null;
94
116
  const radius = await p.select({
95
117
  message: "Border radius preset",
96
118
  initialValue: existing?.radius ?? "rounded",
@@ -255,6 +277,7 @@ async function runPrompts(existing) {
255
277
  brandAccent,
256
278
  brandHighlight,
257
279
  greyScale,
280
+ darkSelector,
258
281
  radius,
259
282
  shadow,
260
283
  motion,
@@ -370,9 +393,17 @@ function generateThemeCSS(config) {
370
393
  ` --font-weight-bold: ${config.fontWeights.bold};`,
371
394
  `}`,
372
395
  ``,
373
- `.dark {`,
374
- ...Object.entries(dark).map(([k, v]) => ` --${k}: ${v};`),
375
- `}`,
396
+ ...config.darkSelector === "@media" ? [
397
+ `@media (prefers-color-scheme: dark) {`,
398
+ ` :root {`,
399
+ ...Object.entries(dark).map(([k, v]) => ` --${k}: ${v};`),
400
+ ` }`,
401
+ `}`
402
+ ] : [
403
+ `${config.darkSelector} {`,
404
+ ...Object.entries(dark).map(([k, v]) => ` --${k}: ${v};`),
405
+ `}`
406
+ ],
376
407
  ``
377
408
  ].join("\n");
378
409
  }
@@ -390,14 +421,14 @@ function generateTailwindConfig(config) {
390
421
  `};`
391
422
  ].join("\n");
392
423
  }
393
- function generateImports(config, themeFile) {
424
+ function generateImports(config, themeImportPath) {
394
425
  return [
395
- `import '@bison-lab/tokens/css/globals.css';`,
426
+ `import '@bison-lab/tokens/css/base.css';`,
396
427
  `import '@bison-lab/tokens/css/themes/radius-${config.radius}.css';`,
397
428
  `import '@bison-lab/tokens/css/themes/shadow-${config.shadow}.css';`,
398
429
  `import '@bison-lab/tokens/css/themes/motion-${config.motion}.css';`,
399
430
  `import '@bison-lab/tokens/css/themes/density-${config.density}.css';`,
400
- `import './${themeFile}';`
431
+ `import '${themeImportPath}';`
401
432
  ].join("\n");
402
433
  }
403
434
  //#endregion
@@ -444,21 +475,21 @@ function areBisonPackagesInstalled() {
444
475
  }
445
476
  });
446
477
  }
447
- function findLayoutFile() {
478
+ function findLayoutFile(baseDir) {
448
479
  for (const candidate of [
449
480
  "app/layout.tsx",
450
481
  "app/layout.jsx",
451
482
  "src/app/layout.tsx",
452
483
  "src/app/layout.jsx"
453
484
  ]) {
454
- const full = resolve(process.cwd(), candidate);
485
+ const full = resolve(baseDir, candidate);
455
486
  if (existsSync(full)) return full;
456
487
  }
457
488
  return null;
458
489
  }
459
490
  function injectImportsIntoLayout(layoutPath, imports) {
460
491
  const content = readFileSync(layoutPath, "utf-8");
461
- if (content.includes("@bison-lab/tokens/css/globals.css")) return false;
492
+ if (content.includes("@bison-lab/tokens/css/base.css") || content.includes("@bison-lab/tokens/css/globals.css")) return false;
462
493
  const importRegex = /^import\s[\s\S]*?from\s+['"][^'"]+['"];?\s*$/gm;
463
494
  let lastMatchEnd = -1;
464
495
  let match;
@@ -475,7 +506,22 @@ const CONFIG_FILE = "bison.config.json";
475
506
  const THEME_FILE = "bison-theme.css";
476
507
  async function main() {
477
508
  p.intro(pc.bgCyan(pc.black(" Bison Lab Theme Generator ")));
478
- const configPath = resolve(process.cwd(), CONFIG_FILE);
509
+ const outputDir = await p.text({
510
+ message: "Output directory for generated files",
511
+ placeholder: ".",
512
+ defaultValue: ".",
513
+ validate: (v) => {
514
+ if (!v) return void 0;
515
+ if (!existsSync(resolve(process.cwd(), v))) return `Directory does not exist: ${v}`;
516
+ }
517
+ });
518
+ if (p.isCancel(outputDir)) {
519
+ p.cancel("Cancelled.");
520
+ process.exit(0);
521
+ }
522
+ const outDir = resolve(process.cwd(), outputDir);
523
+ if (outDir !== process.cwd()) p.log.info(`Output directory: ${pc.cyan(relative(process.cwd(), outDir) || ".")}`);
524
+ const configPath = resolve(outDir, CONFIG_FILE);
479
525
  let existingConfig;
480
526
  if (existsSync(configPath)) {
481
527
  existingConfig = JSON.parse(readFileSync(configPath, "utf-8"));
@@ -531,54 +577,42 @@ async function main() {
531
577
  const s = p.spinner();
532
578
  s.start("Generating theme files...");
533
579
  const themeCSS = generateThemeCSS(config);
534
- writeFileSync(resolve(process.cwd(), THEME_FILE), themeCSS, "utf-8");
580
+ const themePath = resolve(outDir, THEME_FILE);
581
+ writeFileSync(themePath, themeCSS, "utf-8");
535
582
  writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
536
583
  s.stop("Theme files generated!");
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.");
584
+ const outPrefix = outDir === process.cwd() ? "" : relative(process.cwd(), outDir) + "/";
585
+ p.log.success(`${pc.green("Created:")} ${outPrefix}${THEME_FILE}`);
586
+ p.log.success(`${pc.green("Created:")} ${outPrefix}${CONFIG_FILE}`);
587
+ const tailwindPath = resolve(outDir, "tailwind.config.ts");
588
+ const presetSnippet = `import bisonPreset from '@bison-lab/tailwind-preset';\n\n// Add to your Tailwind config:\n// presets: [bisonPreset],\n// content: [..., './node_modules/@bison-lab/ui/dist/**/*.js'],`;
589
+ if (existsSync(tailwindPath)) if (readFileSync(tailwindPath, "utf-8").includes("@bison-lab/tailwind-preset")) p.log.success("tailwind.config.ts already includes Bison Lab preset.");
545
590
  else {
546
- p.note(tailwindSnippet, "tailwind.config.ts");
591
+ p.note(presetSnippet, "Add to your tailwind.config.ts");
547
592
  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
- ]
593
+ message: "Add the Bison Lab preset to your existing tailwind.config.ts manually:",
594
+ options: [{
595
+ value: "copy",
596
+ label: "Copy snippet to clipboard"
597
+ }, {
598
+ value: "skip",
599
+ label: "Skip",
600
+ hint: "I'll handle it"
601
+ }]
566
602
  });
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!");
603
+ if (!p.isCancel(action) && action === "copy") if (copyToClipboard(presetSnippet)) p.log.success("Copied Tailwind preset snippet to clipboard!");
575
604
  else p.log.warning("Could not access clipboard — copy manually from above.");
576
605
  }
577
- const importsSnippet = generateImports(config, THEME_FILE);
578
- const layoutPath = findLayoutFile();
606
+ else {
607
+ writeFileSync(tailwindPath, generateTailwindConfig(config), "utf-8");
608
+ p.log.success(`${pc.green("Created:")} ${outPrefix}tailwind.config.ts`);
609
+ }
610
+ const layoutPath = findLayoutFile(outDir);
611
+ const themeImportPath = layoutPath ? relative(dirname(layoutPath), themePath).replace(/\\/g, "/") : `./${THEME_FILE}`;
612
+ const importsSnippet = generateImports(config, themeImportPath.startsWith(".") ? themeImportPath : `./${themeImportPath}`);
579
613
  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.`);
614
+ const rel = relative(process.cwd(), layoutPath);
615
+ p.log.success(`${pc.green("Updated:")} ${rel} with Bison Lab imports.`);
582
616
  } else p.log.success("Layout file already includes Bison Lab imports.");
583
617
  else {
584
618
  p.note(importsSnippet, "app/layout.tsx imports");
@@ -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 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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"}
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 darkSelector: string;\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 // Dark mode selector\n const darkSelector = await p.select({\n message: \"Dark mode CSS selector\",\n initialValue: existing?.darkSelector ?? '[data-theme=\"dark\"]',\n options: [\n { value: '[data-theme=\"dark\"]' as const, label: '[data-theme=\"dark\"]', hint: \"Attribute selector — works with class & attribute strategies (recommended)\" },\n { value: \".dark\" as const, label: \".dark\", hint: \"Class selector — Tailwind default\" },\n { value: \"@media\" as const, label: \"@media (prefers-color-scheme: dark)\", hint: \"System preference — no JS needed\" },\n ],\n });\n if (p.isCancel(darkSelector)) 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 darkSelector: darkSelector 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 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 ...(config.darkSelector === \"@media\"\n ? [\n `@media (prefers-color-scheme: dark) {`,\n ` :root {`,\n ...Object.entries(dark).map(([k, v]) => ` --${k}: ${v};`),\n ` }`,\n `}`,\n ]\n : [\n `${config.darkSelector} {`,\n ...Object.entries(dark).map(([k, v]) => ` --${k}: ${v};`),\n `}`,\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, themeImportPath: string): string {\n return [\n `import '@bison-lab/tokens/css/base.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 '${themeImportPath}';`,\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, relative, dirname } 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(baseDir: string): 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(baseDir, 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/base.css\") || 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 // --- Output directory ---\n const outputDir = await p.text({\n message: \"Output directory for generated files\",\n placeholder: \".\",\n defaultValue: \".\",\n validate: (v) => {\n if (!v) return undefined;\n const resolved = resolve(process.cwd(), v);\n if (!existsSync(resolved)) return `Directory does not exist: ${v}`;\n return undefined;\n },\n });\n\n if (p.isCancel(outputDir)) {\n p.cancel(\"Cancelled.\");\n process.exit(0);\n }\n\n const outDir = resolve(process.cwd(), outputDir as string);\n\n if (outDir !== process.cwd()) {\n p.log.info(`Output directory: ${pc.cyan(relative(process.cwd(), outDir) || \".\")}`);\n }\n\n const configPath = resolve(outDir, 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(outDir, 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 const outPrefix = outDir === process.cwd() ? \"\" : relative(process.cwd(), outDir) + \"/\";\n p.log.success(`${pc.green(\"Created:\")} ${outPrefix}${THEME_FILE}`);\n p.log.success(`${pc.green(\"Created:\")} ${outPrefix}${CONFIG_FILE}`);\n\n // --- Tailwind config guidance ---\n const tailwindPath = resolve(outDir, \"tailwind.config.ts\");\n const presetSnippet = `import bisonPreset from '@bison-lab/tailwind-preset';\\n\\n// Add to your Tailwind config:\\n// presets: [bisonPreset],\\n// content: [..., './node_modules/@bison-lab/ui/dist/**/*.js'],`;\n\n if (existsSync(tailwindPath)) {\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(presetSnippet, \"Add to your tailwind.config.ts\");\n\n const action = await p.select({\n message: \"Add the Bison Lab preset to your existing tailwind.config.ts manually:\",\n options: [\n { value: \"copy\", label: \"Copy snippet to clipboard\" },\n { value: \"skip\", label: \"Skip\", hint: \"I'll handle it\" },\n ],\n });\n\n if (!p.isCancel(action) && action === \"copy\") {\n if (copyToClipboard(presetSnippet)) {\n p.log.success(\"Copied Tailwind preset snippet to clipboard!\");\n } else {\n p.log.warning(\"Could not access clipboard — copy manually from above.\");\n }\n }\n }\n } else {\n // No config exists — safe to create one\n const tailwindConfig = generateTailwindConfig(config);\n writeFileSync(tailwindPath, tailwindConfig, \"utf-8\");\n p.log.success(`${pc.green(\"Created:\")} ${outPrefix}tailwind.config.ts`);\n }\n\n // --- Layout imports ---\n const layoutPath = findLayoutFile(outDir);\n\n // Compute relative path from layout directory to the theme file\n const themeImportPath = layoutPath\n ? relative(dirname(layoutPath), themePath).replace(/\\\\/g, \"/\")\n : `./${THEME_FILE}`;\n const importsSnippet = generateImports(config, themeImportPath.startsWith(\".\") ? themeImportPath : `./${themeImportPath}`);\n\n if (layoutPath) {\n const injected = injectImportsIntoLayout(layoutPath, importsSnippet);\n if (injected) {\n const rel = relative(process.cwd(), layoutPath);\n p.log.success(`${pc.green(\"Updated:\")} ${rel} 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.0",
3
+ "version": "0.4.0",
4
4
  "description": "Interactive CLI for generating and updating Bison Lab theme files",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,7 +12,7 @@
12
12
  "dependencies": {
13
13
  "@clack/prompts": "^1.1.0",
14
14
  "picocolors": "^1.1.1",
15
- "@bison-lab/tokens": "0.3.0"
15
+ "@bison-lab/tokens": "0.4.0"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@types/node": "^25.5.0",