canvas-ui-sdk 0.1.7 → 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.js CHANGED
@@ -3337,6 +3337,7 @@ var defaultButtonSizes = {
3337
3337
  "--btn-mini-radius": "4px",
3338
3338
  "--btn-mini-font-weight": "500",
3339
3339
  "--btn-mini-letter-spacing": "0em",
3340
+ "--btn-mini-font-family": "",
3340
3341
  // Small
3341
3342
  "--btn-small-height": "32px",
3342
3343
  "--btn-small-font-size": "14px",
@@ -3344,6 +3345,7 @@ var defaultButtonSizes = {
3344
3345
  "--btn-small-radius": "6px",
3345
3346
  "--btn-small-font-weight": "500",
3346
3347
  "--btn-small-letter-spacing": "0em",
3348
+ "--btn-small-font-family": "",
3347
3349
  // Standard
3348
3350
  "--btn-standard-height": "40px",
3349
3351
  "--btn-standard-font-size": "14px",
@@ -3351,13 +3353,15 @@ var defaultButtonSizes = {
3351
3353
  "--btn-standard-radius": "8px",
3352
3354
  "--btn-standard-font-weight": "500",
3353
3355
  "--btn-standard-letter-spacing": "0em",
3356
+ "--btn-standard-font-family": "",
3354
3357
  // Large
3355
3358
  "--btn-large-height": "48px",
3356
3359
  "--btn-large-font-size": "16px",
3357
3360
  "--btn-large-px": "20px",
3358
3361
  "--btn-large-radius": "10px",
3359
3362
  "--btn-large-font-weight": "500",
3360
- "--btn-large-letter-spacing": "0em"
3363
+ "--btn-large-letter-spacing": "0em",
3364
+ "--btn-large-font-family": ""
3361
3365
  };
3362
3366
  var defaultButtonColorStyles = [
3363
3367
  { id: "primary", label: "Primary Save", description: "Main action button", isDefault: true },
@@ -3464,10 +3468,15 @@ var ThemeContext = createContext({
3464
3468
  var PreviewBrandingContext = createContext({
3465
3469
  previewBranding: null,
3466
3470
  setPreviewBranding: () => {
3471
+ },
3472
+ previewImages: null,
3473
+ setPreviewImages: () => {
3467
3474
  }
3468
3475
  });
3469
3476
  function useThemeImages() {
3470
- return useContext(ThemeContext).images;
3477
+ const { images } = useContext(ThemeContext);
3478
+ const { previewImages } = useContext(PreviewBrandingContext);
3479
+ return previewImages ?? images;
3471
3480
  }
3472
3481
  function useThemeBranding() {
3473
3482
  const { branding, isMounted } = useContext(ThemeContext);
@@ -3487,6 +3496,7 @@ function ThemeProvider({
3487
3496
  brandAssets = []
3488
3497
  }) {
3489
3498
  const [previewBranding, setPreviewBranding] = useState(null);
3499
+ const [previewImages, setPreviewImages] = useState(null);
3490
3500
  const contextValue = {
3491
3501
  images,
3492
3502
  branding,
@@ -3495,7 +3505,9 @@ function ThemeProvider({
3495
3505
  };
3496
3506
  const previewBrandingValue = {
3497
3507
  previewBranding,
3498
- setPreviewBranding
3508
+ setPreviewBranding,
3509
+ previewImages,
3510
+ setPreviewImages
3499
3511
  };
3500
3512
  return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(PreviewBrandingContext.Provider, { value: previewBrandingValue, children }) });
3501
3513
  }
@@ -24088,27 +24100,136 @@ function exportCSS(overrides) {
24088
24100
  ${lines.join("\n")}
24089
24101
  }`;
24090
24102
  }
24091
- function exportJSON(overrides) {
24092
- return JSON.stringify({ overrides }, null, 2);
24103
+ function exportJSON(overrides, branding, images, customButtonStyles) {
24104
+ const data = { overrides };
24105
+ if (branding) data.branding = branding;
24106
+ if (images) data.images = images;
24107
+ if (customButtonStyles && customButtonStyles.length > 0) {
24108
+ data.customButtonStyles = customButtonStyles;
24109
+ }
24110
+ return JSON.stringify(data, null, 2);
24093
24111
  }
24094
24112
  function importJSON(json) {
24095
24113
  try {
24096
24114
  const parsed = JSON.parse(json);
24097
- if (parsed && typeof parsed.overrides === "object" && !Array.isArray(parsed.overrides)) {
24098
- const overrides = {};
24115
+ if (!parsed || typeof parsed !== "object") return null;
24116
+ let overrides = {};
24117
+ if (parsed.overrides && typeof parsed.overrides === "object" && !Array.isArray(parsed.overrides)) {
24099
24118
  for (const [key, value] of Object.entries(parsed.overrides)) {
24100
24119
  if (typeof key === "string" && typeof value === "string") {
24101
24120
  overrides[key] = value;
24102
24121
  }
24103
24122
  }
24104
- return Object.keys(overrides).length > 0 ? overrides : null;
24105
24123
  }
24106
- return null;
24124
+ const result = { overrides };
24125
+ if (parsed.branding && typeof parsed.branding === "object") {
24126
+ result.branding = parsed.branding;
24127
+ }
24128
+ if (parsed.images && typeof parsed.images === "object") {
24129
+ result.images = parsed.images;
24130
+ }
24131
+ if (Array.isArray(parsed.customButtonStyles)) {
24132
+ result.customButtonStyles = parsed.customButtonStyles;
24133
+ }
24134
+ if (Object.keys(overrides).length === 0 && !result.branding && !result.images && !result.customButtonStyles) {
24135
+ return null;
24136
+ }
24137
+ return result;
24107
24138
  } catch {
24108
24139
  return null;
24109
24140
  }
24110
24141
  }
24111
24142
 
24143
+ // src/components/theme-drawer/utils/color-utils.ts
24144
+ function hexToHsl2(hex) {
24145
+ hex = hex.replace(/^#/, "");
24146
+ if (hex.length === 3) {
24147
+ hex = hex.split("").map((c) => c + c).join("");
24148
+ }
24149
+ const r = parseInt(hex.slice(0, 2), 16) / 255;
24150
+ const g = parseInt(hex.slice(2, 4), 16) / 255;
24151
+ const b = parseInt(hex.slice(4, 6), 16) / 255;
24152
+ const max = Math.max(r, g, b);
24153
+ const min = Math.min(r, g, b);
24154
+ let h = 0;
24155
+ let s = 0;
24156
+ const l = (max + min) / 2;
24157
+ if (max !== min) {
24158
+ const d = max - min;
24159
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
24160
+ switch (max) {
24161
+ case r:
24162
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
24163
+ break;
24164
+ case g:
24165
+ h = ((b - r) / d + 2) / 6;
24166
+ break;
24167
+ case b:
24168
+ h = ((r - g) / d + 4) / 6;
24169
+ break;
24170
+ }
24171
+ }
24172
+ return {
24173
+ h: Math.round(h * 360),
24174
+ s: Math.round(s * 100),
24175
+ l: Math.round(l * 100)
24176
+ };
24177
+ }
24178
+ function hslToHex2(h, s, l) {
24179
+ h = (h % 360 + 360) % 360;
24180
+ s /= 100;
24181
+ l /= 100;
24182
+ const c = (1 - Math.abs(2 * l - 1)) * s;
24183
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
24184
+ const m = l - c / 2;
24185
+ let r = 0, g = 0, b = 0;
24186
+ if (h >= 0 && h < 60) {
24187
+ r = c;
24188
+ g = x;
24189
+ b = 0;
24190
+ } else if (h >= 60 && h < 120) {
24191
+ r = x;
24192
+ g = c;
24193
+ b = 0;
24194
+ } else if (h >= 120 && h < 180) {
24195
+ r = 0;
24196
+ g = c;
24197
+ b = x;
24198
+ } else if (h >= 180 && h < 240) {
24199
+ r = 0;
24200
+ g = x;
24201
+ b = c;
24202
+ } else if (h >= 240 && h < 300) {
24203
+ r = x;
24204
+ g = 0;
24205
+ b = c;
24206
+ } else if (h >= 300 && h < 360) {
24207
+ r = c;
24208
+ g = 0;
24209
+ b = x;
24210
+ }
24211
+ const toHex = (n) => {
24212
+ const hex = Math.round((n + m) * 255).toString(16);
24213
+ return hex.length === 1 ? "0" + hex : hex;
24214
+ };
24215
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
24216
+ }
24217
+ function resolveBrandingColor(value) {
24218
+ if (!value) return "#ffffff";
24219
+ if (value.startsWith("var(")) {
24220
+ const varName = value.replace("var(", "").replace(")", "");
24221
+ if (typeof window !== "undefined") {
24222
+ const computed = getComputedStyle(document.documentElement).getPropertyValue(varName).trim();
24223
+ return computed || "#ffffff";
24224
+ }
24225
+ return "#ffffff";
24226
+ }
24227
+ return value;
24228
+ }
24229
+ function isVariableReference(value) {
24230
+ return value?.startsWith("var(") ?? false;
24231
+ }
24232
+
24112
24233
  // src/components/theme-drawer/hooks/use-theme-state.ts
24113
24234
  var FONT_VARS = [
24114
24235
  "--typo-h1-font",
@@ -24141,25 +24262,109 @@ var allDefaults = {
24141
24262
  ...defaultButtonColors,
24142
24263
  ...defaultInputSizes
24143
24264
  };
24265
+ var brandColorVars = [
24266
+ "--canvas-primary",
24267
+ "--canvas-primary-dark",
24268
+ "--canvas-flair-bg",
24269
+ "--canvas-surface-brand",
24270
+ "--canvas-sidebar-light-active-bg",
24271
+ "--canvas-sidebar-light-active-text",
24272
+ "--canvas-sidebar-dark-bg",
24273
+ "--canvas-sidebar-dark-active-bg",
24274
+ "--canvas-sidebar-dark-text",
24275
+ "--canvas-sidebar-dark-border",
24276
+ "--canvas-border-input-focus"
24277
+ ];
24278
+ function isEqual(a, b) {
24279
+ if (a === b) return true;
24280
+ if (a == null || b == null) return false;
24281
+ if (typeof a !== typeof b) return false;
24282
+ if (Array.isArray(a) && Array.isArray(b)) {
24283
+ if (a.length !== b.length) return false;
24284
+ return a.every((v, i) => isEqual(v, b[i]));
24285
+ }
24286
+ if (typeof a === "object" && typeof b === "object") {
24287
+ const aObj = a;
24288
+ const bObj = b;
24289
+ const aKeys = Object.keys(aObj);
24290
+ const bKeys = Object.keys(bObj);
24291
+ if (aKeys.length !== bKeys.length) return false;
24292
+ return aKeys.every((k) => isEqual(aObj[k], bObj[k]));
24293
+ }
24294
+ return false;
24295
+ }
24144
24296
  function useThemeState(options) {
24145
24297
  const {
24146
24298
  storageKey = "canvas-ui-theme",
24147
24299
  initialOverrides,
24148
- onThemeChange
24300
+ onThemeChange,
24301
+ onBrandingChange,
24302
+ onImagesChange
24149
24303
  } = options ?? {};
24304
+ const [savedOverrides, setSavedOverrides] = useState(() => {
24305
+ return initialOverrides ?? {};
24306
+ });
24307
+ const [savedBranding, setSavedBranding] = useState({ ...defaultBranding });
24308
+ const [savedImages, setSavedImages] = useState({ ...defaultImages });
24309
+ const [savedCustomButtonStyles, setSavedCustomButtonStyles] = useState([
24310
+ ...defaultCustomButtonStyles
24311
+ ]);
24150
24312
  const [overrides, setOverrides] = useState(() => {
24151
24313
  return initialOverrides ?? {};
24152
24314
  });
24315
+ const [branding, setBrandingState] = useState({ ...defaultBranding });
24316
+ const [images, setImagesState] = useState({ ...defaultImages });
24317
+ const [customButtonStyles, setCustomButtonStyles] = useState([
24318
+ ...defaultCustomButtonStyles
24319
+ ]);
24320
+ const [brandHue, setBrandHueState] = useState(217);
24321
+ const [brandVibrancy, setBrandVibrancyState] = useState(1);
24322
+ const [syncRelatedColors, setSyncRelatedColorsState] = useState(true);
24153
24323
  const onThemeChangeRef = useRef(onThemeChange);
24154
24324
  onThemeChangeRef.current = onThemeChange;
24325
+ const onBrandingChangeRef = useRef(onBrandingChange);
24326
+ onBrandingChangeRef.current = onBrandingChange;
24327
+ const onImagesChangeRef = useRef(onImagesChange);
24328
+ onImagesChangeRef.current = onImagesChange;
24329
+ const persistToStorage = useCallback(
24330
+ (ovr, brd, img, cbs) => {
24331
+ try {
24332
+ localStorage.setItem(
24333
+ storageKey,
24334
+ exportJSON(ovr, brd, img, cbs)
24335
+ );
24336
+ } catch {
24337
+ }
24338
+ },
24339
+ [storageKey]
24340
+ );
24155
24341
  useEffect(() => {
24156
24342
  try {
24157
24343
  const stored = localStorage.getItem(storageKey);
24158
24344
  if (stored) {
24159
24345
  const parsed = importJSON(stored);
24160
24346
  if (parsed) {
24161
- setOverrides(parsed);
24162
- setCSSVariables(parsed);
24347
+ if (parsed.overrides) {
24348
+ setSavedOverrides(parsed.overrides);
24349
+ setOverrides(parsed.overrides);
24350
+ setCSSVariables(parsed.overrides);
24351
+ }
24352
+ if (parsed.branding) {
24353
+ setSavedBranding(parsed.branding);
24354
+ setBrandingState(parsed.branding);
24355
+ }
24356
+ if (parsed.images) {
24357
+ setSavedImages(parsed.images);
24358
+ setImagesState(parsed.images);
24359
+ }
24360
+ if (parsed.customButtonStyles) {
24361
+ setSavedCustomButtonStyles(parsed.customButtonStyles);
24362
+ setCustomButtonStyles(parsed.customButtonStyles);
24363
+ }
24364
+ if (parsed.overrides?.["--canvas-primary"]) {
24365
+ const hsl = hexToHsl2(parsed.overrides["--canvas-primary"]);
24366
+ setBrandHueState(hsl.h);
24367
+ }
24163
24368
  }
24164
24369
  } else if (initialOverrides) {
24165
24370
  setCSSVariables(initialOverrides);
@@ -24171,16 +24376,12 @@ function useThemeState(options) {
24171
24376
  (name, value) => {
24172
24377
  setOverrides((prev) => {
24173
24378
  const next = { ...prev, [name]: value };
24174
- try {
24175
- localStorage.setItem(storageKey, exportJSON(next));
24176
- } catch {
24177
- }
24178
24379
  setCSSVariables({ [name]: value });
24179
24380
  onThemeChangeRef.current?.(next);
24180
24381
  return next;
24181
24382
  });
24182
24383
  },
24183
- [storageKey]
24384
+ []
24184
24385
  );
24185
24386
  const resetCategory = useCallback(
24186
24387
  (prefix) => {
@@ -24196,10 +24397,6 @@ function useThemeState(options) {
24196
24397
  next[key] = value;
24197
24398
  }
24198
24399
  }
24199
- try {
24200
- localStorage.setItem(storageKey, exportJSON(next));
24201
- } catch {
24202
- }
24203
24400
  const fontVarsToRemove = FONT_VARS.filter((v) => v.startsWith(prefix));
24204
24401
  if (fontVarsToRemove.length > 0) {
24205
24402
  removeCSSVariables(fontVarsToRemove);
@@ -24211,10 +24408,65 @@ function useThemeState(options) {
24211
24408
  return next;
24212
24409
  });
24213
24410
  },
24214
- [storageKey]
24411
+ []
24215
24412
  );
24413
+ const save = useCallback(() => {
24414
+ setOverrides((currentOverrides) => {
24415
+ setBrandingState((currentBranding) => {
24416
+ setImagesState((currentImages) => {
24417
+ setCustomButtonStyles((currentCbs) => {
24418
+ setSavedOverrides(currentOverrides);
24419
+ setSavedBranding(currentBranding);
24420
+ setSavedImages(currentImages);
24421
+ setSavedCustomButtonStyles(currentCbs);
24422
+ persistToStorage(currentOverrides, currentBranding, currentImages, currentCbs);
24423
+ return currentCbs;
24424
+ });
24425
+ return currentImages;
24426
+ });
24427
+ return currentBranding;
24428
+ });
24429
+ return currentOverrides;
24430
+ });
24431
+ }, [persistToStorage]);
24432
+ const discard = useCallback(() => {
24433
+ setSavedOverrides((currentSaved) => {
24434
+ setOverrides(currentSaved);
24435
+ removeCSSVariables(FONT_VARS);
24436
+ setCSSVariables({ ...allDefaults, ...currentSaved });
24437
+ onThemeChangeRef.current?.(currentSaved);
24438
+ if (currentSaved["--canvas-primary"]) {
24439
+ const hsl = hexToHsl2(currentSaved["--canvas-primary"]);
24440
+ setBrandHueState(hsl.h);
24441
+ }
24442
+ return currentSaved;
24443
+ });
24444
+ setSavedBranding((currentSaved) => {
24445
+ setBrandingState(currentSaved);
24446
+ onBrandingChangeRef.current?.(currentSaved);
24447
+ return currentSaved;
24448
+ });
24449
+ setSavedImages((currentSaved) => {
24450
+ setImagesState(currentSaved);
24451
+ onImagesChangeRef.current?.(currentSaved);
24452
+ return currentSaved;
24453
+ });
24454
+ setSavedCustomButtonStyles((currentSaved) => {
24455
+ setCustomButtonStyles(currentSaved);
24456
+ return currentSaved;
24457
+ });
24458
+ }, []);
24216
24459
  const resetAll = useCallback(() => {
24217
24460
  setOverrides({});
24461
+ setBrandingState({ ...defaultBranding });
24462
+ setImagesState({ ...defaultImages });
24463
+ setCustomButtonStyles([...defaultCustomButtonStyles]);
24464
+ setBrandHueState(217);
24465
+ setBrandVibrancyState(1);
24466
+ setSavedOverrides({});
24467
+ setSavedBranding({ ...defaultBranding });
24468
+ setSavedImages({ ...defaultImages });
24469
+ setSavedCustomButtonStyles([...defaultCustomButtonStyles]);
24218
24470
  try {
24219
24471
  localStorage.removeItem(storageKey);
24220
24472
  } catch {
@@ -24227,133 +24479,1244 @@ function useThemeState(options) {
24227
24479
  (json) => {
24228
24480
  const parsed = importJSON(json);
24229
24481
  if (!parsed) return false;
24230
- setOverrides(parsed);
24231
- try {
24232
- localStorage.setItem(storageKey, exportJSON(parsed));
24233
- } catch {
24234
- }
24482
+ const ovr = parsed.overrides ?? {};
24483
+ setOverrides(ovr);
24484
+ if (parsed.branding) setBrandingState(parsed.branding);
24485
+ if (parsed.images) setImagesState(parsed.images);
24486
+ if (parsed.customButtonStyles) setCustomButtonStyles(parsed.customButtonStyles);
24235
24487
  removeCSSVariables(FONT_VARS);
24236
- setCSSVariables({ ...allDefaults, ...parsed });
24237
- onThemeChangeRef.current?.(parsed);
24488
+ setCSSVariables({ ...allDefaults, ...ovr });
24489
+ onThemeChangeRef.current?.(ovr);
24238
24490
  return true;
24239
24491
  },
24240
- [storageKey]
24492
+ []
24493
+ );
24494
+ const setBranding = useCallback(
24495
+ (updates) => {
24496
+ setBrandingState((prev) => {
24497
+ const next = { ...prev, ...updates };
24498
+ onBrandingChangeRef.current?.(next);
24499
+ return next;
24500
+ });
24501
+ },
24502
+ []
24503
+ );
24504
+ const setImage = useCallback(
24505
+ (key, url) => {
24506
+ setImagesState((prev) => {
24507
+ const next = { ...prev, [key]: url };
24508
+ onImagesChangeRef.current?.(next);
24509
+ return next;
24510
+ });
24511
+ },
24512
+ []
24513
+ );
24514
+ const deleteImage = useCallback(
24515
+ (key) => {
24516
+ setImagesState((prev) => {
24517
+ const next = { ...prev, [key]: "" };
24518
+ onImagesChangeRef.current?.(next);
24519
+ return next;
24520
+ });
24521
+ },
24522
+ []
24523
+ );
24524
+ const addCustomButtonStyle = useCallback(() => {
24525
+ setCustomButtonStyles((prev) => {
24526
+ const id = `custom-${Date.now()}`;
24527
+ return [
24528
+ ...prev,
24529
+ {
24530
+ id,
24531
+ label: "New Style",
24532
+ description: "Custom button style",
24533
+ bg: "var(--canvas-primary)",
24534
+ text: "var(--canvas-primary-foreground)",
24535
+ border: "var(--canvas-primary)",
24536
+ bgHover: "var(--canvas-primary-dark)",
24537
+ textHover: "var(--canvas-primary-foreground)",
24538
+ borderHover: "var(--canvas-primary-dark)"
24539
+ }
24540
+ ];
24541
+ });
24542
+ }, []);
24543
+ const updateCustomButtonStyle = useCallback(
24544
+ (id, updates) => {
24545
+ setCustomButtonStyles(
24546
+ (prev) => prev.map((s) => s.id === id ? { ...s, ...updates } : s)
24547
+ );
24548
+ },
24549
+ []
24550
+ );
24551
+ const deleteCustomButtonStyle = useCallback(
24552
+ (id) => {
24553
+ setCustomButtonStyles((prev) => prev.filter((s) => s.id !== id));
24554
+ },
24555
+ []
24556
+ );
24557
+ const applyBrandHueVibrancy = useCallback(
24558
+ (hue, vibrancy, skipPrimary = false) => {
24559
+ const newValues = {};
24560
+ const varsToUpdate = skipPrimary ? brandColorVars.filter((v) => v !== "--canvas-primary") : brandColorVars;
24561
+ if (!skipPrimary) {
24562
+ const defaultColor = defaultColors["--canvas-primary"];
24563
+ if (defaultColor && defaultColor.startsWith("#")) {
24564
+ const defaultHsl = hexToHsl2(defaultColor);
24565
+ const newHex = hslToHex2(hue, defaultHsl.s, defaultHsl.l);
24566
+ newValues["--canvas-primary"] = newHex;
24567
+ document.documentElement.style.setProperty("--canvas-primary", newHex);
24568
+ }
24569
+ }
24570
+ setOverrides((prev) => {
24571
+ const effectivePrimaryColor = newValues["--canvas-primary"] || prev["--canvas-primary"] || defaultColors["--canvas-primary"];
24572
+ varsToUpdate.forEach((varName) => {
24573
+ if (varName === "--canvas-sidebar-light-active-text" || varName === "--canvas-border-input-focus") {
24574
+ newValues[varName] = effectivePrimaryColor;
24575
+ document.documentElement.style.setProperty(varName, effectivePrimaryColor);
24576
+ return;
24577
+ }
24578
+ if (varName === "--canvas-primary") return;
24579
+ const defaultColor = defaultColors[varName];
24580
+ if (!defaultColor || !defaultColor.startsWith("#")) return;
24581
+ const defaultHsl = hexToHsl2(defaultColor);
24582
+ const minSaturation = 10;
24583
+ const newS = Math.max(
24584
+ minSaturation,
24585
+ Math.min(100, Math.round(defaultHsl.s * vibrancy))
24586
+ );
24587
+ const minLightness = 10;
24588
+ const lightnessMultiplier = vibrancy < 1 ? vibrancy : 1;
24589
+ const newL = Math.max(
24590
+ minLightness,
24591
+ Math.min(100, Math.round(defaultHsl.l * lightnessMultiplier))
24592
+ );
24593
+ const newHex = hslToHex2(hue, newS, newL);
24594
+ newValues[varName] = newHex;
24595
+ document.documentElement.style.setProperty(varName, newHex);
24596
+ });
24597
+ const next = { ...prev, ...newValues };
24598
+ onThemeChangeRef.current?.(next);
24599
+ return next;
24600
+ });
24601
+ },
24602
+ []
24603
+ );
24604
+ const setBrandHue = useCallback(
24605
+ (hue) => {
24606
+ setBrandHueState(hue);
24607
+ },
24608
+ []
24609
+ );
24610
+ const setBrandVibrancy = useCallback(
24611
+ (vibrancy) => {
24612
+ setBrandVibrancyState(vibrancy);
24613
+ },
24614
+ []
24615
+ );
24616
+ const setSyncRelatedColors = useCallback(
24617
+ (sync) => {
24618
+ setSyncRelatedColorsState(sync);
24619
+ },
24620
+ []
24241
24621
  );
24242
- const variables = { ...allDefaults, ...overrides };
24622
+ const variables = useMemo(() => ({ ...allDefaults, ...overrides }), [overrides]);
24623
+ const isDirty = useMemo(() => {
24624
+ return !isEqual(overrides, savedOverrides) || !isEqual(branding, savedBranding) || !isEqual(images, savedImages) || !isEqual(customButtonStyles, savedCustomButtonStyles);
24625
+ }, [overrides, savedOverrides, branding, savedBranding, images, savedImages, customButtonStyles, savedCustomButtonStyles]);
24626
+ const unsavedChangesCount = useMemo(() => {
24627
+ let count = 0;
24628
+ const allKeys = /* @__PURE__ */ new Set([...Object.keys(overrides), ...Object.keys(savedOverrides)]);
24629
+ for (const key of allKeys) {
24630
+ if (overrides[key] !== savedOverrides[key]) count++;
24631
+ }
24632
+ if (!isEqual(branding, savedBranding)) count++;
24633
+ if (!isEqual(images, savedImages)) count++;
24634
+ if (!isEqual(customButtonStyles, savedCustomButtonStyles)) count++;
24635
+ return count;
24636
+ }, [overrides, savedOverrides, branding, savedBranding, images, savedImages, customButtonStyles, savedCustomButtonStyles]);
24243
24637
  return {
24244
24638
  variables,
24245
24639
  overrides,
24246
- isDirty: Object.keys(overrides).length > 0,
24640
+ isDirty,
24641
+ unsavedChangesCount,
24247
24642
  setVariable,
24248
24643
  resetCategory,
24249
24644
  resetAll,
24250
24645
  exportCSS: () => exportCSS(overrides),
24251
- exportJSON: () => exportJSON(overrides),
24252
- importJSON: handleImportJSON
24646
+ exportJSON: () => exportJSON(overrides, branding, images, customButtonStyles),
24647
+ importJSON: handleImportJSON,
24648
+ save,
24649
+ discard,
24650
+ branding,
24651
+ setBranding,
24652
+ images,
24653
+ setImage,
24654
+ deleteImage,
24655
+ customButtonStyles,
24656
+ addCustomButtonStyle,
24657
+ updateCustomButtonStyle,
24658
+ deleteCustomButtonStyle,
24659
+ brandHue,
24660
+ brandVibrancy,
24661
+ syncRelatedColors,
24662
+ setBrandHue,
24663
+ setBrandVibrancy,
24664
+ setSyncRelatedColors,
24665
+ applyBrandHueVibrancy
24253
24666
  };
24254
24667
  }
24255
- function ColorsPanel({ theme }) {
24256
- return /* @__PURE__ */ jsx("div", { "data-theme-drawer-panel": true, className: "flex flex-col gap-6 p-4", children: colorVariables.map((category) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
24257
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
24258
- /* @__PURE__ */ jsx(
24259
- "h3",
24260
- {
24261
- style: {
24262
- fontSize: "13px",
24263
- fontWeight: 600,
24264
- color: "#374151",
24265
- textTransform: "uppercase",
24266
- letterSpacing: "0.05em"
24267
- },
24268
- children: category.category
24269
- }
24270
- ),
24271
- /* @__PURE__ */ jsx(
24272
- "button",
24273
- {
24274
- onClick: () => {
24275
- const prefix = category.variables[0]?.name.split("-").slice(0, 3).join("-");
24276
- if (prefix) theme.resetCategory(prefix);
24277
- },
24278
- style: {
24279
- fontSize: "11px",
24280
- color: "#6b7280",
24281
- background: "none",
24282
- border: "none",
24283
- cursor: "pointer",
24284
- padding: "2px 6px",
24285
- borderRadius: "4px"
24286
- },
24287
- onMouseEnter: (e) => {
24288
- e.target.style.color = "#374151";
24289
- e.target.style.background = "#f3f4f6";
24290
- },
24291
- onMouseLeave: (e) => {
24292
- e.target.style.color = "#6b7280";
24293
- e.target.style.background = "none";
24294
- },
24295
- children: "Reset"
24296
- }
24297
- )
24298
- ] }),
24299
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: category.variables.map((v) => /* @__PURE__ */ jsx(
24300
- ColorRow,
24668
+ function HslColorPicker({ value, onChange }) {
24669
+ const hsl = hexToHsl2(value);
24670
+ const satLightRef = useRef(null);
24671
+ const [isDragging, setIsDragging] = useState(false);
24672
+ const handleHslChange = (component, newValue) => {
24673
+ const updated = { ...hsl, [component]: newValue };
24674
+ onChange(hslToHex2(updated.h, updated.s, updated.l));
24675
+ };
24676
+ const handleSatLightInteraction = (clientX, clientY) => {
24677
+ if (!satLightRef.current) return;
24678
+ const rect = satLightRef.current.getBoundingClientRect();
24679
+ const x = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
24680
+ const y = Math.max(0, Math.min(1, (clientY - rect.top) / rect.height));
24681
+ const s = Math.round(x * 100);
24682
+ const l = Math.round((1 - y) * 100);
24683
+ onChange(hslToHex2(hsl.h, s, l));
24684
+ };
24685
+ const handlePointerDown = (e) => {
24686
+ e.preventDefault();
24687
+ e.stopPropagation();
24688
+ setIsDragging(true);
24689
+ handleSatLightInteraction(e.clientX, e.clientY);
24690
+ e.target.setPointerCapture(e.pointerId);
24691
+ };
24692
+ const handlePointerMove = (e) => {
24693
+ if (!isDragging) return;
24694
+ handleSatLightInteraction(e.clientX, e.clientY);
24695
+ };
24696
+ const handlePointerUp = (e) => {
24697
+ setIsDragging(false);
24698
+ e.target.releasePointerCapture(e.pointerId);
24699
+ };
24700
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "12px", padding: "12px", width: "256px" }, children: [
24701
+ /* @__PURE__ */ jsx(
24702
+ "div",
24301
24703
  {
24302
- label: v.label,
24303
- value: theme.variables[v.name] ?? v.default,
24304
- defaultValue: v.default,
24305
- onChange: (val) => theme.setVariable(v.name, val)
24306
- },
24307
- v.name
24308
- )) })
24309
- ] }, category.category)) });
24704
+ ref: satLightRef,
24705
+ style: {
24706
+ position: "relative",
24707
+ width: "100%",
24708
+ height: "160px",
24709
+ borderRadius: "6px",
24710
+ cursor: "crosshair",
24711
+ touchAction: "none",
24712
+ background: `
24713
+ linear-gradient(to top, #000, transparent),
24714
+ linear-gradient(to right, #fff, hsl(${hsl.h}, 100%, 50%))
24715
+ `
24716
+ },
24717
+ onPointerDown: handlePointerDown,
24718
+ onPointerMove: handlePointerMove,
24719
+ onPointerUp: handlePointerUp,
24720
+ children: /* @__PURE__ */ jsx(
24721
+ "div",
24722
+ {
24723
+ style: {
24724
+ position: "absolute",
24725
+ width: "16px",
24726
+ height: "16px",
24727
+ border: "2px solid white",
24728
+ borderRadius: "50%",
24729
+ pointerEvents: "none",
24730
+ transform: "translate(-50%, -50%)",
24731
+ left: `${hsl.s}%`,
24732
+ top: `${100 - hsl.l}%`,
24733
+ boxShadow: "0 0 0 1px rgba(0,0,0,0.3), 0 2px 4px rgba(0,0,0,0.2)"
24734
+ }
24735
+ }
24736
+ )
24737
+ }
24738
+ ),
24739
+ /* @__PURE__ */ jsx(
24740
+ SliderRow,
24741
+ {
24742
+ label: "Hue",
24743
+ value: hsl.h,
24744
+ min: 0,
24745
+ max: 360,
24746
+ suffix: "\xB0",
24747
+ inputWidth: "48px",
24748
+ onChange: (v) => handleHslChange("h", v),
24749
+ gradient: `linear-gradient(to right,
24750
+ hsl(0, 100%, 50%),
24751
+ hsl(60, 100%, 50%),
24752
+ hsl(120, 100%, 50%),
24753
+ hsl(180, 100%, 50%),
24754
+ hsl(240, 100%, 50%),
24755
+ hsl(300, 100%, 50%),
24756
+ hsl(360, 100%, 50%)
24757
+ )`
24758
+ }
24759
+ ),
24760
+ /* @__PURE__ */ jsx(
24761
+ SliderRow,
24762
+ {
24763
+ label: "Saturation",
24764
+ value: hsl.s,
24765
+ min: 0,
24766
+ max: 100,
24767
+ suffix: "%",
24768
+ inputWidth: "40px",
24769
+ onChange: (v) => handleHslChange("s", v),
24770
+ gradient: `linear-gradient(to right,
24771
+ hsl(${hsl.h}, 0%, ${hsl.l}%),
24772
+ hsl(${hsl.h}, 100%, ${hsl.l}%)
24773
+ )`
24774
+ }
24775
+ ),
24776
+ /* @__PURE__ */ jsx(
24777
+ SliderRow,
24778
+ {
24779
+ label: "Lightness",
24780
+ value: hsl.l,
24781
+ min: 0,
24782
+ max: 100,
24783
+ suffix: "%",
24784
+ inputWidth: "40px",
24785
+ onChange: (v) => handleHslChange("l", v),
24786
+ gradient: `linear-gradient(to right,
24787
+ hsl(${hsl.h}, ${hsl.s}%, 0%),
24788
+ hsl(${hsl.h}, ${hsl.s}%, 50%),
24789
+ hsl(${hsl.h}, ${hsl.s}%, 100%)
24790
+ )`
24791
+ }
24792
+ )
24793
+ ] });
24310
24794
  }
24311
- function ColorRow({
24795
+ function SliderRow({
24312
24796
  label,
24313
24797
  value,
24314
- defaultValue,
24315
- onChange
24798
+ min,
24799
+ max,
24800
+ suffix,
24801
+ inputWidth,
24802
+ onChange,
24803
+ gradient
24316
24804
  }) {
24317
- const isModified = value !== defaultValue;
24318
- return /* @__PURE__ */ jsxs(
24319
- "div",
24320
- {
24321
- style: {
24322
- display: "flex",
24323
- alignItems: "center",
24324
- gap: "10px"
24325
- },
24326
- children: [
24327
- /* @__PURE__ */ jsx(
24328
- "label",
24329
- {
24330
- style: {
24331
- position: "relative",
24332
- width: "32px",
24333
- height: "32px",
24334
- flexShrink: 0,
24335
- borderRadius: "6px",
24336
- border: "1px solid #e5e7eb",
24337
- overflow: "hidden",
24338
- cursor: "pointer"
24339
- },
24340
- children: /* @__PURE__ */ jsx(
24805
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "4px" }, children: [
24806
+ /* @__PURE__ */ jsxs(
24807
+ "div",
24808
+ {
24809
+ style: {
24810
+ display: "flex",
24811
+ alignItems: "center",
24812
+ justifyContent: "space-between",
24813
+ fontSize: "12px",
24814
+ color: "#6b7280"
24815
+ },
24816
+ children: [
24817
+ /* @__PURE__ */ jsx("span", { children: label }),
24818
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "2px" }, children: [
24819
+ /* @__PURE__ */ jsx(
24341
24820
  "input",
24342
24821
  {
24343
- type: "color",
24822
+ type: "number",
24823
+ min,
24824
+ max,
24344
24825
  value,
24345
- onChange: (e) => onChange(e.target.value),
24826
+ onChange: (e) => onChange(
24827
+ Math.min(max, Math.max(min, parseInt(e.target.value) || 0))
24828
+ ),
24346
24829
  style: {
24347
- position: "absolute",
24348
- inset: "-4px",
24349
- width: "calc(100% + 8px)",
24350
- height: "calc(100% + 8px)",
24351
- cursor: "pointer",
24352
- border: "none",
24353
- padding: 0
24830
+ width: inputWidth,
24831
+ padding: "2px 4px",
24832
+ fontSize: "12px",
24833
+ fontFamily: "monospace",
24834
+ border: "1px solid #e5e7eb",
24835
+ borderRadius: "4px",
24836
+ background: "#ffffff",
24837
+ color: "#374151",
24838
+ textAlign: "right"
24839
+ }
24840
+ }
24841
+ ),
24842
+ /* @__PURE__ */ jsx("span", { children: suffix })
24843
+ ] })
24844
+ ]
24845
+ }
24846
+ ),
24847
+ /* @__PURE__ */ jsx(
24848
+ "input",
24849
+ {
24850
+ type: "range",
24851
+ min,
24852
+ max,
24853
+ value,
24854
+ onChange: (e) => onChange(parseInt(e.target.value)),
24855
+ style: {
24856
+ width: "100%",
24857
+ height: "12px",
24858
+ borderRadius: "6px",
24859
+ appearance: "none",
24860
+ WebkitAppearance: "none",
24861
+ cursor: "pointer",
24862
+ background: gradient
24863
+ }
24864
+ }
24865
+ )
24866
+ ] });
24867
+ }
24868
+ function ColorInputRow({
24869
+ label,
24870
+ value,
24871
+ onChange,
24872
+ variableOptions
24873
+ }) {
24874
+ const [pickerOpen, setPickerOpen] = useState(false);
24875
+ if (variableOptions) {
24876
+ return /* @__PURE__ */ jsx(
24877
+ VariableColorRow,
24878
+ {
24879
+ label,
24880
+ value,
24881
+ onChange,
24882
+ variableOptions
24883
+ }
24884
+ );
24885
+ }
24886
+ const handleHexInput = (e) => {
24887
+ let hex = e.target.value;
24888
+ if (hex && !hex.startsWith("#")) {
24889
+ hex = "#" + hex;
24890
+ }
24891
+ if (/^#[0-9A-Fa-f]{0,6}$/.test(hex)) {
24892
+ onChange(hex);
24893
+ }
24894
+ };
24895
+ return /* @__PURE__ */ jsxs(
24896
+ "div",
24897
+ {
24898
+ style: {
24899
+ display: "flex",
24900
+ alignItems: "center",
24901
+ gap: "8px",
24902
+ padding: "8px 0"
24903
+ },
24904
+ children: [
24905
+ /* @__PURE__ */ jsxs(Popover, { open: pickerOpen, onOpenChange: setPickerOpen, children: [
24906
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
24907
+ "button",
24908
+ {
24909
+ style: {
24910
+ width: "32px",
24911
+ height: "32px",
24912
+ borderRadius: "6px",
24913
+ border: "1px solid #e5e7eb",
24914
+ cursor: "pointer",
24915
+ flexShrink: 0,
24916
+ backgroundColor: value,
24917
+ transition: "transform 150ms"
24918
+ },
24919
+ onMouseEnter: (e) => {
24920
+ e.currentTarget.style.transform = "scale(1.05)";
24921
+ },
24922
+ onMouseLeave: (e) => {
24923
+ e.currentTarget.style.transform = "scale(1)";
24924
+ },
24925
+ "aria-label": `Edit ${label} color`
24926
+ }
24927
+ ) }),
24928
+ /* @__PURE__ */ jsx(
24929
+ PopoverContent,
24930
+ {
24931
+ className: "w-auto p-0",
24932
+ align: "start",
24933
+ onPointerDownOutside: (e) => e.preventDefault(),
24934
+ children: /* @__PURE__ */ jsx(HslColorPicker, { value, onChange })
24935
+ }
24936
+ )
24937
+ ] }),
24938
+ /* @__PURE__ */ jsx(
24939
+ "span",
24940
+ {
24941
+ style: {
24942
+ fontSize: "13px",
24943
+ color: "#374151",
24944
+ flex: 1,
24945
+ minWidth: 0
24946
+ },
24947
+ children: label
24948
+ }
24949
+ ),
24950
+ /* @__PURE__ */ jsx(
24951
+ "input",
24952
+ {
24953
+ type: "text",
24954
+ value,
24955
+ onChange: handleHexInput,
24956
+ style: {
24957
+ width: "80px",
24958
+ fontSize: "12px",
24959
+ fontFamily: "monospace",
24960
+ padding: "4px 8px",
24961
+ border: "1px solid #e5e7eb",
24962
+ borderRadius: "4px",
24963
+ color: "#374151",
24964
+ background: "#ffffff",
24965
+ textTransform: "uppercase",
24966
+ textAlign: "center"
24967
+ },
24968
+ placeholder: "#000000"
24969
+ }
24970
+ )
24971
+ ]
24972
+ }
24973
+ );
24974
+ }
24975
+ function VariableColorRow({
24976
+ label,
24977
+ value,
24978
+ onChange,
24979
+ variableOptions
24980
+ }) {
24981
+ const isVariable = isVariableReference(value);
24982
+ const resolvedColor = resolveBrandingColor(value);
24983
+ const selectedOption = variableOptions.find((opt) => opt.value === value);
24984
+ const selectValue = selectedOption ? value : "__custom__";
24985
+ return /* @__PURE__ */ jsxs(
24986
+ "div",
24987
+ {
24988
+ style: {
24989
+ display: "flex",
24990
+ alignItems: "center",
24991
+ gap: "8px",
24992
+ padding: "8px 0"
24993
+ },
24994
+ children: [
24995
+ /* @__PURE__ */ jsx(
24996
+ "div",
24997
+ {
24998
+ style: {
24999
+ width: "24px",
25000
+ height: "24px",
25001
+ borderRadius: "4px",
25002
+ border: "1px solid #e5e7eb",
25003
+ flexShrink: 0,
25004
+ backgroundColor: resolvedColor
25005
+ }
25006
+ }
25007
+ ),
25008
+ /* @__PURE__ */ jsx(
25009
+ "span",
25010
+ {
25011
+ style: {
25012
+ fontSize: "13px",
25013
+ color: "#374151",
25014
+ flex: 1,
25015
+ minWidth: 0
25016
+ },
25017
+ children: label
25018
+ }
25019
+ ),
25020
+ /* @__PURE__ */ jsxs(
25021
+ "select",
25022
+ {
25023
+ value: selectValue,
25024
+ onChange: (e) => {
25025
+ if (e.target.value === "__custom__") {
25026
+ onChange("#000000");
25027
+ } else {
25028
+ onChange(e.target.value);
25029
+ }
25030
+ },
25031
+ style: {
25032
+ height: "28px",
25033
+ fontSize: "11px",
25034
+ padding: "0 6px",
25035
+ border: "1px solid #e5e7eb",
25036
+ borderRadius: "4px",
25037
+ color: "#374151",
25038
+ background: "#ffffff",
25039
+ cursor: "pointer",
25040
+ flexShrink: 0,
25041
+ maxWidth: "120px"
25042
+ },
25043
+ children: [
25044
+ variableOptions.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value)),
25045
+ /* @__PURE__ */ jsx("option", { value: "__custom__", children: "Custom" })
25046
+ ]
25047
+ }
25048
+ ),
25049
+ !isVariable && /* @__PURE__ */ jsxs(Fragment, { children: [
25050
+ /* @__PURE__ */ jsxs(Popover, { children: [
25051
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
25052
+ "button",
25053
+ {
25054
+ style: {
25055
+ width: "24px",
25056
+ height: "24px",
25057
+ borderRadius: "4px",
25058
+ border: "1px solid #e5e7eb",
25059
+ cursor: "pointer",
25060
+ flexShrink: 0,
25061
+ backgroundColor: value
25062
+ },
25063
+ "aria-label": `Edit ${label} color`
25064
+ }
25065
+ ) }),
25066
+ /* @__PURE__ */ jsx(
25067
+ PopoverContent,
25068
+ {
25069
+ className: "w-auto p-0",
25070
+ align: "start",
25071
+ onPointerDownOutside: (e) => e.preventDefault(),
25072
+ children: /* @__PURE__ */ jsx(HslColorPicker, { value, onChange })
25073
+ }
25074
+ )
25075
+ ] }),
25076
+ /* @__PURE__ */ jsx(
25077
+ "input",
25078
+ {
25079
+ type: "text",
25080
+ value,
25081
+ onChange: (e) => {
25082
+ let hex = e.target.value;
25083
+ if (hex && !hex.startsWith("#")) hex = "#" + hex;
25084
+ if (/^#[0-9A-Fa-f]{0,6}$/.test(hex)) onChange(hex);
25085
+ },
25086
+ style: {
25087
+ width: "72px",
25088
+ fontSize: "11px",
25089
+ fontFamily: "monospace",
25090
+ padding: "4px 6px",
25091
+ border: "1px solid #e5e7eb",
25092
+ borderRadius: "4px",
25093
+ color: "#374151",
25094
+ background: "#ffffff",
25095
+ textTransform: "uppercase",
25096
+ textAlign: "center"
25097
+ },
25098
+ placeholder: "#000000"
25099
+ }
25100
+ )
25101
+ ] })
25102
+ ]
25103
+ }
25104
+ );
25105
+ }
25106
+ function ColorsPanel({ theme }) {
25107
+ return /* @__PURE__ */ jsxs("div", { "data-theme-drawer-panel": true, className: "flex flex-col gap-6 p-4", children: [
25108
+ /* @__PURE__ */ jsxs(
25109
+ "div",
25110
+ {
25111
+ style: {
25112
+ padding: "12px",
25113
+ background: "#f9fafb",
25114
+ borderRadius: "8px",
25115
+ border: "1px solid #e5e7eb"
25116
+ },
25117
+ children: [
25118
+ /* @__PURE__ */ jsx(
25119
+ "h3",
25120
+ {
25121
+ style: {
25122
+ fontSize: "11px",
25123
+ fontWeight: 600,
25124
+ color: "#6b7280",
25125
+ textTransform: "uppercase",
25126
+ letterSpacing: "0.05em",
25127
+ marginBottom: "12px"
25128
+ },
25129
+ children: "Brand Controls"
25130
+ }
25131
+ ),
25132
+ /* @__PURE__ */ jsx(
25133
+ ColorInputRow,
25134
+ {
25135
+ label: "Primary",
25136
+ value: theme.variables["--canvas-primary"] || "#1165ef",
25137
+ onChange: (hex) => {
25138
+ theme.setVariable("--canvas-primary", hex);
25139
+ if (/^#[0-9A-Fa-f]{6}$/.test(hex)) {
25140
+ const hsl = hexToHsl2(hex);
25141
+ theme.setBrandHue(hsl.h);
25142
+ theme.setBrandVibrancy(1);
25143
+ if (theme.syncRelatedColors) {
25144
+ theme.applyBrandHueVibrancy(hsl.h, 1, true);
25145
+ }
25146
+ }
25147
+ }
25148
+ }
25149
+ ),
25150
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: "12px" }, children: [
25151
+ /* @__PURE__ */ jsxs(
25152
+ "div",
25153
+ {
25154
+ style: {
25155
+ display: "flex",
25156
+ alignItems: "center",
25157
+ justifyContent: "space-between",
25158
+ marginBottom: "6px"
25159
+ },
25160
+ children: [
25161
+ /* @__PURE__ */ jsx("label", { style: { fontSize: "12px", color: "#6b7280" }, children: "Brand Hue" }),
25162
+ /* @__PURE__ */ jsxs(
25163
+ "span",
25164
+ {
25165
+ style: { fontSize: "12px", fontFamily: "monospace", color: "#6b7280" },
25166
+ children: [
25167
+ theme.brandHue,
25168
+ "\xB0"
25169
+ ]
25170
+ }
25171
+ )
25172
+ ]
25173
+ }
25174
+ ),
25175
+ /* @__PURE__ */ jsx(
25176
+ "input",
25177
+ {
25178
+ type: "range",
25179
+ min: "0",
25180
+ max: "360",
25181
+ value: theme.brandHue,
25182
+ onChange: (e) => {
25183
+ const newHue = parseInt(e.target.value);
25184
+ theme.setBrandHue(newHue);
25185
+ if (theme.syncRelatedColors) {
25186
+ theme.applyBrandHueVibrancy(newHue, theme.brandVibrancy);
25187
+ }
25188
+ },
25189
+ style: {
25190
+ width: "100%",
25191
+ height: "12px",
25192
+ borderRadius: "6px",
25193
+ appearance: "none",
25194
+ WebkitAppearance: "none",
25195
+ cursor: "pointer",
25196
+ background: "linear-gradient(to right, hsl(0, 80%, 50%), hsl(60, 80%, 50%), hsl(120, 80%, 50%), hsl(180, 80%, 50%), hsl(240, 80%, 50%), hsl(300, 80%, 50%), hsl(360, 80%, 50%))"
25197
+ }
25198
+ }
25199
+ )
25200
+ ] }),
25201
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: "12px" }, children: [
25202
+ /* @__PURE__ */ jsxs(
25203
+ "div",
25204
+ {
25205
+ style: {
25206
+ display: "flex",
25207
+ alignItems: "center",
25208
+ justifyContent: "space-between",
25209
+ marginBottom: "6px"
25210
+ },
25211
+ children: [
25212
+ /* @__PURE__ */ jsx("label", { style: { fontSize: "12px", color: "#6b7280" }, children: "Brand Vibrancy" }),
25213
+ /* @__PURE__ */ jsxs(
25214
+ "span",
25215
+ {
25216
+ style: { fontSize: "12px", fontFamily: "monospace", color: "#6b7280" },
25217
+ children: [
25218
+ Math.round(theme.brandVibrancy * 100),
25219
+ "%"
25220
+ ]
25221
+ }
25222
+ )
25223
+ ]
25224
+ }
25225
+ ),
25226
+ /* @__PURE__ */ jsx(
25227
+ "input",
25228
+ {
25229
+ type: "range",
25230
+ min: "0",
25231
+ max: "150",
25232
+ value: theme.brandVibrancy * 100,
25233
+ onChange: (e) => {
25234
+ const newVibrancy = parseInt(e.target.value) / 100;
25235
+ theme.setBrandVibrancy(newVibrancy);
25236
+ if (theme.syncRelatedColors) {
25237
+ theme.applyBrandHueVibrancy(theme.brandHue, newVibrancy, true);
25238
+ }
25239
+ },
25240
+ style: {
25241
+ width: "100%",
25242
+ height: "8px",
25243
+ borderRadius: "4px",
25244
+ appearance: "none",
25245
+ WebkitAppearance: "none",
25246
+ cursor: "pointer",
25247
+ background: `linear-gradient(to right, #d1d5db, ${theme.variables["--canvas-primary"] || "#1165ef"})`
25248
+ }
25249
+ }
25250
+ )
25251
+ ] }),
25252
+ /* @__PURE__ */ jsxs(
25253
+ "label",
25254
+ {
25255
+ style: {
25256
+ display: "flex",
25257
+ alignItems: "center",
25258
+ gap: "8px",
25259
+ cursor: "pointer",
25260
+ fontSize: "13px",
25261
+ color: "#374151"
25262
+ },
25263
+ children: [
25264
+ /* @__PURE__ */ jsx(
25265
+ "input",
25266
+ {
25267
+ type: "checkbox",
25268
+ checked: theme.syncRelatedColors,
25269
+ onChange: (e) => theme.setSyncRelatedColors(e.target.checked),
25270
+ style: { width: "16px", height: "16px", cursor: "pointer" }
25271
+ }
25272
+ ),
25273
+ "Apply to related colors"
25274
+ ]
25275
+ }
25276
+ )
25277
+ ]
25278
+ }
25279
+ ),
25280
+ colorVariables.map((category) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
25281
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
25282
+ /* @__PURE__ */ jsx(
25283
+ "h3",
25284
+ {
25285
+ style: {
25286
+ fontSize: "11px",
25287
+ fontWeight: 600,
25288
+ color: "#6b7280",
25289
+ textTransform: "uppercase",
25290
+ letterSpacing: "0.05em"
25291
+ },
25292
+ children: category.category
25293
+ }
25294
+ ),
25295
+ /* @__PURE__ */ jsx(
25296
+ "button",
25297
+ {
25298
+ onClick: () => {
25299
+ const prefix = category.variables[0]?.name.split("-").slice(0, 3).join("-");
25300
+ if (prefix) theme.resetCategory(prefix);
25301
+ },
25302
+ style: {
25303
+ fontSize: "11px",
25304
+ color: "#6b7280",
25305
+ background: "none",
25306
+ border: "none",
25307
+ cursor: "pointer",
25308
+ padding: "2px 6px",
25309
+ borderRadius: "4px"
25310
+ },
25311
+ onMouseEnter: (e) => {
25312
+ e.target.style.color = "#374151";
25313
+ e.target.style.background = "#f3f4f6";
25314
+ },
25315
+ onMouseLeave: (e) => {
25316
+ e.target.style.color = "#6b7280";
25317
+ e.target.style.background = "none";
25318
+ },
25319
+ children: "Reset"
25320
+ }
25321
+ )
25322
+ ] }),
25323
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col", children: category.variables.map((v) => /* @__PURE__ */ jsx(
25324
+ ColorInputRow,
25325
+ {
25326
+ label: v.label,
25327
+ value: theme.variables[v.name] ?? v.default,
25328
+ onChange: (val) => theme.setVariable(v.name, val)
25329
+ },
25330
+ v.name
25331
+ )) })
25332
+ ] }, category.category))
25333
+ ] });
25334
+ }
25335
+ var logoIcons = [
25336
+ { name: "Diamond", icon: Diamond },
25337
+ { name: "Hexagon", icon: Hexagon },
25338
+ { name: "Star", icon: Star$1 },
25339
+ { name: "Lightning", icon: Lightning },
25340
+ { name: "Sparkle", icon: Sparkle },
25341
+ { name: "Infinity", icon: Infinity },
25342
+ { name: "Code", icon: Code },
25343
+ { name: "Terminal", icon: Terminal },
25344
+ { name: "Cpu", icon: Cpu },
25345
+ { name: "Database", icon: Database },
25346
+ { name: "Globe", icon: Globe },
25347
+ { name: "Cloud", icon: Cloud },
25348
+ { name: "WifiHigh", icon: WifiHigh },
25349
+ { name: "Briefcase", icon: Briefcase },
25350
+ { name: "Buildings", icon: Buildings },
25351
+ { name: "Storefront", icon: Storefront },
25352
+ { name: "Handshake", icon: Handshake },
25353
+ { name: "ChartLine", icon: ChartLine },
25354
+ { name: "Palette", icon: Palette },
25355
+ { name: "PencilSimple", icon: PencilSimple },
25356
+ { name: "Camera", icon: Camera },
25357
+ { name: "MusicNote", icon: MusicNote },
25358
+ { name: "Lightbulb", icon: Lightbulb },
25359
+ { name: "Leaf", icon: Leaf },
25360
+ { name: "Tree", icon: Tree },
25361
+ { name: "Sun", icon: Sun },
25362
+ { name: "Moon", icon: Moon },
25363
+ { name: "Fire", icon: Fire },
25364
+ { name: "Drop", icon: Drop },
25365
+ { name: "ChatCircle", icon: ChatCircle },
25366
+ { name: "Envelope", icon: Envelope },
25367
+ { name: "Phone", icon: Phone$1 },
25368
+ { name: "Megaphone", icon: Megaphone$1 },
25369
+ { name: "Heart", icon: Heart },
25370
+ { name: "Shield", icon: Shield },
25371
+ { name: "Trophy", icon: Trophy },
25372
+ { name: "Rocket", icon: Rocket },
25373
+ { name: "Target", icon: Target },
25374
+ { name: "Flag", icon: Flag }
25375
+ ];
25376
+ var iconShapes6 = [
25377
+ { id: "rounded", label: "Rounded", borderRadius: "8px" },
25378
+ { id: "circle", label: "Circle", borderRadius: "50%" },
25379
+ { id: "square", label: "Square", borderRadius: "0px" }
25380
+ ];
25381
+ var brandingColorOptions = [
25382
+ { value: "var(--canvas-primary)", label: "Primary" },
25383
+ { value: "var(--canvas-primary-foreground)", label: "Primary Text" },
25384
+ { value: "var(--canvas-primary-dark)", label: "Primary Dark" },
25385
+ { value: "var(--canvas-surface)", label: "Neutral" },
25386
+ { value: "var(--canvas-surface-hover)", label: "Neutral Hovered" },
25387
+ { value: "var(--canvas-text)", label: "Text" },
25388
+ { value: "var(--canvas-text-muted)", label: "Gray" },
25389
+ { value: "var(--canvas-destructive)", label: "Destructive" }
25390
+ ];
25391
+ var imageConfig = [
25392
+ { key: "logoLight", label: "Logo (Light)" },
25393
+ { key: "logoDark", label: "Logo (Dark)" },
25394
+ { key: "faviconLight", label: "Favicon (Light)" },
25395
+ { key: "faviconDark", label: "Favicon (Dark)" }
25396
+ ];
25397
+ function ImagesPanel({ theme, onImageUpload }) {
25398
+ const currentShape = iconShapes6.find((s) => s.id === theme.branding.iconShape) ?? iconShapes6[0];
25399
+ const resolvedBgColor = resolveBrandingColor(theme.branding.bgColor);
25400
+ const resolvedIconColor = resolveBrandingColor(theme.branding.iconColor);
25401
+ const SelectedIcon = logoIcons.find((i) => i.name === theme.branding.iconName)?.icon ?? Buildings;
25402
+ return /* @__PURE__ */ jsxs("div", { "data-theme-drawer-panel": true, style: { display: "flex", flexDirection: "column", gap: "24px", padding: "16px" }, children: [
25403
+ /* @__PURE__ */ jsxs("div", { children: [
25404
+ /* @__PURE__ */ jsx(
25405
+ "h3",
25406
+ {
25407
+ style: {
25408
+ fontSize: "11px",
25409
+ fontWeight: 600,
25410
+ color: "#6b7280",
25411
+ textTransform: "uppercase",
25412
+ letterSpacing: "0.05em",
25413
+ marginBottom: "12px"
25414
+ },
25415
+ children: "Logo Creator"
25416
+ }
25417
+ ),
25418
+ /* @__PURE__ */ jsxs(
25419
+ "div",
25420
+ {
25421
+ style: {
25422
+ display: "flex",
25423
+ alignItems: "center",
25424
+ gap: "12px",
25425
+ marginBottom: "16px",
25426
+ padding: "16px",
25427
+ background: "#f9fafb",
25428
+ borderRadius: "8px",
25429
+ border: "1px solid #e5e7eb"
25430
+ },
25431
+ children: [
25432
+ /* @__PURE__ */ jsx(
25433
+ "div",
25434
+ {
25435
+ style: {
25436
+ width: "48px",
25437
+ height: "48px",
25438
+ borderRadius: currentShape.borderRadius,
25439
+ backgroundColor: resolvedBgColor,
25440
+ display: "flex",
25441
+ alignItems: "center",
25442
+ justifyContent: "center",
25443
+ flexShrink: 0
25444
+ },
25445
+ children: /* @__PURE__ */ jsx(SelectedIcon, { size: 28, color: resolvedIconColor, weight: "bold" })
25446
+ }
25447
+ ),
25448
+ /* @__PURE__ */ jsx(
25449
+ "span",
25450
+ {
25451
+ style: {
25452
+ fontSize: "18px",
25453
+ fontWeight: 700,
25454
+ color: "#0d121c",
25455
+ letterSpacing: "-0.01em"
25456
+ },
25457
+ children: theme.branding.wordmark || "canvas"
25458
+ }
25459
+ )
25460
+ ]
25461
+ }
25462
+ ),
25463
+ /* @__PURE__ */ jsxs(
25464
+ "div",
25465
+ {
25466
+ style: {
25467
+ display: "grid",
25468
+ gridTemplateColumns: "1fr 1fr",
25469
+ gap: "8px",
25470
+ marginBottom: "12px"
25471
+ },
25472
+ children: [
25473
+ /* @__PURE__ */ jsxs("div", { children: [
25474
+ /* @__PURE__ */ jsx(
25475
+ "label",
25476
+ {
25477
+ style: {
25478
+ display: "block",
25479
+ fontSize: "12px",
25480
+ color: "#6b7280",
25481
+ marginBottom: "4px"
25482
+ },
25483
+ children: "Wordmark"
25484
+ }
25485
+ ),
25486
+ /* @__PURE__ */ jsx(
25487
+ "input",
25488
+ {
25489
+ type: "text",
25490
+ value: theme.branding.wordmark,
25491
+ onChange: (e) => theme.setBranding({ wordmark: e.target.value }),
25492
+ style: {
25493
+ width: "100%",
25494
+ fontSize: "13px",
25495
+ padding: "6px 10px",
25496
+ border: "1px solid #e5e7eb",
25497
+ borderRadius: "6px",
25498
+ color: "#374151",
25499
+ background: "#ffffff",
25500
+ boxSizing: "border-box"
25501
+ },
25502
+ placeholder: "Your brand name"
25503
+ }
25504
+ )
25505
+ ] }),
25506
+ /* @__PURE__ */ jsxs("div", { children: [
25507
+ /* @__PURE__ */ jsx(
25508
+ "label",
25509
+ {
25510
+ style: {
25511
+ display: "block",
25512
+ fontSize: "12px",
25513
+ color: "#6b7280",
25514
+ marginBottom: "4px"
25515
+ },
25516
+ children: "Icon Shape"
25517
+ }
25518
+ ),
25519
+ /* @__PURE__ */ jsx(
25520
+ "select",
25521
+ {
25522
+ value: theme.branding.iconShape,
25523
+ onChange: (e) => theme.setBranding({ iconShape: e.target.value }),
25524
+ style: {
25525
+ width: "100%",
25526
+ height: "32px",
25527
+ fontSize: "13px",
25528
+ padding: "0 10px",
25529
+ border: "1px solid #e5e7eb",
25530
+ borderRadius: "6px",
25531
+ color: "#374151",
25532
+ background: "#ffffff",
25533
+ cursor: "pointer",
25534
+ boxSizing: "border-box"
25535
+ },
25536
+ children: iconShapes6.map((shape) => /* @__PURE__ */ jsx("option", { value: shape.id, children: shape.label }, shape.id))
25537
+ }
25538
+ )
25539
+ ] })
25540
+ ]
25541
+ }
25542
+ ),
25543
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: "12px" }, children: [
25544
+ /* @__PURE__ */ jsx(
25545
+ "label",
25546
+ {
25547
+ style: {
25548
+ display: "block",
25549
+ fontSize: "12px",
25550
+ color: "#6b7280",
25551
+ marginBottom: "6px"
25552
+ },
25553
+ children: "Icon"
25554
+ }
25555
+ ),
25556
+ /* @__PURE__ */ jsx(
25557
+ "div",
25558
+ {
25559
+ style: {
25560
+ display: "grid",
25561
+ gridTemplateColumns: "repeat(8, 1fr)",
25562
+ gap: "4px"
25563
+ },
25564
+ children: logoIcons.map((icon) => {
25565
+ const isSelected = theme.branding.iconName === icon.name;
25566
+ const IconComp = icon.icon;
25567
+ return /* @__PURE__ */ jsx(
25568
+ "button",
25569
+ {
25570
+ onClick: () => theme.setBranding({ iconName: icon.name }),
25571
+ title: icon.name,
25572
+ style: {
25573
+ width: "100%",
25574
+ aspectRatio: "1",
25575
+ display: "flex",
25576
+ alignItems: "center",
25577
+ justifyContent: "center",
25578
+ borderRadius: "6px",
25579
+ border: isSelected ? "2px solid #1165ef" : "1px solid transparent",
25580
+ background: isSelected ? "#1165ef" : "transparent",
25581
+ cursor: "pointer",
25582
+ padding: 0,
25583
+ transition: "background 100ms, border-color 100ms"
25584
+ },
25585
+ onMouseEnter: (e) => {
25586
+ if (!isSelected) {
25587
+ e.currentTarget.style.background = "#f3f4f6";
25588
+ }
25589
+ },
25590
+ onMouseLeave: (e) => {
25591
+ if (!isSelected) {
25592
+ e.currentTarget.style.background = "transparent";
25593
+ }
25594
+ },
25595
+ children: /* @__PURE__ */ jsx(
25596
+ IconComp,
25597
+ {
25598
+ size: 20,
25599
+ color: isSelected ? "#ffffff" : "#374151",
25600
+ weight: "regular"
25601
+ }
25602
+ )
25603
+ },
25604
+ icon.name
25605
+ );
25606
+ })
25607
+ }
25608
+ )
25609
+ ] }),
25610
+ /* @__PURE__ */ jsx(
25611
+ ColorInputRow,
25612
+ {
25613
+ label: "Background Color",
25614
+ value: theme.branding.bgColor,
25615
+ onChange: (val) => theme.setBranding({ bgColor: val }),
25616
+ variableOptions: brandingColorOptions
25617
+ }
25618
+ ),
25619
+ /* @__PURE__ */ jsx(
25620
+ ColorInputRow,
25621
+ {
25622
+ label: "Icon Color",
25623
+ value: theme.branding.iconColor,
25624
+ onChange: (val) => theme.setBranding({ iconColor: val }),
25625
+ variableOptions: brandingColorOptions
25626
+ }
25627
+ )
25628
+ ] }),
25629
+ /* @__PURE__ */ jsxs("div", { children: [
25630
+ /* @__PURE__ */ jsx(
25631
+ "h3",
25632
+ {
25633
+ style: {
25634
+ fontSize: "11px",
25635
+ fontWeight: 600,
25636
+ color: "#6b7280",
25637
+ textTransform: "uppercase",
25638
+ letterSpacing: "0.05em",
25639
+ marginBottom: "12px"
25640
+ },
25641
+ children: "Upload Custom Images"
25642
+ }
25643
+ ),
25644
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: imageConfig.map((img) => /* @__PURE__ */ jsx(
25645
+ ImageUploadRow,
25646
+ {
25647
+ imageKey: img.key,
25648
+ label: img.label,
25649
+ url: theme.images[img.key],
25650
+ onImageUpload,
25651
+ onSetImage: (url) => theme.setImage(img.key, url),
25652
+ onDeleteImage: () => theme.deleteImage(img.key)
25653
+ },
25654
+ img.key
25655
+ )) })
25656
+ ] })
25657
+ ] });
25658
+ }
25659
+ function ImageUploadRow({
25660
+ imageKey,
25661
+ label,
25662
+ url,
25663
+ onImageUpload,
25664
+ onSetImage,
25665
+ onDeleteImage
25666
+ }) {
25667
+ const fileInputRef = useRef(null);
25668
+ const handleFileChange = async (e) => {
25669
+ const file = e.target.files?.[0];
25670
+ if (!file || !onImageUpload) return;
25671
+ try {
25672
+ const uploadedUrl = await onImageUpload(imageKey, file);
25673
+ onSetImage(uploadedUrl);
25674
+ } catch {
25675
+ }
25676
+ if (fileInputRef.current) {
25677
+ fileInputRef.current.value = "";
25678
+ }
25679
+ };
25680
+ return /* @__PURE__ */ jsxs(
25681
+ "div",
25682
+ {
25683
+ style: {
25684
+ display: "flex",
25685
+ alignItems: "center",
25686
+ gap: "10px",
25687
+ padding: "8px 10px",
25688
+ background: "#f9fafb",
25689
+ borderRadius: "6px",
25690
+ border: "1px solid #e5e7eb"
25691
+ },
25692
+ children: [
25693
+ /* @__PURE__ */ jsx(
25694
+ "div",
25695
+ {
25696
+ style: {
25697
+ width: "40px",
25698
+ height: "40px",
25699
+ borderRadius: "4px",
25700
+ border: "1px solid #e5e7eb",
25701
+ background: "#ffffff",
25702
+ display: "flex",
25703
+ alignItems: "center",
25704
+ justifyContent: "center",
25705
+ flexShrink: 0,
25706
+ overflow: "hidden"
25707
+ },
25708
+ children: url ? /* @__PURE__ */ jsx(
25709
+ "img",
25710
+ {
25711
+ src: url,
25712
+ alt: label,
25713
+ style: {
25714
+ width: "100%",
25715
+ height: "100%",
25716
+ objectFit: "contain"
24354
25717
  }
24355
25718
  }
24356
- )
25719
+ ) : /* @__PURE__ */ jsx("span", { style: { fontSize: "10px", color: "#9ca3af" }, children: "--" })
24357
25720
  }
24358
25721
  ),
24359
25722
  /* @__PURE__ */ jsx(
@@ -24363,71 +25726,357 @@ function ColorRow({
24363
25726
  fontSize: "13px",
24364
25727
  color: "#374151",
24365
25728
  flex: 1,
24366
- fontWeight: isModified ? 500 : 400
25729
+ minWidth: 0
24367
25730
  },
24368
25731
  children: label
24369
25732
  }
24370
25733
  ),
24371
- /* @__PURE__ */ jsx(
24372
- "input",
25734
+ onImageUpload && /* @__PURE__ */ jsxs(Fragment, { children: [
25735
+ /* @__PURE__ */ jsx(
25736
+ "input",
25737
+ {
25738
+ ref: fileInputRef,
25739
+ type: "file",
25740
+ accept: "image/*",
25741
+ onChange: handleFileChange,
25742
+ style: { display: "none" }
25743
+ }
25744
+ ),
25745
+ /* @__PURE__ */ jsx(
25746
+ "button",
25747
+ {
25748
+ onClick: () => fileInputRef.current?.click(),
25749
+ style: {
25750
+ fontSize: "12px",
25751
+ fontWeight: 500,
25752
+ color: "#1165ef",
25753
+ background: "#ebf2ff",
25754
+ border: "1px solid #1165ef",
25755
+ borderRadius: "4px",
25756
+ padding: "4px 10px",
25757
+ cursor: "pointer",
25758
+ flexShrink: 0,
25759
+ transition: "background 100ms"
25760
+ },
25761
+ onMouseEnter: (e) => {
25762
+ e.currentTarget.style.background = "#dbeafe";
25763
+ },
25764
+ onMouseLeave: (e) => {
25765
+ e.currentTarget.style.background = "#ebf2ff";
25766
+ },
25767
+ children: "Upload"
25768
+ }
25769
+ )
25770
+ ] }),
25771
+ url && /* @__PURE__ */ jsx(
25772
+ "button",
24373
25773
  {
24374
- type: "text",
24375
- value,
24376
- onChange: (e) => onChange(e.target.value),
25774
+ onClick: onDeleteImage,
25775
+ title: `Remove ${label}`,
24377
25776
  style: {
24378
- width: "80px",
24379
- fontSize: "12px",
24380
- fontFamily: "monospace",
24381
- padding: "4px 8px",
24382
- border: "1px solid #e5e7eb",
25777
+ width: "24px",
25778
+ height: "24px",
25779
+ display: "flex",
25780
+ alignItems: "center",
25781
+ justifyContent: "center",
24383
25782
  borderRadius: "4px",
24384
- color: "#374151",
24385
- background: "#ffffff"
24386
- }
25783
+ border: "none",
25784
+ background: "transparent",
25785
+ cursor: "pointer",
25786
+ fontSize: "14px",
25787
+ fontWeight: 600,
25788
+ color: "#9ca3af",
25789
+ flexShrink: 0,
25790
+ lineHeight: 1,
25791
+ transition: "color 100ms, background 100ms"
25792
+ },
25793
+ onMouseEnter: (e) => {
25794
+ e.currentTarget.style.color = "#ef4444";
25795
+ e.currentTarget.style.background = "#fef2f2";
25796
+ },
25797
+ onMouseLeave: (e) => {
25798
+ e.currentTarget.style.color = "#9ca3af";
25799
+ e.currentTarget.style.background = "transparent";
25800
+ },
25801
+ children: "\u2715"
24387
25802
  }
24388
25803
  )
24389
25804
  ]
24390
25805
  }
24391
25806
  );
