diff options
| author | schererleander <leander@schererleander.de> | 2025-07-02 22:18:06 +0200 |
|---|---|---|
| committer | schererleander <leander@schererleander.de> | 2025-07-02 22:18:06 +0200 |
| commit | 899d50098c20c5652040e989932628d63af28301 (patch) | |
| tree | 7947dc9bb983494fc1d3dcffa2c770a3c8db88f8 /src/components/Navbar.tsx | |
| parent | ab03900adf080da08a0b2a3628fd0dcf0af28420 (diff) | |
feat: add UI components
Diffstat (limited to 'src/components/Navbar.tsx')
| -rw-r--r-- | src/components/Navbar.tsx | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx new file mode 100644 index 0000000..2f1e0d4 --- /dev/null +++ b/src/components/Navbar.tsx @@ -0,0 +1,104 @@ +"use client" + +import Link from "next/link" +import { useSession, signOut } from "next-auth/react" +import { Button } from "@/components/ui/button" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { LogIn, Settings, LogOut } from "lucide-react" +import { ThemeToggle } from "@/components/ThemeToggle" + +export default function Navbar() { + const { data: session, status } = useSession() + + const getInitials = (name: string) => { + return name + .split(' ') + .map(word => word[0]) + .join('') + .toUpperCase() + .slice(0, 2) + } + + return ( + <nav className="border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60"> + <div className="container mx-auto px-4 h-16 flex items-center justify-between"> + <Link href="/" className="flex items-center space-x-2"> + <div className="w-8 h-8 bg-primary rounded-md flex items-center justify-center"> + <span className="text-primary-foreground font-bold text-lg">W</span> + </div> + <span className="font-bold text-xl">Widget</span> + </Link> + + <div className="flex items-center space-x-4"> + <ThemeToggle /> + {status === "loading" ? ( + <div className="flex items-center space-x-2"> + <div className="w-16 h-4 bg-muted animate-pulse rounded hidden sm:block" /> + <div className="w-8 h-8 rounded-full bg-muted animate-pulse" /> + </div> + ) : session ? ( + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button variant="ghost" className="relative h-10 w-auto px-2 rounded-full"> + <div className="flex items-center space-x-2"> + <span className="text-sm font-medium hidden sm:block"> + {session.user?.name} + </span> + <Avatar className="h-8 w-8"> + <AvatarImage src={session.user?.image || ""} alt={session.user?.name || ""} /> + <AvatarFallback className="text-xs"> + {session.user?.name ? getInitials(session.user.name) : "U"} + </AvatarFallback> + </Avatar> + </div> + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent className="w-56" align="end" forceMount> + <DropdownMenuLabel className="font-normal"> + <div className="flex flex-col space-y-1"> + <p className="text-sm font-medium leading-none"> + {session.user?.name} + </p> + <p className="text-xs leading-none text-muted-foreground"> + {session.user?.email} + </p> + </div> + </DropdownMenuLabel> + <DropdownMenuSeparator /> + <DropdownMenuItem asChild> + <Link href="/settings" className="w-full cursor-pointer"> + <Settings className="mr-2 h-4 w-4" /> + Settings + </Link> + </DropdownMenuItem> + <DropdownMenuSeparator /> + <DropdownMenuItem + className="cursor-pointer text-destructive hover:text-destructive focus:text-destructive" + onClick={() => signOut()} + > + <LogOut className="mr-2 h-4 w-4 text-destructive" /> + Log out + </DropdownMenuItem> + </DropdownMenuContent> + </DropdownMenu> + ) : ( + <Button asChild> + <Link href="/login"> + <LogIn className="mr-2 h-4 w-4" /> + Sign In + </Link> + </Button> + )} + </div> + </div> + </nav> + ) +} |
