Companion warmth: - ENCOURAGEMENTS grown 5->10; new BEDTIME lines (warm/playful, zh-first) - useCompanion heartbeat gains a bedtime branch (>=11pm, while actively writing) gated by a 30min cooldown; new 'bedtime' BubbleTone paces it Night mode (auto at ~11pm, local clock): - lib/night.ts centralizes isBedtime() + the window, shared with the nag - useNightMode toggles a `petal-night` class on <html>; index.css re-points only the palette tokens, so every Tailwind color utility flips via var() with no component edits (600ms dusk fade; print stays white) - PetalFall gains a `night` prop: chunky cartoon power stars (makeCartoonStar, 5 candy colors) mixed ~70/30 with twinkle sparkles; each star spins at its own rate (~0.5-2.2 rad/s, random direction), falls straight down, shimmers Verified: go vet/test, tsc, vitest 51/51, vite build; real-browser screenshots/video (clock mocked to 23:30). Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
26 lines
945 B
TypeScript
26 lines
945 B
TypeScript
import { useEffect, useState } from 'react'
|
|
import { isBedtime } from '../lib/night'
|
|
|
|
// Tracks whether it's late enough to shift Petal into its calm night mode (dark
|
|
// theme + falling stars instead of petals). Re-checks once a minute so the swap
|
|
// happens on its own as the clock rolls past 11pm — no reload needed. Returns
|
|
// the boolean and also toggles a `petal-night` class on <html> so the CSS token
|
|
// overrides cascade to everything (body background, panels, portals included).
|
|
export function useNightMode(): boolean {
|
|
const [night, setNight] = useState(() => isBedtime())
|
|
|
|
useEffect(() => {
|
|
const tick = () => setNight(isBedtime())
|
|
tick()
|
|
const id = setInterval(tick, 60_000)
|
|
return () => clearInterval(id)
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
document.documentElement.classList.toggle('petal-night', night)
|
|
return () => document.documentElement.classList.remove('petal-night')
|
|
}, [night])
|
|
|
|
return night
|
|
}
|