Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,25 @@ import {
GripVertical,
PlayCircle,
Shield as ShieldIcon,
Moon,
Sun,
} from "lucide-react";

// ── theme ─────────────────────────────────────────────────────────────────────
function useTheme() {
const [dark, setDark] = useState<boolean>(() => {
const saved = localStorage.getItem("theme");
if (saved) return saved === "dark";
return window.matchMedia("(prefers-color-scheme: dark)").matches;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: SSR compatibility issue - window is undefined on server side

The window.matchMedia call will throw a ReferenceError during server-side rendering (SSR) or in any Node.js environment. The fallback for system preference detection needs a guard for window availability.

Suggested change
return window.matchMedia("(prefers-color-scheme: dark)").matches;
if (saved) return saved === "dark";
return typeof window !== "undefined" && window.matchMedia("(prefers-color-scheme: dark)").matches;

This check ensures the code gracefully handles environments where window doesn't exist.

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

});

useEffect(() => {
document.documentElement.classList.toggle("dark", dark);
localStorage.setItem("theme", dark ? "dark" : "light");
}, [dark]);

return { dark, toggle: () => setDark((d) => !d) };
}
import UnixTimeConverter from "./components/UnixTimeConverter";
import JsonValidator from "./components/JsonValidator";
import { Base64SideBySide } from "./components/Base64SideBySide";
Expand Down Expand Up @@ -197,6 +215,7 @@ function Layout({ tools: defaultTools }: { tools: Tool[] }) {
const [isShortcutsOpen, setIsShortcutsOpen] = useState(false);
const [isSidebarExpanded, setIsSidebarExpanded] = useState(true);
const [isDragActive, setIsDragActive] = useState(false);
const { dark, toggle: toggleTheme } = useTheme();
const { state, startTour, hideWelcome, notifyDragComplete } = useOnboarding();
const [tools, setTools] = useState<Tool[]>(() => {
const savedOrder = localStorage.getItem("toolsOrder");
Expand Down Expand Up @@ -398,6 +417,13 @@ function Layout({ tools: defaultTools }: { tools: Tool[] }) {
>
<PlayCircle size={18} />
</button>
<button
onClick={toggleTheme}
className="p-1.5 hover:bg-gray-100 dark:hover:bg-gray-700 rounded"
title={dark ? "Switch to light mode" : "Switch to dark mode"}
>
{dark ? <Sun size={18} /> : <Moon size={18} />}
</button>
<button
onClick={() => setIsSidebarExpanded(false)}
className="p-1.5 hover:bg-gray-100 rounded"
Expand Down
1 change: 1 addition & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
darkMode: 'class',
theme: {
extend: {
animation: {
Expand Down
Loading