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:
parent
914cd79db9
commit
a4f42e6ea0
1 changed files with 29 additions and 3 deletions
|
|
@ -104,6 +104,7 @@ export default function GlassTuner() {
|
||||||
const [open, setOpen] = useState<boolean>(() => initial.open ?? true);
|
const [open, setOpen] = useState<boolean>(() => initial.open ?? true);
|
||||||
const [tab, setTab] = useState<"glass" | "palette">("glass");
|
const [tab, setTab] = useState<"glass" | "palette">("glass");
|
||||||
const [copied, setCopied] = useState(false);
|
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>).
|
// Seed the colour pickers from the live scheme for display (without forcing them onto <html>).
|
||||||
const [swatches, setSwatches] = useState<Record<string, string>>({});
|
const [swatches, setSwatches] = useState<Record<string, string>>({});
|
||||||
|
|
||||||
|
|
@ -173,8 +174,25 @@ export default function GlassTuner() {
|
||||||
setSwatches(sw);
|
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(() => {
|
const cssOut = useMemo(() => {
|
||||||
|
void themeTick; // re-run when the active theme is re-synced
|
||||||
const lines: string[] = [];
|
const lines: string[] = [];
|
||||||
ALL.forEach((s) => {
|
ALL.forEach((s) => {
|
||||||
if (vars[s.k] !== s.def) lines.push(` ${s.k}: ${vars[s.k]}${s.unit};`);
|
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) => {
|
PALETTE.forEach((p) => {
|
||||||
if (palette[p.k]) lines.push(` ${p.k}: ${palette[p.k]};`);
|
if (palette[p.k]) lines.push(` ${p.k}: ${palette[p.k]};`);
|
||||||
});
|
});
|
||||||
return lines.length ? `:root {\n${lines.join("\n")}\n}` : "/* all values at defaults */";
|
const scope = root().dataset.theme === "light" ? 'html[data-theme="light"]' : ":root";
|
||||||
}, [vars, palette]);
|
return lines.length ? `${scope} {\n${lines.join("\n")}\n}` : "/* all values at defaults */";
|
||||||
|
}, [vars, palette, themeTick]);
|
||||||
|
|
||||||
function copy() {
|
function copy() {
|
||||||
navigator.clipboard?.writeText(cssOut).then(() => {
|
navigator.clipboard?.writeText(cssOut).then(() => {
|
||||||
|
|
@ -293,6 +312,13 @@ export default function GlassTuner() {
|
||||||
{/* Export */}
|
{/* Export */}
|
||||||
<div className="flex flex-col gap-1.5 pt-1 border-t border-border/50">
|
<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>
|
<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">
|
<div className="flex gap-1.5">
|
||||||
<button
|
<button
|
||||||
onClick={copy}
|
onClick={copy}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue