header.tsx 9.9 KB

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