Files
petal/web/src/hooks/useNightMode.ts
prosolis 9576340391 Phase 14: bedtime nag + night mode (dark theme + falling stars)
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
2026-06-26 15:10:36 -07:00

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
}