AirShelf/app/page.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

197 lines
7.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Link from "next/link";
import Topbar from "@/components/Topbar";
import Icon from "@/components/Icon";
interface Recent {
name: string;
meta: string;
prog: ("done" | "cur" | "fail" | "")[];
pill: { kind: "info" | "ok" | "err"; label: string };
action: { label: string; href: string };
}
const RECENT: Recent[] = [
{
name: "补水面膜 · 痛点种草",
meta: "补水面膜 / AI 全生 / 6 镜",
prog: ["done", "done", "cur", "", ""],
pill: { kind: "info", label: "故事板 待确认" },
action: { label: "继续", href: "/pipeline?stage=3" },
},
{
name: "蓝牙耳机 · 开箱测评",
meta: "南卡 Lite Pro / 自带脚本 / 5 镜",
prog: ["done", "done", "done", "done", "done"],
pill: { kind: "ok", label: "已完成" },
action: { label: "打开", href: "/pipeline?stage=5" },
},
{
name: "速食牛肉面 · 一句话主题",
meta: "滋啦速食 / 一句话 / 4 镜",
prog: ["done", "cur", "", "", ""],
pill: { kind: "info", label: "资产生成中" },
action: { label: "继续", href: "/pipeline?stage=2" },
},
{
name: "防晒霜 · 对比展示",
meta: "透真防晒 / AI 全生 / 6 镜",
prog: ["done", "done", "done", "cur", ""],
pill: { kind: "info", label: "视频生成 4/6" },
action: { label: "继续", href: "/pipeline?stage=4" },
},
{
name: "咖啡冻干粉 · 剧情带货",
meta: "三顿半同款 / 一句话 / 5 镜",
prog: ["done", "done", "fail", "", ""],
pill: { kind: "err", label: "故事板失败" },
action: { label: "查看", href: "/pipeline?stage=3" },
},
];
export default function WorkspacePage() {
return (
<>
<Topbar />
<section className="content">
<div className="welcome page-head">
<div>
<h1></h1>
<div className="sub">
<span className="mono-sub">// 05.13 · 周三</span>
<span>·</span>
<b style={{ color: "var(--ink)" }}>3 </b>
</div>
</div>
<div className="actions">
<Link className="btn" href="/products">
<Icon name="plus" size={14} />
</Link>
<Link className="btn btn-primary" href="/projects/new">
<Icon name="plus" size={14} />
</Link>
</div>
</div>
<div className="stats has-corners" style={{ marginBottom: 36 }}>
<span className="corner-tr" aria-hidden />
<span className="corner-bl" aria-hidden />
<div className="stat">
<div className="lbl"> <span className="badge">ALL</span></div>
<div className="v">12</div>
<div className="delta up"> +3</div>
</div>
<div className="stat">
<div className="lbl"> <span className="badge">WIP</span></div>
<div className="v">3</div>
<div className="delta">2 </div>
</div>
<div className="stat">
<div className="lbl"> <span className="badge">DONE</span></div>
<div className="v">8</div>
<div className="delta up"> +33%</div>
</div>
<div className="stat">
<div className="lbl"> <span className="badge">¥</span></div>
<div className="v">¥327<small>.40</small></div>
<div className="usage-bar"><span /></div>
<div className="sub-mono"> ¥162.60 / ¥500</div>
</div>
</div>
<div className="grid2">
<div>
<div className="section-h">
<h2></h2>
<Link className="more" href="/projects">[ ALL · 12 ] </Link>
</div>
<div className="list-card">
{RECENT.map((r) => (
<div className="recent-row" key={r.name}>
<div className="thumb">9:16</div>
<div className="r-meta">
<div className="name">{r.name}</div>
<div className="sub">{r.meta}</div>
</div>
<div className="prog">
{r.prog.map((p, i) => <span key={i} className={p || undefined} />)}
</div>
<span className={`pill pill-${r.pill.kind}`}><span className="dot" />{r.pill.label}</span>
<Link className="btn btn-sm" href={r.action.href}>{r.action.label}</Link>
</div>
))}
</div>
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 24 }}>
<div>
<div className="section-h">
<h2></h2>
<span className="more">[ /shortcuts ]</span>
</div>
<div className="shortcuts">
<Link className="shortcut" href="/products">
<div className="ic">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.8}>
<path d="m3 7 9-4 9 4-9 4-9-4z" />
<path d="m3 12 9 4 9-4M3 17l9 4 9-4" />
</svg>
</div>
<div>
<div className="t"></div>
<div className="d">12 SKU</div>
</div>
</Link>
<Link className="shortcut" href="/library">
<div className="ic"><Icon name="bars" /></div>
<div>
<div className="t"></div>
<div className="d"> 8 · 14 · 8</div>
</div>
</Link>
<Link className="shortcut" href="/account">
<div className="ic">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.8}>
<circle cx="12" cy="12" r="9" />
<path d="M12 7v10M9 10h4a1.5 1.5 0 0 1 0 3h-3a1.5 1.5 0 0 0 0 3h4" />
</svg>
</div>
<div>
<div className="t"></div>
<div className="d">¥327.40</div>
</div>
</Link>
<Link className="shortcut" href="/projects">
<div className="ic">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.8}>
<rect x="3" y="4" width="18" height="16" rx="2" />
<path d="M7 4v16M16 4v16M3 9h18M3 15h18" />
</svg>
</div>
<div>
<div className="t"></div>
<div className="d">12 </div>
</div>
</Link>
</div>
</div>
<div>
<div className="section-h">
<h2></h2>
<span className="more">[ FAQ ]</span>
</div>
<div className="tip">
<strong></strong>
{" "}
<span className="mono-pill">[ ]</span> token
</div>
</div>
</div>
</div>
</section>
</>
);
}