ca-grow-ops-manager/frontend/src/components/ThemeToggle.tsx
fullsizemalt efb298e119
Some checks are pending
Deploy to Production / deploy (push) Waiting to run
Test / backend-test (push) Waiting to run
Test / frontend-test (push) Waiting to run
fix: thorough Linear design audit
- ThemeToggle: Single button cycle instead of 3-button bar
- UserMenu: Cleaner styling with accent avatar
- MobileNavSheet: Consistent Linear tokens
- Walkthrough checklists: Desktop two-column layout
- RoleModal: Toggle buttons instead of tiny checkboxes
- IPMScheduleModal: Toggle buttons instead of checkbox
- ScoutingModal: Toggle buttons instead of checkbox
2025-12-12 15:49:21 -08:00

61 lines
2 KiB
TypeScript

import { useState, useEffect } from 'react';
import { Sun, Moon, Monitor } from 'lucide-react';
/**
* ThemeToggle - Minimal icon-only theme switcher
* Linear-inspired: subtle, clean, unobtrusive
*/
type Theme = 'light' | 'dark' | 'system';
export default function ThemeToggle() {
const [theme, setTheme] = useState<Theme>('system');
useEffect(() => {
const savedTheme = localStorage.getItem('theme') as Theme | null;
if (savedTheme) {
setTheme(savedTheme);
applyTheme(savedTheme);
} else {
applyTheme('system');
}
}, []);
function applyTheme(newTheme: Theme) {
const root = window.document.documentElement;
root.classList.remove('light', 'dark');
if (newTheme === 'system') {
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light';
root.classList.add(systemTheme);
} else {
root.classList.add(newTheme);
}
}
function cycleTheme() {
const order: Theme[] = ['light', 'dark', 'system'];
const nextIndex = (order.indexOf(theme) + 1) % order.length;
const newTheme = order[nextIndex];
setTheme(newTheme);
localStorage.setItem('theme', newTheme);
applyTheme(newTheme);
}
const Icon = theme === 'light' ? Sun : theme === 'dark' ? Moon : Monitor;
const label = theme === 'light' ? 'Light' : theme === 'dark' ? 'Dark' : 'System';
return (
<button
onClick={cycleTheme}
className="flex items-center gap-2 px-3 py-2 w-full rounded-md text-secondary hover:text-primary hover:bg-tertiary transition-colors duration-fast text-sm"
aria-label={`Theme: ${label}. Click to change.`}
title={`Theme: ${label}`}
>
<Icon size={16} strokeWidth={1.5} />
<span className="text-xs text-tertiary">{label}</span>
</button>
);
}