diff --git a/configurator/src/App.svelte b/configurator/src/App.svelte index e855442f..12738160 100644 --- a/configurator/src/App.svelte +++ b/configurator/src/App.svelte @@ -8,7 +8,7 @@ import PreviewPanel from './components/shell/PreviewPanel.svelte'; import DomainPanel from './components/DomainPanel.svelte'; import { fa } from './lib/codec'; - import { loadInitialOverrides, injectLivePreview, saveOverrides } from './lib/persistence'; + import { loadInitialOverrides, injectLivePreview, saveOverrides, hasWpBoot } from './lib/persistence'; import { domainOf } from './lib/domains'; import tokensRaw from './data/api-index.generated.json'; import CommandPalette from './components/CommandPalette.svelte'; @@ -31,6 +31,15 @@ return map; } + // Embedded hosts (e.g. the WP admin page) mount us into a sized container in + // normal document flow, not the document body — w-screen/h-screen would then + // size to the viewport while still being offset by the host's own layout + // chrome, overflowing past its right edge. Standalone keeps viewport units + // since it owns the whole page. Uses hasWpBoot() (any host), not + // isEmbedded() (REST persistence specifically) — a host can mount us + // without configuring REST. + const embedded = hasWpBoot(); + // Core state let overrides = $state>(loadInitialOverrides()); let past = $state[]>([]); @@ -232,7 +241,7 @@ }); -
+
string }[] = [ + { label: "Base", expr: (k) => `var(--sf-color-${k})` }, + { label: "Subtle", expr: (k) => `var(--sf-color-${k}-subtle)` }, + { label: "Muted", expr: (k) => `var(--sf-color-${k}-muted)` }, + { label: "Strong", expr: (k) => `var(--sf-color-${k}-strong)` }, + ]; + const ALL_SOURCES: ColorSource[] = [...BRAND_SOURCES, ...STATUS_SOURCES]; // Live semantic-color preview shown at the very top of the panel. Each tile @@ -439,6 +450,16 @@ } +{#snippet swatchTip(name: string)} + + +{/snippet} +
@@ -489,7 +510,9 @@ {#if showBrandSources}

- OKLCH source values — all 200+ derived color steps are computed automatically. + OKLCH source values — all 200+ derived color steps are computed automatically. Tints (50–400) mix toward Base + (the "Surface" color) and shades (600–950) mix toward Text (driven by Neutral) — so editing Base or Neutral below + will shift every family's tints/shades too. That's expected, not a bug.

{#each BRAND_PAIRS as [light, dark] (light.name)} @@ -534,10 +557,10 @@ {#each SWATCH_STEPS as step (step)} {@const resolved = paletteSwatch(light.colorKey, lightSrcVal, step, lSurface, lText)}
+ >{@render swatchTip(`${light.colorKey}-${step}`)}
{/each}
@@ -547,10 +570,10 @@ {#each SWATCH_STEPS as step (step)} {@const resolved = paletteSwatch(light.colorKey, darkSrcVal, step, dSurface, dText)}
+ >{@render swatchTip(`${light.colorKey}-${step}`)}
{/each} @@ -558,6 +581,8 @@ {#if light.colorKey === "base"}

Absolute lightness ramp — each step pins L and inherits chroma + hue from the source. Not the brand mix curve. + Light and dark use the same L per step, so at the default near-zero chroma the two rows look almost + identical — add chroma above to see them diverge by hue.

{/if} {/if} @@ -708,29 +733,37 @@ Dark: auto-derived ({derivedDark}) {/if} - +
- {#each [ - ["L", "light", sourceValue(light), getLightSurface(), getLightText()], - ["D", "dark", isAutoMode - ? deriveDarkFromLight(sourceValue(light), light.colorKey) - : (dark ? (sourceValue(dark)) : (sourceValue(light))), getDarkSurface(), getDarkText()] - ] as [tag, side, srcVal, sfc, txt] (tag)} +
+ +
+ {#each STATUS_VARIANTS as v (v.label)} + {v.label} + {/each} +
+
+ {#each [["L", "light"], ["D", "dark"]] as [tag, side] (tag)}
{tag}
- {#each SWATCH_STEPS as step (step)} - {@const resolved = computePaletteSwatch(srcVal as string, step, sfc as string, txt as string)} + {#each STATUS_VARIANTS as v (v.label)} + {@const resolved = paintTheme(v.expr(light.colorKey), side as "light" | "dark", "")}
+ title={`${light.colorKey}-${v.label.toLowerCase()} (${side}) — ${resolved}`} + >{@render swatchTip(`${light.colorKey}-${v.label.toLowerCase()}`)}
{/each}
{/each} +

+ Status colors don't ride the brand mix curve — only the resolved color plus subtle/muted alpha washes and + a strong shade are derived. There's no -50…-950 ramp for success/warning/info/danger. +

{/each} @@ -899,10 +932,10 @@
{Math.round(val)}
+ >{@render swatchTip(`primary-${step}`)}
{step} {/each} @@ -938,10 +971,10 @@ {#each SWATCH_STEPS as step (step)} {@const swatch = computePaletteSwatch(miniSrc, step, _miniSurface, _miniText)}
+ >{@render swatchTip(`${colorKey}-${step}`)} {/each} diff --git a/configurator/src/lib/persistence.ts b/configurator/src/lib/persistence.ts index 29449e7f..ea5e2c16 100644 --- a/configurator/src/lib/persistence.ts +++ b/configurator/src/lib/persistence.ts @@ -184,6 +184,16 @@ export function isEmbedded(): boolean { return Boolean(wpBoot()?.rest?.url); } +/** + * Whether a host (e.g. the WP admin page) mounted us into its own container, + * regardless of whether REST persistence is configured. This is the same + * boundary loadInitialOverrides() uses, and the one layout sizing needs — + * a host can supply window.slashedApp without `rest` per its typing. + */ +export function hasWpBoot(): boolean { + return Boolean(wpBoot()); +} + export function loadInitialOverrides(): Record { if (typeof window === "undefined") return {};