header.tsx 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. "use client";
  2. import Link from "next/link";
  3. import Image from "next/image";
  4. import { LoginLink, LogoutLink, RegisterLink } from "@kinde-oss/kinde-auth-nextjs/server";
  5. import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";
  6. import { useTheme } from "@/app/providers";
  7. import {
  8. NavigationMenu,
  9. NavigationMenuContent,
  10. NavigationMenuItem,
  11. NavigationMenuLink,
  12. NavigationMenuList,
  13. NavigationMenuTrigger,
  14. } from "@/components/ui/navigation-menu";
  15. import { Button } from "@/components/ui/button";
  16. import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
  17. import { Menu, Home, Settings, User, LogOut, LogIn } from "lucide-react";
  18. import { DarkModeToggle } from "./dark-mode-toggle";
  19. import React from "react";
  20. const userMenuItems = [
  21. {
  22. title: "Profile",
  23. href: "/profile",
  24. description: "Manage your profile settings",
  25. icon: User,
  26. },
  27. {
  28. title: "Settings",
  29. href: "/settings",
  30. description: "Configure your preferences",
  31. icon: Settings,
  32. },
  33. ];
  34. export default function Header() {
  35. const { isAuthenticated, getUser, isLoading } = useKindeBrowserClient();
  36. const { theme } = useTheme();
  37. const user = getUser();
  38. const logoSrc = theme === "dark" ? "/vtorio-dark.svg" : "/vtorio.svg";
  39. if (isLoading) {
  40. return (
  41. <header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
  42. <div className="container flex h-16 items-center justify-between">
  43. <div className="flex items-center gap-6 pl-4 md:pl-6">
  44. <Link href="/" className="flex items-center space-x-2">
  45. <Image
  46. src={logoSrc}
  47. alt="vtor.io"
  48. width={32}
  49. height={8}
  50. className="h-8 w-auto"
  51. priority
  52. />
  53. </Link>
  54. </div>
  55. <div className="flex items-center gap-4 pr-4 md:pr-6">
  56. <div className="h-8 w-20 bg-gray-200 animate-pulse rounded"></div>
  57. </div>
  58. </div>
  59. </header>
  60. );
  61. }
  62. return (
  63. <header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
  64. <div className="container flex h-16 items-center justify-between">
  65. <div className="flex items-center gap-6 pl-4 md:pl-6">
  66. <Link href="/" className="flex items-center space-x-2">
  67. <Image
  68. src={logoSrc}
  69. alt="vtor.io"
  70. width={32}
  71. height={8}
  72. className="h-8 w-auto"
  73. priority
  74. />
  75. </Link>
  76. </div>
  77. <div className="flex items-center gap-4 pr-4 md:pr-6">
  78. <DarkModeToggle />
  79. {isAuthenticated ? (
  80. <>
  81. <NavigationMenu className="hidden md:flex">
  82. <NavigationMenuList>
  83. <NavigationMenuItem>
  84. <NavigationMenuTrigger className="h-9">
  85. <div className="flex items-center gap-2">
  86. <Image
  87. className="rounded-full"
  88. src={user?.picture || "/default-avatar.png"}
  89. alt="User Avatar"
  90. width={24}
  91. height={24}
  92. />
  93. <span className="text-sm font-medium">{user?.given_name || user?.email}</span>
  94. </div>
  95. </NavigationMenuTrigger>
  96. <NavigationMenuContent>
  97. <ul className="grid gap-3 p-6 w-[300px]">
  98. {userMenuItems.map((item) => (
  99. <li key={item.title}>
  100. <NavigationMenuLink asChild>
  101. <Link
  102. href={item.href}
  103. className="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground">
  104. <div className="flex items-center gap-2">
  105. <item.icon className="h-4 w-4" />
  106. <div className="text-sm font-medium leading-none">{item.title}</div>
  107. </div>
  108. <p className="line-clamp-2 text-sm leading-snug text-muted-foreground">
  109. {item.description}
  110. </p>
  111. </Link>
  112. </NavigationMenuLink>
  113. </li>
  114. ))}
  115. <li>
  116. <LogoutLink className="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground">
  117. <div className="flex items-center gap-2">
  118. <LogOut className="h-4 w-4" />
  119. <div className="text-sm font-medium leading-none">Logout</div>
  120. </div>
  121. <p className="line-clamp-2 text-sm leading-snug text-muted-foreground">
  122. Sign out of your account
  123. </p>
  124. </LogoutLink>
  125. </li>
  126. </ul>
  127. </NavigationMenuContent>
  128. </NavigationMenuItem>
  129. </NavigationMenuList>
  130. </NavigationMenu>
  131. </>
  132. ) : (
  133. <div className="hidden md:flex items-center gap-2">
  134. <LoginLink>
  135. <Button variant="ghost" size="sm">
  136. <LogIn className="h-4 w-4 mr-2" />
  137. Login
  138. </Button>
  139. </LoginLink>
  140. <RegisterLink>
  141. <Button size="sm">Sign Up</Button>
  142. </RegisterLink>
  143. </div>
  144. )}
  145. {/* Mobile Menu */}
  146. <Sheet>
  147. <SheetTrigger asChild className="md:hidden">
  148. <Button variant="ghost" size="icon">
  149. <Menu className="h-5 w-5" />
  150. <span className="sr-only">Toggle menu</span>
  151. </Button>
  152. </SheetTrigger>
  153. <SheetContent side="right" className="w-[300px]">
  154. <div className="flex flex-col space-y-4 mt-8">
  155. <Link href="/" className="flex items-center space-x-2">
  156. <Home className="h-4 w-4" />
  157. <span>Home</span>
  158. </Link>
  159. {isAuthenticated ? (
  160. <>
  161. <div className="border-t pt-4">
  162. <div className="flex items-center space-x-2 mb-4">
  163. <Image
  164. className="rounded-full"
  165. src={user?.picture || "/default-avatar.png"}
  166. alt="User Avatar"
  167. width={32}
  168. height={32}
  169. />
  170. <span className="font-medium">{user?.given_name || user?.email}</span>
  171. </div>
  172. {userMenuItems.map((item) => (
  173. <Link
  174. key={item.title}
  175. href={item.href}
  176. className="flex items-center space-x-2 py-2">
  177. <item.icon className="h-4 w-4" />
  178. <span>{item.title}</span>
  179. </Link>
  180. ))}
  181. <LogoutLink className="flex items-center space-x-2 py-2 text-red-600">
  182. <LogOut className="h-4 w-4" />
  183. <span>Logout</span>
  184. </LogoutLink>
  185. </div>
  186. </>
  187. ) : (
  188. <div className="border-t pt-4 space-y-2">
  189. <LoginLink>
  190. <Button variant="ghost" className="w-full justify-start">
  191. <LogIn className="h-4 w-4 mr-2" />
  192. Login
  193. </Button>
  194. </LoginLink>
  195. <RegisterLink>
  196. <Button className="w-full">Sign Up</Button>
  197. </RegisterLink>
  198. </div>
  199. )}
  200. </div>
  201. </SheetContent>
  202. </Sheet>
  203. </div>
  204. </div>
  205. </header>
  206. );
  207. }