import { useState, useRef, useEffect } from "react"; import { Link, useLocation } from "react-router-dom"; import { useAuth } from "../context/AuthContext"; import { useTheme } from "../context/ThemeContext"; import { Home, Search, Folder, Bell, PenSquare, User, LogOut, ChevronDown, Highlighter, Bookmark, Sun, Moon, Monitor, ExternalLink, Menu, X, } from "lucide-react"; import { SiFirefox, SiGooglechrome, SiGithub, SiBluesky, SiDiscord, } from "react-icons/si"; import { FaEdge } from "react-icons/fa"; import tangledLogo from "../assets/tangled.svg"; import { getUnreadNotificationCount } from "../api/client"; import logo from "../assets/logo.svg"; const isFirefox = typeof navigator !== "undefined" && /Firefox/i.test(navigator.userAgent); const isEdge = typeof navigator !== "undefined" && /Edg/i.test(navigator.userAgent); function getExtensionInfo() { if (isFirefox) { return { url: "https://addons.mozilla.org/en-US/firefox/addon/margin/", icon: SiFirefox, label: "Firefox", }; } if (isEdge) { return { url: "https://microsoftedge.microsoft.com/addons/detail/margin/nfjnmllpdgcdnhmmggjihjbidmeadddn", icon: FaEdge, label: "Edge", }; } return { url: "https://chromewebstore.google.com/detail/margin/cgpmbiiagnehkikhcbnhiagfomajncpa/", icon: SiGooglechrome, label: "Chrome", }; } export default function TopNav() { const { user, isAuthenticated, logout, loading } = useAuth(); const { theme, setTheme } = useTheme(); const location = useLocation(); const [userMenuOpen, setUserMenuOpen] = useState(false); const [moreMenuOpen, setMoreMenuOpen] = useState(false); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const [unreadCount, setUnreadCount] = useState(0); const userMenuRef = useRef(null); const moreMenuRef = useRef(null); const isActive = (path) => { if (path === "/") return location.pathname === "/"; return location.pathname.startsWith(path); }; const ext = getExtensionInfo(); const ExtIcon = ext.icon; useEffect(() => { if (isAuthenticated) { getUnreadNotificationCount() .then((data) => setUnreadCount(data.count || 0)) .catch(() => {}); const interval = setInterval(() => { getUnreadNotificationCount() .then((data) => setUnreadCount(data.count || 0)) .catch(() => {}); }, 60000); return () => clearInterval(interval); } }, [isAuthenticated]); useEffect(() => { const handleClickOutside = (e) => { if (userMenuRef.current && !userMenuRef.current.contains(e.target)) { setUserMenuOpen(false); } if (moreMenuRef.current && !moreMenuRef.current.contains(e.target)) { setMoreMenuOpen(false); } }; document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, []); const closeMobileMenu = () => setMobileMenuOpen(false); const getInitials = () => { if (user?.displayName) return user.displayName.substring(0, 2).toUpperCase(); if (user?.handle) return user.handle.substring(0, 2).toUpperCase(); return "U"; }; const cycleTheme = () => { const next = theme === "system" ? "light" : theme === "light" ? "dark" : "system"; setTheme(next); }; return (
Margin Margin
Get Extension
{moreMenuOpen && (
GitHub Tangled Bluesky Discord
setMoreMenuOpen(false)} > Privacy setMoreMenuOpen(false)} > Terms
)}
{isAuthenticated && ( <> setUnreadCount(0)} title="Notifications" > {unreadCount > 0 && } New )} {!loading && (isAuthenticated ? (
{userMenuOpen && (
{user?.displayName || user?.handle} @{user?.handle}
setUserMenuOpen(false)} > View Profile
)}
) : ( Sign In ))}
{mobileMenuOpen && (
Home Browse {isAuthenticated && ( <> Highlights Bookmarks Collections Notifications {unreadCount > 0 && ( {unreadCount} )} New )} )}
); }