header.tsx 9.7 KB

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