File size: 6,074 Bytes
5ef6e9d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | import { useState } from "react";
import { Link, useLocation } from "wouter";
import { Sparkles, Image as ImageIcon, Video, Key, LogIn, LogOut, User, Shield } from "lucide-react";
import { cn } from "@/lib/utils";
import { SettingsButton } from "@/components/SettingsDialog";
import { useLang } from "@/contexts/LanguageContext";
import { useAuth } from "@/contexts/AuthContext";
import { AuthModal } from "@/components/AuthModal";
export function Navbar() {
const [location] = useLocation();
const { lang, setLang, t } = useLang();
const { user, isSignedIn, isAdmin, signOut } = useAuth();
const [authOpen, setAuthOpen] = useState(false);
return (
<>
<nav className="border-b border-border/50 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 sticky top-0 z-50">
<div className="container mx-auto px-4 h-16 flex items-center justify-between">
<Link href="/" className="flex items-center gap-2 no-underline">
<div className="w-8 h-8 rounded-lg bg-primary/20 flex items-center justify-center border border-primary/30 text-primary">
<Sparkles className="w-4 h-4" />
</div>
<span className="font-semibold text-lg tracking-tight bg-gradient-to-r from-primary to-accent bg-clip-text text-transparent">
{t.appName}
</span>
</Link>
<div className="flex items-center gap-1">
<Link href="/" className={cn(
"px-4 py-2 rounded-md text-sm font-medium transition-colors hover:text-foreground",
location === "/" ? "bg-secondary text-foreground" : "text-muted-foreground"
)}>
<div className="flex items-center gap-2">
<Sparkles className="w-4 h-4" />
<span>{t.navCreate}</span>
</div>
</Link>
<Link href="/history" className={cn(
"px-4 py-2 rounded-md text-sm font-medium transition-colors hover:text-foreground",
location === "/history" ? "bg-secondary text-foreground" : "text-muted-foreground"
)}>
<div className="flex items-center gap-2">
<ImageIcon className="w-4 h-4" />
<span className="hidden sm:inline">{t.navHistory}</span>
</div>
</Link>
<Link href="/video" className={cn(
"px-4 py-2 rounded-md text-sm font-medium transition-colors hover:text-foreground",
location === "/video" ? "bg-secondary text-foreground" : "text-muted-foreground"
)}>
<div className="flex items-center gap-2">
<Video className="w-4 h-4" />
<span className="hidden sm:inline">{t.navVideo}</span>
</div>
</Link>
{isSignedIn && (
<Link href="/api-keys" className={cn(
"px-4 py-2 rounded-md text-sm font-medium transition-colors hover:text-foreground",
location === "/api-keys" ? "bg-secondary text-foreground" : "text-muted-foreground"
)}>
<div className="flex items-center gap-2">
<Key className="w-4 h-4" />
<span className="hidden sm:inline">{t.navApiKeys}</span>
</div>
</Link>
)}
{isAdmin && (
<Link href="/admin" className={cn(
"px-4 py-2 rounded-md text-sm font-medium transition-colors hover:text-foreground",
location === "/admin" ? "bg-secondary text-foreground" : "text-muted-foreground"
)}>
<div className="flex items-center gap-2">
<Shield className="w-4 h-4 text-yellow-400" />
<span className="hidden sm:inline">{t.navAdmin}</span>
</div>
</Link>
)}
<button
onClick={() => setLang(lang === "zh" ? "en" : "zh")}
className="px-3 py-1.5 rounded-md text-xs font-semibold border border-border/60 text-muted-foreground hover:text-foreground hover:border-primary/50 transition-colors ml-1"
title={lang === "zh" ? "Switch to English" : "切換為繁體中文"}
>
{lang === "zh" ? "EN" : "中"}
</button>
{isSignedIn ? (
<div className="flex items-center gap-2 ml-1">
<div className="flex items-center gap-2 px-2 py-1 rounded-md">
<div className="w-6 h-6 rounded-full bg-primary/20 border border-primary/30 flex items-center justify-center">
<User className="w-3 h-3 text-primary" />
</div>
<span className="text-xs text-muted-foreground hidden md:inline max-w-[100px] truncate">
{user?.displayName || user?.email?.split("@")[0] || ""}
</span>
</div>
<button
onClick={signOut}
className="flex items-center gap-1.5 px-2 py-1.5 rounded-md text-xs text-muted-foreground hover:text-foreground hover:bg-secondary transition-colors"
title={t.navSignOut}
>
<LogOut className="w-3.5 h-3.5" />
<span className="hidden sm:inline">{t.navSignOut}</span>
</button>
</div>
) : (
<button
onClick={() => setAuthOpen(true)}
className="flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-secondary transition-colors ml-1"
>
<LogIn className="w-4 h-4" />
<span className="hidden sm:inline">{t.navSignIn}</span>
</button>
)}
<div className="ml-1">
<SettingsButton />
</div>
</div>
</div>
</nav>
<AuthModal open={authOpen} onOpenChange={setAuthOpen} />
</>
);
}
|