AirShelf/components/Sidebar.tsx
iye f420af2069
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 6s
chore: 全量推送 · 累积页面改动 + Next.js 工程骨架 + v1/ 归档 + 文档
页面 (电商AI平台/)
- account / team / settings / index / products / projects: 累积迭代
- restraint.css: 设计 token 补充
- login.html / register.html: 新增登录注册页
- _ARCHIVE.md: 归档说明

Next.js 工程骨架
- app/ + components/: 新一代 SPA 雏形 (page / layout / sidebar / topbar / GridBg / Icon)
- package.json / package-lock.json / next.config.mjs / tsconfig.json / postcss.config.mjs / next-env.d.ts

历史归档 / 文档
- v1/: 原 V1 静态稿镜像 (含 mockup-A/B/C)
- PRD.md / deployment-guide.md / _check.html
- ui参考/ / screenshots/

杂项
- .gitignore 调整
- 删除根 README.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 21:16:46 +08:00

80 lines
2.6 KiB
TypeScript

"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import Icon from "./Icon";
const NAV = [
{ id: "workspace", label: "工作台", icon: "home" as const, href: "/" },
{ id: "play", label: "试拍台", icon: "play" as const, href: "/play" },
{
id: "projects",
label: "项目",
icon: "folder" as const,
href: "/projects",
chev: true,
},
{ id: "products", label: "商品库", icon: "tile" as const, href: "/products" },
{ id: "library", label: "资产库", icon: "bars" as const, href: "/library" },
{ id: "usage", label: "用量", icon: "bars2" as const, href: "/usage" },
{ id: "api", label: "API Keys", icon: "key" as const, href: "/api-keys" },
{ id: "settings", label: "设置", icon: "cog" as const, href: "/settings" },
];
function isActive(pathname: string, href: string): boolean {
if (href === "/") return pathname === "/";
return pathname === href || pathname.startsWith(href + "/");
}
export default function Sidebar() {
const pathname = usePathname();
// /account is reached via the user pill in the topbar — not in nav.
return (
<aside className="sidebar">
<div className="brand">
<div className="flame">
<Icon name="flame" size={22} />
</div>
<div className="brand-name">·Studio</div>
<div className="brand-ver">v1</div>
</div>
<div className="search-box">
<Icon name="search" />
<span></span>
<span className="kbd">K</span>
</div>
<nav className="sidebar-nav">
{NAV.map((n) => {
const active = isActive(pathname, n.href);
return (
<Link key={n.id} href={n.href} className={active ? "active" : ""}>
<Icon name={n.icon} />
<span className="label">{n.label}</span>
{n.chev && <Icon name="chev-down" className="chev" />}
</Link>
);
})}
<div className="nav-section"></div>
<div className="nav-item disabled" title="V1.5 上线 · 敬请期待">
<Icon name="team" />
<span className="label"></span>
<span className="badge-mini">V1.5</span>
</div>
</nav>
<div className="aside-foot">
<Link href="/account" className="aside-user">
<div className="av"></div>
<div className="em">li.dao@studio.cn</div>
</Link>
<div className="aside-collapse">
<Icon name="chev-right" size={12} style={{ transform: "rotate(180deg)" }} />
</div>
</div>
</aside>
);
}