feat(glass): make the dev tuner theme-aware (Sync to current theme)

The tuner writes inline vars (global), so its sliders always showed the dark/
backdrop-on baseline even when viewing light. Add a 'Sync to current theme'
button that clears the inline overrides, reads the live theme-driven values into
the sliders, and headers the Copy-CSS export for the active scope (:root for
dark, html[data-theme="light"] for light) — so light-theme glass can be dialled
in and exported straight into the right block.
This commit is contained in:
npeter83 2026-07-13 00:02:04 +02:00
parent 914cd79db9
commit a4f42e6ea0

View file

@ -104,6 +104,7 @@ export default function GlassTuner() {
const [open, setOpen] = useState<boolean>(() => initial.open ?? true);
const [tab, setTab] = useState<"glass" | "palette">("glass");
const [copied, setCopied] = useState(false);
const [themeTick, setThemeTick] = useState(0);
// Seed the colour pickers from the live scheme for display (without forcing them onto <html>).
const [swatches, setSwatches] = useState<Record<string, string>>({});
@ -173,8 +174,25 @@ export default function GlassTuner() {
setSwatches(sw);
}
// Export only what differs from the shipped defaults, ready to paste into index.css.
// Re-read the LIVE, theme-driven glass values into the sliders (clearing inline overrides first),
// so the panel reflects whatever theme is active — switch to light, hit this, and the opacity
// sliders show the light-theme values (index.css `html[data-theme="light"]`) ready to tune.
function syncToTheme() {
ALL.forEach((s) => root().style.removeProperty(s.k));
const next: Record<string, number> = { ...vars };
ALL.forEach((s) => {
const n = parseFloat(readVar(s.k));
if (!Number.isNaN(n)) next[s.k] = n;
});
setVars(next);
persist({ vars: {} });
setThemeTick((t) => t + 1);
}
// Export the values that differ from the baseline, headered for the active theme's scope so a
// light-theme tune pastes into the right block.
const cssOut = useMemo(() => {
void themeTick; // re-run when the active theme is re-synced
const lines: string[] = [];
ALL.forEach((s) => {
if (vars[s.k] !== s.def) lines.push(` ${s.k}: ${vars[s.k]}${s.unit};`);
@ -182,8 +200,9 @@ export default function GlassTuner() {
PALETTE.forEach((p) => {
if (palette[p.k]) lines.push(` ${p.k}: ${palette[p.k]};`);
});
return lines.length ? `:root {\n${lines.join("\n")}\n}` : "/* all values at defaults */";
}, [vars, palette]);
const scope = root().dataset.theme === "light" ? 'html[data-theme="light"]' : ":root";
return lines.length ? `${scope} {\n${lines.join("\n")}\n}` : "/* all values at defaults */";
}, [vars, palette, themeTick]);
function copy() {
navigator.clipboard?.writeText(cssOut).then(() => {
@ -293,6 +312,13 @@ export default function GlassTuner() {
{/* Export */}
<div className="flex flex-col gap-1.5 pt-1 border-t border-border/50">
<div className="text-[10px] uppercase tracking-wider text-muted font-semibold">Export bake in</div>
<button
onClick={syncToTheme}
title="Load the values of the theme you're currently viewing (light or dark) into the sliders"
className="glass-card glass-hover rounded-lg px-2 py-1.5 text-xs text-fg text-left"
>
Sync to current theme
</button>
<div className="flex gap-1.5">
<button
onClick={copy}