Skip to content

Commit

Permalink
Merge pull request #1555 from zkfriendly/main
Browse files Browse the repository at this point in the history
feat: add theme toggle functionality with dark and light mode support
  • Loading branch information
monilpat authored Dec 29, 2024
2 parents 53ecdbf + f308a60 commit b386b26
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 1 deletion.
6 changes: 5 additions & 1 deletion client/src/components/app-sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { Calendar, Home, Inbox, Search, Settings } from "lucide-react";
import { useParams } from "react-router-dom";
import { ThemeToggle } from "@/components/theme-toggle";

import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarTrigger,
} from "@/components/ui/sidebar";

// Menu items.
Expand Down Expand Up @@ -51,6 +52,9 @@ export function AppSidebar() {
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
<SidebarFooter>
<ThemeToggle />
</SidebarFooter>
</Sidebar>
);
}
19 changes: 19 additions & 0 deletions client/src/components/theme-toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Moon, Sun } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useTheme } from "@/hooks/use-theme";

export function ThemeToggle() {
const { theme, setTheme } = useTheme();

return (
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
>
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
);
}
32 changes: 32 additions & 0 deletions client/src/hooks/use-theme.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useEffect, useState } from "react";

type Theme = "dark" | "light" | "system";

function useTheme() {
const [theme, setTheme] = useState<Theme>(
() => (localStorage.getItem("theme") as Theme) || "system"
);

useEffect(() => {
const media = window.matchMedia("(prefers-color-scheme: dark)");

function applyTheme() {
const root = window.document.documentElement;
const systemTheme = media.matches ? "dark" : "light";
const activeTheme = theme === "system" ? systemTheme : theme;

root.classList.remove("light", "dark");
root.classList.add(activeTheme);
localStorage.setItem("theme", theme);
}

applyTheme();
media.addEventListener("change", applyTheme);
return () => media.removeEventListener("change", applyTheme);
}, [theme]);

return { theme, setTheme } as const;
}

export { useTheme };
export type { Theme };
6 changes: 6 additions & 0 deletions client/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import "./index.css";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { RouterProvider } from "react-router-dom";
import { router } from "./router.tsx";

// Initialize theme
const theme = localStorage.getItem("theme") || "system";
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
document.documentElement.classList.add(theme === "system" ? systemTheme : theme);

// Create a client
const queryClient = new QueryClient();

Expand Down

0 comments on commit b386b26

Please sign in to comment.