iot-playground / src /components /Layout.tsx
3v324v23's picture
Initial commit: IoT Playground
847854e
Raw
History Blame Contribute Delete
3.71 kB
import React from 'react';
import { Link, useLocation } from 'react-router-dom';
import { Home, Cpu, MessageSquare, Activity, Settings, Menu, X } from 'lucide-react';
import { useState } from 'react';
import { clsx } from 'clsx';
const navItems = [
{ path: '/', icon: Home, label: '首页' },
{ path: '/devices', icon: Cpu, label: '设备控制' },
{ path: '/ai', icon: MessageSquare, label: 'AI 交互' },
{ path: '/system', icon: Activity, label: '系统状态' },
];
export const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const location = useLocation();
return (
<div className="min-h-screen bg-zinc-950 text-zinc-100 flex">
{/* Sidebar - Desktop */}
<aside className="hidden md:flex flex-col w-64 border-r border-zinc-800 bg-zinc-900/50 backdrop-blur-xl">
<div className="p-6">
<h1 className="text-xl font-bold bg-gradient-to-r from-blue-400 to-emerald-400 bg-clip-text text-transparent">
IoT Playground
</h1>
</div>
<nav className="flex-1 px-4 space-y-2">
{navItems.map((item) => (
<Link
key={item.path}
to={item.path}
className={clsx(
"flex items-center space-x-3 px-4 py-3 rounded-xl transition-all duration-200",
location.pathname === item.path
? "bg-blue-600/20 text-blue-400 shadow-[inset_0_0_20px_rgba(37,99,235,0.1)]"
: "hover:bg-zinc-800 text-zinc-400 hover:text-zinc-200"
)}
>
<item.icon size={20} />
<span className="font-medium">{item.label}</span>
</Link>
))}
</nav>
<div className="p-4 border-t border-zinc-800">
<button className="flex items-center space-x-3 px-4 py-3 w-full rounded-xl hover:bg-zinc-800 text-zinc-400 transition-all">
<Settings size={20} />
<span className="font-medium">设置</span>
</button>
</div>
</aside>
{/* Mobile Header */}
<div className="md:hidden fixed top-0 left-0 right-0 h-16 bg-zinc-900/80 backdrop-blur-lg border-b border-zinc-800 z-50 px-4 flex items-center justify-between">
<h1 className="text-lg font-bold bg-gradient-to-r from-blue-400 to-emerald-400 bg-clip-text text-transparent">
IoT Playground
</h1>
<button onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)} className="p-2 text-zinc-400 hover:text-zinc-200">
{isMobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
</button>
</div>
{/* Mobile Menu Overlay */}
{isMobileMenuOpen && (
<div className="md:hidden fixed inset-0 bg-zinc-950/90 backdrop-blur-md z-40 pt-20 px-6">
<nav className="space-y-4">
{navItems.map((item) => (
<Link
key={item.path}
to={item.path}
onClick={() => setIsMobileMenuOpen(false)}
className={clsx(
"flex items-center space-x-4 px-6 py-4 rounded-2xl text-lg font-medium transition-all",
location.pathname === item.path ? "bg-blue-600 text-white" : "text-zinc-400"
)}
>
<item.icon size={24} />
<span>{item.label}</span>
</Link>
))}
</nav>
</div>
)}
{/* Main Content */}
<main className="flex-1 pt-16 md:pt-0 overflow-y-auto">
<div className="max-w-7xl mx-auto p-6 md:p-10">
{children}
</div>
</main>
</div>
);
};