Files
OpenClaw-bot-review/lib/theme.tsx
T
xmanrui 7915a913c9 feat: add dark/light theme toggle
- Add light theme CSS variables in globals.css
- Create ThemeProvider with localStorage persistence (lib/theme.tsx)
- Add ThemeSwitcher button (☀️/🌙) to sidebar
- Wrap app with ThemeProvider in providers.tsx
2026-02-23 07:09:45 +08:00

63 lines
1.6 KiB
TypeScript

"use client";
import { createContext, useContext, useState, useCallback, useEffect, ReactNode } from "react";
export type Theme = "dark" | "light";
interface ThemeContextType {
theme: Theme;
setTheme: (t: Theme) => void;
toggleTheme: () => void;
}
const ThemeContext = createContext<ThemeContextType>({
theme: "dark",
setTheme: () => {},
toggleTheme: () => {},
});
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setThemeState] = useState<Theme>("dark");
useEffect(() => {
const saved = localStorage.getItem("theme") as Theme;
if (saved === "light" || saved === "dark") {
setThemeState(saved);
document.documentElement.setAttribute("data-theme", saved);
}
}, []);
const setTheme = useCallback((t: Theme) => {
setThemeState(t);
document.documentElement.setAttribute("data-theme", t);
localStorage.setItem("theme", t);
}, []);
const toggleTheme = useCallback(() => {
setTheme(theme === "dark" ? "light" : "dark");
}, [theme, setTheme]);
return (
<ThemeContext.Provider value={{ theme, setTheme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
return useContext(ThemeContext);
}
export function ThemeSwitcher() {
const { theme, toggleTheme } = useTheme();
return (
<button
onClick={toggleTheme}
className="px-2 py-1.5 rounded-lg bg-[var(--bg)] border border-[var(--border)] text-sm hover:border-[var(--accent)] transition cursor-pointer"
title={theme === "dark" ? "切换到亮色模式" : "切换到暗色模式"}
>
{theme === "dark" ? "☀️" : "🌙"}
</button>
);
}