mirror of
https://github.com/ershisan99/www.git
synced 2025-12-17 12:34:17 +00:00
add dark mode
This commit is contained in:
206
src/components/header.tsx
Normal file
206
src/components/header.tsx
Normal file
@@ -0,0 +1,206 @@
|
||||
'use client'
|
||||
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
import { LogIn, LogOut, Menu, Moon, Settings, Sun, User, X } from 'lucide-react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
|
||||
export function MainHeader() {
|
||||
const { setTheme, theme } = useTheme()
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||
|
||||
// Mock authentication state - replace with your actual auth logic
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(false)
|
||||
|
||||
// Mock user data - replace with your actual user data
|
||||
const userData = {
|
||||
name: 'Player123',
|
||||
avatar: '/placeholder.svg?height=40&width=40',
|
||||
}
|
||||
|
||||
// Toggle authentication for demo purposes
|
||||
const toggleAuth = () => {
|
||||
setIsAuthenticated(!isAuthenticated)
|
||||
}
|
||||
|
||||
return (
|
||||
<header className='sticky top-0 z-40 border-gray-200 border-b bg-white dark:border-zinc-800 dark:bg-zinc-900'>
|
||||
<div className='container mx-auto px-4'>
|
||||
<div className='flex h-16 items-center justify-between'>
|
||||
{/* Logo and Brand */}
|
||||
<div className='flex items-center'>
|
||||
<Link href='/' className='flex items-center gap-2'>
|
||||
<span className='hidden font-bold text-xl sm:inline-block'>
|
||||
Balatro Multiplayer
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Desktop Navigation */}
|
||||
<nav className='hidden items-center space-x-6 md:flex'>
|
||||
<Link
|
||||
href='/'
|
||||
className='font-medium text-gray-700 text-sm transition-colors hover:text-violet-500 dark:text-zinc-300 dark:hover:text-violet-400'
|
||||
>
|
||||
Home
|
||||
</Link>
|
||||
<Link
|
||||
href='/leaderboards'
|
||||
className='font-medium text-gray-700 text-sm transition-colors hover:text-violet-500 dark:text-zinc-300 dark:hover:text-violet-400'
|
||||
>
|
||||
Leaderboards
|
||||
</Link>
|
||||
{/*<Link*/}
|
||||
{/* href='/matches'*/}
|
||||
{/* className='font-medium text-gray-700 text-sm transition-colors hover:text-violet-500 dark:text-zinc-300 dark:hover:text-violet-400'*/}
|
||||
{/*>*/}
|
||||
{/* Matches*/}
|
||||
{/*</Link>*/}
|
||||
<Link
|
||||
href='/about'
|
||||
className='font-medium text-gray-700 text-sm transition-colors hover:text-violet-500 dark:text-zinc-300 dark:hover:text-violet-400'
|
||||
>
|
||||
About
|
||||
</Link>
|
||||
</nav>
|
||||
|
||||
{/* Actions: Theme Toggle, Sign In/User Menu */}
|
||||
<div className='flex items-center gap-2'>
|
||||
{/* Theme Toggle */}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant='ghost' size='icon' className='h-9 w-9'>
|
||||
<Sun className='dark:-rotate-90 h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all 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>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align='end'>
|
||||
<DropdownMenuItem onClick={() => setTheme('light')}>
|
||||
Light
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setTheme('dark')}>
|
||||
Dark
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setTheme('system')}>
|
||||
System
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
{/* Sign In Button or User Menu */}
|
||||
{isAuthenticated ? (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant='ghost'
|
||||
className='relative h-9 w-9 rounded-full'
|
||||
>
|
||||
<Avatar className='h-9 w-9'>
|
||||
<AvatarImage src={userData.avatar} alt={userData.name} />
|
||||
<AvatarFallback className='bg-violet-50 text-violet-600 dark:bg-violet-900/50 dark:text-violet-300'>
|
||||
{userData.name.slice(0, 2).toUpperCase()}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className='w-56' align='end' forceMount>
|
||||
<div className='flex items-center justify-start gap-2 p-2'>
|
||||
<div className='flex flex-col space-y-1 leading-none'>
|
||||
<p className='font-medium'>{userData.name}</p>
|
||||
</div>
|
||||
</div>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link href='/profile' className='flex w-full items-center'>
|
||||
<User className='mr-2 h-4 w-4' />
|
||||
<span>Profile</span>
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link href='/settings' className='flex w-full items-center'>
|
||||
<Settings className='mr-2 h-4 w-4' />
|
||||
<span>Settings</span>
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={toggleAuth}>
|
||||
<LogOut className='mr-2 h-4 w-4' />
|
||||
<span>Log out</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
) : (
|
||||
<Button
|
||||
variant='default'
|
||||
size='sm'
|
||||
className='bg-violet-600 hover:bg-violet-700 dark:text-zinc-100'
|
||||
onClick={toggleAuth}
|
||||
>
|
||||
<LogIn className='mr-2 h-4 w-4' />
|
||||
Sign In
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* Mobile Menu Toggle */}
|
||||
<Button
|
||||
variant='ghost'
|
||||
size='icon'
|
||||
className='h-9 w-9 md:hidden'
|
||||
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||
>
|
||||
{mobileMenuOpen ? (
|
||||
<X className='h-5 w-5' />
|
||||
) : (
|
||||
<Menu className='h-5 w-5' />
|
||||
)}
|
||||
<span className='sr-only'>Toggle menu</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Navigation */}
|
||||
{mobileMenuOpen && (
|
||||
<div className='border-gray-200 border-t px-4 py-4 md:hidden dark:border-zinc-800'>
|
||||
<nav className='flex flex-col space-y-4'>
|
||||
<Link
|
||||
href='/'
|
||||
className='font-medium text-gray-700 text-sm transition-colors hover:text-violet-500 dark:text-zinc-300 dark:hover:text-violet-400'
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
Home
|
||||
</Link>
|
||||
<Link
|
||||
href='/leaderboards'
|
||||
className='font-medium text-gray-700 text-sm transition-colors hover:text-violet-500 dark:text-zinc-300 dark:hover:text-violet-400'
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
Leaderboards
|
||||
</Link>
|
||||
{/*<Link*/}
|
||||
{/* href='/matches'*/}
|
||||
{/* className='font-medium text-gray-700 text-sm transition-colors hover:text-violet-500 dark:text-zinc-300 dark:hover:text-violet-400'*/}
|
||||
{/* onClick={() => setMobileMenuOpen(false)}*/}
|
||||
{/*>*/}
|
||||
{/* Matches*/}
|
||||
{/*</Link>*/}
|
||||
<Link
|
||||
href='/about'
|
||||
className='font-medium text-gray-700 text-sm transition-colors hover:text-violet-500 dark:text-zinc-300 dark:hover:text-violet-400'
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
About
|
||||
</Link>
|
||||
</nav>
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
)
|
||||
}
|
||||
40
src/components/mode-toggle.tsx
Normal file
40
src/components/mode-toggle.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
'use client'
|
||||
|
||||
import { Moon, Sun } from 'lucide-react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import * as React from 'react'
|
||||
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
|
||||
export function ModeToggle() {
|
||||
const { setTheme } = useTheme()
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant='outline' size='icon'>
|
||||
<Sun className='dark:-rotate-90 h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all 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>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align='end'>
|
||||
<DropdownMenuItem onClick={() => setTheme('light')}>
|
||||
Light
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setTheme('dark')}>
|
||||
Dark
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setTheme('system')}>
|
||||
System
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
11
src/components/theme-provider.tsx
Normal file
11
src/components/theme-provider.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
'use client'
|
||||
|
||||
import { ThemeProvider as NextThemesProvider } from 'next-themes'
|
||||
import type * as React from 'react'
|
||||
|
||||
export function ThemeProvider({
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NextThemesProvider>) {
|
||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
|
||||
}
|
||||
Reference in New Issue
Block a user