diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index c2a64a7..35421a8 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -1,6 +1,7 @@ import { Routes, Route, Navigate } from 'react-router-dom'; import { Sidebar } from './components/Sidebar'; import { ToastProvider } from './components/Toast'; +import { useTheme } from './hooks/useTheme'; import { Channels } from './pages/Channels'; import { ChannelDetail } from './pages/ChannelDetail'; import { Library } from './pages/Library'; @@ -10,6 +11,8 @@ import { SettingsPage } from './pages/Settings'; import { SystemPage } from './pages/System'; function AuthenticatedLayout() { + // Apply theme from settings to documentElement at the app root + useTheme(); return (
diff --git a/src/frontend/src/hooks/useTheme.ts b/src/frontend/src/hooks/useTheme.ts new file mode 100644 index 0000000..6a94dbd --- /dev/null +++ b/src/frontend/src/hooks/useTheme.ts @@ -0,0 +1,21 @@ +import { useEffect } from 'react'; +import { useAppSettings } from '../api/hooks/useSystem'; + +/** + * Reads the user-configured theme from app settings and applies it + * to the document element. Falls back to localStorage (set by the + * inline script in index.html) then 'dark'. + * + * Call once near the app root so theme stays in sync across all pages. + */ +export function useTheme(): 'dark' | 'light' { + const { data: settings } = useAppSettings(); + const theme: 'dark' | 'light' = settings?.theme ?? (localStorage.getItem('tubearr-theme') as 'dark' | 'light') ?? 'dark'; + + useEffect(() => { + document.documentElement.dataset.theme = theme; + localStorage.setItem('tubearr-theme', theme); + }, [theme]); + + return theme; +} diff --git a/src/frontend/src/pages/ChannelDetail.tsx b/src/frontend/src/pages/ChannelDetail.tsx index 99dafb1..9e96b53 100644 --- a/src/frontend/src/pages/ChannelDetail.tsx +++ b/src/frontend/src/pages/ChannelDetail.tsx @@ -1891,12 +1891,12 @@ export function ChannelDetail() { alignItems: 'center', gap: 'var(--space-3)', padding: 'var(--space-3) var(--space-5)', - backgroundColor: 'rgba(30, 32, 40, 0.75)', + backgroundColor: 'var(--glass-bg)', backdropFilter: 'blur(16px) saturate(1.4)', WebkitBackdropFilter: 'blur(16px) saturate(1.4)', - border: '1px solid rgba(255, 255, 255, 0.08)', + border: '1px solid var(--glass-border)', borderRadius: 'var(--radius-xl)', - boxShadow: '0 8px 32px rgba(0, 0, 0, 0.35), inset 0 0.5px 0 rgba(255, 255, 255, 0.06)', + boxShadow: 'var(--shadow-md)', }} > { document.documentElement.dataset.theme = theme; localStorage.setItem('tubearr-theme', theme); diff --git a/src/frontend/src/styles/global.css b/src/frontend/src/styles/global.css index eb1bc1f..704be1c 100644 --- a/src/frontend/src/styles/global.css +++ b/src/frontend/src/styles/global.css @@ -60,12 +60,12 @@ a:hover { } ::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.08); + background: var(--bg-selected); border-radius: 3px; } ::-webkit-scrollbar-thumb:hover { - background: rgba(255, 255, 255, 0.15); + background: var(--border-light); } /* ── Buttons base ── */ @@ -158,7 +158,7 @@ tr:hover { background: linear-gradient( 90deg, var(--bg-input) 25%, - rgba(255, 255, 255, 0.04) 50%, + var(--bg-hover) 50%, var(--bg-input) 75% ); background-size: 200% 100%;