7abfddd607
Implement 400ms debounce with AbortController in useGeocode and useDestinationStation to prevent excessive API calls. Add dark mode toggle via new useTheme hook, persisting preference to localStorage and applying to document root. Pre-group calendar events by date using a Map in CalendarView to replace O(n) filter operations with O(1) lookups.
35 lines
885 B
TypeScript
35 lines
885 B
TypeScript
"use client";
|
|
|
|
import { useState, useCallback, useEffect } from "react";
|
|
|
|
const THEME_KEY = "ttl_theme";
|
|
|
|
function getServerTheme(): "dark" | "light" {
|
|
return "light";
|
|
}
|
|
|
|
function getClientTheme(): "dark" | "light" {
|
|
if (typeof window === "undefined") return getServerTheme();
|
|
const stored = localStorage.getItem(THEME_KEY);
|
|
if (stored) return stored as "dark" | "light";
|
|
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
}
|
|
|
|
export function useTheme() {
|
|
const [dark, setDark] = useState(() => getClientTheme() === "dark");
|
|
|
|
useEffect(() => {
|
|
document.documentElement.classList.toggle("dark", dark);
|
|
}, [dark]);
|
|
|
|
const toggle = useCallback(() => {
|
|
setDark((prev) => {
|
|
const next = !prev;
|
|
localStorage.setItem(THEME_KEY, next ? "dark" : "light");
|
|
return next;
|
|
});
|
|
}, []);
|
|
|
|
return { dark, toggle };
|
|
}
|