24392
25807
  }
24393
- var typographyGroups = [
24394
- {
24395
- label: "Global",
24396
- prefix: "--typo-global",
24397
- fields: [{ key: "--typo-global-font", label: "Font Family", type: "text" }]
24398
- },
24399
- ...["h1", "h2", "h3", "h4", "h5", "h6"].map((level) => ({
24400
- label: level.toUpperCase(),
24401
- prefix: `--typo-${level}`,
24402
- fields: [
24403
- { key: `--typo-${level}-font`, label: "Font", type: "text" },
24404
- { key: `--typo-${level}-size`, label: "Size", type: "text" },
24405
- { key: `--typo-${level}-size-mobile`, label: "Mobile Size", type: "text" },
24406
- { key: `--typo-${level}-weight`, label: "Weight", type: "text" },
24407
- { key: `--typo-${level}-spacing`, label: "Spacing", type: "text" },
24408
- { key: `--typo-${level}-line-height`, label: "Line Height", type: "text" }
24409
- ]
24410
- })),
24411
- ...["body-xl", "body-l", "body-m", "body-s", "body-xs"].map((level) => ({
24412
- label: level.replace("body-", "Body ").toUpperCase(),
24413
- prefix: `--typo-${level}`,
24414
- fields: [
24415
- { key: `--typo-${level}-font`, label: "Font", type: "text" },
24416
- { key: `--typo-${level}-size`, label: "Size", type: "text" },
24417
- { key: `--typo-${level}-weight`, label: "Weight", type: "text" },
24418
- { key: `--typo-${level}-spacing`, label: "Spacing", type: "text" },
24419
- { key: `--typo-${level}-line-height`, label: "Line Height", type: "text" }
24420
- ]
24421
- }))
25808
+
25809
+ // src/components/theme-drawer/components/font-config.ts
25810
+ var googleFontFamilies = {
25811
+ // Sans-Serif
25812
+ Inter: "Inter",
25813
+ Geist: "Geist",
25814
+ "Plus Jakarta Sans": "Plus+Jakarta+Sans",
25815
+ Poppins: "Poppins",
25816
+ "IBM Plex Sans": "IBM+Plex+Sans",
25817
+ Roboto: "Roboto",
25818
+ "Open Sans": "Open+Sans",
25819
+ "Noto Sans": "Noto+Sans",
25820
+ Montserrat: "Montserrat",
25821
+ Lato: "Lato",
25822
+ Raleway: "Raleway",
25823
+ "DM Sans": "DM+Sans",
25824
+ "Work Sans": "Work+Sans",
25825
+ Manrope: "Manrope",
25826
+ Outfit: "Outfit",
25827
+ "Source Sans 3": "Source+Sans+3",
25828
+ // Serif
25829
+ "Playfair Display": "Playfair+Display",
25830
+ Merriweather: "Merriweather",
25831
+ "Noto Serif": "Noto+Serif",
25832
+ "Libre Baskerville": "Libre+Baskerville",
25833
+ // Monospace
25834
+ "IBM Plex Mono": "IBM+Plex+Mono",
25835
+ "Courier Prime": "Courier+Prime",
25836
+ "Geist Mono": "Geist+Mono"
25837
+ };
25838
+ var loadedFonts = /* @__PURE__ */ new Set();
25839
+ function loadGoogleFont(fontName) {
25840
+ if (loadedFonts.has(fontName)) return;
25841
+ const fontFamily = googleFontFamilies[fontName];
25842
+ if (!fontFamily) return;
25843
+ const link = document.createElement("link");
25844
+ link.rel = "stylesheet";
25845
+ link.href = `https://fonts.googleapis.com/css2?family=${fontFamily}:wght@400;500;600;700&display=swap`;
25846
+ document.head.appendChild(link);
25847
+ loadedFonts.add(fontName);
25848
+ }
25849
+ var fontsPreloaded = false;
25850
+ function preloadAllFonts() {
25851
+ if (fontsPreloaded) return;
25852
+ Object.keys(googleFontFamilies).forEach((fontName) => {
25853
+ loadGoogleFont(fontName);
25854
+ });
25855
+ fontsPreloaded = true;
25856
+ }
25857
+ var fontOptions = [
25858
+ { value: "Courier Prime", label: "Courier Prime" },
25859
+ { value: "DM Sans", label: "DM Sans" },
25860
+ { value: "Geist", label: "Geist" },
25861
+ { value: "Geist Mono", label: "Geist Mono" },
25862
+ { value: "IBM Plex Mono", label: "IBM Plex Mono" },
25863
+ { value: "IBM Plex Sans", label: "IBM Plex Sans" },
25864
+ { value: "Inter", label: "Inter" },
25865
+ { value: "Lato", label: "Lato" },
25866
+ { value: "Libre Baskerville", label: "Libre Baskerville" },
25867
+ { value: "Manrope", label: "Manrope" },
25868
+ { value: "Merriweather", label: "Merriweather" },
25869
+ { value: "Montserrat", label: "Montserrat" },
25870
+ { value: "Noto Sans", label: "Noto Sans" },
25871
+ { value: "Noto Serif", label: "Noto Serif" },
25872
+ { value: "Open Sans", label: "Open Sans" },
25873
+ { value: "Outfit", label: "Outfit" },
25874
+ { value: "Playfair Display", label: "Playfair Display" },
25875
+ { value: "Plus Jakarta Sans", label: "Plus Jakarta Sans" },
25876
+ { value: "Poppins", label: "Poppins" },
25877
+ { value: "Raleway", label: "Raleway" },
25878
+ { value: "Roboto", label: "Roboto" },
25879
+ { value: "Source Sans 3", label: "Source Sans 3" },
25880
+ { value: "Work Sans", label: "Work Sans" }
25881
+ ];
25882
+ var fontWeightOptions = [
25883
+ { value: "400", label: "Regular (400)" },
25884
+ { value: "500", label: "Medium (500)" },
25885
+ { value: "600", label: "Semibold (600)" },
25886
+ { value: "700", label: "Bold (700)" }
25887
+ ];
25888
+ var typographyColorOptions = [
25889
+ { value: "var(--canvas-text)", label: "Text" },
25890
+ { value: "var(--canvas-text-muted)", label: "Text Muted" },
25891
+ { value: "var(--canvas-text-placeholder)", label: "Placeholder" },
25892
+ { value: "var(--canvas-primary)", label: "Primary" },
25893
+ { value: "var(--canvas-destructive)", label: "Destructive" }
25894
+ ];
25895
+ var generalPurposeStyles = [
25896
+ { prefix: "h1", label: "H1", description: "Hero headlines" },
25897
+ { prefix: "h2", label: "H2", description: "Major section headers" },
25898
+ { prefix: "h3", label: "H3", description: "Banner titles" },
25899
+ { prefix: "h4", label: "H4", description: "Page titles" },
25900
+ { prefix: "h5", label: "H5", description: "Large section headers" },
25901
+ { prefix: "h6", label: "H6", description: "Section titles" },
25902
+ { prefix: "body-xl", label: "Body XL", description: "Lead paragraphs" },
25903
+ { prefix: "body-l", label: "Body L", description: "Descriptions" },
25904
+ { prefix: "body-m", label: "Body M", description: "Standard body text" },
25905
+ { prefix: "body-s", label: "Body S", description: "Captions, metadata" },
25906
+ { prefix: "body-xs", label: "Body XS", description: "Fine print, labels" }
25907
+ ];
25908
+ var componentStyles = [
25909
+ { prefix: "menu-label", label: "Menu Label" },
25910
+ { prefix: "sidebar-label", label: "Sidebar Label" },
25911
+ { prefix: "sidebar-tab", label: "Sidebar Tab" },
25912
+ { prefix: "sidebar-subtab", label: "Sidebar Subtab" },
25913
+ { prefix: "header", label: "Header" },
25914
+ { prefix: "input-label", label: "Input Label" },
25915
+ { prefix: "button", label: "Button" }
24422
25916
  ];
24423
25917
  function TypographyPanel({ theme }) {
24424
- return /* @__PURE__ */ jsx("div", { "data-theme-drawer-panel": true, className: "flex flex-col gap-5 p-4", children: typographyGroups.map((group) => /* @__PURE__ */ jsx(TypoGroup, { group, theme }, group.prefix)) });
25918
+ useEffect(() => {
25919
+ preloadAllFonts();
25920
+ }, []);
25921
+ const globalFont = theme.variables["--typo-global-font"] || "Inter";
25922
+ return /* @__PURE__ */ jsxs("div", { "data-theme-drawer-panel": true, style: { padding: "16px" }, children: [
25923
+ /* @__PURE__ */ jsxs(
25924
+ "div",
25925
+ {
25926
+ style: {
25927
+ display: "flex",
25928
+ alignItems: "center",
25929
+ justifyContent: "space-between",
25930
+ padding: "12px",
25931
+ background: "#f9fafb",
25932
+ borderRadius: "8px",
25933
+ border: "1px solid #e5e7eb",
25934
+ marginBottom: "20px"
25935
+ },
25936
+ children: [
25937
+ /* @__PURE__ */ jsxs("div", { children: [
25938
+ /* @__PURE__ */ jsx(
25939
+ "div",
25940
+ {
25941
+ style: {
25942
+ fontSize: "13px",
25943
+ fontWeight: 600,
25944
+ color: "#374151"
25945
+ },
25946
+ children: "Global Font"
25947
+ }
25948
+ ),
25949
+ /* @__PURE__ */ jsx(
25950
+ "div",
25951
+ {
25952
+ style: {
25953
+ fontSize: "11px",
25954
+ color: "#6b7280",
25955
+ marginTop: "2px"
25956
+ },
25957
+ children: "Default font for all text styles"
25958
+ }
25959
+ )
25960
+ ] }),
25961
+ /* @__PURE__ */ jsx(
25962
+ "select",
25963
+ {
25964
+ value: globalFont,
25965
+ onChange: (e) => {
25966
+ const v = e.target.value;
25967
+ loadGoogleFont(v);
25968
+ theme.setVariable("--typo-global-font", v);
25969
+ },
25970
+ style: {
25971
+ height: "32px",
25972
+ fontSize: "12px",
25973
+ padding: "0 8px",
25974
+ border: "1px solid #e5e7eb",
25975
+ borderRadius: "6px",
25976
+ color: "#374151",
25977
+ background: "#ffffff",
25978
+ cursor: "pointer",
25979
+ maxWidth: "180px"
25980
+ },
25981
+ children: fontOptions.map((f) => /* @__PURE__ */ jsx(
25982
+ "option",
25983
+ {
25984
+ value: f.value,
25985
+ style: { fontFamily: f.value },
25986
+ children: f.label
25987
+ },
25988
+ f.value
25989
+ ))
25990
+ }
25991
+ )
25992
+ ]
25993
+ }
25994
+ ),
25995
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: "20px" }, children: [
25996
+ /* @__PURE__ */ jsx(
25997
+ "h3",
25998
+ {
25999
+ style: {
26000
+ fontSize: "11px",
26001
+ fontWeight: 600,
26002
+ color: "#6b7280",
26003
+ textTransform: "uppercase",
26004
+ letterSpacing: "0.05em",
26005
+ marginBottom: "4px"
26006
+ },
26007
+ children: "General Purpose"
26008
+ }
26009
+ ),
26010
+ /* @__PURE__ */ jsx(
26011
+ "p",
26012
+ {
26013
+ style: {
26014
+ fontSize: "11px",
26015
+ color: "#6b7280",
26016
+ marginBottom: "12px"
26017
+ },
26018
+ children: "Headings and body text used across the application."
26019
+ }
26020
+ ),
26021
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: generalPurposeStyles.map((s) => /* @__PURE__ */ jsx(
26022
+ TypographyRow,
26023
+ {
26024
+ config: s,
26025
+ theme,
26026
+ globalFont,
26027
+ hasMutedColor: true
26028
+ },
26029
+ s.prefix
26030
+ )) })
26031
+ ] }),
26032
+ /* @__PURE__ */ jsxs("div", { children: [
26033
+ /* @__PURE__ */ jsx(
26034
+ "h3",
26035
+ {
26036
+ style: {
26037
+ fontSize: "11px",
26038
+ fontWeight: 600,
26039
+ color: "#6b7280",
26040
+ textTransform: "uppercase",
26041
+ letterSpacing: "0.05em",
26042
+ marginBottom: "4px"
26043
+ },
26044
+ children: "Component-Specific"
26045
+ }
26046
+ ),
26047
+ /* @__PURE__ */ jsx(
26048
+ "p",
26049
+ {
26050
+ style: {
26051
+ fontSize: "11px",
26052
+ color: "#6b7280",
26053
+ marginBottom: "12px"
26054
+ },
26055
+ children: "Typography styles scoped to specific UI components."
26056
+ }
26057
+ ),
26058
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: componentStyles.map((s) => /* @__PURE__ */ jsx(
26059
+ TypographyRow,
26060
+ {
26061
+ config: s,
26062
+ theme,
26063
+ globalFont,
26064
+ hasMutedColor: false
26065
+ },
26066
+ s.prefix
26067
+ )) })
26068
+ ] })
26069
+ ] });
24425
26070
  }
