小优化,产品愿景,视觉规范,交互和导航大版本
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useApp } from "@/lib/app-context";
|
||||
import { useAuth } from "@/lib/auth-context";
|
||||
import { ProfileModal } from "@/components/profile-modal";
|
||||
import { slideUp } from "@/components/ui/motion-presets";
|
||||
|
||||
const NAV_ITEMS = [
|
||||
{
|
||||
@@ -51,7 +53,7 @@ export function TopNav() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<header className="relative z-10 flex-shrink-0 h-14 border-b border-[var(--border)] bg-[var(--bg-secondary)]/80 backdrop-blur-xl flex items-center px-4 md:px-5 gap-4 md:gap-6">
|
||||
<header className="relative z-10 flex-shrink-0 h-14 border-b border-[var(--border)] surface-1 backdrop-blur-xl flex items-center px-4 md:px-5 gap-4 md:gap-6">
|
||||
{/* 移动端汉堡菜单 */}
|
||||
<button
|
||||
onClick={() => setSidebarCollapsed(!sidebarCollapsed)}
|
||||
@@ -68,13 +70,13 @@ export function TopNav() {
|
||||
{/* Logo */}
|
||||
<Link href="/" className="flex items-center gap-2.5 flex-shrink-0 group">
|
||||
<div className="w-8 h-8 rounded-lg bg-[var(--accent)] flex items-center justify-center
|
||||
shadow-[0_0_12px_rgba(77,184,164,0.25)]
|
||||
group-hover:shadow-[0_0_20px_rgba(77,184,164,0.4)] transition-shadow">
|
||||
shadow-[0_0_12px_rgba(46,139,122,0.25)]
|
||||
group-hover:shadow-[0_0_20px_rgba(46,139,122,0.4)] transition-shadow">
|
||||
<svg width="18" height="18" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 22L12.5 10h2.2L19 22h-2.3l-1.1-3h-4.2l-1.1 3H8Zm3.7-5h3.1l-1.5-4.6h-.1L11.7 17Z" fill="#0C1210" />
|
||||
<circle cx="23" cy="12" r="3.5" stroke="#0C1210" strokeWidth="1.8" fill="none" />
|
||||
<path d="M23 15.5v5" stroke="#0C1210" strokeWidth="1.8" strokeLinecap="round" />
|
||||
<circle cx="23" cy="22.5" r="1" fill="#0C1210" />
|
||||
<path d="M8 22L12.5 10h2.2L19 22h-2.3l-1.1-3h-4.2l-1.1 3H8Zm3.7-5h3.1l-1.5-4.6h-.1L11.7 17Z" fill="white" />
|
||||
<circle cx="23" cy="12" r="3.5" stroke="white" strokeWidth="1.8" fill="none" />
|
||||
<path d="M23 15.5v5" stroke="white" strokeWidth="1.8" strokeLinecap="round" />
|
||||
<circle cx="23" cy="22.5" r="1" fill="white" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-base font-bold tracking-tight text-[var(--text-primary)]">
|
||||
@@ -90,10 +92,10 @@ export function TopNav() {
|
||||
<Link
|
||||
key={href}
|
||||
href={href}
|
||||
className={`relative flex items-center gap-1.5 px-3 md:px-4 py-2 text-sm rounded-lg ${
|
||||
className={`relative flex items-center gap-1.5 px-3 md:px-4 py-2 text-sm rounded-lg transition-all ${
|
||||
active
|
||||
? "glow-border text-[var(--accent)] font-medium !bg-[var(--bg-secondary)]"
|
||||
: "text-[var(--text-secondary)] hover:text-[var(--text-primary)] border border-transparent hover:border-[var(--border-glow)] transition-all"
|
||||
: "text-[var(--text-secondary)] hover:text-[var(--text-primary)] border border-transparent hover:border-[var(--border-glow)]"
|
||||
}`}
|
||||
>
|
||||
{icon}
|
||||
@@ -123,33 +125,41 @@ export function TopNav() {
|
||||
{user.display_name || user.username}
|
||||
</span>
|
||||
</button>
|
||||
{menuOpen && (
|
||||
<div className="absolute right-0 top-full mt-1.5 w-48 rounded-xl
|
||||
glass-panel shadow-xl shadow-black/30 py-1.5 z-50">
|
||||
<button
|
||||
onClick={() => { setMenuOpen(false); setProfileOpen(true); }}
|
||||
className="w-full text-left px-3.5 py-2 text-xs text-[var(--text-secondary)]
|
||||
hover:text-[var(--accent)] hover:bg-[var(--bg-tertiary)]
|
||||
border-b border-[var(--border)] transition-colors cursor-pointer
|
||||
flex items-center gap-1.5"
|
||||
<AnimatePresence>
|
||||
{menuOpen && (
|
||||
<motion.div
|
||||
variants={slideUp}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
exit={{ opacity: 0, y: 4, transition: { duration: 0.1 } }}
|
||||
className="absolute right-0 top-full mt-1.5 w-48 rounded-xl
|
||||
surface-3 py-1.5 z-50"
|
||||
>
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" />
|
||||
<circle cx="12" cy="7" r="4" />
|
||||
</svg>
|
||||
<span>{user.username}</span>
|
||||
{user.is_admin && <span className="text-[var(--accent)]">(管理员)</span>}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => { setMenuOpen(false); logout(); }}
|
||||
className="w-full text-left px-3.5 py-2 text-sm text-[var(--text-secondary)]
|
||||
hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)]
|
||||
transition-colors cursor-pointer"
|
||||
>
|
||||
退出登录
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
onClick={() => { setMenuOpen(false); setProfileOpen(true); }}
|
||||
className="w-full text-left px-3.5 py-2 text-xs text-[var(--text-secondary)]
|
||||
hover:text-[var(--accent)] hover:bg-[var(--bg-tertiary)]
|
||||
border-b border-[var(--border)] transition-colors cursor-pointer
|
||||
flex items-center gap-1.5"
|
||||
>
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" />
|
||||
<circle cx="12" cy="7" r="4" />
|
||||
</svg>
|
||||
<span>{user.username}</span>
|
||||
{user.is_admin && <span className="text-[var(--accent)]">(管理员)</span>}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => { setMenuOpen(false); logout(); }}
|
||||
className="w-full text-left px-3.5 py-2 text-sm text-[var(--text-secondary)]
|
||||
hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)]
|
||||
transition-colors cursor-pointer"
|
||||
>
|
||||
退出登录
|
||||
</button>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
|
||||
Reference in New Issue
Block a user