Add auto theme mode (light/dark/auto by time of day)

- ThemeContext: add 'auto' mode that switches light 7:00-22:00, dark otherwise, re-checks every minute
- Topbar: cycle through 3 modes on click, show Monitor icon for auto mode
- Settings → Внешний вид: 3-button grid with split preview for auto

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-17 18:22:37 +03:00
parent 7b045b38a6
commit dd9a2a3da9
3 changed files with 63 additions and 22 deletions

View File

@@ -1,21 +1,44 @@
import { createContext, useContext, useEffect, useState } from 'react'
export type ThemeMode = 'light' | 'dark' | 'auto'
type Theme = 'light' | 'dark'
interface ThemeContextValue {
mode: ThemeMode
theme: Theme
setMode: (mode: ThemeMode) => void
toggle: () => void
}
const ThemeContext = createContext<ThemeContextValue | null>(null)
function getAutoTheme(): Theme {
const h = new Date().getHours()
return h >= 7 && h < 22 ? 'light' : 'dark'
}
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<Theme>(() => {
const stored = localStorage.getItem('hotelsync-theme') as Theme | null
if (stored) return stored
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
const [mode, setModeState] = useState<ThemeMode>(() => {
return (localStorage.getItem('hotelsync-theme') as ThemeMode | null) ?? 'light'
})
const [theme, setTheme] = useState<Theme>(() => {
const stored = localStorage.getItem('hotelsync-theme') as ThemeMode | null
if (!stored || stored === 'light') return 'light'
if (stored === 'dark') return 'dark'
return getAutoTheme()
})
useEffect(() => {
if (mode === 'auto') {
setTheme(getAutoTheme())
const interval = setInterval(() => setTheme(getAutoTheme()), 60_000)
return () => clearInterval(interval)
} else {
setTheme(mode)
}
}, [mode])
useEffect(() => {
const root = document.documentElement
if (theme === 'dark') {
@@ -23,13 +46,20 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
} else {
root.classList.remove('dark')
}
localStorage.setItem('hotelsync-theme', theme)
}, [theme])
const toggle = () => setTheme(t => t === 'light' ? 'dark' : 'light')
const setMode = (m: ThemeMode) => {
setModeState(m)
localStorage.setItem('hotelsync-theme', m)
}
const toggle = () => {
const next: ThemeMode = mode === 'light' ? 'dark' : mode === 'dark' ? 'auto' : 'light'
setMode(next)
}
return (
<ThemeContext.Provider value={{ theme, toggle }}>
<ThemeContext.Provider value={{ mode, theme, setMode, toggle }}>
{children}
</ThemeContext.Provider>
)