diff --git a/badges/badge-optimal.json b/badges/badge-optimal.json
index 18209ea4..38f8d927 100644
--- a/badges/badge-optimal.json
+++ b/badges/badge-optimal.json
@@ -1,7 +1,7 @@
{
"schemaVersion": 1,
"label": "optimal",
- "message": "17.6 kB gzip",
+ "message": "37.0 kB gzip",
"color": "brightgreen",
"namedLogo": "css3"
}
diff --git a/configurator/src/components/inputs/SliderRow.svelte b/configurator/src/components/inputs/SliderRow.svelte
index 363639c7..35a6a730 100644
--- a/configurator/src/components/inputs/SliderRow.svelte
+++ b/configurator/src/components/inputs/SliderRow.svelte
@@ -1,8 +1,11 @@
-
{label}
- {#if overridden}
-
+ {#if label}
+
{label}
+ {:else}
+
{/if}
+
+ {#if rawDefault && onRawSet}
+
+ {/if}
+ {#if overridden}
+
+ {/if}
+
-
+
+ {#if showRaw && rawDefault}
+
{ isEditing = true; }}
+ onblur={() => { isEditing = false; }}
+ oninput={(e) => {
+ rawDraft = (e.target as HTMLInputElement).value;
+ const v = rawDraft.trim();
+ if (!v) {
+ onReset();
+ } else if (onRawSet) {
+ onRawSet(v);
+ }
+ }}
+ class="w-full bg-white/5 border border-white/10 rounded px-2 py-1.5 text-[11px] font-mono text-slate-300 placeholder:text-slate-500 focus:outline-none focus:border-indigo-500"
+ />
+ {:else}
+
+ {#if rawDefault && !overridden}
+
default: {rawDefault}
+ {/if}
+ {/if}
+
{#if help}
{help}
{/if}
diff --git a/configurator/src/components/panels/BordersPanel.svelte b/configurator/src/components/panels/BordersPanel.svelte
index b4adda51..d7f2fcc8 100644
--- a/configurator/src/components/panels/BordersPanel.svelte
+++ b/configurator/src/components/panels/BordersPanel.svelte
@@ -15,24 +15,24 @@
const BORDER_STYLES = ["solid", "dashed", "dotted"];
const RADIUS_STEPS = ["xs", "s", "m", "l", "xl", "2xl", "full"];
- const BASE_RADII: Record
= { xs: 2, s: 4, m: 6, l: 10, xl: 14, "2xl": 20, full: 9999 };
+ const BASE_RADII: Record = { xs: 2, s: 4, m: 8, l: 12, xl: 16, "2xl": 24, full: 9999 };
- const RADIUS_FINE: Array<{ step: string; name: string; default: number; max: number; step_size: number }> = [
- { step: "xs", name: "--sf-radius-xs", default: 2, max: 16, step_size: 0.5 },
- { step: "s", name: "--sf-radius-s", default: 4, max: 24, step_size: 0.5 },
- { step: "m", name: "--sf-radius-m", default: 6, max: 32, step_size: 1 },
- { step: "l", name: "--sf-radius-l", default: 10, max: 48, step_size: 1 },
- { step: "xl", name: "--sf-radius-xl", default: 14, max: 64, step_size: 1 },
- { step: "2xl", name: "--sf-radius-2xl", default: 20, max: 80, step_size: 2 },
+ const RADIUS_FINE: Array<{ step: string; name: string; default: number; max: number; step_size: number; rawDefault: string }> = [
+ { step: "xs", name: "--sf-radius-xs", default: 2, max: 16, step_size: 0.5, rawDefault: "calc(2px * var(--sf-radius-scale))" },
+ { step: "s", name: "--sf-radius-s", default: 4, max: 24, step_size: 0.5, rawDefault: "calc(4px * var(--sf-radius-scale))" },
+ { step: "m", name: "--sf-radius-m", default: 8, max: 32, step_size: 1, rawDefault: "calc(8px * var(--sf-radius-scale))" },
+ { step: "l", name: "--sf-radius-l", default: 12, max: 48, step_size: 1, rawDefault: "calc(12px * var(--sf-radius-scale))" },
+ { step: "xl", name: "--sf-radius-xl", default: 16, max: 64, step_size: 1, rawDefault: "calc(16px * var(--sf-radius-scale))" },
+ { step: "2xl", name: "--sf-radius-2xl", default: 24, max: 80, step_size: 2, rawDefault: "calc(24px * var(--sf-radius-scale))" },
];
const COMPONENT_TOKENS = [
- { label: "Button radius", token: "--sf-button-radius", unit: "rem", min: 0, max: 2, step: 0.05, default: 0.375, help: "--sf-button-radius" },
- { label: "Button padding block", token: "--sf-button-padding-block", unit: "rem", min: 0, max: 1, step: 0.025, default: 0.375, help: "--sf-button-padding-block" },
- { label: "Button padding inline", token: "--sf-button-padding-inline", unit: "rem", min: 0, max: 2, step: 0.025, default: 0.875, help: "--sf-button-padding-inline" },
- { label: "Field radius", token: "--sf-field-radius", unit: "rem", min: 0, max: 2, step: 0.05, default: 0.375, help: "--sf-field-radius" },
- { label: "Field padding block", token: "--sf-field-padding-block", unit: "rem", min: 0, max: 1, step: 0.025, default: 0.375, help: "--sf-field-padding-block" },
- { label: "Field padding inline", token: "--sf-field-padding-inline", unit: "rem", min: 0, max: 2, step: 0.025, default: 0.75, help: "--sf-field-padding-inline" },
+ { label: "Button radius", token: "--sf-btn-radius", unit: "rem", min: 0, max: 2, step: 0.05, default: 0.5, rawDefault: "var(--sf-radius-m)", help: "--sf-btn-radius" },
+ { label: "Button padding block", token: "--sf-btn-padding-block", unit: "rem", min: 0, max: 1, step: 0.025, default: 0.375, rawDefault: "var(--sf-space-xs)", help: "--sf-btn-padding-block" },
+ { label: "Button padding inline", token: "--sf-btn-padding-inline", unit: "rem", min: 0, max: 2, step: 0.025, default: 1, rawDefault: "var(--sf-space-m)", help: "--sf-btn-padding-inline" },
+ { label: "Field radius", token: "--sf-field-radius", unit: "rem", min: 0, max: 2, step: 0.05, default: 0.5, rawDefault: "var(--sf-radius-m)", help: "--sf-field-radius" },
+ { label: "Field padding block", token: "--sf-field-padding-block", unit: "rem", min: 0, max: 1, step: 0.025, default: 0.375, rawDefault: "var(--sf-space-xs)", help: "--sf-field-padding-block" },
+ { label: "Field padding inline", token: "--sf-field-padding-inline", unit: "rem", min: 0, max: 2, step: 0.025, default: 0.75, rawDefault: "var(--sf-space-s)", help: "--sf-field-padding-inline" },
];
const knobs = KNOBS_BY_DOMAIN["borders"] ?? [];
@@ -58,7 +58,7 @@
let focusWidth = $derived(parseNum(overrides["--sf-focus-ring-width"], 2, "px"));
let focusOffset = $derived(parseNum(overrides["--sf-focus-ring-offset"], 2, "px"));
let dividerWidth = $derived(parseNum(overrides["--sf-divider-width"]?.replace("px",""), 1));
- let dividerGap = $derived(parseNum(overrides["--sf-divider-gap"]?.replace("rem",""), 1));
+ let dividerGap = $derived(parseNum(overrides["--sf-divider-gap"]?.replace("rem",""), 1)); // ~1rem ≈ var(--sf-space-m) at default scale
let borderColor = $derived(overrides["--sf-color-border"] ?? "");
let borderStyle = $derived(overrides["--sf-border-style"] ?? "solid");
let focusRingColor = $derived(overrides["--sf-focus-ring-color"] ?? "");
@@ -71,13 +71,15 @@
function getRadiusValue(r: typeof RADIUS_FINE[0]): number {
const raw = overrides[r.name];
if (!raw) return r.default;
- return parseFloat(raw);
+ if (/^(var|calc|clamp)\(/.test(raw.trim())) return r.default;
+ return parseFloat(raw) || r.default;
}
function getComponentVal(t: typeof COMPONENT_TOKENS[0]): number {
const raw = overrides[t.token];
if (!raw) return t.default;
- return parseFloat(raw);
+ if (/^(var|calc|clamp)\(/.test(raw.trim())) return t.default;
+ return parseFloat(raw) || t.default;
}
@@ -254,6 +256,9 @@
overridden={"--sf-divider-width" in overrides}
onChange={(v) => onSet("--sf-divider-width", `${v}px`)}
onReset={() => onReset("--sf-divider-width")}
+ rawDefault="var(--sf-border-width-1)"
+ currentRaw={overrides["--sf-divider-width"]}
+ onRawSet={(v) => onSet("--sf-divider-width", v)}
/>
onSet("--sf-divider-gap", `${v}rem`)}
onReset={() => onReset("--sf-divider-gap")}
+ rawDefault="var(--sf-space-m)"
+ currentRaw={overrides["--sf-divider-gap"]}
+ onRawSet={(v) => onSet("--sf-divider-gap", v)}
/>
{/if}
@@ -363,6 +371,9 @@
overridden={r.name in overrides}
onChange={(v) => onSet(r.name, `${v}px`)}
onReset={() => onReset(r.name)}
+ rawDefault={r.rawDefault}
+ currentRaw={overrides[r.name]}
+ onRawSet={(v) => onSet(r.name, v)}
/>
{/each}
@@ -419,6 +430,9 @@
overridden={t.token in overrides}
onChange={(v) => onSet(t.token, `${v}${t.unit}`)}
onReset={() => onReset(t.token)}
+ rawDefault={t.rawDefault}
+ currentRaw={overrides[t.token]}
+ onRawSet={(v) => onSet(t.token, v)}
/>
{/each}
diff --git a/configurator/src/components/panels/LayoutPanel.svelte b/configurator/src/components/panels/LayoutPanel.svelte
index b526e292..89b8f2c7 100644
--- a/configurator/src/components/panels/LayoutPanel.svelte
+++ b/configurator/src/components/panels/LayoutPanel.svelte
@@ -169,6 +169,9 @@
overridden={"--sf-center-max" in overrides}
onChange={(v) => onSet("--sf-center-max", `${v}rem`)}
onReset={() => onReset("--sf-center-max")}
+ rawDefault="var(--sf-container-default)"
+ currentRaw={overrides["--sf-center-max"]}
+ onRawSet={(v) => onSet("--sf-center-max", v)}
/>
onSet("--sf-center-gutter", `${v}rem`)}
onReset={() => onReset("--sf-center-gutter")}
+ rawDefault="var(--sf-gutter)"
+ currentRaw={overrides["--sf-center-gutter"]}
+ onRawSet={(v) => onSet("--sf-center-gutter", v)}
/>
{/if}
@@ -307,6 +313,9 @@
overridden={"--sf-sticky-offset-mobile" in overrides}
onChange={(v) => onSet("--sf-sticky-offset-mobile", `${v}rem`)}
onReset={() => onReset("--sf-sticky-offset-mobile")}
+ rawDefault="var(--sf-header-height-mobile)"
+ currentRaw={overrides["--sf-sticky-offset-mobile"]}
+ onRawSet={(v) => onSet("--sf-sticky-offset-mobile", v)}
/>
@@ -316,6 +325,9 @@
overridden={"--sf-sticky-offset-desktop" in overrides}
onChange={(v) => onSet("--sf-sticky-offset-desktop", `${v}rem`)}
onReset={() => onReset("--sf-sticky-offset-desktop")}
+ rawDefault="var(--sf-header-height-desktop)"
+ currentRaw={overrides["--sf-sticky-offset-desktop"]}
+ onRawSet={(v) => onSet("--sf-sticky-offset-desktop", v)}
/>
@@ -552,6 +564,9 @@
overridden={"--sf-imposter-margin" in overrides}
onChange={(v) => onSet("--sf-imposter-margin", `${v}rem`)}
onReset={() => onReset("--sf-imposter-margin")}
+ rawDefault="var(--sf-space-m)"
+ currentRaw={overrides["--sf-imposter-margin"]}
+ onRawSet={(v) => onSet("--sf-imposter-margin", v)}
/>
@@ -564,6 +579,9 @@
overridden={"--sf-content-width" in overrides}
onChange={(v) => onSet("--sf-content-width", `${v}rem`)}
onReset={() => onReset("--sf-content-width")}
+ rawDefault="var(--sf-container-default)"
+ currentRaw={overrides["--sf-content-width"]}
+ onRawSet={(v) => onSet("--sf-content-width", v)}
/>
onSet("--sf-breakout-width", `${v}rem`)}
onReset={() => onReset("--sf-breakout-width")}
+ rawDefault="var(--sf-container-wide)"
+ currentRaw={overrides["--sf-breakout-width"]}
+ onRawSet={(v) => onSet("--sf-breakout-width", v)}
/>
@@ -583,6 +604,9 @@
overridden={"--sf-alternate-inner-gap" in overrides}
onChange={(v) => onSet("--sf-alternate-inner-gap", `${v}rem`)}
onReset={() => onReset("--sf-alternate-inner-gap")}
+ rawDefault="var(--sf-gap)"
+ currentRaw={overrides["--sf-alternate-inner-gap"]}
+ onRawSet={(v) => onSet("--sf-alternate-inner-gap", v)}
/>
diff --git a/configurator/src/components/panels/SpacingPanel.svelte b/configurator/src/components/panels/SpacingPanel.svelte
index 61fb7d28..cc754e16 100644
--- a/configurator/src/components/panels/SpacingPanel.svelte
+++ b/configurator/src/components/panels/SpacingPanel.svelte
@@ -86,6 +86,9 @@
overridden={"--sf-gap" in overrides}
onChange={(v) => onSet("--sf-gap", `${v}rem`)}
onReset={() => onReset("--sf-gap")}
+ rawDefault="var(--sf-space-m)"
+ currentRaw={overrides["--sf-gap"]}
+ onRawSet={(v) => onSet("--sf-gap", v)}
/>
onSet("--sf-content-gap", `${v}rem`)}
onReset={() => onReset("--sf-content-gap")}
+ rawDefault="var(--sf-space-s)"
+ currentRaw={overrides["--sf-content-gap"]}
+ onRawSet={(v) => onSet("--sf-content-gap", v)}
/>
onSet("--sf-gutter", `${v}rem`)}
onReset={() => onReset("--sf-gutter")}
+ rawDefault="var(--sf-space-l)"
+ currentRaw={overrides["--sf-gutter"]}
+ onRawSet={(v) => onSet("--sf-gutter", v)}
/>
{/if}