canvas-ui-sdk 0.3.1 → 0.3.3

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.js CHANGED
@@ -27268,14 +27268,185 @@ function InputSizeGroup({
27268
27268
  }
27269
27269
  );
27270
27270
  }
27271
+
27272
+ // src/components/theme-drawer/utils/generate-bake-prompt.ts
27273
+ var BASELINE_FONTS = /* @__PURE__ */ new Set(["Inter", "Geist", "Geist Mono"]);
27274
+ function fontToImportName(name) {
27275
+ return name.replace(/ /g, "_");
27276
+ }
27277
+ function fontToVarName(name) {
27278
+ return `--font-${name.toLowerCase().replace(/ /g, "-")}`;
27279
+ }
27280
+ function fontToInstanceName(name) {
27281
+ const words = name.split(/\s+/);
27282
+ return words.map(
27283
+ (w, i) => i === 0 ? w.toLowerCase() : w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()
27284
+ ).join("");
27285
+ }
27286
+ function generateBakePrompt(theme) {
27287
+ const overrides = theme.overrides;
27288
+ const rootVars = [];
27289
+ const bodyVars = [];
27290
+ const fontVarsToRemoveFromRoot = [];
27291
+ for (const [name, value] of Object.entries(overrides)) {
27292
+ if (name.startsWith("--canvas-")) {
27293
+ rootVars.push([name, value]);
27294
+ } else if (name === "--typo-global-font") {
27295
+ const cssVar = fontToVarName(value);
27296
+ bodyVars.push([name, `var(${cssVar}), "${value}", sans-serif`]);
27297
+ } else if (/^--typo-.*-font$/.test(name)) {
27298
+ bodyVars.push([name, `"${value}", sans-serif`]);
27299
+ fontVarsToRemoveFromRoot.push(name);
27300
+ } else {
27301
+ bodyVars.push([name, value]);
27302
+ }
27303
+ }
27304
+ rootVars.sort(([a], [b]) => a.localeCompare(b));
27305
+ bodyVars.sort(([a], [b]) => a.localeCompare(b));
27306
+ fontVarsToRemoveFromRoot.sort();
27307
+ const fontNames = /* @__PURE__ */ new Set();
27308
+ for (const [name, value] of Object.entries(overrides)) {
27309
+ if ((name === "--typo-global-font" || /^--typo-.*-font$/.test(name)) && value && !BASELINE_FONTS.has(value)) {
27310
+ fontNames.add(value);
27311
+ }
27312
+ }
27313
+ const newFonts = Array.from(fontNames).sort();
27314
+ const sections = [];
27315
+ let sectionNum = 0;
27316
+ if (rootVars.length > 0 || bodyVars.length > 0) {
27317
+ sectionNum++;
27318
+ const lines = [];
27319
+ lines.push(`## ${sectionNum}. Update \`src/app/globals.css\``);
27320
+ lines.push("");
27321
+ if (rootVars.length > 0) {
27322
+ lines.push("In the `:root` block, update these variables:");
27323
+ lines.push("");
27324
+ lines.push("```css");
27325
+ for (const [name, value] of rootVars) {
27326
+ lines.push(`${name}: ${value};`);
27327
+ }
27328
+ lines.push("```");
27329
+ lines.push("");
27330
+ }
27331
+ if (bodyVars.length > 0) {
27332
+ lines.push(
27333
+ "In the `body` block inside `@layer base`, add these CSS variable declarations (before the existing `font-family` rule):"
27334
+ );
27335
+ lines.push("");
27336
+ lines.push("```css");
27337
+ for (const [name, value] of bodyVars) {
27338
+ lines.push(`${name}: ${value};`);
27339
+ }
27340
+ lines.push("```");
27341
+ lines.push("");
27342
+ }
27343
+ if (fontVarsToRemoveFromRoot.length > 0) {
27344
+ lines.push(
27345
+ "Remove these lines from the `:root` block (they are now overridden in `body`):"
27346
+ );
27347
+ lines.push("");
27348
+ for (const name of fontVarsToRemoveFromRoot) {
27349
+ lines.push(`- \`${name}: var(--typo-global-font);\``);
27350
+ }
27351
+ lines.push("");
27352
+ }
27353
+ sections.push(lines.join("\n"));
27354
+ }
27355
+ if (newFonts.length > 0) {
27356
+ sectionNum++;
27357
+ const lines = [];
27358
+ lines.push(`## ${sectionNum}. Update \`src/app/layout.tsx\``);
27359
+ lines.push("");
27360
+ const allImports = ["Inter", ...newFonts.map(fontToImportName)];
27361
+ lines.push("Update the `next/font/google` import:");
27362
+ lines.push("");
27363
+ lines.push("```typescript");
27364
+ lines.push(`import { ${allImports.join(", ")} } from "next/font/google";`);
27365
+ lines.push("```");
27366
+ lines.push("");
27367
+ lines.push("Add these font instances after the existing `inter` declaration:");
27368
+ lines.push("");
27369
+ lines.push("```typescript");
27370
+ for (let i = 0; i < newFonts.length; i++) {
27371
+ const font = newFonts[i];
27372
+ const importName = fontToImportName(font);
27373
+ const instanceName = fontToInstanceName(font);
27374
+ const varName = fontToVarName(font);
27375
+ lines.push(`const ${instanceName} = ${importName}({`);
27376
+ lines.push(` variable: "${varName}",`);
27377
+ lines.push(` subsets: ["latin"],`);
27378
+ lines.push(` weight: ["400", "500", "600", "700"],`);
27379
+ lines.push(`});`);
27380
+ if (i < newFonts.length - 1) lines.push("");
27381
+ }
27382
+ lines.push("```");
27383
+ lines.push("");
27384
+ const varRefs = newFonts.map((f) => `\${${fontToInstanceName(f)}.variable}`).join(" ");
27385
+ lines.push("Update the `<body>` className to include the new font variables:");
27386
+ lines.push("");
27387
+ lines.push("```tsx");
27388
+ lines.push(
27389
+ `<body className={\`\${inter.variable} ${varRefs} antialiased\`}>`
27390
+ );
27391
+ lines.push("```");
27392
+ lines.push("");
27393
+ sections.push(lines.join("\n"));
27394
+ }
27395
+ sectionNum++;
27396
+ {
27397
+ const lines = [];
27398
+ lines.push(`## ${sectionNum}. Update \`src/lib/theme-config.ts\``);
27399
+ lines.push("");
27400
+ lines.push("Create or replace this file with:");
27401
+ lines.push("");
27402
+ lines.push("```typescript");
27403
+ lines.push(`import type { BrandingState, ImageKey } from "canvas-ui-sdk";`);
27404
+ lines.push("");
27405
+ const b = theme.branding;
27406
+ lines.push(`export const savedBranding: BrandingState = {`);
27407
+ lines.push(` iconShape: "${b.iconShape}",`);
27408
+ lines.push(` iconName: "${b.iconName}",`);
27409
+ lines.push(` bgColor: "${b.bgColor}",`);
27410
+ lines.push(` iconColor: "${b.iconColor}",`);
27411
+ lines.push(` wordmark: "${b.wordmark}",`);
27412
+ lines.push(`};`);
27413
+ lines.push("");
27414
+ lines.push(`export const savedImages: Record<ImageKey, string> = {`);
27415
+ const imageKeys = ["logoLight", "logoDark", "faviconLight", "faviconDark"];
27416
+ for (const key of imageKeys) {
27417
+ lines.push(` ${key}: "${theme.images[key] || ""}",`);
27418
+ }
27419
+ lines.push(`};`);
27420
+ lines.push("```");
27421
+ lines.push("");
27422
+ sections.push(lines.join("\n"));
27423
+ }
27424
+ sectionNum++;
27425
+ {
27426
+ const lines = [];
27427
+ lines.push(`## ${sectionNum}. Delete \`.data/theme.json\``);
27428
+ lines.push("");
27429
+ lines.push("Remove the runtime overrides file:");
27430
+ lines.push("");
27431
+ lines.push("```bash");
27432
+ lines.push("rm .data/theme.json");
27433
+ lines.push("```");
27434
+ sections.push(lines.join("\n"));
27435
+ }
27436
+ const header = [
27437
+ "# Bake Theme Into Source Code",
27438
+ "",
27439
+ "Apply the following theme overrides as source-code defaults so the app loads with the correct styling on first paint \u2014 no flash of unstyled content.",
27440
+ ""
27441
+ ].join("\n");
27442
+ return header + sections.join("\n");
27443
+ }
27271
27444
  function ExportPanel({ theme }) {
27272
- const [importValue, setImportValue] = useState("");
27273
- const [importStatus, setImportStatus] = useState("idle");
27274
27445
  const [copyStatus, setCopyStatus] = useState(null);
27275
- const handleCopy = async (content, type) => {
27446
+ const handleCopy = async (content) => {
27276
27447
  try {
27277
27448
  await navigator.clipboard.writeText(content);
27278
- setCopyStatus(type);
27449
+ setCopyStatus("bake");
27279
27450
  setTimeout(() => setCopyStatus(null), 2e3);
27280
27451
  } catch {
27281
27452
  const textarea = document.createElement("textarea");
@@ -27284,16 +27455,10 @@ function ExportPanel({ theme }) {
27284
27455
  textarea.select();
27285
27456
  document.execCommand("copy");
27286
27457
  document.body.removeChild(textarea);
27287
- setCopyStatus(type);
27458
+ setCopyStatus("bake");
27288
27459
  setTimeout(() => setCopyStatus(null), 2e3);
27289
27460
  }
27290
27461
  };
27291
- const handleImport = () => {
27292
- const success = theme.importJSON(importValue);
27293
- setImportStatus(success ? "success" : "error");
27294
- if (success) setImportValue("");
27295
- setTimeout(() => setImportStatus("idle"), 3e3);
27296
- };
27297
27462
  const overrideCount = Object.keys(theme.overrides).length;
27298
27463
  return /* @__PURE__ */ jsxs("div", { "data-theme-drawer-panel": true, className: "flex flex-col gap-5 p-4", children: [
27299
27464
  /* @__PURE__ */ jsx(
@@ -27309,59 +27474,7 @@ function ExportPanel({ theme }) {
27309
27474
  children: theme.isDirty ? `${overrideCount} variable${overrideCount !== 1 ? "s" : ""} modified` : "No modifications \u2014 using defaults"
27310
27475
  }
27311
27476
  ),
27312
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
27313
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
27314
- /* @__PURE__ */ jsx(
27315
- "h3",
27316
- {
27317
- style: {
27318
- fontSize: "13px",
27319
- fontWeight: 600,
27320
- color: "#374151",
27321
- textTransform: "uppercase",
27322
- letterSpacing: "0.05em"
27323
- },
27324
- children: "Export CSS"
27325
- }
27326
- ),
27327
- /* @__PURE__ */ jsx(
27328
- "button",
27329
- {
27330
- onClick: () => handleCopy(theme.exportCSS(), "css"),
27331
- style: {
27332
- fontSize: "12px",
27333
- color: copyStatus === "css" ? "#059669" : "#1165ef",
27334
- background: "none",
27335
- border: "none",
27336
- cursor: "pointer",
27337
- fontWeight: 500
27338
- },
27339
- children: copyStatus === "css" ? "Copied!" : "Copy"
27340
- }
27341
- )
27342
- ] }),
27343
- /* @__PURE__ */ jsx(
27344
- "pre",
27345
- {
27346
- style: {
27347
- fontSize: "11px",
27348
- fontFamily: "monospace",
27349
- padding: "12px",
27350
- background: "#f9fafb",
27351
- border: "1px solid #e5e7eb",
27352
- borderRadius: "6px",
27353
- overflowX: "auto",
27354
- maxHeight: "200px",
27355
- overflowY: "auto",
27356
- color: "#374151",
27357
- whiteSpace: "pre-wrap",
27358
- wordBreak: "break-all"
27359
- },
27360
- children: theme.exportCSS()
27361
- }
27362
- )
27363
- ] }),
27364
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
27477
+ overrideCount > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
27365
27478
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
27366
27479
  /* @__PURE__ */ jsx(
27367
27480
  "h3",
@@ -27373,102 +27486,37 @@ function ExportPanel({ theme }) {
27373
27486
  textTransform: "uppercase",
27374
27487
  letterSpacing: "0.05em"
27375
27488
  },
27376
- children: "Export JSON"
27489
+ children: "Bake into source code"
27377
27490
  }
