feat(theme): add theme switching functionality with ModeSwitcher and ThemeProvider

This commit is contained in:
ngc2207 2024-12-09 16:48:38 +08:00
parent 398c56b38b
commit 8808b4fb9b
5 changed files with 49 additions and 1 deletions

View File

@ -23,6 +23,7 @@
"lucide-react": "^0.468.0", "lucide-react": "^0.468.0",
"next": "15.0.4", "next": "15.0.4",
"next-auth": "^5.0.0-beta.25", "next-auth": "^5.0.0-beta.25",
"next-themes": "^0.4.4",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"tailwind-merge": "^2.5.5", "tailwind-merge": "^2.5.5",

View File

@ -14,6 +14,7 @@ import {
import { SessionProvider } from "next-auth/react"; import { SessionProvider } from "next-auth/react";
import { AppSidebar } from "@/components/app-sidebar"; import { AppSidebar } from "@/components/app-sidebar";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { ModeSwitcher } from "@/components/mode-switcher";
import ConfirmationDialog from "@/dialogs/ConfirmationDialog"; import ConfirmationDialog from "@/dialogs/ConfirmationDialog";
export default function DashboardLayout({ export default function DashboardLayout({
@ -27,6 +28,7 @@ export default function DashboardLayout({
<header className="flex h-16 shrink-0 items-center gap-2"> <header className="flex h-16 shrink-0 items-center gap-2">
<div className="flex items-center gap-2 px-4"> <div className="flex items-center gap-2 px-4">
<SidebarTrigger className="-ml-1" /> <SidebarTrigger className="-ml-1" />
<ModeSwitcher />
<Separator orientation="vertical" className="mr-2 h-4" /> <Separator orientation="vertical" className="mr-2 h-4" />
<Breadcrumb> <Breadcrumb>
<BreadcrumbList> <BreadcrumbList>

View File

@ -2,6 +2,7 @@ import "@/app/globals.css";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import type { Metadata } from "next"; import type { Metadata } from "next";
import { Inter } from "next/font/google"; import { Inter } from "next/font/google";
import { ThemeProvider } from "@/components/theme-provider";
const inter = Inter({ subsets: ["latin"], variable: "--font-sans" }); const inter = Inter({ subsets: ["latin"], variable: "--font-sans" });
@ -20,8 +21,15 @@ export default function RootLayout({
<html lang="en" className="h-full" suppressHydrationWarning> <html lang="en" className="h-full" suppressHydrationWarning>
<body <body
className={cn("font-sans antialiased flex min-h-full", inter.variable)} className={cn("font-sans antialiased flex min-h-full", inter.variable)}
>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
> >
<div className="w-full">{children}</div> <div className="w-full">{children}</div>
</ThemeProvider>
</body> </body>
</html> </html>
); );

View File

@ -0,0 +1,26 @@
"use client";
import * as React from "react";
import { useTheme } from "next-themes";
import { Sun, Moon } from "lucide-react";
import { Button } from "@/components/ui/button";
export function ModeSwitcher() {
const { setTheme, resolvedTheme } = useTheme();
const toggleTheme = React.useCallback(() => {
setTheme(resolvedTheme === "dark" ? "light" : "dark");
}, [resolvedTheme, setTheme]);
return (
<Button
variant="ghost"
className="group/toggle h-8 w-8 px-0"
onClick={toggleTheme}
>
<Sun className="hidden [html.dark_&]:block" />
<Moon className="hidden [html.light_&]:block" />
<span className="sr-only">Toggle theme</span>
</Button>
);
}

View File

@ -0,0 +1,11 @@
"use client";
import * as React from "react";
import { ThemeProvider as NextThemesProvider } from "next-themes";
export function ThemeProvider({
children,
...props
}: React.ComponentProps<typeof NextThemesProvider>) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}