24426
- function TypoGroup({
24427
- group,
24428
- theme
26071
+ function TypographyRow({
26072
+ config,
26073
+ theme,
26074
+ globalFont,
26075
+ hasMutedColor
24429
26076
  }) {
24430
- const [expanded, setExpanded] = React13__default.useState(false);
26077
+ const [expanded, setExpanded] = useState(false);
26078
+ const { prefix, label, description } = config;
26079
+ const varKey = (suffix) => `--typo-${prefix}-${suffix}`;
24431
26080
  return /* @__PURE__ */ jsxs(
24432
26081
  "div",
24433
26082
  {
@@ -24455,7 +26104,20 @@ function TypoGroup({
24455
26104
  color: "#374151"
24456
26105
  },
24457
26106
  children: [
24458
- /* @__PURE__ */ jsx("span", { children: group.label }),
26107
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "baseline", gap: "8px" }, children: [
26108
+ /* @__PURE__ */ jsx("span", { children: label }),
26109
+ description && /* @__PURE__ */ jsx(
26110
+ "span",
26111
+ {
26112
+ style: {
26113
+ fontSize: "11px",
26114
+ fontWeight: 400,
26115
+ color: "#6b7280"
26116
+ },
26117
+ children: description
26118
+ }
26119
+ )
26120
+ ] }),
24459
26121
  /* @__PURE__ */ jsx(
24460
26122
  "span",
24461
26123
  {
@@ -24471,69 +26133,332 @@ function TypoGroup({
24471
26133
  ]
24472
26134
  }
24473
26135
  ),
24474
- expanded && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", style: { padding: "10px 12px" }, children: [
24475
- group.fields.map((field) => /* @__PURE__ */ jsxs(
26136
+ expanded && /* @__PURE__ */ jsxs("div", { style: { padding: "12px" }, children: [
26137
+ /* @__PURE__ */ jsxs(
24476
26138
  "div",
24477
26139
  {
24478
26140
  style: {
24479
- display: "flex",
24480
- alignItems: "center",
24481
- gap: "8px"
26141
+ display: "grid",
26142
+ gridTemplateColumns: "1fr 1fr",
26143
+ gap: "8px",
26144
+ marginBottom: "8px"
24482
26145
  },
24483
26146
  children: [
24484
- /* @__PURE__ */ jsx(
24485
- "label",
24486
- {
24487
- style: {
24488
- fontSize: "12px",
24489
- color: "#6b7280",
24490
- width: "90px",
24491
- flexShrink: 0
24492
- },
24493
- children: field.label
24494
- }
24495
- ),
24496
- /* @__PURE__ */ jsx(
24497
- "input",
24498
- {
24499
- type: "text",
24500
- value: theme.variables[field.key] ?? "",
24501
- onChange: (e) => theme.setVariable(field.key, e.target.value),
24502
- placeholder: field.label,
24503
- style: {
24504
- flex: 1,
24505
- fontSize: "12px",
24506
- fontFamily: "monospace",
24507
- padding: "4px 8px",
24508
- border: "1px solid #e5e7eb",
24509
- borderRadius: "4px",
24510
- color: "#374151",
24511
- background: "#ffffff"
26147
+ /* @__PURE__ */ jsxs("div", { children: [
26148
+ /* @__PURE__ */ jsx(
26149
+ "label",
26150
+ {
26151
+ style: {
26152
+ display: "block",
26153
+ fontSize: "11px",
26154
+ color: "#6b7280",
26155
+ marginBottom: "4px"
26156
+ },
26157
+ children: "Font Family"
24512
26158
  }
24513
- }
24514
- )
26159
+ ),
26160
+ /* @__PURE__ */ jsxs(
26161
+ "select",
26162
+ {
26163
+ value: theme.variables[varKey("font")] ?? "",
26164
+ onChange: (e) => {
26165
+ const v = e.target.value;
26166
+ if (v) {
26167
+ loadGoogleFont(v);
26168
+ theme.setVariable(varKey("font"), v);
26169
+ } else {
26170
+ theme.setVariable(varKey("font"), "");
26171
+ }
26172
+ },
26173
+ style: {
26174
+ width: "100%",
26175
+ height: "30px",
26176
+ fontSize: "12px",
26177
+ padding: "0 6px",
26178
+ border: "1px solid #e5e7eb",
26179
+ borderRadius: "4px",
26180
+ color: "#374151",
26181
+ background: "#ffffff",
26182
+ cursor: "pointer"
26183
+ },
26184
+ children: [
26185
+ /* @__PURE__ */ jsxs("option", { value: "", style: { fontFamily: globalFont }, children: [
26186
+ "Use Global (",
26187
+ globalFont,
26188
+ ")"
26189
+ ] }),
26190
+ fontOptions.map((f) => /* @__PURE__ */ jsx(
26191
+ "option",
26192
+ {
26193
+ value: f.value,
26194
+ style: { fontFamily: f.value },
26195
+ children: f.label
26196
+ },
26197
+ f.value
26198
+ ))
26199
+ ]
26200
+ }
26201
+ )
26202
+ ] }),
26203
+ /* @__PURE__ */ jsxs("div", { children: [
26204
+ /* @__PURE__ */ jsx(
26205
+ "label",
26206
+ {
26207
+ style: {
26208
+ display: "block",
26209
+ fontSize: "11px",
26210
+ color: "#6b7280",
26211
+ marginBottom: "4px"
26212
+ },
26213
+ children: "Size"
26214
+ }
26215
+ ),
26216
+ /* @__PURE__ */ jsx(
26217
+ "input",
26218
+ {
26219
+ type: "text",
26220
+ value: theme.variables[varKey("size")] ?? "",
26221
+ onChange: (e) => theme.setVariable(varKey("size"), e.target.value),
26222
+ placeholder: "e.g. 16px",
26223
+ style: {
26224
+ width: "100%",
26225
+ height: "30px",
26226
+ fontSize: "12px",
26227
+ fontFamily: "monospace",
26228
+ padding: "0 8px",
26229
+ border: "1px solid #e5e7eb",
26230
+ borderRadius: "4px",
26231
+ color: "#374151",
26232
+ background: "#ffffff",
26233
+ boxSizing: "border-box"
26234
+ }
26235
+ }
26236
+ )
26237
+ ] })
24515
26238
  ]
24516
- },
24517
- field.key
24518
- )),
26239
+ }
26240
+ ),
24519
26241
  /* @__PURE__ */ jsxs(
24520
- "button",
26242
+ "div",
24521
26243
  {
24522
- onClick: () => theme.resetCategory(group.prefix),
24523
26244
  style: {
24524
- fontSize: "11px",
24525
- color: "#6b7280",
24526
- background: "none",
24527
- border: "none",
24528
- cursor: "pointer",
24529
- textAlign: "right",
24530
- padding: "2px 0"
26245
+ display: "grid",
26246
+ gridTemplateColumns: "1fr 1fr",
26247
+ gap: "8px",
26248
+ marginBottom: "8px"
26249
+ },
26250
+ children: [
26251
+ /* @__PURE__ */ jsxs("div", { children: [
26252
+ /* @__PURE__ */ jsx(
26253
+ "label",
26254
+ {
26255
+ style: {
26256
+ display: "block",
26257
+ fontSize: "11px",
26258
+ color: "#6b7280",
26259
+ marginBottom: "4px"
26260
+ },
26261
+ children: "Mobile Size"
26262
+ }
26263
+ ),
26264
+ /* @__PURE__ */ jsx(
26265
+ "input",
26266
+ {
26267
+ type: "text",
26268
+ value: theme.variables[varKey("size-mobile")] ?? "",
26269
+ onChange: (e) => theme.setVariable(varKey("size-mobile"), e.target.value),
26270
+ placeholder: "e.g. 14px",
26271
+ style: {
26272
+ width: "100%",
26273
+ height: "30px",
26274
+ fontSize: "12px",
26275
+ fontFamily: "monospace",
26276
+ padding: "0 8px",
26277
+ border: "1px solid #e5e7eb",
26278
+ borderRadius: "4px",
26279
+ color: "#374151",
26280
+ background: "#ffffff",
26281
+ boxSizing: "border-box"
26282
+ }
26283
+ }
26284
+ )
26285
+ ] }),
26286
+ /* @__PURE__ */ jsxs("div", { children: [
26287
+ /* @__PURE__ */ jsx(
26288
+ "label",
26289
+ {
26290
+ style: {
26291
+ display: "block",
26292
+ fontSize: "11px",
26293
+ color: "#6b7280",
26294
+ marginBottom: "4px"
26295
+ },
26296
+ children: "Weight"
26297
+ }
26298
+ ),
26299
+ /* @__PURE__ */ jsxs(
26300
+ "select",
26301
+ {
26302
+ value: theme.variables[varKey("weight")] ?? "",
26303
+ onChange: (e) => theme.setVariable(varKey("weight"), e.target.value),
26304
+ style: {
26305
+ width: "100%",
26306
+ height: "30px",
26307
+ fontSize: "12px",
26308
+ padding: "0 6px",
26309
+ border: "1px solid #e5e7eb",
26310
+ borderRadius: "4px",
26311
+ color: "#374151",
26312
+ background: "#ffffff",
26313
+ cursor: "pointer"
26314
+ },
26315
+ children: [
26316
+ /* @__PURE__ */ jsx("option", { value: "", children: "Default" }),
26317
+ fontWeightOptions.map((w) => /* @__PURE__ */ jsx("option", { value: w.value, children: w.label }, w.value))
26318
+ ]
26319
+ }
26320
+ )
26321
+ ] })
26322
+ ]
26323
+ }
26324
+ ),
26325
+ /* @__PURE__ */ jsxs(
26326
+ "div",
26327
+ {
26328
+ style: {
26329
+ display: "grid",
26330
+ gridTemplateColumns: "1fr 1fr",
26331
+ gap: "8px",
26332
+ marginBottom: "8px"
24531
26333
  },
24532
26334
  children: [
24533
- "Reset ",
24534
- group.label
26335
+ /* @__PURE__ */ jsxs("div", { children: [
26336
+ /* @__PURE__ */ jsx(
26337
+ "label",
26338
+ {
26339
+ style: {
26340
+ display: "block",
26341
+ fontSize: "11px",
26342
+ color: "#6b7280",
26343
+ marginBottom: "4px"
26344
+ },
26345
+ children: "Letter Spacing"
26346
+ }
26347
+ ),
26348
+ /* @__PURE__ */ jsx(
26349
+ "input",
26350
+ {
26351
+ type: "text",
26352
+ value: theme.variables[varKey("spacing")] ?? "",
26353
+ onChange: (e) => theme.setVariable(varKey("spacing"), e.target.value),
26354
+ placeholder: "e.g. -0.02em",
26355
+ style: {
26356
+ width: "100%",
26357
+ height: "30px",
26358
+ fontSize: "12px",
26359
+ fontFamily: "monospace",
26360
+ padding: "0 8px",
26361
+ border: "1px solid #e5e7eb",
26362
+ borderRadius: "4px",
26363
+ color: "#374151",
26364
+ background: "#ffffff",
26365
+ boxSizing: "border-box"
26366
+ }
26367
+ }
26368
+ )
26369
+ ] }),
26370
+ /* @__PURE__ */ jsxs("div", { children: [
26371
+ /* @__PURE__ */ jsx(
26372
+ "label",
26373
+ {
26374
+ style: {
26375
+ display: "block",
26376
+ fontSize: "11px",
26377
+ color: "#6b7280",
26378
+ marginBottom: "4px"
26379
+ },
26380
+ children: "Line Height"
26381
+ }
26382
+ ),
26383
+ /* @__PURE__ */ jsx(
26384
+ "input",
26385
+ {
26386
+ type: "text",
26387
+ value: theme.variables[varKey("line-height")] ?? "",
26388
+ onChange: (e) => theme.setVariable(varKey("line-height"), e.target.value),
26389
+ placeholder: "e.g. 1.5",
26390
+ style: {
26391
+ width: "100%",
26392
+ height: "30px",
26393
+ fontSize: "12px",
26394
+ fontFamily: "monospace",
26395
+ padding: "0 8px",
26396
+ border: "1px solid #e5e7eb",
26397
+ borderRadius: "4px",
26398
+ color: "#374151",
26399
+ background: "#ffffff",
26400
+ boxSizing: "border-box"
26401
+ }
26402
+ }
26403
+ )
26404
+ ] })
24535
26405
  ]
24536
26406
  }
26407
+ ),
26408
+ /* @__PURE__ */ jsx(
26409
+ ColorInputRow,
26410
+ {
26411
+ label: "Color",
26412
+ value: theme.variables[varKey("color")] ?? "var(--canvas-text)",
26413
+ onChange: (val) => theme.setVariable(varKey("color"), val),
26414
+ variableOptions: typographyColorOptions
26415
+ }
26416
+ ),
26417
+ hasMutedColor && /* @__PURE__ */ jsx(
26418
+ ColorInputRow,
26419
+ {
26420
+ label: "Muted Color",
26421
+ value: theme.variables[varKey("color-muted")] ?? "var(--canvas-text-muted)",
26422
+ onChange: (val) => theme.setVariable(varKey("color-muted"), val),
26423
+ variableOptions: typographyColorOptions
26424
+ }
26425
+ ),
26426
+ /* @__PURE__ */ jsx(
26427
+ "div",
26428
+ {
26429
+ style: {
26430
+ display: "flex",
26431
+ justifyContent: "flex-end",
26432
+ marginTop: "8px"
26433
+ },
26434
+ children: /* @__PURE__ */ jsxs(
26435
+ "button",
26436
+ {
26437
+ onClick: () => theme.resetCategory("--typo-" + prefix),
26438
+ style: {
26439
+ fontSize: "11px",
26440
+ color: "#6b7280",
26441
+ background: "none",
26442
+ border: "none",
26443
+ cursor: "pointer",
26444
+ padding: "4px 8px",
26445
+ borderRadius: "4px"
26446
+ },
26447
+ onMouseEnter: (e) => {
26448
+ e.currentTarget.style.color = "#374151";
26449
+ e.currentTarget.style.background = "#f3f4f6";
26450
+ },
26451
+ onMouseLeave: (e) => {
26452
+ e.currentTarget.style.color = "#6b7280";
26453
+ e.currentTarget.style.background = "none";
26454
+ },
26455
+ children: [
26456
+ "Reset ",
26457
+ label
26458
+ ]
26459
+ }
26460
+ )
26461
+ }
24537
26462
  )
24538
26463
  ] })
24539
26464
  ]
@@ -24552,15 +26477,24 @@ var sizeFields = [
24552
26477
  { suffix: "-px", label: "Padding X" },
24553
26478
  { suffix: "-radius", label: "Radius" },
24554
26479
  { suffix: "-font-weight", label: "Weight" },
24555
- { suffix: "-letter-spacing", label: "Spacing" }
26480
+ { suffix: "-letter-spacing", label: "Spacing" },
26481
+ { suffix: "-font-family", label: "Font Family" }
24556
26482
  ];
24557
- var colorFields = [
24558
- { suffix: "-bg", label: "Background" },
24559
- { suffix: "-text", label: "Text" },
24560
- { suffix: "-border", label: "Border" },
24561
- { suffix: "-bg-hover", label: "Bg Hover" },
24562
- { suffix: "-text-hover", label: "Text Hover" },
24563
- { suffix: "-border-hover", label: "Border Hover" }
26483
+ var buttonColorVariableOptions = [
26484
+ { value: "var(--canvas-primary)", label: "Primary" },
26485
+ { value: "var(--canvas-primary-dark)", label: "Primary Dark" },
26486
+ { value: "var(--canvas-primary-foreground)", label: "Primary Text" },
26487
+ { value: "var(--canvas-background)", label: "Background" },
26488
+ { value: "var(--canvas-surface)", label: "Surface" },
26489
+ { value: "var(--canvas-surface-hover)", label: "Surface Hover" },
26490
+ { value: "var(--canvas-surface-brand)", label: "Brand Surface" },
26491
+ { value: "var(--canvas-outline-bg)", label: "Outline Bg" },
26492
+ { value: "var(--canvas-text)", label: "Text" },
26493
+ { value: "var(--canvas-text-muted)", label: "Text Muted" },
26494
+ { value: "var(--canvas-border)", label: "Border" },
26495
+ { value: "var(--canvas-border-input)", label: "Input Border" },
26496
+ { value: "var(--canvas-destructive)", label: "Destructive" },
26497
+ { value: "var(--canvas-transparent)", label: "Transparent" }
24564
26498
  ];
24565
26499
  function ButtonsPanel({ theme }) {
24566
26500
  return /* @__PURE__ */ jsxs("div", { "data-theme-drawer-panel": true, className: "flex flex-col gap-5 p-4", children: [
@@ -24569,9 +26503,9 @@ function ButtonsPanel({ theme }) {
24569
26503
  "h3",
24570
26504
  {
24571
26505
  style: {
24572
- fontSize: "13px",
26506
+ fontSize: "11px",
24573
26507
  fontWeight: 600,
24574
- color: "#374151",
26508
+ color: "#6b7280",
24575
26509
  textTransform: "uppercase",
24576
26510
  letterSpacing: "0.05em",
24577
26511
  marginBottom: "12px"
@@ -24582,21 +26516,75 @@ function ButtonsPanel({ theme }) {
24582
26516
  buttonSizeConfigs.map((size) => /* @__PURE__ */ jsx(SizeGroup, { size, theme }, size.id))
24583
26517
  ] }),
24584
26518
  /* @__PURE__ */ jsxs("div", { children: [
24585
- /* @__PURE__ */ jsx(
24586
- "h3",
26519
+ /* @__PURE__ */ jsxs(
26520
+ "div",
24587
26521
  {
24588
26522
  style: {
24589
- fontSize: "13px",
24590
- fontWeight: 600,
24591
- color: "#374151",
24592
- textTransform: "uppercase",
24593
- letterSpacing: "0.05em",
26523
+ display: "flex",
26524
+ alignItems: "center",
26525
+ justifyContent: "space-between",
24594
26526
  marginBottom: "12px"
24595
26527
  },
24596
- children: "Button Colors"
26528
+ children: [
26529
+ /* @__PURE__ */ jsx(
26530
+ "h3",
26531
+ {
26532
+ style: {
26533
+ fontSize: "11px",
26534
+ fontWeight: 600,
26535
+ color: "#6b7280",
26536
+ textTransform: "uppercase",
26537
+ letterSpacing: "0.05em"
26538
+ },
26539
+ children: "Color Styles"
26540
+ }
26541
+ ),
26542
+ /* @__PURE__ */ jsx(
26543
+ "button",
26544
+ {
26545
+ onClick: theme.addCustomButtonStyle,
26546
+ style: {
26547
+ fontSize: "11px",
26548
+ fontWeight: 500,
26549
+ color: "#1165ef",
26550
+ background: "none",
26551
+ border: "1px solid #e5e7eb",
26552
+ cursor: "pointer",
26553
+ padding: "4px 10px",
26554
+ borderRadius: "4px",
26555
+ display: "flex",
26556
+ alignItems: "center",
26557
+ gap: "4px"
26558
+ },
26559
+ children: "+ Add Style"
26560
+ }
26561
+ )
26562
+ ]
24597
26563
  }
24598
26564
  ),
24599
- defaultButtonColorStyles.map((style) => /* @__PURE__ */ jsx(ColorGroup, { style, theme }, style.id))
26565
+ defaultButtonColorStyles.map((style) => /* @__PURE__ */ jsx(ButtonColorGroup, { style, theme }, style.id)),
26566
+ theme.customButtonStyles.length > 0 && /* @__PURE__ */ jsxs("div", { style: { marginTop: "16px", paddingTop: "16px", borderTop: "1px solid #e5e7eb" }, children: [
26567
+ /* @__PURE__ */ jsx(
26568
+ "h4",
26569
+ {
26570
+ style: {
26571
+ fontSize: "11px",
26572
+ fontWeight: 600,
26573
+ color: "#6b7280",
26574
+ marginBottom: "12px"
26575
+ },
26576
+ children: "Custom Styles"
26577
+ }
26578
+ ),
26579
+ theme.customButtonStyles.map((style) => /* @__PURE__ */ jsx(
26580
+ CustomButtonColorGroup,
26581
+ {
26582
+ style,
26583
+ theme
26584
+ },
26585
+ style.id
26586
+ ))
26587
+ ] })
24600
26588
  ] })
24601
26589
  ] });
24602
26590
  }
@@ -24692,7 +26680,18 @@ function SizeGroup({
24692
26680
  children: field.label
24693
26681
  }
24694
26682
  ),
24695
- /* @__PURE__ */ jsx(
26683
+ field.suffix === "-font-family" ? /* @__PURE__ */ jsx(
26684
+ "span",
26685
+ {
26686
+ style: {
26687
+ flex: 1,
26688
+ fontSize: "12px",
26689
+ color: "#9ca3af",
26690
+ fontStyle: "italic"
26691
+ },
26692
+ children: "Uses Button Text style"
26693
+ }
26694
+ ) : /* @__PURE__ */ jsx(
24696
26695
  "input",
24697
26696
  {
24698
26697
  type: "text",
@@ -24720,7 +26719,7 @@ function SizeGroup({
24720
26719
  }
24721
26720
  );
24722
26721
  }
24723
- function ColorGroup({
26722
+ function ButtonColorGroup({
24724
26723
  style,
24725
26724
  theme
24726
26725
  }) {
@@ -24770,52 +26769,287 @@ function ColorGroup({
24770
26769
  ]
24771
26770
  }
24772
26771
  ),
24773
- expanded && /* @__PURE__ */ jsx("div", { style: { padding: "10px 12px" }, className: "flex flex-col gap-2", children: colorFields.map((field) => {
24774
- const key = `${prefix}${field.suffix}`;
24775
- return /* @__PURE__ */ jsxs(
24776
- "div",
24777
- {
24778
- style: {
24779
- display: "flex",
24780
- alignItems: "center",
24781
- gap: "8px"
24782
- },
24783
- children: [
26772
+ expanded && /* @__PURE__ */ jsxs("div", { style: { padding: "10px 12px" }, className: "flex flex-col gap-1", children: [
26773
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: "8px" }, children: [
26774
+ /* @__PURE__ */ jsx(
26775
+ "span",
26776
+ {
26777
+ style: {
26778
+ fontSize: "11px",
26779
+ fontWeight: 600,
26780
+ color: "#9ca3af",
26781
+ textTransform: "uppercase",
26782
+ letterSpacing: "0.05em"
26783
+ },
26784
+ children: "Normal"
26785
+ }
26786
+ ),
26787
+ /* @__PURE__ */ jsx(
26788
+ ColorInputRow,
26789
+ {
26790
+ label: "Background",
26791
+ value: theme.variables[`${prefix}-bg`] ?? "",
26792
+ onChange: (val) => theme.setVariable(`${prefix}-bg`, val),
26793
+ variableOptions: buttonColorVariableOptions
26794
+ }
26795
+ ),
26796
+ /* @__PURE__ */ jsx(
26797
+ ColorInputRow,
26798
+ {
26799
+ label: "Text",
26800
+ value: theme.variables[`${prefix}-text`] ?? "",
26801
+ onChange: (val) => theme.setVariable(`${prefix}-text`, val),
26802
+ variableOptions: buttonColorVariableOptions
26803
+ }
26804
+ ),
26805
+ /* @__PURE__ */ jsx(
26806
+ ColorInputRow,
26807
+ {
26808
+ label: "Border",
26809
+ value: theme.variables[`${prefix}-border`] ?? "",
26810
+ onChange: (val) => theme.setVariable(`${prefix}-border`, val),
26811
+ variableOptions: buttonColorVariableOptions
26812
+ }
26813
+ )
26814
+ ] }),
26815
+ /* @__PURE__ */ jsxs("div", { children: [
26816
+ /* @__PURE__ */ jsx(
26817
+ "span",
26818
+ {
26819
+ style: {
26820
+ fontSize: "11px",
26821
+ fontWeight: 600,
26822
+ color: "#9ca3af",
26823
+ textTransform: "uppercase",
26824
+ letterSpacing: "0.05em"
26825
+ },
26826
+ children: "Hover"
26827
+ }
26828
+ ),
26829
+ /* @__PURE__ */ jsx(
26830
+ ColorInputRow,
26831
+ {
26832
+ label: "Background",
26833
+ value: theme.variables[`${prefix}-bg-hover`] ?? "",
26834
+ onChange: (val) => theme.setVariable(`${prefix}-bg-hover`, val),
26835
+ variableOptions: buttonColorVariableOptions
26836
+ }
26837
+ ),
26838
+ /* @__PURE__ */ jsx(
26839
+ ColorInputRow,
26840
+ {
26841
+ label: "Text",
26842
+ value: theme.variables[`${prefix}-text-hover`] ?? "",
26843
+ onChange: (val) => theme.setVariable(`${prefix}-text-hover`, val),
26844
+ variableOptions: buttonColorVariableOptions
26845
+ }
26846
+ ),
26847
+ /* @__PURE__ */ jsx(
26848
+ ColorInputRow,
26849
+ {
26850
+ label: "Border",
26851
+ value: theme.variables[`${prefix}-border-hover`] ?? "",
26852
+ onChange: (val) => theme.setVariable(`${prefix}-border-hover`, val),
26853
+ variableOptions: buttonColorVariableOptions
26854
+ }
26855
+ )
26856
+ ] })
26857
+ ] })
26858
+ ]
26859
+ }
26860
+ );
26861
+ }
26862
+ function CustomButtonColorGroup({
26863
+ style,
26864
+ theme
26865
+ }) {
26866
+ const [expanded, setExpanded] = React13__default.useState(false);
26867
+ const [editing, setEditing] = React13__default.useState(false);
26868
+ return /* @__PURE__ */ jsxs(
26869
+ "div",
26870
+ {
26871
+ style: {
26872
+ border: "1px solid #e5e7eb",
26873
+ borderRadius: "8px",
26874
+ marginBottom: "8px",
26875
+ overflow: "hidden"
26876
+ },
26877
+ children: [
26878
+ /* @__PURE__ */ jsxs(
26879
+ "div",
26880
+ {
26881
+ style: {
26882
+ display: "flex",
26883
+ alignItems: "center",
26884
+ justifyContent: "space-between",
26885
+ width: "100%",
26886
+ padding: "10px 12px",
26887
+ background: "#f9fafb"
26888
+ },
26889
+ children: [
26890
+ editing ? /* @__PURE__ */ jsx(
26891
+ "input",
26892
+ {
26893
+ type: "text",
26894
+ value: style.label,
26895
+ onChange: (e) => theme.updateCustomButtonStyle(style.id, { label: e.target.value }),
26896
+ onBlur: () => setEditing(false),
26897
+ onKeyDown: (e) => e.key === "Enter" && setEditing(false),
26898
+ autoFocus: true,
26899
+ style: {
26900
+ fontSize: "13px",
26901
+ fontWeight: 600,
26902
+ color: "#374151",
26903
+ border: "1px solid #e5e7eb",
26904
+ borderRadius: "4px",
26905
+ padding: "2px 6px",
26906
+ background: "#ffffff",
26907
+ flex: 1
26908
+ }
26909
+ }
26910
+ ) : /* @__PURE__ */ jsx(
26911
+ "button",
26912
+ {
26913
+ onClick: () => setExpanded(!expanded),
26914
+ style: {
26915
+ flex: 1,
26916
+ textAlign: "left",
26917
+ fontSize: "13px",
26918
+ fontWeight: 600,
26919
+ color: "#374151",
26920
+ background: "none",
26921
+ border: "none",
26922
+ cursor: "pointer"
26923
+ },
26924
+ onDoubleClick: (e) => {
26925
+ e.stopPropagation();
26926
+ setEditing(true);
26927
+ },
26928
+ children: style.label
26929
+ }
26930
+ ),
26931
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
24784
26932
  /* @__PURE__ */ jsx(
24785
- "label",
26933
+ "button",
24786
26934
  {
26935
+ onClick: () => theme.deleteCustomButtonStyle(style.id),
24787
26936
  style: {
24788
- fontSize: "12px",
24789
- color: "#6b7280",
24790
- width: "80px",
24791
- flexShrink: 0
26937
+ fontSize: "11px",
26938
+ color: "#dc2626",
26939
+ background: "none",
26940
+ border: "none",
26941
+ cursor: "pointer",
26942
+ padding: "2px 6px"
24792
26943
  },
24793
- children: field.label
26944
+ children: "Delete"
24794
26945
  }
24795
26946
  ),
24796
26947
  /* @__PURE__ */ jsx(
24797
- "input",
26948
+ "button",
24798
26949
  {
24799
- type: "text",
24800
- value: theme.variables[key] ?? "",
24801
- onChange: (e) => theme.setVariable(key, e.target.value),
26950
+ onClick: () => setExpanded(!expanded),
24802
26951
  style: {
24803
- flex: 1,
24804
- fontSize: "12px",
24805
- fontFamily: "monospace",
24806
- padding: "4px 8px",
24807
- border: "1px solid #e5e7eb",
24808
- borderRadius: "4px",
24809
- color: "#374151",
24810
- background: "#ffffff"
24811
- }
26952
+ fontSize: "11px",
26953
+ color: "#9ca3af",
26954
+ background: "none",
26955
+ border: "none",
26956
+ cursor: "pointer",
26957
+ transform: expanded ? "rotate(180deg)" : "rotate(0deg)",
26958
+ transition: "transform 150ms"
26959
+ },
26960
+ children: "\u25BC"
24812
26961
  }
24813
26962
  )
24814
- ]
24815
- },
24816
- key
24817
- );
24818
- }) })
26963
+ ] })
26964
+ ]
26965
+ }
26966
+ ),
26967
+ expanded && /* @__PURE__ */ jsxs("div", { style: { padding: "10px 12px" }, className: "flex flex-col gap-1", children: [
26968
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: "8px" }, children: [
26969
+ /* @__PURE__ */ jsx(
26970
+ "span",
26971
+ {
26972
+ style: {
26973
+ fontSize: "11px",
26974
+ fontWeight: 600,
26975
+ color: "#9ca3af",
26976
+ textTransform: "uppercase",
26977
+ letterSpacing: "0.05em"
26978
+ },
26979
+ children: "Normal"
26980
+ }
26981
+ ),
26982
+ /* @__PURE__ */ jsx(
26983
+ ColorInputRow,
26984
+ {
26985
+ label: "Background",
26986
+ value: style.bg,
26987
+ onChange: (val) => theme.updateCustomButtonStyle(style.id, { bg: val }),
26988
+ variableOptions: buttonColorVariableOptions
26989
+ }
26990
+ ),
26991
+ /* @__PURE__ */ jsx(
26992
+ ColorInputRow,
26993
+ {
26994
+ label: "Text",
26995
+ value: style.text,
26996
+ onChange: (val) => theme.updateCustomButtonStyle(style.id, { text: val }),
26997
+ variableOptions: buttonColorVariableOptions
26998
+ }
26999
+ ),
27000
+ /* @__PURE__ */ jsx(
27001
+ ColorInputRow,
27002
+ {
27003
+ label: "Border",
27004
+ value: style.border,
27005
+ onChange: (val) => theme.updateCustomButtonStyle(style.id, { border: val }),
27006
+ variableOptions: buttonColorVariableOptions
27007
+ }
27008
+ )
27009
+ ] }),
27010
+ /* @__PURE__ */ jsxs("div", { children: [
27011
+ /* @__PURE__ */ jsx(
27012
+ "span",
27013
+ {
27014
+ style: {
27015
+ fontSize: "11px",
27016
+ fontWeight: 600,
27017
+ color: "#9ca3af",
27018
+ textTransform: "uppercase",
27019
+ letterSpacing: "0.05em"
27020
+ },
27021
+ children: "Hover"
27022
+ }
27023
+ ),
27024
+ /* @__PURE__ */ jsx(
27025
+ ColorInputRow,
27026
+ {
27027
+ label: "Background",
27028
+ value: style.bgHover,
27029
+ onChange: (val) => theme.updateCustomButtonStyle(style.id, { bgHover: val }),
27030
+ variableOptions: buttonColorVariableOptions
27031
+ }
27032
+ ),
27033
+ /* @__PURE__ */ jsx(
27034
+ ColorInputRow,
27035
+ {
27036
+ label: "Text",
27037
+ value: style.textHover,
27038
+ onChange: (val) => theme.updateCustomButtonStyle(style.id, { textHover: val }),
27039
+ variableOptions: buttonColorVariableOptions
27040
+ }
27041
+ ),
27042
+ /* @__PURE__ */ jsx(
27043
+ ColorInputRow,
27044
+ {
27045
+ label: "Border",
27046
+ value: style.borderHover,
27047
+ onChange: (val) => theme.updateCustomButtonStyle(style.id, { borderHover: val }),
27048
+ variableOptions: buttonColorVariableOptions
27049
+ }
27050
+ )
27051
+ ] })
27052
+ ] })
24819
27053
  ]