27378
27491
  ),
27379
27492
  /* @__PURE__ */ jsx(
27380
27493
  "button",
27381
27494
  {
27382
- onClick: () => handleCopy(theme.exportJSON(), "json"),
27495
+ onClick: () => handleCopy(generateBakePrompt(theme)),
27383
27496
  style: {
27384
27497
  fontSize: "12px",
27385
- color: copyStatus === "json" ? "#059669" : "#1165ef",
27498
+ color: copyStatus === "bake" ? "#059669" : "#1165ef",
27386
27499
  background: "none",
27387
27500
  border: "none",
27388
27501
  cursor: "pointer",
27389
27502
  fontWeight: 500
27390
27503
  },
27391
- children: copyStatus === "json" ? "Copied!" : "Copy"
27504
+ children: copyStatus === "bake" ? "Copied!" : "Copy prompt"
27392
27505
  }
27393
27506
  )
27394
27507
  ] }),
27395
27508
  /* @__PURE__ */ jsx(
27396
- "pre",
27509
+ "p",
27397
27510
  {
27398
27511
  style: {
27399
- fontSize: "11px",
27400
- fontFamily: "monospace",
27401
- padding: "12px",
27402
- background: "#f9fafb",
27403
- border: "1px solid #e5e7eb",
27404
- borderRadius: "6px",
27405
- overflowX: "auto",
27406
- maxHeight: "200px",
27407
- overflowY: "auto",
27408
- color: "#374151",
27409
- whiteSpace: "pre-wrap",
27410
- wordBreak: "break-all"
27512
+ fontSize: "12px",
27513
+ color: "#6b7280",
27514
+ lineHeight: "1.4"
27411
27515
  },
27412
- children: theme.exportJSON()
27516
+ children: "Copies a prompt for Claude Code that updates your source files with the current theme values."
27413
27517
  }
27414
27518
  )
