Skip to content
Open
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
2 changes: 2 additions & 0 deletions apps/web/src/app/projects/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Skeleton } from "@/components/ui/skeleton";
import { ThemeToggle } from "@/components/theme-toggle";
import { useProjectStore } from "@/stores/project-store";
import { useTimelineStore } from "@/stores/timeline-store";
import type { TProject } from "@/types/project";
Expand Down Expand Up @@ -207,6 +208,7 @@ export default function ProjectsPage() {
</div>
) : (
<div className="flex items-center gap-2">
<ThemeToggle />
<Button
variant="outline"
onClick={() => setIsSelectionMode(true)}
Expand Down
37 changes: 32 additions & 5 deletions apps/web/src/components/theme-toggle.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client";

import { useEffect, useState } from "react";
import { Button } from "./ui/button";
import { Sun, Moon } from "lucide-react";
import { useTheme } from "next-themes";
Expand All @@ -9,17 +10,43 @@ interface ThemeToggleProps {
}

export function ThemeToggle({ className }: ThemeToggleProps) {
const { theme, setTheme } = useTheme();
const { setTheme, resolvedTheme } = useTheme();
const [mounted, setMounted] = useState(false);

useEffect(() => {
setMounted(true);
}, []);

// Avoid hydration mismatch by not rendering until mounted
if (!mounted) {
return (
<Button type="button" size="icon" variant="text" className={`h-7 ${className ?? ""}`}>
<span className="!size-[1.1rem]" />
<span className="sr-only">Toggle theme</span>
</Button>
);
}

const isDark = resolvedTheme === "dark";

return (
<Button
type="button"
size="icon"
variant="text"
className="h-7"
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
className={`h-7 ${className ?? ""}`}
onClick={() => setTheme(isDark ? "light" : "dark")}
>
<Sun className="!size-[1.1rem]" />
<span className="sr-only">{theme === "dark" ? "Light" : "Dark"}</span>
{isDark ? (
<Sun className="!size-[1.1rem]">
<title>Switch to light mode</title>
</Sun>
) : (
<Moon className="!size-[1.1rem]">
<title>Switch to dark mode</title>
</Moon>
)}
<span className="sr-only">{isDark ? "Light mode" : "Dark mode"}</span>
</Button>
);
}