mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-05-20 16:42:25 +00:00
Batch stream deltas, window long transcripts, lazy-load syntax highlighting, and refine activity/composer interactions. Add title refresh retries plus tests for streaming, windowing, code blocks, and live activity behavior.
70 lines
1.6 KiB
TypeScript
70 lines
1.6 KiB
TypeScript
import {
|
|
createContext,
|
|
createElement,
|
|
useCallback,
|
|
useContext,
|
|
useEffect,
|
|
useState,
|
|
type ReactNode,
|
|
} from "react";
|
|
|
|
type Theme = "light" | "dark";
|
|
const STORAGE_KEY = "nanobot-webui.theme";
|
|
const ThemeContext = createContext<Theme>("light");
|
|
|
|
function readStored(): Theme | null {
|
|
try {
|
|
const v = localStorage.getItem(STORAGE_KEY);
|
|
return v === "light" || v === "dark" ? v : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function applyTheme(theme: Theme): void {
|
|
const root = document.documentElement;
|
|
if (theme === "dark") root.classList.add("dark");
|
|
else root.classList.remove("dark");
|
|
}
|
|
|
|
export function useTheme(): {
|
|
theme: Theme;
|
|
toggle: () => void;
|
|
setTheme: (t: Theme) => void;
|
|
} {
|
|
const [theme, setThemeState] = useState<Theme>(() => {
|
|
const stored = readStored();
|
|
if (stored) return stored;
|
|
if (typeof window !== "undefined" && window.matchMedia) {
|
|
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
? "dark"
|
|
: "light";
|
|
}
|
|
return "light";
|
|
});
|
|
|
|
useEffect(() => {
|
|
applyTheme(theme);
|
|
try {
|
|
localStorage.setItem(STORAGE_KEY, theme);
|
|
} catch {
|
|
// ignore
|
|
}
|
|
}, [theme]);
|
|
|
|
const setTheme = useCallback((t: Theme) => setThemeState(t), []);
|
|
const toggle = useCallback(
|
|
() => setThemeState((t) => (t === "dark" ? "light" : "dark")),
|
|
[],
|
|
);
|
|
return { theme, toggle, setTheme };
|
|
}
|
|
|
|
export function ThemeProvider({ theme, children }: { theme: Theme; children: ReactNode }) {
|
|
return createElement(ThemeContext.Provider, { value: theme }, children);
|
|
}
|
|
|
|
export function useThemeValue(): Theme {
|
|
return useContext(ThemeContext);
|
|
}
|