AirShelf/v1/mockups/mockup-C.html
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

477 lines
22 KiB
HTML
Raw Permalink 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.

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>方案 C · 双栏工作台 · 新建商品(AI 生成)</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="../assets/restraint.css">
<style>
body { background: var(--bg); }
.demo-bar { padding: 16px 24px; background: var(--card); border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 16px; font-family: 'Inter', sans-serif; }
.demo-bar .ti { font-weight: 700; font-size: 15px; }
.demo-bar .desc { font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--ink-3); }
/* Workbench - full screen */
.wb {
height: calc(100vh - 60px);
display: grid;
grid-template-rows: 56px 1fr;
background: var(--bg);
}
/* Top bar */
.wb-top {
padding: 0 24px;
background: var(--card);
border-bottom: 1px solid var(--border);
display: flex; align-items: center; gap: 18px;
}
.wb-top .ti { font-size: 15px; font-weight: 700; }
.wb-top .ti span { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--orange); background: var(--orange-tint); border: 1px solid var(--orange-soft); padding: 2px 6px; margin-left: 8px; letter-spacing: .04em; }
.wb-top .meta-line { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--ink-3); letter-spacing: .04em; }
.wb-top .right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.wb-top .x { width: 32px; height: 32px; display: grid; place-items: center; cursor: pointer; color: var(--ink-2); border: 1px solid var(--border); }
.wb-top .x:hover { color: var(--orange); border-color: var(--orange); }
/* Main split */
.wb-main { display: grid; grid-template-columns: 280px 1fr 340px; min-height: 0; }
/* Left sidebar - steps */
.wb-side {
border-right: 1px solid var(--border);
background: var(--bg);
overflow-y: auto;
padding: 18px 0;
}
.step-item {
padding: 14px 20px;
display: flex; align-items: flex-start; gap: 12px;
cursor: pointer;
border-left: 3px solid transparent;
position: relative;
}
.step-item:hover { background: var(--bg-soft); }
.step-item.active { background: var(--orange-tint); border-left-color: var(--orange); }
.step-item .num {
width: 24px; height: 24px;
border: 1px solid var(--border); background: var(--card);
color: var(--ink-3);
font-family: 'JetBrains Mono', monospace; font-size: 11px; font-weight: 700;
display: grid; place-items: center;
flex-shrink: 0;
}
.step-item.done .num { background: var(--ink); color: #FFF; border-color: var(--ink); }
.step-item.active .num { background: var(--orange); color: #FFF; border-color: var(--orange); }
.step-item .info { flex: 1; min-width: 0; }
.step-item .ti2 { font-size: 13.5px; font-weight: 600; color: var(--ink-2); }
.step-item.active .ti2 { color: var(--ink); }
.step-item .sub { font-size: 11px; color: var(--ink-3); margin-top: 3px; font-family: 'JetBrains Mono', monospace; letter-spacing: .02em; line-height: 1.5; }
.step-item.done .sub { color: var(--ink-2); font-family: 'Inter', sans-serif; letter-spacing: 0; }
.side-divider { height: 1px; background: var(--border); margin: 14px 20px; }
.side-section-h { padding: 4px 20px 8px; font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--ink-3); letter-spacing: .08em; text-transform: uppercase; font-weight: 600; }
/* Center canvas - big preview */
.wb-canvas {
background: var(--bg);
overflow-y: auto;
padding: 32px;
display: flex; flex-direction: column;
position: relative;
min-width: 0;
}
.canvas-h {
margin-bottom: 24px;
display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
}
.canvas-h h2 { font-size: 22px; font-weight: 700; letter-spacing: -.012em; }
.canvas-h p { font-size: 13px; color: var(--ink-2); margin-top: 4px; }
.canvas-h .step-tag { font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--ink-3); padding: 3px 8px; background: var(--bg-soft); border: 1px solid var(--border-soft); letter-spacing: .04em; flex-shrink: 0; }
/* Center grid - bigger images */
.big-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; max-width: 720px; }
.big-card {
aspect-ratio: 1;
background: var(--card);
border: 1px solid var(--border);
cursor: pointer;
position: relative;
overflow: hidden;
}
.big-card:hover { border-color: var(--ink-3); }
.big-card .placeholder { width: 100%; height: 100%; }
.big-card.selected { border: 3px solid var(--orange); }
.big-card.selected::after {
content: '✓'; position: absolute; top: 12px; right: 12px;
width: 32px; height: 32px; background: var(--orange); color: #FFF;
display: grid; place-items: center; font-weight: 700; font-size: 16px;
}
.big-card .corner-info {
position: absolute; bottom: 12px; left: 12px;
background: rgba(255,255,255,.94);
border: 1px solid var(--border);
padding: 4px 10px;
font-family: 'JetBrains Mono', monospace; font-size: 11px;
letter-spacing: .04em; color: var(--ink-2);
}
/* Right panel - controls */
.wb-controls {
border-left: 1px solid var(--border);
background: var(--bg);
overflow-y: auto;
padding: 22px 22px 100px;
display: flex; flex-direction: column;
position: relative;
}
.ctrl-section { margin-bottom: 24px; }
.ctrl-section h3 {
font-family: 'JetBrains Mono', monospace;
font-size: 10.5px;
color: var(--ink-3);
letter-spacing: .08em;
text-transform: uppercase;
font-weight: 600;
margin-bottom: 10px;
}
.ctrl-card {
background: var(--card);
border: 1px solid var(--border);
padding: 14px;
font-size: 12.5px;
color: var(--ink-2);
line-height: 1.6;
}
.ctrl-card strong { color: var(--ink); font-weight: 600; }
.selected-mini { display: flex; gap: 6px; margin-top: 8px; }
.selected-mini .placeholder { width: 36px; height: 36px; }
.selected-mini .placeholder.empty { background: transparent; border: 1px dashed var(--border); }
/* Model row in controls */
.model-row-side { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
.model-card-side { aspect-ratio: 3/4; background: var(--card); border: 1px solid var(--border); cursor: pointer; position: relative; }
.model-card-side:hover { border-color: var(--ink-3); }
.model-card-side.selected { border: 2px solid var(--orange); }
.model-card-side.selected::after { content: '✓'; position: absolute; top: 4px; right: 4px; width: 16px; height: 16px; background: var(--orange); color: #FFF; display: grid; place-items: center; font-weight: 700; font-size: 9px; }
.model-card-side .placeholder { width: 100%; height: 100%; }
.model-card-side .lbl { position: absolute; bottom: 0; left: 0; right: 0; background: rgba(255,255,255,.95); padding: 2px 4px; font-size: 9.5px; color: var(--ink-2); font-family: 'JetBrains Mono', monospace; text-align: center; letter-spacing: .02em; }
/* Bottom bar */
.wb-bottom {
position: absolute; left: 0; right: 0; bottom: 0;
padding: 14px 22px;
background: var(--card);
border-top: 1px solid var(--border);
display: flex; flex-direction: column; gap: 10px;
}
.wb-bottom .row1 { display: flex; align-items: center; justify-content: space-between; }
.cost-info { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--ink-3); letter-spacing: .04em; }
.cost-info .price { color: var(--orange); font-weight: 700; }
/* Step 1 form (used when step 1 active) */
.form-card { background: var(--card); border: 1px solid var(--border); padding: 22px; max-width: 720px; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.upload-c {
aspect-ratio: 4/5;
background: var(--card);
border: 1.5px dashed var(--border);
display: grid; place-items: center;
text-align: center;
cursor: pointer;
color: var(--ink-2);
margin-bottom: 18px;
}
.upload-c.has-file { border-style: solid; padding: 0; border-color: var(--orange); background: var(--bg-soft); }
.upload-c.has-file .placeholder { width: 100%; height: 100%; }
.upload-c .ic-cam { width: 40px; height: 40px; border: 1px solid currentColor; display: grid; place-items: center; margin: 0 auto 12px; }
.bullet-list { list-style: none; padding: 0; }
.bullet-list li { display: flex; gap: 8px; align-items: center; padding: 8px 10px; background: var(--bg-soft); border: 1px solid var(--border); margin-bottom: 6px; font-size: 13px; }
.bullet-list .num { width: 18px; height: 18px; background: var(--card); border: 1px solid var(--border); font-size: 11px; color: var(--ink-2); display: grid; place-items: center; flex-shrink: 0; font-family: 'JetBrains Mono', monospace; }
/* Tip box */
.tip-mini { padding: 10px 12px; background: var(--orange-tint); border: 1px solid var(--orange-soft); font-size: 11.5px; color: var(--ink-2); margin-bottom: 18px; line-height: 1.5; }
.tip-mini strong { color: var(--orange); display: block; font-family: 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: .04em; margin-bottom: 4px; }
</style>
</head>
<body>
<div class="demo-bar">
<a href="index.html" class="btn btn-ghost btn-sm">← 返回方案对比</a>
<span class="ti">方案 C · 双栏工作台(Canvas + Sidebar)</span>
<span class="desc">// 全屏工作台,左侧导航 + 中间大预览 + 右侧操作 · 视觉空间最大</span>
</div>
<div class="wb">
<!-- Top -->
<header class="wb-top">
<div class="ti">透真玻尿酸补水面膜 <span>[ AI 生成模式 ]</span></div>
<div class="meta-line">// 美妆个护 · ¥39.9 · 已上传原图</div>
<div class="right">
<button class="btn btn-sm">保存草稿</button>
<div class="x" onclick="alert('演示原型')"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg></div>
</div>
</header>
<div class="wb-main">
<!-- Left sidebar -->
<aside class="wb-side">
<div class="side-section-h">// CREATE FLOW</div>
<div class="step-item done" data-step="1">
<div class="num"></div>
<div class="info">
<div class="ti2">商品信息</div>
<div class="sub">名称、品类、价格、卖点</div>
</div>
</div>
<div class="step-item active" data-step="2">
<div class="num">2</div>
<div class="info">
<div class="ti2">生成头图</div>
<div class="sub">// AI 生成 · 4 选 1</div>
</div>
</div>
<div class="step-item" data-step="3">
<div class="num">3</div>
<div class="info">
<div class="ti2">模特上身图</div>
<div class="sub">// 选模特 + 4 选 N</div>
</div>
</div>
<div class="step-item" data-step="4">
<div class="num">4</div>
<div class="info">
<div class="ti2">完成创建</div>
<div class="sub">// 预览 · 提交</div>
</div>
</div>
<div class="side-divider"></div>
<div class="side-section-h">// SELECTED ASSETS</div>
<div style="padding: 0 20px;">
<div style="font-size:11.5px; color:var(--ink-3); margin-bottom:8px; font-family:'JetBrains Mono',monospace; letter-spacing:.02em;">原图 · 1 张</div>
<div class="placeholder" style="width:100%; aspect-ratio: 4/5; margin-bottom:14px;"><span class="ph-frame">补水面膜<br>1200×1500</span></div>
<div style="font-size:11.5px; color:var(--ink-3); font-family:'JetBrains Mono',monospace; letter-spacing:.02em;">头图 · 待选</div>
</div>
</aside>
<!-- Center canvas (changes per step) -->
<main class="wb-canvas" id="canvas">
<!-- STEP 2 default view: 生成头图 -->
<div class="canvas-h">
<div>
<h2>选一张你最满意的头图</h2>
<p>AI 已基于原图生成 4 张候选,点击你想要的那张。可以重新生成。</p>
</div>
<span class="step-tag">// STEP 2 / 4 · HEAD IMAGES</span>
</div>
<div class="big-grid" id="head-grid">
<div class="big-card selected" data-id="h1">
<div class="placeholder"><span class="ph-frame">候选 A · 白底简约 · 适合电商详情</span></div>
<span class="corner-info">[ A · 1920×1920 · WHITE-BG ]</span>
</div>
<div class="big-card" data-id="h2">
<div class="placeholder"><span class="ph-frame">候选 B · 木纹背景 · 自然温暖</span></div>
<span class="corner-info">[ B · 1920×1920 · WOOD ]</span>
</div>
<div class="big-card" data-id="h3">
<div class="placeholder"><span class="ph-frame">候选 C · 浅米石材 · 高级质感</span></div>
<span class="corner-info">[ C · 1920×1920 · STONE ]</span>
</div>
<div class="big-card" data-id="h4">
<div class="placeholder"><span class="ph-frame">候选 D · 暖光氛围 · 生活场景</span></div>
<span class="corner-info">[ D · 1920×1920 · AMBIENT ]</span>
</div>
</div>
</main>
<!-- Right controls -->
<aside class="wb-controls">
<div class="ctrl-section">
<h3>// 当前选中</h3>
<div class="ctrl-card">
<strong>候选 A · 白底简约</strong>
<div style="margin-top:6px; color:var(--ink-3); font-family:'JetBrains Mono',monospace; font-size:11px; letter-spacing:.02em;">1920×1920 · 适合主图</div>
</div>
</div>
<div class="ctrl-section">
<h3>// 重新生成参数</h3>
<div class="field" style="margin-bottom:10px;">
<label class="field-label" style="font-size:11.5px;">背景风格</label>
<select class="select" style="height:32px; font-size:12px;">
<option>纯白底(电商主图)</option>
<option>木纹/石材</option>
<option>居家场景</option>
<option>自定义</option>
</select>
</div>
<div class="field" style="margin-bottom:10px;">
<label class="field-label" style="font-size:11.5px;">画面氛围</label>
<select class="select" style="height:32px; font-size:12px;">
<option>明亮简洁</option>
<option>暖光氛围</option>
<option>冷调高级</option>
</select>
</div>
<button class="btn" style="width:100%; margin-top:6px;">↻ 用以上参数重新生成</button>
</div>
<div class="ctrl-section">
<h3>// 提示</h3>
<div class="tip-mini">
<strong>不满意不扣费</strong>
重新生成 4 张约 ¥0.20。已生成共 4 张,确认后才扣费。
</div>
</div>
<div class="wb-bottom">
<div class="row1">
<span class="cost-info">// 累计 <span class="price">¥0.20</span></span>
<span class="cost-info">2 / 4</span>
</div>
<div class="hstack">
<button class="btn" style="flex:1;">← 上一步</button>
<button class="btn btn-primary" style="flex:1;" id="next-btn">下一步 →</button>
</div>
</div>
</aside>
</div>
</div>
<script>
// single select for head
document.querySelectorAll('#head-grid .big-card').forEach(c => {
c.onclick = () => {
document.querySelectorAll('#head-grid .big-card').forEach(x => x.classList.remove('selected'));
c.classList.add('selected');
};
});
// Step navigation
document.querySelectorAll('.step-item').forEach(item => {
item.onclick = () => {
const step = +item.dataset.step;
switchStep(step);
};
});
document.getElementById('next-btn').onclick = () => {
const cur = document.querySelector('.step-item.active');
const n = +cur.dataset.step;
if (n < 4) switchStep(n + 1);
else alert('✓ 商品已创建!');
};
function switchStep(n) {
document.querySelectorAll('.step-item').forEach((s, i) => {
s.classList.remove('active', 'done');
if (i + 1 < n) s.classList.add('done');
if (i + 1 === n) s.classList.add('active');
});
renderCanvas(n);
}
function renderCanvas(n) {
const c = document.getElementById('canvas');
if (n === 1) {
c.innerHTML = `
<div class="canvas-h">
<div><h2>填写商品信息 · 上传原图</h2><p>上传一张你拍的商品图(任何角度都行,AI 会优化),并填写商品基本信息。</p></div>
<span class="step-tag">// STEP 1 / 4 · INFO + UPLOAD</span>
</div>
<div style="display:grid; grid-template-columns: 280px 1fr; gap:24px; max-width: 920px;">
<div>
<div class="upload-c has-file"><div class="placeholder"><span class="ph-frame">补水面膜.jpg<br>1200×1500</span></div></div>
<div style="font-family:'JetBrains Mono',monospace; font-size:11px; color:var(--ink-3); text-align:center; letter-spacing:.02em;">// 已上传 · 点击重选</div>
</div>
<div class="form-card">
<div class="field"><label class="field-label">商品名称<span class="req">*</span></label><input class="input" value="透真玻尿酸补水面膜"></div>
<div class="field-row">
<div class="field"><label class="field-label">品类</label><select class="select"><option>美妆个护</option></select></div>
<div class="field"><label class="field-label">参考价</label><input class="input" value="¥39.9"></div>
</div>
<div class="field"><label class="field-label">核心卖点<span class="req">*</span></label>
<ul class="bullet-list">
<li><span class="num">1</span> 透明质酸 + B5,敷完不黏不闷</li>
<li><span class="num">2</span> 30g 大容量精华液</li>
<li><span class="num">+</span> <input class="input" style="height:24px; border:0; padding:0 4px; background:transparent;" placeholder="添加新卖点"></li>
</ul>
</div>
<div class="field"><label class="field-label">目标人群</label><input class="input" value="22-32 岁女性、熬夜党、敏感肌"></div>
</div>
</div>
`;
} else if (n === 2) {
c.innerHTML = `
<div class="canvas-h">
<div><h2>选一张你最满意的头图</h2><p>AI 已基于原图生成 4 张候选,点击你想要的那张。可以重新生成。</p></div>
<span class="step-tag">// STEP 2 / 4 · HEAD IMAGES</span>
</div>
<div class="big-grid" id="head-grid">
<div class="big-card selected" data-id="h1"><div class="placeholder"><span class="ph-frame">候选 A · 白底简约</span></div><span class="corner-info">[ A · 1920×1920 ]</span></div>
<div class="big-card" data-id="h2"><div class="placeholder"><span class="ph-frame">候选 B · 木纹背景</span></div><span class="corner-info">[ B · 1920×1920 ]</span></div>
<div class="big-card" data-id="h3"><div class="placeholder"><span class="ph-frame">候选 C · 浅米石材</span></div><span class="corner-info">[ C · 1920×1920 ]</span></div>
<div class="big-card" data-id="h4"><div class="placeholder"><span class="ph-frame">候选 D · 暖光氛围</span></div><span class="corner-info">[ D · 1920×1920 ]</span></div>
</div>
`;
bindBig('#head-grid');
} else if (n === 3) {
c.innerHTML = `
<div class="canvas-h">
<div><h2>选模特,生成上身图</h2><p>选好模特后,AI 会让 ta 持你刚选的商品图生成 4 张参考图,可多选。</p></div>
<span class="step-tag">// STEP 3 / 4 · MODEL + WEAR</span>
</div>
<div class="big-grid" id="wear-grid" style="grid-template-columns: repeat(2,1fr);">
<div class="big-card selected" data-id="w1"><div class="placeholder"><span class="ph-frame">上身 A · 持物半身</span></div><span class="corner-info">[ A · 持物半身 ]</span></div>
<div class="big-card" data-id="w2"><div class="placeholder"><span class="ph-frame">上身 B · 敷面膜中</span></div><span class="corner-info">[ B · 敷面膜中 ]</span></div>
<div class="big-card selected" data-id="w3"><div class="placeholder"><span class="ph-frame">上身 C · 镜前自拍</span></div><span class="corner-info">[ C · 镜前自拍 ]</span></div>
<div class="big-card" data-id="w4"><div class="placeholder"><span class="ph-frame">上身 D · 床边特写</span></div><span class="corner-info">[ D · 床边特写 ]</span></div>
</div>
`;
bindMulti('#wear-grid');
} else if (n === 4) {
c.innerHTML = `
<div class="canvas-h">
<div><h2>预览 · 创建</h2><p>检查下面的素材和信息无误后,点击右下「创建商品」。</p></div>
<span class="step-tag">// STEP 4 / 4 · CONFIRM</span>
</div>
<div style="background:var(--card); border:1px solid var(--border); padding:32px; max-width: 760px;">
<h3 style="font-size:20px; font-weight:700;">透真玻尿酸补水面膜</h3>
<div style="font-family:'JetBrains Mono',monospace; font-size:11.5px; color:var(--ink-3); margin-top:4px; letter-spacing:.02em;">// 美妆个护 · ¥39.9 · AI 生成 · 模特: 林夕</div>
<div style="display:grid; grid-template-columns: repeat(4,1fr); gap:10px; margin-top:18px;">
<div class="placeholder" style="aspect-ratio:1;"><span class="ph-frame">原图</span></div>
<div class="placeholder" style="aspect-ratio:1;"><span class="ph-frame">头图 A</span></div>
<div class="placeholder" style="aspect-ratio:1;"><span class="ph-frame">上身 A</span></div>
<div class="placeholder" style="aspect-ratio:1;"><span class="ph-frame">上身 C</span></div>
</div>
</div>
`;
}
}
function bindBig(sel) {
document.querySelectorAll(sel + ' .big-card').forEach(c => {
c.onclick = () => {
document.querySelectorAll(sel + ' .big-card').forEach(x => x.classList.remove('selected'));
c.classList.add('selected');
};
});
}
function bindMulti(sel) {
document.querySelectorAll(sel + ' .big-card').forEach(c => {
c.onclick = () => c.classList.toggle('selected');
});
}
bindBig('#head-grid');
</script>
</body>
</html>