Requests / src /components /Navbar.tsx
armand0e's picture
init
101ebaa
"use client";
import { useEffect, useRef, useState } from "react";
import { Menu, Sun, Moon } from "lucide-react";
import Link from "next/link";
import Image from "next/image";
import { useRouter } from "next/navigation";
import { useTheme } from "./ThemeProvider";
import { Button } from "@/components/ui/button";
export default function Navbar() {
const [isOpen, setIsOpen] = useState(false);
const { theme, toggleTheme } = useTheme();
const router = useRouter();
const adminHoldTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const adminGestureTriggeredRef = useRef(false);
const clearAdminHoldTimer = () => {
if (adminHoldTimerRef.current) {
clearTimeout(adminHoldTimerRef.current);
adminHoldTimerRef.current = null;
}
};
useEffect(() => {
const onWindowBlur = () => {
clearAdminHoldTimer();
adminGestureTriggeredRef.current = false;
};
window.addEventListener("blur", onWindowBlur);
return () => {
window.removeEventListener("blur", onWindowBlur);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<nav className="fixed inset-x-0 top-0 z-50 bg-background/90 backdrop-blur supports-[backdrop-filter]:bg-background/70 shadow-[0_1px_0_rgba(255,255,255,0.03)]">
<div className="mx-auto flex h-16 max-w-6xl items-center justify-between px-4 sm:px-6">
<Link
href="/"
className="flex items-center gap-2.5"
onPointerDown={(e) => {
if (!e.ctrlKey) return;
adminGestureTriggeredRef.current = false;
clearAdminHoldTimer();
adminHoldTimerRef.current = setTimeout(() => {
adminGestureTriggeredRef.current = true;
router.push("/admin");
}, 3000);
}}
onPointerUp={() => {
clearAdminHoldTimer();
}}
onPointerLeave={() => {
clearAdminHoldTimer();
}}
onPointerCancel={() => {
clearAdminHoldTimer();
}}
onClick={(e) => {
if (adminGestureTriggeredRef.current) {
e.preventDefault();
adminGestureTriggeredRef.current = false;
}
}}
>
<Image
src="/teich.svg"
alt="TeichAI Logo"
width={32}
height={32}
className="rounded-lg"
/>
<span className="text-lg font-semibold tracking-tight text-foreground">TeichAI Requests</span>
</Link>
<div className="hidden items-center gap-1 md:flex">
<Button
onClick={toggleTheme}
variant="ghost"
size="icon"
className="ml-1"
aria-label="Toggle theme"
>
{theme === "dark" ? <Sun className="size-4" /> : <Moon className="size-4" />}
</Button>
<Button asChild className="ml-1">
<a href="https://huggingface.co/TeichAI" target="_blank" rel="noopener noreferrer">
HF Hub
</a>
</Button>
</div>
<div className="flex items-center gap-1 md:hidden">
<Button
onClick={toggleTheme}
variant="ghost"
size="icon"
aria-label="Toggle theme"
>
{theme === "dark" ? <Sun className="size-5" /> : <Moon className="size-5" />}
</Button>
<Button
variant="ghost"
size="icon"
aria-label="Open menu"
onClick={() => setIsOpen(!isOpen)}
>
<Menu className="size-5" />
</Button>
</div>
</div>
{isOpen && (
<div className="border-t border-border bg-background p-4 md:hidden">
<Button asChild className="w-full">
<a href="https://huggingface.co/TeichAI" target="_blank" rel="noopener noreferrer">
HF Hub
</a>
</Button>
</div>
)}
</nav>
);
}