diff --git a/web/src/components/header.tsx b/web/src/components/header.tsx index a2cc21a5..bfc91762 100644 --- a/web/src/components/header.tsx +++ b/web/src/components/header.tsx @@ -1,19 +1,26 @@ "use client" -import { Github, PlusCircle, Search } from "lucide-react" +import { Github, LogOut, PlusCircle, Search, Star, LayoutDashboard } from "lucide-react" import Link from "next/link" import { useEffect, useState } from "react" import { IconSubmissionForm } from "@/components/icon-submission-form" +import { LoginModal } from "@/components/login-modal" import { ThemeSwitcher } from "@/components/theme-switcher" -import { REPO_PATH } from "@/constants" +import { REPO_NAME, REPO_PATH } from "@/constants" import { getIconsArray } from "@/lib/api" import { pb } from "@/lib/pb" import type { IconWithName } from "@/types/icons" import { CommandMenu } from "./command-menu" import { HeaderNav } from "./header-nav" +import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar" import { Button } from "./ui/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "./ui/dropdown-menu" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./ui/tooltip" -import { LoginPopup } from "./user-button" interface UserData { username: string @@ -21,12 +28,21 @@ interface UserData { avatar?: string } +function formatStars(stars: number): string { + if (stars >= 1000) { + return `${(stars / 1000).toFixed(1)}K` + } + return stars.toString() +} + export function Header() { const [iconsData, setIconsData] = useState([]) const [isLoaded, setIsLoaded] = useState(false) const [commandMenuOpen, setCommandMenuOpen] = useState(false) + const [loginModalOpen, setLoginModalOpen] = useState(false) const [isLoggedIn, setIsLoggedIn] = useState(false) const [userData, setUserData] = useState(undefined) + const [stars, setStars] = useState(0) useEffect(() => { async function loadIcons() { @@ -44,7 +60,20 @@ export function Header() { }, []) useEffect(() => { - // Initialize auth state from PocketBase authStore + async function fetchStars() { + try { + const response = await fetch(`https://api.github.com/repos/${REPO_NAME}`) + const data = await response.json() + setStars(Math.round(data.stargazers_count / 100) * 100) + } catch (error) { + console.error("Failed to fetch stars:", error) + } + } + + fetchStars() + }, []) + + useEffect(() => { const updateAuthState = () => { if (pb.authStore.isValid && pb.authStore.record) { setIsLoggedIn(true) @@ -61,30 +90,31 @@ export function Header() { } } - // Set initial state updateAuthState() - // Listen for auth changes const unsubscribe = pb.authStore.onChange(() => { updateAuthState() }) - // Cleanup listener on unmount return () => { unsubscribe() } }, []) - // Function to open the command menu const openCommandMenu = () => { setCommandMenuOpen(true) } - // Handle sign out using PocketBase const handleSignOut = () => { pb.authStore.clear() } + const handleSubmitClick = () => { + if (!isLoggedIn) { + setLoginModalOpen(true) + } + } + return (
@@ -98,7 +128,7 @@ export function Header() {
- +
@@ -106,7 +136,7 @@ export function Header() {
- {/* Mobile Submit Button -> triggers IconSubmissionForm dialog */} + {/* Mobile Submit Button */}
- - - Submit icon(s) - - } - /> + {isLoggedIn ? ( + + + Submit icon(s) + + } + /> + ) : ( + + )}
{/* Desktop Submit Button */} - + {isLoggedIn ? ( + + ) : ( + + )} @@ -171,11 +224,72 @@ export function Header() {
- + + {isLoggedIn && userData && ( + + + + + +
+
+ + + + {userData.username.slice(0, 2).toUpperCase()} + + +
+

{userData.username}

+

+ {userData.email} +

+
+
+ + + + + + +
+
+
+ )}
@@ -187,6 +301,9 @@ export function Header() { onOpenChange={setCommandMenuOpen} /> )} + + {/* Login Modal */} +
- ); + ) }