Initial commit: 提交控制器版本2核心代码
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
/* ============================================================
|
||||
BOTTOM NAV — Luxsin X9 Controller (Mobile)
|
||||
Design: iOS/Android App-style bottom tab bar
|
||||
5 tabs: 社区 / HP-EQ / 主页 / Effect / 我的AI
|
||||
- Active tab: cyan icon + top indicator bar
|
||||
- Inactive: muted icon + label
|
||||
============================================================ */
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
Activity,
|
||||
Bot,
|
||||
Home,
|
||||
MessageSquare,
|
||||
Sliders,
|
||||
} from "lucide-react";
|
||||
import { Link, useLocation } from "wouter";
|
||||
|
||||
interface NavItem {
|
||||
path: string;
|
||||
icon: React.ComponentType<{ size?: number; className?: string }>;
|
||||
label: string;
|
||||
placeholder?: boolean;
|
||||
}
|
||||
|
||||
const NAV_ITEMS: NavItem[] = [
|
||||
{ path: "/community", icon: MessageSquare, label: "社区", placeholder: true },
|
||||
{ path: "/eq", icon: Sliders, label: "HP-EQ" },
|
||||
{ path: "/", icon: Home, label: "主页" },
|
||||
{ path: "/effects", icon: Activity, label: "Effect" },
|
||||
{ path: "/ai", icon: Bot, label: "我的AI", placeholder: true },
|
||||
];
|
||||
|
||||
export default function BottomNav() {
|
||||
const [location] = useLocation();
|
||||
|
||||
return (
|
||||
<nav
|
||||
className="fixed bottom-0 left-0 right-0 z-50 lg:hidden"
|
||||
style={{
|
||||
background: "rgba(10, 10, 12, 0.96)",
|
||||
backdropFilter: "blur(40px) saturate(200%)",
|
||||
WebkitBackdropFilter: "blur(40px) saturate(200%)",
|
||||
borderTop: "0.5px solid rgba(255,255,255,0.1)",
|
||||
boxShadow: "0 -1px 0 rgba(0,255,246,0.05)",
|
||||
paddingBottom: "env(safe-area-inset-bottom, 8px)",
|
||||
}}
|
||||
>
|
||||
<div className="flex items-stretch justify-around">
|
||||
{NAV_ITEMS.map((item) => {
|
||||
const isActive = location === item.path ||
|
||||
(item.path === "/" && location === "/") ||
|
||||
(item.path !== "/" && location.startsWith(item.path));
|
||||
const Icon = item.icon;
|
||||
|
||||
return (
|
||||
<Link key={item.path} href={item.placeholder ? "#" : item.path}>
|
||||
<div className="flex flex-col items-center justify-center relative pt-2.5 pb-1.5 px-3">
|
||||
{/* Active indicator bar */}
|
||||
<div
|
||||
className="absolute top-0 left-1/2 -translate-x-1/2 rounded-b-full transition-all duration-300"
|
||||
style={{
|
||||
width: isActive ? 24 : 0,
|
||||
height: 2.5,
|
||||
background: "#00FFF6",
|
||||
boxShadow: isActive ? "0 0 8px rgba(0,255,246,0.9)" : "none",
|
||||
opacity: isActive ? 1 : 0,
|
||||
transition: "width 0.25s cubic-bezier(0.34,1.56,0.64,1), opacity 0.2s ease",
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Icon */}
|
||||
<div
|
||||
className="flex items-center justify-center rounded-[12px] transition-all duration-200"
|
||||
style={{
|
||||
width: 38,
|
||||
height: 32,
|
||||
background: isActive ? "rgba(0,255,246,0.1)" : "transparent",
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
size={isActive ? 20 : 19}
|
||||
className={cn(
|
||||
"transition-all duration-200",
|
||||
isActive ? "text-[#00FFF6]" : "text-white/30"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Label */}
|
||||
<span
|
||||
className="mt-0.5 transition-all duration-200 leading-none"
|
||||
style={{
|
||||
fontFamily: "-apple-system, 'SF Pro Text', sans-serif",
|
||||
fontSize: 10,
|
||||
fontWeight: isActive ? 600 : 400,
|
||||
color: isActive ? "#00FFF6" : "rgba(255,255,255,0.28)",
|
||||
textShadow: isActive ? "0 0 8px rgba(0,255,246,0.5)" : "none",
|
||||
}}
|
||||
>
|
||||
{item.label}
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user