feat(glass): dev-prototype feed backdrop (blurred rotating thumbnail)
Idea from UAT-2: give the feeds the same 'content behind glass' lift the Plex detail page gets. New FeedBackdrop paints a faint, slowly-rotating feed thumbnail as a fixed backdrop on <main> (the proven art-backdrop path — a fixed z:-1 layer is occluded by the root's opaque bg-bg). Blur = tiny-canvas downscale + cover upscale (no CSS filter; ytimg is CORS-readable so it uses a data-URL, else raw). Flat --bg stays as the 'perf mode' look. Behind the GlassTuner toggle + a Backdrop-fade slider (--feedbg-fade) so it's judged/tuned in UAT before anything is committed for real.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import FeedBackdrop from "./FeedBackdrop";
|
||||
|
||||
/**
|
||||
* DEV-ONLY live appearance tuner. Mounted at the App root so it stays reachable on every page.
|
||||
@@ -77,13 +78,19 @@ const PRESETS: { id: string; name: string; hint: string; over: Record<string, nu
|
||||
},
|
||||
];
|
||||
|
||||
const ALL = SLIDERS;
|
||||
// Dev-prototype feed-backdrop control (only meaningful while the backdrop toggle is on).
|
||||
const FEEDBG_SLIDERS: Slider[] = [
|
||||
{ k: "--feedbg-fade", label: "Backdrop fade", min: 60, max: 97, step: 1, unit: "%", def: 86 },
|
||||
];
|
||||
|
||||
const ALL = [...SLIDERS, ...FEEDBG_SLIDERS];
|
||||
const root = () => document.documentElement;
|
||||
const readVar = (k: string) => getComputedStyle(root()).getPropertyValue(k).trim();
|
||||
|
||||
type Saved = {
|
||||
vars?: Record<string, number>;
|
||||
palette?: Record<string, string>;
|
||||
feedbg?: boolean;
|
||||
open?: boolean;
|
||||
};
|
||||
|
||||
@@ -103,6 +110,7 @@ export default function GlassTuner() {
|
||||
return { ...base, ...(initial.vars || {}) };
|
||||
});
|
||||
const [palette, setPalette] = useState<Record<string, string>>(() => initial.palette || {});
|
||||
const [feedbg, setFeedbg] = useState<boolean>(() => Boolean(initial.feedbg));
|
||||
const [open, setOpen] = useState<boolean>(() => initial.open ?? true);
|
||||
const [tab, setTab] = useState<"glass" | "palette">("glass");
|
||||
const [copied, setCopied] = useState(false);
|
||||
@@ -199,10 +207,17 @@ export default function GlassTuner() {
|
||||
persist({ open: v });
|
||||
}
|
||||
|
||||
function toggleFeedbg(v: boolean) {
|
||||
setFeedbg(v);
|
||||
persist({ feedbg: v });
|
||||
}
|
||||
|
||||
if (!DEV_TUNER) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed right-0 top-24 z-[9999] flex items-start" style={{ pointerEvents: "none" }}>
|
||||
<>
|
||||
{feedbg && <FeedBackdrop />}
|
||||
<div className="fixed right-0 top-24 z-[9999] flex items-start" style={{ pointerEvents: "none" }}>
|
||||
{!open && (
|
||||
<button
|
||||
onClick={() => persistOpen(true)}
|
||||
@@ -249,6 +264,17 @@ export default function GlassTuner() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Feed backdrop (dev prototype) */}
|
||||
<label className="flex items-center gap-2 text-xs text-fg cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={feedbg}
|
||||
onChange={(e) => toggleFeedbg(e.target.checked)}
|
||||
className="accent-accent"
|
||||
/>
|
||||
Feed backdrop <span className="text-muted">(blurred thumbnail)</span>
|
||||
</label>
|
||||
|
||||
{/* Tab switch */}
|
||||
<div className="flex gap-1.5">
|
||||
{(["glass", "palette"] as const).map((t) => (
|
||||
@@ -269,6 +295,13 @@ export default function GlassTuner() {
|
||||
{SLIDERS.map((s) => (
|
||||
<Ctl key={s.k} s={s} value={vars[s.k]} onChange={(v) => setVar(s.k, v)} />
|
||||
))}
|
||||
{feedbg && (
|
||||
<div className="flex flex-col gap-2.5 pt-1 border-t border-border/50">
|
||||
{FEEDBG_SLIDERS.map((s) => (
|
||||
<Ctl key={s.k} s={s} value={vars[s.k]} onChange={(v) => setVar(s.k, v)} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -313,7 +346,8 @@ export default function GlassTuner() {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user