24820
27054
  }
24821
27055
  );
@@ -25221,6 +27455,7 @@ function ExportPanel({ theme }) {
25221
27455
  }
25222
27456
  var panelConfig = [
25223
27457
  { id: "colors", label: "Colors" },
27458
+ { id: "images", label: "Images" },
25224
27459
  { id: "typography", label: "Type" },
25225
27460
  { id: "buttons", label: "Buttons" },
25226
27461
  { id: "inputs", label: "Inputs" },
@@ -25257,7 +27492,8 @@ var drawerStyles = {
25257
27492
  background: "#f9fafb",
25258
27493
  padding: "0",
25259
27494
  gap: "0",
25260
- flexShrink: 0
27495
+ flexShrink: 0,
27496
+ overflowX: "auto"
25261
27497
  },
25262
27498
  tab: (active) => ({
25263
27499
  flex: 1,
@@ -25270,8 +27506,18 @@ var drawerStyles = {
25270
27506
  borderBottom: active ? "2px solid #1f2937" : "2px solid transparent",
25271
27507
  cursor: "pointer",
25272
27508
  transition: "color 150ms, border-color 150ms",
25273
- textAlign: "center"
25274
- })
27509
+ textAlign: "center",
27510
+ whiteSpace: "nowrap"
27511
+ }),
27512
+ footer: {
27513
+ display: "flex",
27514
+ flexDirection: "column",
27515
+ gap: "8px",
27516
+ padding: "12px 16px",
27517
+ borderTop: "1px solid #e5e7eb",
27518
+ flexShrink: 0,
27519
+ background: "#ffffff"
27520
+ }
25275
27521
  };
