feat: migrate simple theme switcher component

This commit is contained in:
ArraysID
2025-04-27 05:56:52 +07:00
parent c07c75f23b
commit 10da7d0a16
7 changed files with 79 additions and 1 deletions
@@ -9,6 +9,7 @@ import { cn } from '@imphnen-frontend-service/utils';
import Image from 'next/image'; import Image from 'next/image';
import Link from 'next/link'; import Link from 'next/link';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { SimpleThemeToggle } from './simple-theme-toggle';
export function Header() { export function Header() {
const [isScrolled, setIsScrolled] = useState(false); const [isScrolled, setIsScrolled] = useState(false);
@@ -80,6 +81,7 @@ export function Header() {
</nav> </nav>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<SimpleThemeToggle />
<Button className="hidden md:flex bg-gradient-to-r from-primary to-blue-400 hover:from-primary/90 hover:to-blue-400/90 transition-all duration-300"> <Button className="hidden md:flex bg-gradient-to-r from-primary to-blue-400 hover:from-primary/90 hover:to-blue-400/90 transition-all duration-300">
Gabung Discord Gabung Discord
</Button> </Button>
@@ -0,0 +1,42 @@
'use client';
import {
Button,
MoonIcon,
SunIcon,
} from '@imphnen-frontend-service/shadcn-ui/atoms';
import { useTheme } from 'next-themes';
import { useEffect, useState } from 'react';
export function SimpleThemeToggle() {
const { theme, setTheme } = useTheme();
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return null;
}
const toggleTheme = () => {
setTheme(theme === 'dark' ? 'light' : 'dark');
};
return (
<Button
variant="outline"
size="icon"
onClick={toggleTheme}
className="focus-visible:ring-0"
>
{theme === 'dark' ? (
<SunIcon className="h-[1.2rem] w-[1.2rem]" />
) : (
<MoonIcon className="h-[1.2rem] w-[1.2rem]" />
)}
<span className="sr-only">Toggle theme</span>
</Button>
);
}
@@ -0,0 +1,8 @@
'use client';
import type { ThemeProviderProps } from 'next-themes';
import { ThemeProvider as NextThemesProvider } from 'next-themes';
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}
+11 -1
View File
@@ -1,6 +1,7 @@
import { type Metadata } from 'next'; import { type Metadata } from 'next';
import { Inter } from 'next/font/google'; import { Inter } from 'next/font/google';
import '../styles/globals.css'; import '../styles/globals.css';
import { ThemeProvider } from './_components/theme-provider';
const inter = Inter({ subsets: ['latin'] }); const inter = Inter({ subsets: ['latin'] });
@@ -16,7 +17,16 @@ export default function RootLayout({
}) { }) {
return ( return (
<html lang="id" suppressHydrationWarning> <html lang="id" suppressHydrationWarning>
<body className={inter.className}>{children}</body> <body className={inter.className}>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
{children}
</ThemeProvider>
</body>
</html> </html>
); );
} }
+4
View File
@@ -7,9 +7,11 @@ import {
LuLaptop as LaptopIcon, LuLaptop as LaptopIcon,
LuMenu as MenuIcon, LuMenu as MenuIcon,
LuMessageCircle as MessageCircleIcon, LuMessageCircle as MessageCircleIcon,
LuMoon as MoonIcon,
LuQuote as QuoteIcon, LuQuote as QuoteIcon,
LuShare2 as Share2Icon, LuShare2 as Share2Icon,
LuSparkles as SparklesIcon, LuSparkles as SparklesIcon,
LuSun as SunIcon,
LuUsers as UsersIcon, LuUsers as UsersIcon,
LuVideo as VideoIcon, LuVideo as VideoIcon,
LuX as XIcon, LuX as XIcon,
@@ -24,9 +26,11 @@ export {
LaptopIcon, LaptopIcon,
MenuIcon, MenuIcon,
MessageCircleIcon, MessageCircleIcon,
MoonIcon,
QuoteIcon, QuoteIcon,
Share2Icon, Share2Icon,
SparklesIcon, SparklesIcon,
SunIcon,
UsersIcon, UsersIcon,
VideoIcon, VideoIcon,
XIcon, XIcon,
+11
View File
@@ -19,6 +19,7 @@
"framer-motion": "^12.9.2", "framer-motion": "^12.9.2",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"next": "~15.2.4", "next": "~15.2.4",
"next-themes": "^0.4.6",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-hook-form": "^7.55.0", "react-hook-form": "^7.55.0",
@@ -24544,6 +24545,16 @@
} }
} }
}, },
"node_modules/next-themes": {
"version": "0.4.6",
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
"integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==",
"license": "MIT",
"peerDependencies": {
"react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
}
},
"node_modules/next/node_modules/@swc/helpers": { "node_modules/next/node_modules/@swc/helpers": {
"version": "0.5.15", "version": "0.5.15",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
+1
View File
@@ -34,6 +34,7 @@
"framer-motion": "^12.9.2", "framer-motion": "^12.9.2",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"next": "~15.2.4", "next": "~15.2.4",
"next-themes": "^0.4.6",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-hook-form": "^7.55.0", "react-hook-form": "^7.55.0",