useTheme
Read and set the app theme through the same cookie and class the pre-paint script owns.
With theme: 'system' the framework already emits a <head> script that reads
the voltro:theme cookie (falling back to prefers-color-scheme) and toggles
.dark on <html> before first paint. What was missing was the in-app
switcher — so apps layered a second theme system on top, and then two writers
raced on one class attribute: a flash on navigation, and a stored preference
that disagreed with the rendered class. useTheme is that switcher, reading and
writing exactly the cookie and class the pre-paint script already uses.
import { useTheme } from '@voltro/web'
const { theme, resolvedTheme, setTheme } = useTheme()
<button onClick={() => setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')}>theme is the stored preference — 'light' | 'dark' | 'system', where
'system' means no explicit choice. resolvedTheme is what is actually applied
right now ('light' | 'dark'), resolving 'system' against matchMedia, and
it stays live when the OS flips. setTheme persists the cookie and applies the
class immediately; setTheme('system') clears the cookie and falls back to the
OS.
Requires theme: 'system' in the web app.config.ts — that is what emits the
pre-paint script. Do not also install a third-party theme provider.