25276
27522
  function PaletteIcon6() {
25277
27523
  return /* @__PURE__ */ jsxs(
@@ -25301,20 +27547,66 @@ function ThemeDrawer({
25301
27547
  defaultOpen = false,
25302
27548
  panels: enabledPanels,
25303
27549
  onThemeChange,
27550
+ onBrandingChange,
27551
+ onImagesChange,
27552
+ onImageUpload,
25304
27553
  initialOverrides,
25305
- storageKey
27554
+ storageKey,
27555
+ title = "Design Variables",
27556
+ width = 464
25306
27557
  }) {
25307
27558
  if (devOnly && process.env.NODE_ENV === "production") {
25308
27559
  return null;
25309
27560
  }
25310
27561
  const [open, setOpen] = useState(defaultOpen);
25311
27562
  const [activeTab, setActiveTab] = useState("colors");
27563
+ const [resetConfirmOpen, setResetConfirmOpen] = useState(false);
25312
27564
  const theme = useThemeState({
25313
27565
  storageKey,
25314
27566
  initialOverrides,
25315
- onThemeChange
27567
+ onThemeChange,
27568
+ onBrandingChange,
27569
+ onImagesChange
25316
27570
  });
27571
+ const { setPreviewBranding, setPreviewImages } = usePreviewBranding();
27572
+ useEffect(() => {
27573
+ if (open) {
27574
+ setPreviewBranding(theme.branding);
27575
+ }
27576
+ }, [open, theme.branding, setPreviewBranding]);
27577
+ useEffect(() => {
27578
+ if (open) {
27579
+ setPreviewImages(theme.images);
27580
+ }
27581
+ }, [open, theme.images, setPreviewImages]);
27582
+ const handleOpenChange = useCallback(
27583
+ (newOpen) => {
27584
+ if (!newOpen) {
27585
+ if (theme.isDirty) {
27586
+ theme.discard();
27587
+ }
27588
+ setPreviewBranding(null);
27589
+ setPreviewImages(null);
27590
+ setResetConfirmOpen(false);
27591
+ }
27592
+ setOpen(newOpen);
27593
+ },
27594
+ [theme, setPreviewBranding, setPreviewImages]
27595
+ );
27596
+ const handleSave = useCallback(() => {
27597
+ theme.save();
27598
+ }, [theme]);
27599
+ const handleDiscard = useCallback(() => {
27600
+ theme.discard();
27601
+ }, [theme]);
27602
+ const handleReset = useCallback(() => {
27603
+ theme.resetAll();
27604
+ setPreviewBranding(null);
27605
+ setPreviewImages(null);
27606
+ setResetConfirmOpen(false);
27607
+ }, [theme, setPreviewBranding, setPreviewImages]);
25317
27608
  const activePanels = enabledPanels ? panelConfig.filter((p) => enabledPanels.includes(p.id)) : panelConfig;
27609
+ const showFooter = theme.isDirty || resetConfirmOpen;
25318
27610
  return /* @__PURE__ */ jsxs(Fragment, { children: [
25319
27611
  !open && /* @__PURE__ */ jsx(
25320
27612
  "button",
@@ -25333,13 +27625,17 @@ function ThemeDrawer({
25333
27625
  children: /* @__PURE__ */ jsx(PaletteIcon6, {})
25334
27626
  }
25335
27627
  ),
25336
- /* @__PURE__ */ jsx(Sheet, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(
27628
+ /* @__PURE__ */ jsx(Sheet, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs(
25337
27629
  SheetContent,
25338
27630
  {
25339
27631
  side: "right",
25340
27632
  "data-theme-drawer": true,
25341
- className: "!p-0 !gap-0 !w-[380px] !max-w-[380px]",
25342
- style: drawerStyles.container,
27633
+ className: `!p-0 !gap-0 !w-[${width}px] !max-w-[${width}px]`,
27634
+ style: {
27635
+ ...drawerStyles.container,
27636
+ width: `${width}px`,
27637
+ maxWidth: `${width}px`
27638
+ },
25343
27639
  children: [
25344
27640
  /* @__PURE__ */ jsx(
25345
27641
  SheetHeader,
@@ -25360,7 +27656,7 @@ function ThemeDrawer({
25360
27656
  color: "#1f2937",
25361
27657
  fontFamily: drawerStyles.container.fontFamily
25362
27658
  },
25363
- children: "Theme Editor"
27659
+ children: title
25364
27660
  }
25365
27661
  ),
25366
27662
  /* @__PURE__ */ jsx(
@@ -25372,7 +27668,7 @@ function ThemeDrawer({
25372
27668
  marginTop: "2px",
25373
27669
  fontFamily: drawerStyles.container.fontFamily
25374
27670
  },
25375
- children: "Customize your design system"
27671
+ children: theme.unsavedChangesCount > 0 ? `${theme.unsavedChangesCount} unsaved change${theme.unsavedChangesCount !== 1 ? "s" : ""}` : "Customize your design system"
25376
27672
  }
25377
27673
  )
25378
27674
  ] })
@@ -25387,12 +27683,158 @@ function ThemeDrawer({
25387
27683
  },
25388
27684
  panel.id
25389
27685
  )) }),
25390
- /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1 overflow-hidden", style: { height: "calc(100vh - 140px)" }, children: /* @__PURE__ */ jsxs("div", { style: drawerStyles.container, children: [
25391
- activeTab === "colors" && /* @__PURE__ */ jsx(ColorsPanel, { theme }),
25392
- activeTab === "typography" && /* @__PURE__ */ jsx(TypographyPanel, { theme }),
25393
- activeTab === "buttons" && /* @__PURE__ */ jsx(ButtonsPanel, { theme }),
25394
- activeTab === "inputs" && /* @__PURE__ */ jsx(InputsPanel, { theme }),
25395
- activeTab === "export" && /* @__PURE__ */ jsx(ExportPanel, { theme })
27686
+ /* @__PURE__ */ jsx(
27687
+ ScrollArea,
27688
+ {
27689
+ className: "flex-1 overflow-hidden",
27690
+ style: { height: `calc(100vh - ${showFooter ? 200 : 150}px)` },
27691
+ children: /* @__PURE__ */ jsxs("div", { style: drawerStyles.container, children: [
27692
+ activeTab === "colors" && /* @__PURE__ */ jsx(ColorsPanel, { theme }),
27693
+ activeTab === "images" && /* @__PURE__ */ jsx(ImagesPanel, { theme, onImageUpload }),
27694
+ activeTab === "typography" && /* @__PURE__ */ jsx(TypographyPanel, { theme }),
27695
+ activeTab === "buttons" && /* @__PURE__ */ jsx(ButtonsPanel, { theme }),
27696
+ activeTab === "inputs" && /* @__PURE__ */ jsx(InputsPanel, { theme }),
27697
+ activeTab === "export" && /* @__PURE__ */ jsx(ExportPanel, { theme })
27698
+ ] })
27699
+ }
27700
+ ),
27701
+ showFooter && /* @__PURE__ */ jsx("div", { style: drawerStyles.footer, children: resetConfirmOpen ? /* @__PURE__ */ jsxs(
27702
+ "div",
27703
+ {
27704
+ style: {
27705
+ display: "flex",
27706
+ flexDirection: "column",
27707
+ gap: "8px",
27708
+ width: "100%"
27709
+ },
27710
+ children: [
27711
+ /* @__PURE__ */ jsx(
27712
+ "span",
27713
+ {
27714
+ style: {
27715
+ fontSize: "13px",
27716
+ color: "#374151",
27717
+ textAlign: "center"
27718
+ },
27719
+ children: "Reset all settings to defaults?"
27720
+ }
27721
+ ),
27722
+ /* @__PURE__ */ jsxs(
27723
+ "div",
27724
+ {
27725
+ style: {
27726
+ display: "flex",
27727
+ gap: "8px",
27728
+ justifyContent: "center"
27729
+ },
27730
+ children: [
27731
+ /* @__PURE__ */ jsx(
27732
+ "button",
27733
+ {
27734
+ onClick: () => setResetConfirmOpen(false),
27735
+ style: {
27736
+ fontSize: "13px",
27737
+ fontWeight: 500,
27738
+ color: "#374151",
27739
+ background: "#ffffff",
27740
+ border: "1px solid #e5e7eb",
27741
+ cursor: "pointer",
27742
+ padding: "6px 16px",
27743
+ borderRadius: "6px"
27744
+ },
27745
+ children: "Cancel"
27746
+ }
27747
+ ),
27748
+ /* @__PURE__ */ jsx(
27749
+ "button",
27750
+ {
27751
+ onClick: handleReset,
27752
+ style: {
27753
+ fontSize: "13px",
27754
+ fontWeight: 500,
27755
+ color: "#ffffff",
27756
+ background: "#dc2626",
27757
+ border: "1px solid #dc2626",
27758
+ cursor: "pointer",
27759
+ padding: "6px 16px",
27760
+ borderRadius: "6px"
27761
+ },
27762
+ children: "Reset All"
27763
+ }
27764
+ )
27765
+ ]
27766
+ }
27767
+ )
27768
+ ]
27769
+ }
27770
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
27771
+ /* @__PURE__ */ jsxs(
27772
+ "div",
27773
+ {
27774
+ style: {
27775
+ display: "flex",
27776
+ gap: "8px",
27777
+ width: "100%"
27778
+ },
27779
+ children: [
27780
+ /* @__PURE__ */ jsx(
27781
+ "button",
27782
+ {
27783
+ onClick: handleDiscard,
27784
+ style: {
27785
+ flex: 1,
27786
+ fontSize: "13px",
27787
+ fontWeight: 500,
27788
+ color: "#374151",
27789
+ background: "#ffffff",
27790
+ border: "1px solid #e5e7eb",
27791
+ cursor: "pointer",
27792
+ padding: "8px 16px",
27793
+ borderRadius: "6px"
27794
+ },
27795
+ children: "Discard"
27796
+ }
27797
+ ),
27798
+ /* @__PURE__ */ jsx(
27799
+ "button",
27800
+ {
27801
+ onClick: handleSave,
27802
+ style: {
27803
+ flex: 1,
27804
+ fontSize: "13px",
27805
+ fontWeight: 600,
27806
+ color: "#ffffff",
27807
+ background: "#1f2937",
27808
+ border: "1px solid #1f2937",
27809
+ cursor: "pointer",
27810
+ padding: "8px 16px",
27811
+ borderRadius: "6px"
27812
+ },
27813
+ children: "Save"
27814
+ }
27815
+ )
27816
+ ]
27817
+ }
27818
+ ),
27819
+ /* @__PURE__ */ jsx(
27820
+ "button",
27821
+ {
27822
+ onClick: () => setResetConfirmOpen(true),
27823
+ style: {
27824
+ fontSize: "12px",
27825
+ fontWeight: 400,
27826
+ color: "#9ca3af",
27827
+ background: "none",
27828
+ border: "none",
27829
+ cursor: "pointer",
27830
+ padding: "2px 0",
27831
+ textAlign: "center",
27832
+ textDecoration: "underline",
27833
+ textUnderlineOffset: "2px"
27834
+ },
27835
+ children: "Reset all to defaults"
27836
+ }
27837
+ )
25396
27838
  ] }) })
25397
27839
  ]
25398
27840
  }
@@ -25419,6 +27861,6 @@ function getTopLevelScreens(allScreens) {
25419
27861
  return allScreens.filter((s) => !s.parentId);
25420
27862
  }
25421
27863
 
25422
- export { AccountSettingsShell, ActivityFeed, Avatar, AvatarFallback, AvatarImage, BadgesCard, BlogCards, BottomInputChatWidget, Button, Calendar, CanvasItem, CategoryGrid, CenteredHero, ChatBubble, ChatDateSeparator, ChatInput, ChatMessageList, Checkbox, CheckboxWithLabel, CircularProgressBar, CircularProgressBarList, ComponentPalette, ComponentSearch, ContentDropzone, ContentWithImage, CoreValuesGrid, CreditCardDisplay, CtaBanner, CustomComponentHelper, DashboardHeader, DashboardShell, DateInput, DescriptionCard, DestinationCards, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DonutChartWidget, DoubleSidebar, DoubleSidebarShell, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, FaqAccordion, FaqsTable, FeatureWithImage, FeaturedNewsCards, FeaturedPlaces, FeaturesComparison, FileUploader, FilterPopover, FixedColumnDataTable, FlairBanner, FooterNavbar, FormGroup, GallerySection, GradientBanner, GraphMetricTilesDemo, GridTilesList, Header, HeroDarkCentered, HeroDarkWithImage, HeroFullwidthImage, HeroSection, HowItWorks, IconSidebar, IconSidebarShell, ImageFeedWithNestedComments, ImageUploader, InfoCard, Input, Label2 as Label, LargeImageLabelsList, Sidebar2 as LayoutSidebar, LineChartWidget, LineTabs, LinksCard, Loader, LoginBrandingPanel, MenuSection, MenufocusTemplate, MessengerInput, MessengerSidebar, MetricCard, MetricCardsRow, MetricListCard, MetricsSection, MobileBottomNav, MobileMenuShell, MonthlyCalendarWidget, MultiselectCheckboxField, MultiselectTags, MultistepProgressBarShell, MultistepShell, MultistepSidebarShell, NestedCommentsTable, NestedDataTable, OfficeLocations, PageHeaderSection, Pagination, ParticipantList, PersonaCard, PersonaGrid, PillTabs, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PortfolioCard, PreviewBrandingContext, PricingCards, PricingCta, ProfileCard, ProfileGridTilesList, ProfileImageUploader, ProgressBar, ProgressMetricCard, ProjectContextShell, PromptChipsRow, PromptTemplate, RadioGroup2 as RadioGroup, RadioGroupItem, RangeInput, ReviewsGrid, ReviewsTable, ScreenFlowchart, ScreenPromptBuilder, ScreenPromptTemplate, ScrollArea, ScrollBar, SearchBar, SearchBarShell, SearchSidebar, Searchbox, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SelectablePills, Separator3 as Separator, SettingsListRow, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarNav, SidebarProfileCard, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, SkillsCard, Slider, SlideshowGridTiles, SocialFeed, SocialProof, StandardDataTable, StandardListWithImage, StandardPageShell, StatsCard, StepTracker, Switch, Tabs, TabsContent, TabsList, TabsTrigger, TeamCardsGrid, TeamCircularGrid, TestimonialCarousel, TextInput, Textarea, ThemeContext, ThemeDrawer, ThemeProvider, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TwoColumnWidgets, Typography, UpvotingPostsTable, VerticalHowItWorks, VerticalMultistepShell, VerticalStepTracker, VideoChatControls, VideoContentSection, VideoPlaylistCard, VideoPlaylistItem, WebcamPreview, YouTubePlayer, accountTabs, allColorVariables, blocks, broadcastCSSVariables, buttonVariants, canvasBlocks, cn, colorVariables, defaultBranding, defaultButtonColorStyles, defaultButtonColors, defaultButtonSizes, defaultColors, defaultCustomButtonStyles, defaultDoubleSidebarSections, defaultIconNavItems, defaultImages, defaultInputSizes, defaultProgressBarSteps, defaultSteps, defaultSupportLinks, defaultTypography, defaultVerticalSteps, getChildScreens, getScreenUrl, getTopLevelScreens, groupModalDrawerBlocks, layoutPrimitives, layoutShells, marketingBlocks, pageTemplates, pricingBlocks, removeCSSVariables, setCSSVariable, setCSSVariables, setupCSSVariableListener, useCSSVariableSync, useIsMobile, usePreviewBranding, useSidebar, useThemeBrandAssets, useThemeBranding, useThemeImages, videoBlocks };
27864
+ export { AccountSettingsShell, ActivityFeed, Avatar, AvatarFallback, AvatarImage, BadgesCard, BlogCards, BottomInputChatWidget, Button, Calendar, CanvasItem, CategoryGrid, CenteredHero, ChatBubble, ChatDateSeparator, ChatInput, ChatMessageList, Checkbox, CheckboxWithLabel, CircularProgressBar, CircularProgressBarList, ColorInputRow, ComponentPalette, ComponentSearch, ContentDropzone, ContentWithImage, CoreValuesGrid, CreditCardDisplay, CtaBanner, CustomComponentHelper, DashboardHeader, DashboardShell, DateInput, DescriptionCard, DestinationCards, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DonutChartWidget, DoubleSidebar, DoubleSidebarShell, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, FaqAccordion, FaqsTable, FeatureWithImage, FeaturedNewsCards, FeaturedPlaces, FeaturesComparison, FileUploader, FilterPopover, FixedColumnDataTable, FlairBanner, FooterNavbar, FormGroup, GallerySection, GradientBanner, GraphMetricTilesDemo, GridTilesList, Header, HeroDarkCentered, HeroDarkWithImage, HeroFullwidthImage, HeroSection, HowItWorks, HslColorPicker, IconSidebar, IconSidebarShell, ImageFeedWithNestedComments, ImageUploader, InfoCard, Input, Label2 as Label, LargeImageLabelsList, Sidebar2 as LayoutSidebar, LineChartWidget, LineTabs, LinksCard, Loader, LoginBrandingPanel, MenuSection, MenufocusTemplate, MessengerInput, MessengerSidebar, MetricCard, MetricCardsRow, MetricListCard, MetricsSection, MobileBottomNav, MobileMenuShell, MonthlyCalendarWidget, MultiselectCheckboxField, MultiselectTags, MultistepProgressBarShell, MultistepShell, MultistepSidebarShell, NestedCommentsTable, NestedDataTable, OfficeLocations, PageHeaderSection, Pagination, ParticipantList, PersonaCard, PersonaGrid, PillTabs, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PortfolioCard, PreviewBrandingContext, PricingCards, PricingCta, ProfileCard, ProfileGridTilesList, ProfileImageUploader, ProgressBar, ProgressMetricCard, ProjectContextShell, PromptChipsRow, PromptTemplate, RadioGroup2 as RadioGroup, RadioGroupItem, RangeInput, ReviewsGrid, ReviewsTable, ScreenFlowchart, ScreenPromptBuilder, ScreenPromptTemplate, ScrollArea, ScrollBar, SearchBar, SearchBarShell, SearchSidebar, Searchbox, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SelectablePills, Separator3 as Separator, SettingsListRow, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarNav, SidebarProfileCard, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, SkillsCard, Slider, SlideshowGridTiles, SocialFeed, SocialProof, StandardDataTable, StandardListWithImage, StandardPageShell, StatsCard, StepTracker, Switch, Tabs, TabsContent, TabsList, TabsTrigger, TeamCardsGrid, TeamCircularGrid, TestimonialCarousel, TextInput, Textarea, ThemeContext, ThemeDrawer, ThemeProvider, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TwoColumnWidgets, Typography, UpvotingPostsTable, VerticalHowItWorks, VerticalMultistepShell, VerticalStepTracker, VideoChatControls, VideoContentSection, VideoPlaylistCard, VideoPlaylistItem, WebcamPreview, YouTubePlayer, accountTabs, allColorVariables, blocks, broadcastCSSVariables, buttonVariants, canvasBlocks, cn, colorVariables, defaultBranding, defaultButtonColorStyles, defaultButtonColors, defaultButtonSizes, defaultColors, defaultCustomButtonStyles, defaultDoubleSidebarSections, defaultIconNavItems, defaultImages, defaultInputSizes, defaultProgressBarSteps, defaultSteps, defaultSupportLinks, defaultTypography, defaultVerticalSteps, getChildScreens, getScreenUrl, getTopLevelScreens, groupModalDrawerBlocks, layoutPrimitives, layoutShells, marketingBlocks, pageTemplates, pricingBlocks, removeCSSVariables, setCSSVariable, setCSSVariables, setupCSSVariableListener, useCSSVariableSync, useIsMobile, usePreviewBranding, useSidebar, useThemeBrandAssets, useThemeBranding, useThemeImages, videoBlocks };
25423
27865
  //# sourceMappingURL=index.js.map
25424
27866
  //# sourceMappingURL=index.js.map