feat(glass): per-scheme background images + glass-over-image mode

Land the UAT-approved backdrop direction as a real feature (replacing the dev
thumbnail prototype):
- 6 generated abstract SVG backdrops in public/backdrops/, one tuned to each
  accent scheme (dark, mixed-colour, few light areas). Non-figurative + generated
  = repo-safe, tiny, accent-matched.
- New data-backdrop="on" state (dark theme + the setting + not perf) paints the
  per-scheme image on <body> (app root now transparent so it shows app-wide and
  the glass refracts it) AND switches the glass to its translucent tier (the
  user's tuned values: surface 50 / card 60 / scrim 30 / blur 10 / edge 25).
  Off / light / perf -> flat colour + solid glass (the readable fallback).
- Settings > Appearance 'Background image' toggle (bgImage pref, dark-only),
  trilingual. Flat is the fallback + opt-out.
- Remove the FeedBackdrop prototype + its tuner controls; tuner baseline resynced
  to the glass-over-image tier, add a Backdrop-fade slider.
GOTCHA fixed: the dark-mode ambient 'background' shorthand reset background-size
to auto (image rendered un-covered); out-specified it with [data-theme="dark"].
This commit is contained in:
npeter83 2026-07-12 21:20:40 +02:00
parent 036e2fe7ea
commit f9f90cf609
15 changed files with 191 additions and 162 deletions

View file

@ -381,6 +381,14 @@ export default function App() {
document.documentElement.dataset.perf = perf ? "1" : "";
setAccountRaw(PERF_KEY, perf ? "1" : "0");
}, [perf]);
// The per-scheme background image (the "glass over image" look) is on only in dark theme, when
// the user hasn't opted out, and not in perf mode. Drives `html[data-backdrop]` (see index.css),
// which both paints the image on <body> and switches the glass to its translucent tier.
useEffect(() => {
const on = theme.mode === "dark" && theme.bgImage && !perf;
document.documentElement.dataset.backdrop = on ? "on" : "off";
}, [theme.mode, theme.bgImage, perf]);
useEffect(() => setHintsEnabled(hints), [hints]);
useEffect(() => configureNotifications(notif), [notif]);
@ -726,7 +734,7 @@ export default function App() {
);
return (
<div className="h-screen flex bg-bg text-fg">
<div className="h-screen flex text-fg">
<NavSidebar
me={meQuery.data!}
page={page}