Add night mode red overlay for dark-adapted vision
- NightModeProvider context (localStorage persisted) in contexts/NightMode.tsx - Full-screen fixed red overlay (rgba 160,0,0 @ 55%, mix-blend-mode: multiply) fades in over the entire UI; multiply blend keeps dark backgrounds black while turning all white/bright content deep red - Desktop: toggle button at the bottom of the sidebar, glows red when active - Mobile: floating red circle button fixed just above the bottom nav bar Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import { useTonight } from '../../hooks/useTonight';
|
||||
import { useWeather, useForecast } from '../../hooks/useWeather';
|
||||
import MoonPhaseIcon from '../sky/MoonPhaseIcon';
|
||||
import GoNogo from '../weather/GoNogo';
|
||||
import { useNightMode } from '../../contexts/NightMode';
|
||||
|
||||
const SEEING_LABELS: Record<number, string> = {
|
||||
1: '0.5″', 2: '0.75″', 3: '1.0″', 4: '1.25″',
|
||||
@@ -31,19 +32,48 @@ function fmtTime(utc?: string): string {
|
||||
}
|
||||
|
||||
export function BottomNav() {
|
||||
const { on, toggle } = useNightMode();
|
||||
return (
|
||||
<nav className="bottom-nav">
|
||||
{navItems.map(item => (
|
||||
<NavLink
|
||||
key={item.path}
|
||||
to={item.path}
|
||||
className={({ isActive }) => isActive ? 'active' : ''}
|
||||
>
|
||||
<span className="bnav-icon">{item.icon}</span>
|
||||
{item.label}
|
||||
</NavLink>
|
||||
))}
|
||||
</nav>
|
||||
<>
|
||||
{/* Night mode floating toggle — sits just above bottom nav */}
|
||||
<button
|
||||
onClick={toggle}
|
||||
title={on ? 'Exit night mode' : 'Night mode'}
|
||||
style={{
|
||||
position: 'fixed',
|
||||
bottom: 66,
|
||||
right: 14,
|
||||
zIndex: 210,
|
||||
width: 36, height: 36,
|
||||
borderRadius: '50%',
|
||||
background: on ? 'rgba(160,0,0,0.85)' : 'var(--bg-panel)',
|
||||
border: `1px solid ${on ? '#800000' : 'var(--border)'}`,
|
||||
color: on ? '#ff6666' : 'var(--text-lo)',
|
||||
fontSize: 16,
|
||||
display: 'none', // shown by .bottom-nav display:flex breakpoint via CSS class
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
cursor: 'pointer',
|
||||
boxShadow: on ? '0 0 12px rgba(160,0,0,0.5)' : 'none',
|
||||
transition: 'all 0.3s',
|
||||
}}
|
||||
className="night-fab"
|
||||
>
|
||||
🔴
|
||||
</button>
|
||||
<nav className="bottom-nav">
|
||||
{navItems.map(item => (
|
||||
<NavLink
|
||||
key={item.path}
|
||||
to={item.path}
|
||||
className={({ isActive }) => isActive ? 'active' : ''}
|
||||
>
|
||||
<span className="bnav-icon">{item.icon}</span>
|
||||
{item.label}
|
||||
</NavLink>
|
||||
))}
|
||||
</nav>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -51,6 +81,7 @@ export default function Sidebar() {
|
||||
const { data: tonight } = useTonight();
|
||||
const { data: weather } = useWeather();
|
||||
const { data: forecast } = useForecast();
|
||||
const { on: nightOn, toggle: nightToggle } = useNightMode();
|
||||
|
||||
const slot = (forecast as { dataseries?: { seeing?: number; transparency?: number; cloudcover?: number }[] })?.dataseries?.[0];
|
||||
|
||||
@@ -147,6 +178,25 @@ export default function Sidebar() {
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* Night mode toggle */}
|
||||
<div style={{ borderTop: '1px solid var(--border)', padding: '10px 16px' }}>
|
||||
<button
|
||||
onClick={nightToggle}
|
||||
style={{
|
||||
width: '100%', display: 'flex', alignItems: 'center', gap: 10,
|
||||
background: nightOn ? 'rgba(160,0,0,0.2)' : 'transparent',
|
||||
border: `1px solid ${nightOn ? '#600000' : 'var(--border)'}`,
|
||||
borderRadius: 4, padding: '7px 10px', cursor: 'pointer',
|
||||
color: nightOn ? '#ff4444' : 'var(--text-lo)',
|
||||
fontFamily: 'var(--font-mono)', fontSize: 11,
|
||||
letterSpacing: '0.06em', transition: 'all 0.2s',
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: 13 }}>🔴</span>
|
||||
{nightOn ? 'Exit Night Mode' : 'Night Mode'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Conditions widget */}
|
||||
<div style={{ borderTop: '1px solid var(--border)', padding: '12px 16px' }}>
|
||||
<div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text-lo)', letterSpacing: '0.1em', marginBottom: 8, textTransform: 'uppercase' }}>
|
||||
|
||||
Reference in New Issue
Block a user