Files
zeekayandHanzo Dev d1a39698ee Give the ramp every hue and boot it dark
Yellow and orange were dropped for failing 3:1 against the light ground at
one uniform rung, which was a fact about the rung. Each stop now names the
rung that shows it on each scheme, and every dot carries an ink hairline —
the edge that draws white on white, black on black, and the yellow that no
rung can both darken and keep yellow. White, grey and black join as stops;
grey still clears the accent, and none of the three washes the page, since
an absolute palette under the other scheme's ink is a page with its text
turned off.

Dark is the default a reader who has named neither scheme gets: the meta
hands the UA dark rather than the machine's own answer, and the setting
that meant "ask the machine" is dropped, since the pre-paint script and the
app resolved it differently and the page turned light a frame after booting.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-07 23:35:59 -07:00

69 lines
1.8 KiB
TypeScript

import { Moon, Sun } from '@hanzogui/lucide-icons-2'
import { useUserScheme } from '@vxrn/color-scheme'
import { memo, useEffect, useState } from 'react'
import { Appearance } from 'react-native'
import type { ButtonProps } from '@hanzo/gui'
import { Button, isWeb, TooltipSimple } from '@hanzo/gui'
export const ThemeToggle = memo((props: ButtonProps) => {
const { onPress, Icon, scheme } = useToggleTheme()
return (
<TooltipSimple
groupId="header-actions-theme"
label={scheme === 'dark' ? 'Dark' : 'Light'}
>
<Button
size="$3"
onPress={onPress}
{...props}
aria-label="Toggle light/dark color scheme"
icon={Icon}
hoverStyle={{
bg: 'rgba(0,0,0,0.15)',
}}
/>
</TooltipSimple>
)
})
/**
* Dark or light, and nothing else.
*
* A third setting that follows the machine is a second answer to a question the
* site has already answered — dark — and the two readers of it disagree: the
* pre-paint script resolves it to the default while the runtime asks the OS, so
* a page boots dark and turns light a frame later. The toggle names the two
* schemes it can be in, and the default is what a reader who has named neither
* gets.
*/
export function useToggleTheme() {
const userScheme = useUserScheme()
// for faster re renders on heavy pages
const [val, setVal] = useState(userScheme.value)
useEffect(() => {
if (userScheme.value !== val) {
setVal(userScheme.value)
}
}, [userScheme.value])
return {
scheme: val,
Icon: val === 'dark' ? Moon : Sun,
onPress: () => {
const next = val === 'dark' ? 'light' : 'dark'
setVal(next)
setTimeout(() => {
if (!isWeb) {
Appearance.setColorScheme(next)
}
userScheme.set(next)
}, 20)
},
}
}