feat(navbar) a navbar with theme switcher

This commit is contained in:
lumither committed 2024-04-25 00:41:32 +08:00
1 parent 65e7c101ac
commit d26d45c65a
7 files changed
+137 -9

No files matched your search

+9
View File
@@ -0,0 +1,9 @@
import React from 'react';
function About() {
return (
<div></div>
);
}
export default About;
+9
View File
@@ -0,0 +1,9 @@
import React from 'react';
function Blog() {
return (
<div></div>
);
}
export default Blog;
+2
View File
@@ -3,6 +3,7 @@ import { Inter } from 'next/font/google';
import './globals.css'; import './globals.css';
import React from 'react'; import React from 'react';
import { ThemeProvider as NextThemesProvider } from 'next-themes'; import { ThemeProvider as NextThemesProvider } from 'next-themes';
import Navbar from '@/components/Navbar';
const inter = Inter({ subsets: [ 'latin' ] }); const inter = Inter({ subsets: [ 'latin' ] });
@@ -20,6 +21,7 @@ export default function RootLayout({
<html lang="en" suppressHydrationWarning> <html lang="en" suppressHydrationWarning>
<body className={ inter.className }> <body className={ inter.className }>
<NextThemesProvider attribute="class" defaultTheme="dark"> <NextThemesProvider attribute="class" defaultTheme="dark">
<Navbar />
{ children } { children }
</NextThemesProvider> </NextThemesProvider>
</body> </body>
+1 -3
View File
@@ -1,9 +1,7 @@
import ThemeSwitcher from '@/components/ThemeSwitcher';
export default function Home() { export default function Home() {
return ( return (
<main> <main>
<ThemeSwitcher /> {/*<ThemeSwitcher />*/ }
</main> </main>
); );
} }
+102
View File
@@ -0,0 +1,102 @@
'use client';
import React, { useEffect, useState } from 'react';
import {
Navbar as NextUINavbar,
NavbarBrand,
NavbarContent,
NavbarItem,
NavbarMenu,
NavbarMenuItem,
NavbarMenuToggle
} from '@nextui-org/react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import ThemeSwitcher from '@/components/ThemeSwitcher';
const entries: { display_name: string; href: string; }[] = [
{
display_name: 'Home',
href: '/'
},
{
display_name: 'About',
href: '/about'
},
{
display_name: 'Blog',
href: '/blog'
}
];
function Navbar() {
const [ scrolled, setScrolled ] = useState(false);
useEffect(() => {
const handleScroll = () => {
const isScrolled = window.scrollY > 0;
setScrolled(isScrolled);
};
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
return (
<>
<NextUINavbar isBlurred isBordered>
<NavbarContent className="sm:hidden" justify="start">
<NavbarMenuToggle />
</NavbarContent>
<NavbarContent className="sm:hidden pr-3" justify="center">
<NavbarBrand>
<p className="font-bold text-inherit">{ 'Lumither\'s site' }</p>
</NavbarBrand>
</NavbarContent>
<NavbarContent className="hidden sm:flex gap-4" justify="center">
<NavbarBrand>
<p className="font-bold text-inherit">{ 'Lumither\'s site' }</p>
</NavbarBrand>
{ entries.map((item, index) => (
// eslint-disable-next-line react-hooks/rules-of-hooks
<NavbarItem key={ index } isActive={ usePathname() === item.href }>
<Link
className="w-full"
href={ item.href }
>
{ item.display_name }
</Link>
</NavbarItem>
)) }
</NavbarContent>
<NavbarContent justify="end">
<NavbarItem>
<ThemeSwitcher />
</NavbarItem>
</NavbarContent>
<NavbarMenu>
{ entries.map((item, index) => (
<NavbarMenuItem key={ index }>
<Link
className="w-full"
href={ item.href }
>
{ item.display_name }
</Link>
</NavbarMenuItem>
)) }
</NavbarMenu>
</NextUINavbar>
</>
);
}
export default Navbar;
+12 -5
View File
@@ -2,7 +2,8 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useTheme } from 'next-themes'; import { useTheme } from 'next-themes';
import { Button } from '@nextui-org/react'; import { Switch } from '@nextui-org/react';
import { MdOutlineDarkMode, MdOutlineLightMode } from 'react-icons/md';
function ThemeSwitcher() { function ThemeSwitcher() {
const [ mounted, setMounted ] = useState(false); const [ mounted, setMounted ] = useState(false);
@@ -18,12 +19,18 @@ function ThemeSwitcher() {
return ( return (
<div> <div>
<Button onClick={ () => { <Switch
color={ 'default' }
startContent={ <MdOutlineLightMode /> }
endContent={ <MdOutlineDarkMode /> }
onValueChange={ (isSelected) => {
if (isSelected) {
setTheme('light'); setTheme('light');
} }>Light Mode</Button> } else {
<Button onClick={ () => {
setTheme('dark'); setTheme('dark');
} }>Dark Mode</Button> }
} }
></Switch>
</div> </div>
); );
} }
+2 -1
View File
@@ -14,7 +14,8 @@
"next": "14.2.2", "next": "14.2.2",
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
"react": "^18", "react": "^18",
"react-dom": "^18" "react-dom": "^18",
"react-icons": "^5.1.0"
}, },
"devDependencies": { "devDependencies": {
"typescript": "^5", "typescript": "^5",