feat(glass): re-theme the public WatchPage onto the token system (Phase 3)
The standalone /watch share page was on a hard-coded slate/teal palette (it renders outside <App> with no theme). Add a baseline theme (dark/midnight) in main.tsx so the token CSS vars resolve on every route incl. the public pages, then swap all of WatchPage's slate/teal/hex to theme tokens (bg-bg/text-fg/ text-muted/accent, surface/border), with the password card as glass. Now consistent with the app's default look; the app still overrides with the user's saved theme when it mounts.
This commit is contained in:
parent
b09923661a
commit
f0330fa57f
2 changed files with 23 additions and 16 deletions
|
|
@ -122,29 +122,29 @@ export default function WatchPage() {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-[#0b0f14] text-slate-100 flex flex-col items-center">
|
<div className="min-h-screen bg-bg text-fg flex flex-col items-center">
|
||||||
<div className="w-full max-w-4xl px-4 py-6 flex-1 flex flex-col">
|
<div className="w-full max-w-4xl px-4 py-6 flex-1 flex flex-col">
|
||||||
<div className="flex items-center gap-2 mb-5 text-sm text-slate-400">
|
<div className="flex items-center gap-2 mb-5 text-sm text-muted">
|
||||||
<PlayCircle className="w-5 h-5 text-teal-400" />
|
<PlayCircle className="w-5 h-5 text-accent" />
|
||||||
<span className="font-semibold text-slate-200">Siftlode</span>
|
<span className="font-semibold text-fg">Siftlode</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{status === "loading" && <div className="flex-1 grid place-items-center text-slate-400">{T.loading}</div>}
|
{status === "loading" && <div className="flex-1 grid place-items-center text-muted">{T.loading}</div>}
|
||||||
|
|
||||||
{status === "gone" && (
|
{status === "gone" && (
|
||||||
<div className="flex-1 grid place-items-center text-center">
|
<div className="flex-1 grid place-items-center text-center">
|
||||||
<div>
|
<div>
|
||||||
<div className="text-lg font-semibold">{T.gone}</div>
|
<div className="text-lg font-semibold">{T.gone}</div>
|
||||||
<div className="text-sm text-slate-400 mt-1">{T.goneHint}</div>
|
<div className="text-sm text-muted mt-1">{T.goneHint}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{status === "password" && (
|
{status === "password" && (
|
||||||
<div className="flex-1 grid place-items-center">
|
<div className="flex-1 grid place-items-center">
|
||||||
<div className="w-full max-w-sm rounded-2xl bg-slate-900/60 border border-slate-700 p-6">
|
<div className="w-full max-w-sm rounded-2xl glass p-6">
|
||||||
<div className="flex items-center gap-2 font-medium mb-4">
|
<div className="flex items-center gap-2 font-medium mb-4">
|
||||||
<Lock className="w-4 h-4 text-teal-400" /> {T.passwordTitle}
|
<Lock className="w-4 h-4 text-accent" /> {T.passwordTitle}
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
|
|
@ -153,13 +153,13 @@ export default function WatchPage() {
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
onKeyDown={(e) => e.key === "Enter" && password && unlock()}
|
onKeyDown={(e) => e.key === "Enter" && password && unlock()}
|
||||||
placeholder={T.passwordPlaceholder}
|
placeholder={T.passwordPlaceholder}
|
||||||
className="w-full rounded-lg bg-slate-800 border border-slate-700 px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-teal-500/40"
|
className="w-full rounded-lg bg-surface border border-border px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-accent/40"
|
||||||
/>
|
/>
|
||||||
{error && <div className="text-sm text-red-400 mt-2">{error}</div>}
|
{error && <div className="text-sm text-red-400 mt-2">{error}</div>}
|
||||||
<button
|
<button
|
||||||
onClick={unlock}
|
onClick={unlock}
|
||||||
disabled={!password || unlocking}
|
disabled={!password || unlocking}
|
||||||
className="mt-4 w-full rounded-lg bg-teal-600 hover:bg-teal-500 disabled:opacity-50 py-2 text-sm font-medium transition"
|
className="mt-4 w-full rounded-lg bg-accent text-accent-fg hover:opacity-90 disabled:opacity-50 py-2 text-sm font-medium transition"
|
||||||
>
|
>
|
||||||
{T.watch}
|
{T.watch}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -171,7 +171,7 @@ export default function WatchPage() {
|
||||||
<div>
|
<div>
|
||||||
{/* Shrink-wrap the player to the video so a vertical/short clip renders as a narrow
|
{/* Shrink-wrap the player to the video so a vertical/short clip renders as a narrow
|
||||||
player instead of a wide box with black bars; a landscape clip fills the width. */}
|
player instead of a wide box with black bars; a landscape clip fills the width. */}
|
||||||
<div className="rounded-xl overflow-hidden bg-black border border-slate-800 w-fit max-w-full mx-auto">
|
<div className="rounded-xl overflow-hidden bg-black border border-border w-fit max-w-full mx-auto">
|
||||||
<video
|
<video
|
||||||
controls
|
controls
|
||||||
playsInline
|
playsInline
|
||||||
|
|
@ -189,18 +189,18 @@ export default function WatchPage() {
|
||||||
href={meta.uploader_url}
|
href={meta.uploader_url}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-sm text-slate-400 hover:text-teal-400 hover:underline"
|
className="text-sm text-muted hover:text-accent hover:underline"
|
||||||
>
|
>
|
||||||
{meta.uploader}
|
{meta.uploader}
|
||||||
</a>
|
</a>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-sm text-slate-400">{meta.uploader}</div>
|
<div className="text-sm text-muted">{meta.uploader}</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{meta.allow_download && (
|
{meta.allow_download && (
|
||||||
<a
|
<a
|
||||||
href={meta.file_url}
|
href={meta.file_url}
|
||||||
className="shrink-0 inline-flex items-center gap-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 px-3 py-2 text-sm font-medium transition"
|
className="shrink-0 inline-flex items-center gap-1.5 rounded-lg bg-surface hover:bg-card px-3 py-2 text-sm font-medium transition"
|
||||||
>
|
>
|
||||||
<Download className="w-4 h-4" /> {T.download}
|
<Download className="w-4 h-4" /> {T.download}
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -217,7 +217,7 @@ export default function WatchPage() {
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
title={url}
|
title={url}
|
||||||
className="inline-flex items-center gap-1.5 text-sm text-slate-400 hover:text-teal-400 hover:underline min-w-0"
|
className="inline-flex items-center gap-1.5 text-sm text-muted hover:text-accent hover:underline min-w-0"
|
||||||
>
|
>
|
||||||
<Link2 className="w-3.5 h-3.5 shrink-0" />
|
<Link2 className="w-3.5 h-3.5 shrink-0" />
|
||||||
<span className="truncate">{displayUrl(url)}</span>
|
<span className="truncate">{displayUrl(url)}</span>
|
||||||
|
|
@ -228,7 +228,7 @@ export default function WatchPage() {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-slate-600 py-4">{T.brand}</div>
|
<div className="text-xs text-muted py-4">{T.brand}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,13 @@ const queryClient = new QueryClient({
|
||||||
defaultOptions: { queries: { retry: false, staleTime: 30_000, refetchOnWindowFocus: false } },
|
defaultOptions: { queries: { retry: false, staleTime: 30_000, refetchOnWindowFocus: false } },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Baseline theme so the token CSS vars (--bg/--surface/--accent/…) resolve on first paint — including
|
||||||
|
// the standalone public pages (/watch, /privacy, /terms) that render outside <App> and never call
|
||||||
|
// applyTheme. The app overrides this with the user's saved theme once it mounts.
|
||||||
|
const de = document.documentElement.dataset;
|
||||||
|
de.theme ||= "dark";
|
||||||
|
de.scheme ||= "midnight";
|
||||||
|
|
||||||
const path = window.location.pathname;
|
const path = window.location.pathname;
|
||||||
const root =
|
const root =
|
||||||
path === "/privacy" ? <PrivacyPolicy /> :
|
path === "/privacy" ? <PrivacyPolicy /> :
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue