header.tsx 9.8 KB

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