27415
27519
  ] }),
27416
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
27417
- /* @__PURE__ */ jsx(
27418
- "h3",
27419
- {
27420
- style: {
27421
- fontSize: "13px",
27422
- fontWeight: 600,
27423
- color: "#374151",
27424
- textTransform: "uppercase",
27425
- letterSpacing: "0.05em"
27426
- },
27427
- children: "Import JSON"
27428
- }
27429
- ),
27430
- /* @__PURE__ */ jsx(
27431
- "textarea",
27432
- {
27433
- value: importValue,
27434
- onChange: (e) => setImportValue(e.target.value),
27435
- placeholder: "Paste exported JSON here...",
27436
- rows: 5,
27437
- style: {
27438
- fontSize: "11px",
27439
- fontFamily: "monospace",
27440
- padding: "12px",
27441
- border: "1px solid #e5e7eb",
27442
- borderRadius: "6px",
27443
- color: "#374151",
27444
- background: "#ffffff",
27445
- resize: "vertical"
27446
- }
27447
- }
27448
- ),
27449
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
27450
- /* @__PURE__ */ jsx(
27451
- "button",
27452
- {
27453
- onClick: handleImport,
27454
- disabled: !importValue.trim(),
27455
- style: {
27456
- fontSize: "13px",
27457
- fontWeight: 500,
27458
- color: "#ffffff",
27459
- background: importValue.trim() ? "#1165ef" : "#9ca3af",
27460
- border: "none",
27461
- cursor: importValue.trim() ? "pointer" : "not-allowed",
27462
- padding: "8px 16px",
27463
- borderRadius: "6px"
27464
- },
27465
- children: "Import"
27466
- }
27467
- ),
27468
- importStatus === "success" && /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "#059669" }, children: "Theme imported!" }),
27469
- importStatus === "error" && /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "#dc2626" }, children: "Invalid JSON format" })
27470
- ] })
27471
- ] }),
27472
27520
  theme.isDirty && /* @__PURE__ */ jsx(
27473
27521
  "div",
27474
27522
  {