init: 电商AI平台 v2.1 静态设计稿
- 10 个页面 (工作台/项目/商品/流水线/资产/账户/创建向导) - V2.1 Restraint 设计规范 (冷灰底 + #FA5D19 + 8px 圆角) - 完整 design-system.html 组件库参考 - SVG line icon · stroke 1.5 全合规 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
commit
cae935588b
28
.gitignore
vendored
Normal file
28
.gitignore
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
# 工程文件
|
||||
node_modules/
|
||||
.next/
|
||||
.turbo/
|
||||
dist/
|
||||
build/
|
||||
|
||||
# OS / IDE
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
|
||||
# 日志
|
||||
*.log
|
||||
npm-debug.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# 本地环境
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# 临时
|
||||
*.tmp
|
||||
*.bak
|
||||
screenshots/
|
||||
33
README.md
Normal file
33
README.md
Normal file
@ -0,0 +1,33 @@
|
||||
# AirShelf · UI 设计稿货架
|
||||
|
||||
@zyc / iye 的 UI 设计稿合集。每个子目录是一个独立项目,各自有自己的设计规范和静态稿。
|
||||
|
||||
## 货架内容
|
||||
|
||||
| 项目 | 风格 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| [电商AI平台/](电商AI平台/) | Restraint V2.1 (Firecrawl-aligned) | AI 短视频带货生成平台 · 10 个页面 · 完整 5 阶段流水线 |
|
||||
|
||||
---
|
||||
|
||||
## 浏览方式
|
||||
|
||||
直接 clone + 用浏览器打开任意 `*.html`:
|
||||
|
||||
```bash
|
||||
git clone https://gitea.airlabs.art/zyc/AirShelf.git
|
||||
cd AirShelf/电商AI平台
|
||||
# 浏览器直开 index.html · 或本地起 server
|
||||
npx http-server . -p 8080
|
||||
```
|
||||
|
||||
## 添加新项目
|
||||
|
||||
新项目作为根目录下的兄弟文件夹(中文命名 OK),保持各自独立:
|
||||
|
||||
```
|
||||
AirShelf/
|
||||
├── 电商AI平台/
|
||||
├── <未来项目 B>/
|
||||
└── <未来项目 C>/
|
||||
```
|
||||
952
电商AI平台/DESIGN_SPEC_V2.md
Normal file
952
电商AI平台/DESIGN_SPEC_V2.md
Normal file
@ -0,0 +1,952 @@
|
||||
# 流·Studio 设计规范 · V2.1
|
||||
|
||||
> **版本:** V2.1(2026-05-15)
|
||||
> **风格代号:** Restraint(克制)· Firecrawl-aligned
|
||||
> **适用范围:** 流·Studio 全产品(工作台 / 项目 / 商品库 / 流水线 / 资产库 / 编辑器 / 账户)
|
||||
> **V2.1 更新:** 色彩系统全面对齐 Firecrawl 实测——**冷灰底色**(放弃米白)· **主橙 #FA5D19**(从 #E55B26 调亮)· **20 档 black-alpha**(从 11 档扩展)· **5 色 accent 多彩点**(新增)· accent-black 替代 ink。保留 V2 所有结构性决策(8 px 圆角、inside-border、装订线、mono 装饰)。
|
||||
> **与 V2 关系:** V2.1 兼容 V2 的所有 token 命名(`--ink` `--bg` `--card` `--green` `--red` 等保留为 legacy 别名),代码层无需重写。
|
||||
|
||||
---
|
||||
|
||||
## 0. 变更速查
|
||||
|
||||
### V2 → V2.1(本次 · 色彩系统对齐 Firecrawl)
|
||||
|
||||
| # | 维度 | V2 | V2.1 |
|
||||
| - | ---- | -- | ---- |
|
||||
| C1 | 底色 | `#FAF9F5` 暖米白 | **`#f9f9f9` 冷灰**(`--background-base`) |
|
||||
| C2 | 主橙 | `#E55B26` 砖红 | **`#FA5D19`** 更红更饱和 |
|
||||
| C3 | 文字基色 | `--ink: #15140F` | **`--accent-black: #262626`**(更柔和)· `--ink` 作 legacy 别名 |
|
||||
| C4 | Alpha 阶梯 | 11 档 `--ink-alpha-*` | **20 档 `--black-alpha-*`**(1/2/3/4/5/6/7/8/10/12/16/20/24/32/40/48/56/64/72/88) |
|
||||
| C5 | Alpha base | 全部用 `rgba(0,0,0,...)` | **32% 起换 `rgba(38,38,38,...)`**(避免叠出"灰中带蓝") |
|
||||
| C6 | 状态色 | `--green #3F6B3F` 深森林绿 / `--red #B33A2A` 暗砖红 | **`--accent-forest #42c366`** / **`--accent-crimson #eb3424`**(信号灯感) |
|
||||
| C7 | Accent 多彩 | 仅橙+绿+红 | **新增 5 色** amethyst/bluetron/crimson/forest/honey(仅用于语义信号) |
|
||||
| C8 | 边框 | `#EFEBE0` 暖色 | **`#ededed`** 冷灰(无色相) |
|
||||
| C9 | Selection | 未定义 | **`background: var(--heat-20)` + `color: var(--heat)`**(Firecrawl 签名) |
|
||||
|
||||
### V1 → V2(上次 · 结构性变更,保留)
|
||||
|
||||
| # | 维度 | V1 | V2 | 决策类型 |
|
||||
| - | ---- | -- | -- | -------- |
|
||||
| Δ1 | 圆角 | 大容器 0 / 按钮 9 / pill 999 | **大容器 8 / 按钮 8 / pill 999 / dot 999** | **变更** |
|
||||
| Δ2 | mono `[ STATUS ]` | 大量使用 | **保留**(品牌签名) | 保留 |
|
||||
| Δ3 | 字体 | Inter | **Inter Tight + 字重 500 替代 450**(免费) | 变更(轻) |
|
||||
| Δ4 | 边框 | 真 `border:1px` | **`::before` inside-border**(hover 不抖动) | 变更 |
|
||||
| Δ5 | 主容器左右垂直边 | 无 | **加 `border-x` + 四角准星**(图纸装订线) | 新增 |
|
||||
| Δ6 | 主 CTA 阴影 | 全场无 | **4 层橙色发光** | 变更(小幅) |
|
||||
|
||||
---
|
||||
|
||||
## 1. 设计哲学
|
||||
|
||||
**一句话:** 一台精密设备的工作面板。
|
||||
|
||||
**三条铁律:**
|
||||
1. **克制大于装饰** — 留白 > 容器 > 内容,大量空气感。
|
||||
2. **单色锚点** — 全场只有一种 accent(橙色),且只用于 CTA / 关键状态 / 强调单词。
|
||||
3. **结构清晰可见** — 用 **1 px 边框 + 8 px 圆角 + 四角准星 + 容器纵向装订线 + mono `[ ]` 标签**暴露"图纸感",而非阴影/渐变隐藏结构。
|
||||
|
||||
**避免的"AI 味":**
|
||||
- 渐变铺面 / 玻璃拟态 / 彩色阴影
|
||||
- 多色 emoji 图标
|
||||
- 圆角无差别(全部 8px / 16px 的 SaaS 模板感)
|
||||
- 卡片浮在背景上的"贴纸感"
|
||||
- 装饰盖过内容(场记板 / 霓虹 / 丝绒幕布)
|
||||
|
||||
**新增禁令:**
|
||||
- ❌ **0 px 硬切角的卡片** —— V2 起所有结构性容器都用 8 px 圆角
|
||||
- ❌ **变深 hue 的 hover 色** —— 橙色 hover 用 alpha 阶梯,不用更深的橙
|
||||
|
||||
---
|
||||
|
||||
## 2. 色彩系统(V2.1 · 对齐 Firecrawl)
|
||||
|
||||
### 2.1 表面 / 背景(冷灰 · 无色相)
|
||||
|
||||
| Token | Hex | 用途 |
|
||||
| ---------------------- | --------- | --------------------------- |
|
||||
| `--background-base` | `#f9f9f9` | 页面底色 · 冷灰 |
|
||||
| `--background-lighter` | `#fbfbfb` | 容器底色 / hover 浅底 |
|
||||
| `--surface` | `#ffffff` | 卡片 / 容器表面 |
|
||||
| `--surface-raised` | `#ffffff` | 浮层 / Modal 表面 |
|
||||
|
||||
> **Legacy 别名(V2 → V2.1):** `--bg = var(--background-base)` / `--bg-soft = var(--background-lighter)` / `--card = var(--surface)`。组件 CSS 不用改。
|
||||
|
||||
### 2.2 边框(冷灰 · 3 档差距极小)
|
||||
|
||||
| Token | Hex | 用途 |
|
||||
| ---------------- | --------- | --------------------- |
|
||||
| `--border-faint` | `#ededed` | **默认 1 px 边框 ★ 80% 场景** |
|
||||
| `--border-muted` | `#e8e8e8` | 略深 |
|
||||
| `--border-loud` | `#e6e6e6` | 最深(强分隔) |
|
||||
|
||||
> **设计意图:** 3 档之间只差 1–2 个色阶,**肉眼几乎看不出**。**用语义(faint/muted/loud)选择,不用视觉对比选择。** 这是 Firecrawl 的细节哲学。
|
||||
|
||||
### 2.3 Heat · 主橙(单 hue + 8 档 alpha)
|
||||
|
||||
| Token | Value | 用途 |
|
||||
| ----------- | ----------------------- | ----------------------------- |
|
||||
| `--heat` | `#fa5d19` | **主橙 100% · CTA / 链接 ★** |
|
||||
| `--heat-90` | `rgba(250,93,25,.90)` | hover(替代 V1 `#D04E1F`) |
|
||||
| `--heat-40` | `rgba(250,93,25,.40)` | focus ring / 边框次级 |
|
||||
| `--heat-20` | `rgba(250,93,25,.20)` | pill 边框 / **selection 底色 ★** |
|
||||
| `--heat-16` | `rgba(250,93,25,.16)` | hover 软底 |
|
||||
| `--heat-12` | `rgba(250,93,25,.12)` | tint 底(active nav / icon-box) |
|
||||
| `--heat-8` | `rgba(250,93,25,.08)` | |
|
||||
| `--heat-4` | `rgba(250,93,25,.04)` | 极弱底 |
|
||||
|
||||
> **从 V2 `#E55B26` 调亮到 V2.1 `#FA5D19`** —— 更红更饱和,与 Firecrawl 100% 实测一致。**hover 永远不换 hue,只换 alpha。**
|
||||
|
||||
### 2.4 Accent · 5 色信号(新增)
|
||||
|
||||
> **作用:** 仅用于**语义信号**——代码高亮、图标色、状态色源。**禁止做大面积背景或装饰**。全场仍只有 1 个 accent(橙)。
|
||||
|
||||
| Token | Hex | 用途 |
|
||||
| ------------------ | --------- | ----------------------------- |
|
||||
| `--accent-black` | `#262626` | **主前景**(替代 V2 `--ink #15140F`,更柔和) |
|
||||
| `--accent-white` | `#ffffff` | 反色文字(在橙底 / 黑底上) |
|
||||
| `--accent-amethyst`| `#9061ff` | 紫 · 代码 property |
|
||||
| `--accent-bluetron`| `#2a6dfb` | 蓝 · info |
|
||||
| `--accent-crimson` | `#eb3424` | 红 · **error / 失败 ★** |
|
||||
| `--accent-forest` | `#42c366` | 绿 · **success / 成功 ★** |
|
||||
| `--accent-honey` | `#ecb730` | 黄 · warning |
|
||||
|
||||
> **Legacy 别名:** `--ink = var(--accent-black)` / `--green = var(--accent-forest)` / `--red = var(--accent-crimson)`。
|
||||
|
||||
### 2.5 Black-Alpha 阶梯(20 档 · 核心工具尺)
|
||||
|
||||
> **替代 V2 的 11 档 ink-alpha**。这是日常用得最多的 token。0–24% 用 `rgba(0,0,0,...)`;**32% 起换 `rgba(38,38,38,...)`**(=`--accent-black` 作底),避免叠出"灰中带蓝"——Firecrawl 实测细节。
|
||||
|
||||
| Token | Light 值 | Dark 值 | 典型用途 |
|
||||
| ------------------ | ---------------------- | ---------------------- | ----------------------- |
|
||||
| `--black-alpha-1` | `rgba(0,0,0,.01)` | `rgba(255,255,255,.01)`| 极弱底 |
|
||||
| `--black-alpha-2` | `rgba(0,0,0,.02)` | `rgba(255,255,255,.02)`| |
|
||||
| `--black-alpha-3` | `rgba(0,0,0,.03)` | `rgba(255,255,255,.03)`| |
|
||||
| `--black-alpha-4` | `rgba(0,0,0,.04)` | `rgba(255,255,255,.04)`| **hover bg ★** |
|
||||
| `--black-alpha-5` | `rgba(0,0,0,.05)` | `rgba(255,255,255,.05)`| tab 间分隔条 |
|
||||
| `--black-alpha-6` | `rgba(0,0,0,.06)` | `rgba(255,255,255,.06)`| |
|
||||
| `--black-alpha-7` | `rgba(0,0,0,.07)` | `rgba(255,255,255,.07)`| **active bg ★** |
|
||||
| `--black-alpha-8` | `rgba(0,0,0,.08)` | `rgba(255,255,255,.08)`| |
|
||||
| `--black-alpha-10` | `rgba(0,0,0,.10)` | `rgba(255,255,255,.10)`| |
|
||||
| `--black-alpha-12` | `rgba(0,0,0,.12)` | `rgba(255,255,255,.12)`| **inside-border ★** |
|
||||
| `--black-alpha-16` | `rgba(0,0,0,.16)` | `rgba(255,255,255,.16)`| |
|
||||
| `--black-alpha-20` | `rgba(0,0,0,.20)` | `rgba(255,255,255,.20)`| |
|
||||
| `--black-alpha-24` | `rgba(0,0,0,.24)` | `rgba(255,255,255,.24)`| input hover 边框 |
|
||||
| `--black-alpha-32` | `rgba(38,38,38,.32)` | `rgba(255,255,255,.32)`| ← base 切换 → ↓ |
|
||||
| `--black-alpha-40` | `rgba(38,38,38,.40)` | `rgba(255,255,255,.40)`| |
|
||||
| `--black-alpha-48` | `rgba(38,38,38,.48)` | `rgba(255,255,255,.48)`| **占位字色 ★** |
|
||||
| `--black-alpha-56` | `rgba(38,38,38,.56)` | `rgba(255,255,255,.56)`| **次级文字 / 未选中 Tab ★** |
|
||||
| `--black-alpha-64` | `rgba(38,38,38,.64)` | `rgba(255,255,255,.64)`| 描述文字 |
|
||||
| `--black-alpha-72` | `rgba(38,38,38,.72)` | `rgba(255,255,255,.72)`| 强次级 |
|
||||
| `--black-alpha-88` | `rgba(38,38,38,.88)` | `rgba(255,255,255,.88)`| 近主前景 |
|
||||
|
||||
> **V2 → V2.1 兼容映射(legacy 别名,组件 CSS 不必改):**
|
||||
> - `--ink-alpha-4` → `--black-alpha-4`
|
||||
> - `--ink-alpha-7` → `--black-alpha-7`
|
||||
> - `--ink-alpha-12` → `--black-alpha-12`
|
||||
> - `--ink-alpha-24` → `--black-alpha-24`
|
||||
> - `--ink-alpha-32` → `--black-alpha-32`
|
||||
> - `--ink-alpha-48` → `--black-alpha-48`
|
||||
> - `--ink-alpha-56` → `--black-alpha-56`
|
||||
> - `--ink-alpha-64` → `--black-alpha-64`
|
||||
> - `--ink-alpha-72` → `--black-alpha-72`
|
||||
> - `--ink-alpha-88` → `--black-alpha-88`
|
||||
|
||||
### 2.6 状态色配套底/边
|
||||
|
||||
| 含义 | 主色 | 配套底色(8% alpha) | 配套边框(20% alpha) |
|
||||
| ---- | -------------------------- | --------------------------- | --------------------------- |
|
||||
| 成功 | `--green` (`#42c366`) | `rgba(66,195,102,.08)` | `rgba(66,195,102,.20)` |
|
||||
| 失败 | `--red` (`#eb3424`) | `rgba(235,52,36,.08)` | `rgba(235,52,36,.20)` |
|
||||
| 信息 | `--heat` (`#fa5d19`) | `--heat-12` | `--heat-20` |
|
||||
| 警告 | `--accent-honey`(`#ecb730`)| `rgba(236,183,48,.08)` | `rgba(236,183,48,.20)` |
|
||||
|
||||
### 2.7 Selection · 文字选中色(Firecrawl 签名)
|
||||
|
||||
```css
|
||||
::selection {
|
||||
background: var(--heat-20);
|
||||
color: var(--heat);
|
||||
}
|
||||
```
|
||||
|
||||
选中任何文字时,底色 20% 橙、文字 100% 橙。这是 Firecrawl 易被忽略但**整站感知到位**的细节。
|
||||
|
||||
---
|
||||
|
||||
## 3. 字体系统(V2.1 · 中英混排策略)
|
||||
|
||||
### 3.1 字体族 · Inter + 阿里巴巴普惠体
|
||||
|
||||
| 用途 | 字体声明 |
|
||||
| ------------ | ------------------------------------------------------------------------------------------------- |
|
||||
| **正文 / UI**| `'Inter', 'Alibaba PuHuiTi', 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif` |
|
||||
| **纯英文场景** | `'Inter', system-ui, sans-serif`(`--font-inter`)· 用于"Ctrl K"等强制纯英文徽标 |
|
||||
| **Mono 装饰** | `'JetBrains Mono', 'Geist Mono', ui-monospace, monospace` |
|
||||
|
||||
**核心策略 · 浏览器字符级 fallthrough:**
|
||||
|
||||
```
|
||||
Inter ────────→ 英文 / 数字 / 符号(命中)
|
||||
│
|
||||
↓ (CJK 不命中,继续找)
|
||||
Alibaba PuHuiTi ──→ 中文(命中)
|
||||
│
|
||||
↓ (字体未加载到)
|
||||
PingFang SC / Microsoft YaHei ──→ 系统中文兜底
|
||||
```
|
||||
|
||||
浏览器对每个字符**逐个查找** font-family 链,Inter 不含 CJK 字形 → 中文字符自动跳到下一个候选。这是中英混排的标准做法,**不需要 JS、不会字重错位**。
|
||||
|
||||
**V2 → V2.1 → V2.1 变更轨迹:**
|
||||
- V2: `Inter Tight` → 中文走系统 fallback → 字重错位
|
||||
- V2.1 (前一版): 单一 `Alibaba PuHuiTi` → 英文用普惠体英文字形 → 英文略圆,缺乏 Inter 的"科技感"
|
||||
- **V2.1 (本版)** : **Inter(英)+ Alibaba PuHuiTi(中)双字体协作** → 各自处理最擅长的语种
|
||||
|
||||
**为什么这个组合最优:**
|
||||
- Inter:Vercel / Linear / Stripe 御用,**工程产品默认审美**。专门给屏幕 UI 优化,数字字形漂亮(同宽)。中文不擅长。
|
||||
- Alibaba PuHuiTi:阿里出品,免费商用,**为中英混排专门设计的笔画粗细配比**(45/55/65/85 多档),中文笔画与 Inter 视觉重量贴近。专门给中文优化。
|
||||
- 两者结合:**英文有 Inter 的锐利,中文有普惠体的清晰**,字重之间衔接自然。
|
||||
|
||||
**Inter 载入:**
|
||||
|
||||
```html
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
```
|
||||
|
||||
**Alibaba PuHuiTi 载入:**
|
||||
|
||||
```css
|
||||
@font-face {
|
||||
font-family: 'Alibaba PuHuiTi';
|
||||
font-weight: 400; /* 55 Regular */
|
||||
src: local('Alibaba PuHuiTi 3.0'),
|
||||
local('AlibabaPuHuiTi-3-55-Regular'),
|
||||
url('https://chinese-fonts-cdn.deno.dev/packages/alibaba_puhuiti/dist/AlibabaPuHuiTi-3-55-Regular/AlibabaPuHuiTi-3-55-Regular.woff2') format('woff2');
|
||||
}
|
||||
/* 同写法处理 500 Medium / 600 SemiBold / 700 Bold */
|
||||
```
|
||||
|
||||
> **优先级:** 本地安装(设计师机器一般装了)→ CDN 加载 → 系统中文兜底。**永远不会出现假字或方框。**
|
||||
|
||||
**特殊场景 · 强制纯英文用 `--font-inter`:**
|
||||
|
||||
某些场景必须确保用 Inter(比如 "Ctrl K" 这种快捷键徽标想要 Inter Bold 的紧凑感),直接用专属变量:
|
||||
|
||||
```css
|
||||
.search-wrap .k {
|
||||
font-family: var(--font-inter); /* 跳过 fallback 链,锁定 Inter */
|
||||
font-weight: 700;
|
||||
font-size: 11.5px;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
```
|
||||
|
||||
Mono 字体保留 `JetBrains Mono`——用作装饰元素 `[ 200 OK ]` `// 05.14` `/v2`,**不参与中文**。
|
||||
|
||||
### 3.2 字号 / 字重 / 行高(V2.1 整体放大半档,行高提升)
|
||||
|
||||
| 角色 | 字号 | 字重 | 字距 | 行高 | 用途 |
|
||||
| ---------------- | ------- | ---- | ---------- | ---- | ---------------- |
|
||||
| H1 / Hero | 36 px | 500 | -0.024em | 1.2 | 页面主标题(从 V2 的 32 上调) |
|
||||
| 区块 H2 | 28 px | 500 | -0.02em | 1.25 | section-head 标题 |
|
||||
| KPI 数值 | 32 px | 500 | -0.02em | 1.1 | 统计大数字 |
|
||||
| 子区 H3 | 16 px | 500 | -0.01em | 1.4 | subsection 标题(从 15 上调) |
|
||||
| 卡片标题 | 14 px | 500 | normal | 1.4 | 项目名 / 商品名(从 13.5 上调) |
|
||||
| 正文 body | 14 px | 400 | normal | **1.65** | 默认正文(行高从 1.5 上调) |
|
||||
| 区块描述 | 14 px | 400 | normal | 1.75 | section-head 描述 |
|
||||
| 子区 lead | 13 px | 400 | normal | 1.8 | 子区下方说明 |
|
||||
| Label(按钮/Tab)| 13 px | 500 | normal | 1.4 | 按钮文字 / Tab |
|
||||
| Pill 文字 | 11.5 px | 500 | normal | 1.3 | 状态徽标 |
|
||||
| Mono 标签 | 11–11.5 px | 400/500 | 0.04em | 1.5 | `[ STATUS ]` |
|
||||
| Mono 散点 | 8.5 px | 400 | 0.04em | 1 | 背景 ASCII 装饰 |
|
||||
|
||||
**字重档位仍仅 3 档:400 / 500 / 600**。普惠体 500(Medium 65)的中文笔画比 Inter 500 重一些,**整体不显单薄**,因此 600 几乎不需要。
|
||||
|
||||
**关键属性:**
|
||||
- 数值类必须加 `font-variant-numeric: tabular-nums`
|
||||
- 标题用 negative letter-spacing(-0.01 ~ -0.024em)
|
||||
- 正文行高 **1.65–1.8**(V2 是 1.5–1.7),中文字间留呼吸
|
||||
|
||||
---
|
||||
|
||||
## 4. 圆角规则 · V2 统一 8 px
|
||||
|
||||
> **核心原则(V2 改写):统一 8 px / 状态徽标完全圆 / 极少数微元素降到 4–6 px**
|
||||
|
||||
| 元素类型 | 圆角值 | 例子 |
|
||||
| ------------------------------ | ---------- | ------------------------------- |
|
||||
| 所有结构性容器(大卡片 / 区块) | **8 px** | `.stats` `.list-card` `.shortcut` `.tip` `.modal` |
|
||||
| 所有按钮 / 输入框 | **8 px** | `.btn` `.pill-btn` `.icon-btn` `.search` |
|
||||
| nav 项 | **8 px** | `nav a`(V1 是 7,V2 统一) |
|
||||
| 缩略图 / 画面占位 | **8 px** | `.thumb` `.ic` |
|
||||
| 头像 / 小色块 | **6 px** | `.av` `.team .p`(可选 8) |
|
||||
| Mono 标签 / badge / kbd | **4 px** | `.kbd` `.badge` |
|
||||
| 进度条段位 | **2 px** | `.prog span` |
|
||||
| Pill 状态徽标 / dot | **999 px** | `.pill` `.dot`(完全圆) |
|
||||
|
||||
**为什么改:** Firecrawl 实测全站统一 8 px,工程感来自"准星 + 装订线 + mono 装饰",**不是硬切角**。0 圆角容器在小尺寸下会显得"卡顿、廉价",8 px 是同时兼顾"图纸感"和"成品感"的最佳值。
|
||||
|
||||
---
|
||||
|
||||
## 5. 边框 / 阴影 / 描边
|
||||
|
||||
### 5.1 边框策略 · V2 改为 inside-border
|
||||
|
||||
> **V2 改进:** 默认边框用 `::before` 伪元素绘制,而非真 `border`。原因:hover 时让 `::before` 透明度 → 0 不会触发布局抖动。
|
||||
|
||||
**通用工具类:**
|
||||
|
||||
```css
|
||||
.inside-border {
|
||||
position: relative;
|
||||
}
|
||||
.inside-border::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: inherit;
|
||||
pointer-events: none;
|
||||
transition: opacity .2s ease, border-color .2s ease;
|
||||
}
|
||||
.inside-border:hover::before { opacity: 0; }
|
||||
```
|
||||
|
||||
**层级:**
|
||||
- 默认:`var(--border-faint)`
|
||||
- 略深:`var(--border-muted)`(主分隔线)
|
||||
- 最深:`var(--border-loud)`(强分隔,少用)
|
||||
- **禁止 2px / 3px 实线**
|
||||
- **虚线**仅用于 `.tip` 提示框:`1px dashed var(--border-faint)`
|
||||
|
||||
### 5.2 阴影 · V2 引入主 CTA 专属橙色发光
|
||||
|
||||
**默认无阴影**(V1 规则保留)。
|
||||
|
||||
**新增例外 · 主 CTA 4 层橙色阴影**(替代 V1 的"全场无"):
|
||||
|
||||
```css
|
||||
.btn-primary {
|
||||
box-shadow:
|
||||
inset 0 -4px 8px rgba(250, 93, 25, 0.20), /* 内阴影:底部暗一点 = 立体 */
|
||||
0 1px 1px rgba(250, 93, 25, 0.12),
|
||||
0 2px 4px rgba(250, 93, 25, 0.10),
|
||||
0 0.5px 0.5px rgba(250, 93, 25, 0.16);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
box-shadow:
|
||||
inset 0 -4px 8px rgba(250, 93, 25, 0.20),
|
||||
0 1px 1px rgba(250, 93, 25, 0.16),
|
||||
0 4px 8px rgba(250, 93, 25, 0.20), /* 更高更亮 */
|
||||
0 0.5px 0.5px rgba(250, 93, 25, 0.16);
|
||||
}
|
||||
```
|
||||
|
||||
**Toast 阴影**(V1 保留):`0 4px 20px rgba(21,20,15,0.06)`,白色调,不属于橙色发光体系。
|
||||
|
||||
### 5.3 容器四角"+"准星(签名元素 · V2 升级为 SVG)
|
||||
|
||||
V1 用字符 `+`(font-family JetBrains Mono);V2 升级为 SVG 路径,带圆弧内凹,质感更工程化:
|
||||
|
||||
```html
|
||||
<svg width="22" height="21" viewBox="0 0 22 21" fill="none" class="corner">
|
||||
<path d="M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z" fill="var(--border-muted)"/>
|
||||
</svg>
|
||||
```
|
||||
|
||||
**位置:** 容器四角,中心精确落在边框交点上(用 `-translate-x-1/2 -translate-y-1/2`)。
|
||||
|
||||
**字符版本兼容:** 简单卡片(如 modal 内嵌)仍可用 `content: '+'` 字符版,但全屏主容器必须用 SVG。
|
||||
|
||||
---
|
||||
|
||||
## 6. 主内容容器 · 新增装订线规则(V2 新增章节)
|
||||
|
||||
> **核心签名:** 主工作区始终被两条 1 px 垂直边线包夹,配合四角准星,形成图纸装订线效果。
|
||||
|
||||
```html
|
||||
<div class="workbench-container">
|
||||
<svg class="corner top-left">...</svg>
|
||||
<svg class="corner top-right">...</svg>
|
||||
<svg class="corner bottom-left">...</svg>
|
||||
<svg class="corner bottom-right">...</svg>
|
||||
<!-- content -->
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.workbench-container {
|
||||
max-width: 1480px;
|
||||
margin: 0 auto;
|
||||
border-left: 1px solid var(--border-faint);
|
||||
border-right: 1px solid var(--border-faint);
|
||||
position: relative;
|
||||
/* 上下边线不要,只左右 */
|
||||
}
|
||||
.workbench-container .corner {
|
||||
position: absolute;
|
||||
width: 22px; height: 21px;
|
||||
}
|
||||
.workbench-container .corner.top-left { top: -10.5px; left: -11px; }
|
||||
.workbench-container .corner.top-right { top: -10.5px; right: -11px; }
|
||||
.workbench-container .corner.bottom-left { bottom: -10.5px; left: -11px; }
|
||||
.workbench-container .corner.bottom-right { bottom: -10.5px; right: -11px; }
|
||||
```
|
||||
|
||||
适用范围:工作台 / 项目列表页 / 商品库 / 流水线主区。**编辑器全屏画布、Modal 内不必加。**
|
||||
|
||||
---
|
||||
|
||||
## 7. 间距 / 栅格(V2.1 全局放大,Firecrawl-level 呼吸)
|
||||
|
||||
**基础栅格:** 4 px
|
||||
|
||||
**常用间距阶梯:** 4 / 8 / 12 / 16 / 20 / 24 / 28 / 32 / 40 / 48 / 64 / 80 / 104
|
||||
|
||||
> **V2 → V2.1 变更:** 全局垂直间距系统性放大 30%。原因:Alibaba PuHuiTi 中文笔画比 Inter 厚一档,**字体密度提升 → 必须用更大的留白补偿**,否则视觉拥挤。这就是为什么 Firecrawl 的间距看起来"奢侈"——它的字体也是出版级偏紧凑的 Suisse Intl,留白补偿到位。
|
||||
|
||||
**主区块布局:**
|
||||
- 侧边栏宽度:`248 px`(无变)
|
||||
- **主内容 padding:`72 px 80 px 120 px`**(从 V2 的 `48 56 56` 上调)
|
||||
- 内容最大宽度:`1280 px`(从 1480 收窄,留更多自然边距)
|
||||
- 区块间垂直:**`104 px`**(`section margin-bottom` · 从 80 上调)
|
||||
- 子区间垂直:**`64 px`**(`subsection margin-bottom` · 从 48 上调)
|
||||
- 子区标题底距:**`22 px`**(`h3 → 内容` · 从 16 上调)
|
||||
- 卡片网格间距:`24 px`(主区) / `14 px`(子区)
|
||||
- 卡片内 padding:
|
||||
- 大卡片 / stats: **`28 px 30 px`**(从 22 24 上调)
|
||||
- 列表行: **`20 px 24 px`**(从 14 18 上调)
|
||||
- 快捷入口: **`18 px 20 px`**(从 14 上调)
|
||||
- Modal 头/体: **`24 px 28 px`**(从 20 24 上调)
|
||||
- Hero / section-head: **`52 px 56 px`** / `padding-bottom: 28 px`
|
||||
|
||||
**最重要的一条:** 别再吝啬空气。**当不确定 padding 是 16 还是 24 时,选 24。** 当不确定 margin 是 48 还是 64 时,选 64。
|
||||
|
||||
**间距/字号配对原则:**
|
||||
- 标题旁边的描述/副标:`mb 10–14 px`(紧凑组合)
|
||||
- 标题下方的正文/列表:`mb 22–28 px`(分组组合)
|
||||
- section 顶部 mono-tag → h2:`mb 14 px`
|
||||
- h2 → section description:`mb 12 px`
|
||||
- section-head 整体下方边线:`pb 28 px / mb 44 px`
|
||||
|
||||
---
|
||||
|
||||
## 8. 背景:制图纸网格(V1 保留)
|
||||
|
||||
### 8.1 三层叠加
|
||||
|
||||
```
|
||||
图层 1(最上):主交叉点 "+" 准星 SVG — 240×240 重复
|
||||
图层 2(中间):子交叉点小圆点 — 60×60 重复
|
||||
图层 3(最下):虚线网格 — 240×240 重复(stroke-dasharray: 1.5 4)
|
||||
```
|
||||
|
||||
**配色:**
|
||||
- "+" 准星:`#B8B3A4`(stroke 1 px)
|
||||
- 小点:`#CFCABB`(r=0.9)
|
||||
- 虚线:`#E2DED2`(stroke 1 px)
|
||||
|
||||
### 8.2 视觉聚焦遮罩
|
||||
|
||||
```css
|
||||
mask-image: radial-gradient(ellipse 95% 80% at 50% 35%, #000 25%, transparent 95%);
|
||||
```
|
||||
|
||||
### 8.3 装饰散点(Mono ASCII)
|
||||
|
||||
主区域 4 个固定位置撒 ASCII 散点。字号 8.5 px / 颜色 `--ink-alpha-12` / 透明度 0.8 / `pointer-events: none`。
|
||||
|
||||
### 8.4 边角 Mono 标签(品牌签名 · 保留)
|
||||
|
||||
主区域 4 个角各放一个 Mono 标签:
|
||||
```
|
||||
左上 [ 200 OK ] 右上 [ /v2 ]
|
||||
左下 [ .MP4 · 9:16 ] 右下 [ STUDIO ]
|
||||
```
|
||||
|
||||
字号 10.5 px / 颜色 `--ink-alpha-48` / 字距 0.06em。
|
||||
|
||||
> **作用:** 让页面看起来像「在某个开发环境 / 调试视图里」,而不是普通官网。Firecrawl **没有**这个元素,这是流·Studio 的独特品牌资产。
|
||||
|
||||
---
|
||||
|
||||
## 9. Icon 系统(V2 强化章节,直接对应用户优化诉求 ①)
|
||||
|
||||
### 9.1 通用规则
|
||||
|
||||
- **格式:** 一律 SVG inline,**禁止** `<img>` 引图标
|
||||
- **库选择:** 推荐 Lucide(line icon,1.5–2 px stroke)或 Phosphor Regular
|
||||
- **stroke width:** 统一 **1.5 px**(替代 V1 提到的 1.8)
|
||||
- **stroke linecap / linejoin:** `round`
|
||||
- **填充:** **不填充**(纯 line icon)
|
||||
- **颜色:** 通过 `stroke="currentColor"`,继承父元素 `color`
|
||||
- **emoji 禁用:** 任何场景都不允许彩色 emoji
|
||||
|
||||
### 9.2 尺寸阶梯
|
||||
|
||||
| 场景 | 尺寸 | 用途 |
|
||||
| ------------------- | ------- | ----------------------------- |
|
||||
| Icon-S | 14 px | 内嵌 inline 文字旁 |
|
||||
| Icon-M(默认) | 16 px | 按钮内 / Tab / list 行 |
|
||||
| Icon-L | 20 px | 顶栏 / 快捷入口 / dropdown 触发器 |
|
||||
| Icon-XL | 24 px | Modal 头部 / Toast / 空状态 |
|
||||
| Icon-Hero | 36 px | 空状态插画 / 大占位 |
|
||||
|
||||
### 9.3 颜色规则
|
||||
|
||||
| 场景 | 颜色 |
|
||||
| ------------ | --------------------- |
|
||||
| 默认 | `--ink-alpha-56` |
|
||||
| Hover | `--ink` |
|
||||
| Active / 选中| `--heat` |
|
||||
| Disabled | `--ink-alpha-12` |
|
||||
| 在主 CTA 内 | `#FFFFFF` |
|
||||
|
||||
### 9.4 Icon-Box(快捷入口左侧的方块图标容器)
|
||||
|
||||
```css
|
||||
.icon-box {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 8px; /* V1 是 0,V2 改 8 */
|
||||
background: var(--heat-12);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
.icon-box svg { width: 16px; stroke: var(--heat); }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 组件规范 · 含完整状态(V2 大幅扩充,对应用户诉求 ②③④)
|
||||
|
||||
### 10.1 按钮(3 种类型 × 5 种状态 × 3 种尺寸)
|
||||
|
||||
**类型:**
|
||||
|
||||
| 类型 | 背景 | 文字 | 边框/描边 |
|
||||
| ----------------- | ---------------- | ------------------ | ---------------------------------- |
|
||||
| `.btn` 默认 | `--card` 白 | `--ink` | inside-border `--ink-alpha-12` |
|
||||
| `.btn-primary` 主 | `--heat` | `#FFFFFF` | 无,靠橙色阴影分层 |
|
||||
| `.btn-ghost` 无框 | transparent | `--ink-alpha-56` | 无 |
|
||||
|
||||
**尺寸:**
|
||||
|
||||
| 尺寸 | 高度 | padding | 字号 | icon 尺寸 |
|
||||
| ------ | ----- | ------------ | ------- | --------- |
|
||||
| `-sm` | 28 px | `0 10 px` | 12 px | 14 px |
|
||||
| 默认 | 32 px | `0 14 px` | 13 px | 16 px |
|
||||
| `-lg` | 40 px | `0 18 px` | 14 px | 16 px |
|
||||
|
||||
**5 种状态(每种类型都要实现):**
|
||||
|
||||
| 状态 | `.btn` 默认 | `.btn-primary` 主 |
|
||||
| -------- | ------------------------------------------ | ---------------------------------------------- |
|
||||
| Default | 白底 / inside-border `--ink-alpha-12` | 橙底 + 4 层橙阴影 |
|
||||
| Hover | 底色 `--ink-alpha-4` + 边框 opacity → 0 | 阴影第 3 层加亮(`0 4px 8px rgba(229,91,38,0.20)`) |
|
||||
| Active(按下) | 底色 `--ink-alpha-7` + `scale(0.99)` | `scale(0.995)` + 阴影 inset 加深 |
|
||||
| Focused | 外层 2 px `--heat-40` ring,offset 2 px | 同左 |
|
||||
| Disabled | 底 `--bg-soft` + 文字 `--ink-alpha-12` + `cursor: not-allowed` + 无 hover | 底 `--heat-40` + 文字 `#FFFFFF` + 阴影消失 + `cursor: not-allowed` |
|
||||
|
||||
**过渡:** 全场统一 `transition: background-color 200ms, opacity 200ms, transform 100ms, box-shadow 100ms ease`。
|
||||
|
||||
### 10.2 Pill(状态徽标)· 严格分级(对应用户诉求 ②)
|
||||
|
||||
> **V2 核心改进:Pill 分 3 级,同级别尺寸完全一致**
|
||||
|
||||
| 级别 | 高度 | padding | 字号 | 圆角 | dot 尺寸 | 用途 |
|
||||
| ------------ | ----- | ------------ | ------- | ----- | -------- | --------------------- |
|
||||
| **L1 大胶囊** | 28 px | `0 12 px` | 13 px | 999 px| 8 px | 项目状态 / 列表行 |
|
||||
| **L2 中胶囊** | 22 px | `0 10 px` | 11.5 px | 999 px| 6 px | **默认 / 通用** |
|
||||
| **L3 小胶囊** | 18 px | `0 8 px` | 10.5 px | 999 px| 5 px | KPI 卡角标 / Mono 标签 |
|
||||
|
||||
**色调(3 种,通用所有级别):**
|
||||
|
||||
| 状态 | 文字色 | 底色 | 边框(20% alpha)|
|
||||
| ---- | --------------- | ------------- | ---------------- |
|
||||
| info | `--heat` | `--heat-12` | `--heat-20` |
|
||||
| ok | `--green` | `--green-bg`(`#3F6B3F14`) | `--green-bd`(`#3F6B3F33`) |
|
||||
| err | `--red` | `--red-bg`(`#B33A2A14`) | `--red-bd`(`#B33A2A33`) |
|
||||
|
||||
每个 pill 前置圆点(`.dot`,直径同上表,颜色继承文字色)。
|
||||
|
||||
**HTML 写法:**
|
||||
|
||||
```html
|
||||
<span class="pill pill-l2 pill-info">
|
||||
<span class="dot"></span>
|
||||
生成中
|
||||
</span>
|
||||
```
|
||||
|
||||
### 10.3 输入框 / 搜索(V2.1 · 含 Firecrawl 式快捷键提示)
|
||||
|
||||
**尺寸:** 高 **36 px**(从 V2 的 32 上调,中文留白更舒展)/ padding `0 14 px` / 字号 14 px / 圆角 8 px
|
||||
|
||||
**状态:**
|
||||
|
||||
| 状态 | 边框 | 底色 |
|
||||
| -------- | --------------------------------- | --------------------- |
|
||||
| Default | inside-border `--black-alpha-12` | `--card` |
|
||||
| Hover | inside-border `--black-alpha-24` | `--card` |
|
||||
| Focused | inside-border `--heat-40` + inset 1 px | `--card` |
|
||||
| Error | inside-border `--red` | `--red-bg` |
|
||||
| Disabled | inside-border `--black-alpha-12` | **`--black-alpha-5`**(从 `--bg-soft` 改 · 冷灰底太接近白,看不出禁用) |
|
||||
|
||||
占位字色 `--black-alpha-48`,disabled 占位 `--black-alpha-24`。
|
||||
|
||||
**带图标 / 快捷键搜索框(参考 Firecrawl 实测):**
|
||||
|
||||
```
|
||||
[🔍] [ 搜索任意内容... ] Ctrl K
|
||||
│ │
|
||||
│ 16px line icon, color: --black-alpha-56 │ mono · 11.5px · --black-alpha-48
|
||||
│ 左 14 px,**z-index: 2**(关键) │ 右 14 px,**z-index: 2**
|
||||
│ │ 平铺文本(无边框盒),不用 kbd 样式
|
||||
```
|
||||
|
||||
**关键坑(已修):**
|
||||
1. **搜索 icon 看不见** —— `<input>` 的白色 bg 会盖住同级的 SVG icon。**SVG 必须加 `z-index: 2`** 才能抬到 input 之上。同理 Ctrl K 提示也要 z-index。
|
||||
2. **快捷键不用 `⌘`** —— JetBrains Mono webfont 不带 U+2318 `⌘` 字形,会显示成方框。**Windows 用户体系用 "Ctrl K" 纯文本**;Mac 端要显示 ⌘ 时用 SVG command 图标(见 §9.4)。
|
||||
3. **快捷键提示不要用 kbd 边框盒** —— Firecrawl 是平铺灰色 mono 文本,无任何 border / bg / radius。**显得克制,符合"克制大于装饰"。**
|
||||
|
||||
### 10.4 KPI 统计行(`.stats`)
|
||||
|
||||
- 1 行 4 格,共用一个 inside-border 容器,圆角 8 px,**无 gap**
|
||||
- 列与列之间用 `border-right: 1px solid var(--border-faint)` 分隔(最后一列去掉)
|
||||
- 容器四角加 SVG "+" 准星
|
||||
- 每格结构:label + L3 pill → 大数字(30 px) → delta / progress
|
||||
|
||||
### 10.5 列表行(`.list-row`)
|
||||
|
||||
```
|
||||
[缩略图 54×70] [标题 + meta] [进度条 5 段] [L2 pill] [按钮 -sm]
|
||||
```
|
||||
|
||||
- grid 5 列:`54px 1fr auto auto auto`
|
||||
- 行高 padding `14 px 18 px`
|
||||
- 行间 1 px 分隔线(`--border-faint`),最后行去掉
|
||||
- **整行 hover** → `--ink-alpha-4` 底色
|
||||
- **整行 active**(键盘选中)→ `--ink-alpha-7` 底色
|
||||
- **整行 disabled** → opacity 0.5 + `cursor: not-allowed`
|
||||
|
||||
### 10.6 进度条段位(流水线 5 阶段专用)· **V2.1 语义色重写**
|
||||
|
||||
5 个 `18×5 px` 小段,3 px 间距,**每段颜色映射真实业务状态**(替代 V2 的"全灰已完成"——那样像项目失败):
|
||||
|
||||
| 状态 | 颜色 | 视觉处理 |
|
||||
| -------- | --------------------- | ------------------------------ |
|
||||
| 未开始 | `--black-alpha-8` | 极弱灰底 · 静态 |
|
||||
| **已完成** | `--accent-forest`(`#42c366`)| **绿色 · 静态**(替代 V2 灰色) |
|
||||
| **进行中** | `--heat`(`#fa5d19`) | **橙色 + 1.4s 脉动**(opacity 1↔0.55 + scaleY 1↔0.7)· 区别于失败 |
|
||||
| 失败 | `--accent-crimson`(`#eb3424`)| 红色 · 静态 |
|
||||
|
||||
圆角:每段 2 px。
|
||||
|
||||
**关键设计:**
|
||||
- **绿/橙/红/灰** 四色一眼可辨:已完成的绿色让"5/5 全绿"=完美交付,**不会再有"全灰像失败了"的误读**
|
||||
- **橙色脉动动画** 是区分"进行中"与"失败"的关键——红色永远静态,只有橙色会呼吸,潜意识上"动 = 在运行,静 = 出错"
|
||||
|
||||
```css
|
||||
.prog span.now {
|
||||
background: var(--heat);
|
||||
animation: prog-pulse 1.4s ease-in-out infinite;
|
||||
}
|
||||
@keyframes prog-pulse {
|
||||
0%,100% { opacity: 1; transform: scaleY(1); }
|
||||
50% { opacity: .55; transform: scaleY(.7); }
|
||||
}
|
||||
```
|
||||
|
||||
### 10.7 快捷入口卡(`.shortcut`)
|
||||
|
||||
- 白底 / inside-border / **8 px 圆角**(V1 是 0) / 14 px padding
|
||||
- 左侧 32×32 橙色 tint 图标块(`--heat-12` 底 / 8 px 圆角 / 居中 16 px line icon)
|
||||
- 右侧:标题(13 px 500)+ Mono 描述(11.5 px,`--ink-alpha-48`)
|
||||
- **Default → Hover → Active 完整状态:**
|
||||
- Hover:底色 `--ink-alpha-4` / 标题 underline-from-orange 1 px(可选)
|
||||
- Active(点击瞬间):scale(0.99)
|
||||
- Focused(键盘):2 px `--heat-40` ring
|
||||
|
||||
### 10.8 提示框(`.tip`)
|
||||
|
||||
- 白底 / **1 px 虚线**边框(`dashed`)/ **8 px 圆角**
|
||||
- 加粗标题独立一行 + 正文
|
||||
- 内联代码用 `.mono` 类:橙色文字 + `--heat-12` 底 + 4 px 圆角
|
||||
|
||||
### 10.9 Toast
|
||||
|
||||
- 右下角 24 px 偏移 / 白底 / inside-border / **8 px 圆角**
|
||||
- 唯一允许的"白阴影":`0 4px 20px rgba(21,20,15,0.06)`
|
||||
- 进入动画:`translateX(420px → 0)`,缓动 `cubic-bezier(0.34, 1.56, 0.64, 1)`,300 ms
|
||||
- 自动消失:2400 ms
|
||||
- 内容结构:左侧 24×24 橙色 tint 图标(`--heat-12` 底)+ 右侧标题 + Mono 副文本(`[ 200 OK ]`)
|
||||
|
||||
### 10.10 弹窗(Modal)
|
||||
|
||||
- 居中,460–480 px 宽,白底,**8 px 圆角**(V1 是 0)
|
||||
- 四角加 SVG "+" 准星
|
||||
- 遮罩 `rgba(21,20,15,0.42)`,带 `backdrop-filter: blur(8px)`
|
||||
- 进入动画:`scale(0.96 → 1)`,250 ms 弹性缓动
|
||||
- 三段结构:
|
||||
- **Header:** 36 px 橙色 tint 图标 + 标题 + Mono 副标
|
||||
- **Body:** 13 px / `--ink-alpha-56` / 行高 1.7
|
||||
- **Footer:** 右对齐两个按钮(取消 + 主 CTA)
|
||||
- ESC 关闭 / 点击遮罩关闭
|
||||
|
||||
### 10.11 Tab(双层)
|
||||
|
||||
**主 Tab:**
|
||||
- 高 36 px / padding `0 14 px` / 字号 13 px / 字重 500
|
||||
- 未选中:`--ink-alpha-56` 文字
|
||||
- 选中:`--ink` 文字 + 底部 2 px `--heat` 横线(整个 tab 宽度)
|
||||
- Hover(未选中态):`--ink-alpha-7` 底色
|
||||
|
||||
**副 Tab(过滤型):**
|
||||
- 高 28 px / padding `0 10 px` / 字号 12 px
|
||||
- 未选中:`--ink-alpha-56` + 灰度 icon
|
||||
- 选中:`--ink` + 多色 icon(grayscale: 0)
|
||||
- Tab 之间用 1 px 高 12 px 的 `--ink-alpha-7` 竖条分隔(可选)
|
||||
|
||||
### 10.12 Dropdown / Select
|
||||
|
||||
- 触发器:同输入框样式(高 32 / 圆角 8 / inside-border)
|
||||
- 右侧 16 px chevron-down icon,色 `--ink-alpha-48`,展开时旋转 180°
|
||||
- 弹层:白底 / 8 px 圆角 / `0 4px 20px rgba(21,20,15,0.06)` 阴影 / **唯一允许阴影场景之二**
|
||||
- 选项:高 32 / padding `0 12 / hover `--ink-alpha-4` / 选中 `--heat-12` + 右侧 14 px checkmark `--heat`
|
||||
- 分组分隔:1 px `--border-faint`
|
||||
|
||||
### 10.13 Checkbox / Radio / Switch(V2.1 · 全部用 SVG icon)
|
||||
|
||||
**通用原则:** 所有 indicator 都用真 SVG(via background-image data URI 或 inline `<svg>`),**禁止用 border-width / transform: rotate(45deg) 凑对勾**——那种 CSS hack 在缩放/字体渲染下会变形。
|
||||
|
||||
**Checkbox:**
|
||||
- **容器:** 16×16 / 4 px 圆角 / inside-border `--black-alpha-24`(hover 时 → `--black-alpha-48`)
|
||||
- **Checked:** `--heat` 底 · 居中 12×12 白色 SVG checkmark(`<path d="M20 6 9 17l-5-5"/>` · stroke 3 · linecap round)
|
||||
- **Indeterminate:** `--heat` 底 · 居中 12×12 白色 SVG 横线(`<path d="M5 12h14"/>` · stroke 3)
|
||||
- **Disabled:** 底 `--black-alpha-5` + 边 `--black-alpha-12` + icon 不渲染或半透明
|
||||
- **实现方式:** `background-image: url("data:image/svg+xml,...")` · `background-size: 12px 12px` · `background-position: center` · 这样不需要 ::after 凑出 icon,SVG 是真实的
|
||||
|
||||
**Radio:**
|
||||
- 16×16 圆 / inside-border `--black-alpha-24`
|
||||
- Checked:内嵌 8×8 `--heat` 实心圆(纯几何形状,不算 icon,用 ::after 即可)
|
||||
- Disabled:底 `--black-alpha-5`
|
||||
|
||||
**Switch:**
|
||||
- 容器 28×16 / 999 px 圆角
|
||||
- Off:底 `--black-alpha-12` / 圆球 `#FFFFFF` 12×12 + 1 px subtle shadow
|
||||
- On:底 `--heat` / 圆球右移到 `left: 14px`
|
||||
- 过渡:`background 200 ms`,圆球位移 `left 200 ms`
|
||||
|
||||
> **为什么不用字符 `✓` `✗` 这种 Unicode:** 不同系统、不同字体对这些字符的字形支持差异巨大(`⌘` 在 JetBrains Mono Web 字体里就是缺字形 → 显示成方框)。**SVG 是唯一可靠的解。**
|
||||
|
||||
---
|
||||
|
||||
## 11. 微观细节(品牌签名 · V1 保留)
|
||||
|
||||
### 11.1 标签全部包方括号
|
||||
`[ 200 OK ]` `[ .MP4 · 9:16 ]` `[ /v2 ]` `[ /sidebar collapse ]`
|
||||
|
||||
### 11.2 时间戳像代码注释
|
||||
`// 05.14 · 周五`
|
||||
|
||||
### 11.3 数值后缀
|
||||
`¥327` 主体大字 + `.40` 小字次级(`<small>`)
|
||||
|
||||
### 11.4 强调单词上色
|
||||
正文里 `<b style="color: var(--ink)">3 个项目</b>` —— 让具体数值/名词比周围文字更深一档(不是变橙)。**橙色只留给 CTA。**
|
||||
|
||||
### 11.5 ASCII 字符做装饰
|
||||
`↑ 本月 +3` `↓ -1.2%`
|
||||
|
||||
### 11.6 链接式"更多"按钮
|
||||
`[ ALL · 12 ] →` —— Mono 标签 + 箭头,色 `--ink-alpha-48`,hover 转橙。
|
||||
|
||||
### 11.7 缩略图不放图,放比例
|
||||
`9:16` Mono 字符占位。
|
||||
|
||||
---
|
||||
|
||||
## 12. Don't List(绝对禁止)
|
||||
|
||||
- ❌ **0 px 卡片**(V1 → V2 反转)
|
||||
- ❌ 渐变背景(只有 hero 区可考虑,但首选纯色)
|
||||
- ❌ 玻璃拟态(`backdrop-filter` 只用于 modal 遮罩)
|
||||
- ❌ 彩色 emoji 图标(用 SVG line icon,1.5 px stroke)
|
||||
- ❌ 多个 accent 色(全场只有橙色)
|
||||
- ❌ 大圆角容器(>12 px 直接判错)
|
||||
- ❌ 灰色阴影 / 文字阴影(只允许橙色主 CTA 阴影 + Toast/Dropdown 白阴影)
|
||||
- ❌ 鲜艳的状态色(避免荧光绿、电光蓝、霓虹粉)
|
||||
- ❌ 居中对齐大段正文(全部左对齐)
|
||||
- ❌ 把装饰当主角(场记板、丝绒、霓虹灯)
|
||||
- ❌ 无意义的微动效(hover 旋转、缩放、彩虹流光)
|
||||
- ❌ **hover 时换深 hue 的橙**(用 alpha)
|
||||
- ❌ **真 `border` + hover 边框消失**(用 inside-border ::before)
|
||||
- ❌ **同一行混用直角和圆角**(用户原话:"不要有些是直角,胶囊又是圆角")
|
||||
|
||||
---
|
||||
|
||||
## 13. Sass / CSS Token 速查表(V2.1)
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* ============================================================
|
||||
Color system V2.1 · Firecrawl-aligned
|
||||
============================================================ */
|
||||
|
||||
/* === 表面 / 背景(冷灰)=== */
|
||||
--background-base: #f9f9f9;
|
||||
--background-lighter: #fbfbfb;
|
||||
--surface: #ffffff;
|
||||
--surface-raised: #ffffff;
|
||||
|
||||
/* === 边框(冷灰 · 3 档)=== */
|
||||
--border-faint: #ededed; /* 默认 1 px */
|
||||
--border-muted: #e8e8e8;
|
||||
--border-loud: #e6e6e6;
|
||||
|
||||
/* === Accent 多彩(5 色信号)=== */
|
||||
--accent-black: #262626;
|
||||
--accent-white: #ffffff;
|
||||
--accent-amethyst: #9061ff;
|
||||
--accent-bluetron: #2a6dfb;
|
||||
--accent-crimson: #eb3424;
|
||||
--accent-forest: #42c366;
|
||||
--accent-honey: #ecb730;
|
||||
|
||||
/* === Heat · 单 hue + 8 档 alpha === */
|
||||
--heat: #fa5d19;
|
||||
--heat-90: rgba(250, 93, 25, .90);
|
||||
--heat-40: rgba(250, 93, 25, .40);
|
||||
--heat-20: rgba(250, 93, 25, .20);
|
||||
--heat-16: rgba(250, 93, 25, .16);
|
||||
--heat-12: rgba(250, 93, 25, .12);
|
||||
--heat-8: rgba(250, 93, 25, .08);
|
||||
--heat-4: rgba(250, 93, 25, .04);
|
||||
|
||||
/* === Black-Alpha 阶梯(20 档 · 0–24 用 #000,32+ 用 #262626)=== */
|
||||
--black-alpha-1: rgba(0, 0, 0, .01);
|
||||
--black-alpha-2: rgba(0, 0, 0, .02);
|
||||
--black-alpha-3: rgba(0, 0, 0, .03);
|
||||
--black-alpha-4: rgba(0, 0, 0, .04);
|
||||
--black-alpha-5: rgba(0, 0, 0, .05);
|
||||
--black-alpha-6: rgba(0, 0, 0, .06);
|
||||
--black-alpha-7: rgba(0, 0, 0, .07);
|
||||
--black-alpha-8: rgba(0, 0, 0, .08);
|
||||
--black-alpha-10: rgba(0, 0, 0, .10);
|
||||
--black-alpha-12: rgba(0, 0, 0, .12);
|
||||
--black-alpha-16: rgba(0, 0, 0, .16);
|
||||
--black-alpha-20: rgba(0, 0, 0, .20);
|
||||
--black-alpha-24: rgba(0, 0, 0, .24);
|
||||
--black-alpha-32: rgba(38, 38, 38, .32);
|
||||
--black-alpha-40: rgba(38, 38, 38, .40);
|
||||
--black-alpha-48: rgba(38, 38, 38, .48);
|
||||
--black-alpha-56: rgba(38, 38, 38, .56);
|
||||
--black-alpha-64: rgba(38, 38, 38, .64);
|
||||
--black-alpha-72: rgba(38, 38, 38, .72);
|
||||
--black-alpha-88: rgba(38, 38, 38, .88);
|
||||
|
||||
/* === Legacy aliases(V2 命名 → V2.1 token,组件 CSS 无需重写)=== */
|
||||
--bg: var(--background-base);
|
||||
--bg-soft: var(--background-lighter);
|
||||
--card: var(--surface);
|
||||
--ink: var(--accent-black);
|
||||
--green: var(--accent-forest);
|
||||
--red: var(--accent-crimson);
|
||||
--green-bg: rgba(66, 195, 102, .08);
|
||||
--green-bd: rgba(66, 195, 102, .20);
|
||||
--red-bg: rgba(235, 52, 36, .08);
|
||||
--red-bd: rgba(235, 52, 36, .20);
|
||||
--ink-alpha-4: var(--black-alpha-4);
|
||||
--ink-alpha-7: var(--black-alpha-7);
|
||||
--ink-alpha-12: var(--black-alpha-12);
|
||||
--ink-alpha-24: var(--black-alpha-24);
|
||||
--ink-alpha-32: var(--black-alpha-32);
|
||||
--ink-alpha-48: var(--black-alpha-48);
|
||||
--ink-alpha-56: var(--black-alpha-56);
|
||||
--ink-alpha-64: var(--black-alpha-64);
|
||||
--ink-alpha-72: var(--black-alpha-72);
|
||||
--ink-alpha-88: var(--black-alpha-88);
|
||||
|
||||
/* === 圆角 === */
|
||||
--r-sm: 4px;
|
||||
--r-md: 8px; /* 默认主圆角 */
|
||||
--r-pill: 999px;
|
||||
|
||||
/* === 字体 === */
|
||||
--font-sans: 'Inter Tight', 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||
--font-mono: 'JetBrains Mono', 'Geist Mono', monospace;
|
||||
|
||||
/* === 容器宽度 === */
|
||||
--container-max: 1480px;
|
||||
--sidebar-w: 248px;
|
||||
|
||||
/* === 过渡 === */
|
||||
--t-fast: 100ms ease;
|
||||
--t-base: 200ms ease;
|
||||
--t-slow: 300ms cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
/* === Selection · Firecrawl 签名细节 === */
|
||||
::selection {
|
||||
background: var(--heat-20);
|
||||
color: var(--heat);
|
||||
}
|
||||
|
||||
/* === Dark mode · 翻转底色 + black-alpha 改用 white-alpha === */
|
||||
.dark {
|
||||
--background-base: #0a0a0a;
|
||||
--background-lighter: #141414;
|
||||
--surface: #171717;
|
||||
--surface-raised: #1f1f1f;
|
||||
--border-faint: #2a2a2a;
|
||||
--border-muted: #333333;
|
||||
--border-loud: #404040;
|
||||
--accent-black: #f5f5f5;
|
||||
--black-alpha-1: rgba(255,255,255,.01);
|
||||
--black-alpha-2: rgba(255,255,255,.02);
|
||||
--black-alpha-3: rgba(255,255,255,.03);
|
||||
--black-alpha-4: rgba(255,255,255,.04);
|
||||
--black-alpha-5: rgba(255,255,255,.05);
|
||||
--black-alpha-6: rgba(255,255,255,.06);
|
||||
--black-alpha-7: rgba(255,255,255,.07);
|
||||
--black-alpha-8: rgba(255,255,255,.08);
|
||||
--black-alpha-10: rgba(255,255,255,.10);
|
||||
--black-alpha-12: rgba(255,255,255,.12);
|
||||
--black-alpha-16: rgba(255,255,255,.16);
|
||||
--black-alpha-20: rgba(255,255,255,.20);
|
||||
--black-alpha-24: rgba(255,255,255,.24);
|
||||
--black-alpha-32: rgba(255,255,255,.32);
|
||||
--black-alpha-40: rgba(255,255,255,.40);
|
||||
--black-alpha-48: rgba(255,255,255,.48);
|
||||
--black-alpha-56: rgba(255,255,255,.56);
|
||||
--black-alpha-64: rgba(255,255,255,.64);
|
||||
--black-alpha-72: rgba(255,255,255,.72);
|
||||
--black-alpha-88: rgba(255,255,255,.88);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14. V1 → V2 迁移检查清单(给后续改代码用)
|
||||
|
||||
- [ ] 全局替换 `border-radius: 0` → `border-radius: 8px`(卡片 / stats / shortcut / modal / toast / thumb)
|
||||
- [ ] 替换 V1 ink-2/3/4 token 为 ink-alpha-56/48/12
|
||||
- [ ] 替换 `--orange-tint` `--orange-soft` 为 `--heat-12` `--heat-20`
|
||||
- [ ] 主 CTA hover 移除 `#D04E1F`,改用 4 层橙阴影变化
|
||||
- [ ] 所有 `.btn` `.input` 加 `inside-border` 类
|
||||
- [ ] 主工作区容器加 `border-left + border-right` + 4 个 SVG 准星
|
||||
- [ ] 字体 Inter → Inter Tight
|
||||
- [ ] 所有 icon 转 SVG line icon,stroke 1.5
|
||||
- [ ] Pill 按 L1/L2/L3 三级规范化高度/字号/圆点尺寸
|
||||
- [ ] 每个交互组件补齐 hover / active / focused / disabled 状态
|
||||
|
||||
---
|
||||
|
||||
## 15. 参考与来源
|
||||
|
||||
- **视觉灵感(实测):** [Firecrawl Playground](https://www.firecrawl.dev/playground?endpoint=parse) · 详见 [firecrawl_playground_spec.md](_design_src/firecrawl_playground_spec.md)
|
||||
- **结构灵感:** Linear / Stripe Dashboard
|
||||
- **图纸感来源:** 印刷套版准星 + 老 Unix 终端
|
||||
- **V1 文档:** [DESIGN_SPEC.md](DESIGN_SPEC.md)(保留作为历史)
|
||||
53
电商AI平台/README.md
Normal file
53
电商AI平台/README.md
Normal file
@ -0,0 +1,53 @@
|
||||
# 电商AI平台 · 流·Studio
|
||||
|
||||
AI 短视频带货生成平台 · 静态设计稿(V2.1 Restraint)。
|
||||
|
||||
## 快速浏览
|
||||
|
||||
直接用浏览器打开任意 HTML,或本地起服务:
|
||||
|
||||
```bash
|
||||
npx http-server . -p 8080
|
||||
# 然后访问 http://localhost:8080/
|
||||
```
|
||||
|
||||
入口页:[index.html](index.html)(工作台)
|
||||
|
||||
## 页面索引
|
||||
|
||||
| 页面 | 文件 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 工作台 | [index.html](index.html) | 进入后首屏 · 4 块 KPI + 最近项目 + 快捷入口 |
|
||||
| 视频项目 | [projects.html](projects.html) | 项目列表 · 表格 + 状态 + 进度 |
|
||||
| 新建项目 | [projects-new.html](projects-new.html) | 4 步向导 · 含实时预估面板 + 推荐气泡 |
|
||||
| 商品库 | [products.html](products.html) | SKU 列表 |
|
||||
| 创建商品 | [product-create.html](product-create.html) | 4 步向导 + 子流程(挑模特 → 生上身) |
|
||||
| 流水线 | [pipeline.html](pipeline.html) | 5 阶段:脚本 → 资产 → 故事板 → 片段 → 拼接 |
|
||||
| 资产库 | [library.html](library.html) | 人物 / 场景 / 视频片段管理 |
|
||||
| 账户 | [account.html](account.html) | 余额 / 充值 / 消费明细 |
|
||||
| 设计系统 | [design-system.html](design-system.html) | 完整 V2.1 token + 组件 + 状态 + Modal/Toast |
|
||||
|
||||
## 设计规范
|
||||
|
||||
详见 [DESIGN_SPEC_V2.md](DESIGN_SPEC_V2.md) · 当前 V2.1。
|
||||
|
||||
**核心视觉特征:**
|
||||
- 配色:冷灰底 `#f9f9f9` + 单橙 accent `#FA5D19`(Firecrawl-aligned)
|
||||
- 圆角:统一 8 px / pill 999 px / 微元素 4 px
|
||||
- Icon:SVG line · stroke 1.5 · linecap round · `currentColor` 继承
|
||||
- 签名元素:容器装订线(左右 1 px 边)+ 四角 22×21 px SVG 准星(圆弧内凹)
|
||||
- 字体:Inter Tight + JetBrains Mono + Alibaba PuHuiTi
|
||||
- 主 CTA:橙底 + 4 层橙阴影(全场唯一允许阴影的组件)
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
电商AI平台/
|
||||
├── README.md ← 本文档
|
||||
├── DESIGN_SPEC_V2.md ← 设计规范 source of truth
|
||||
├── design-system.html ← 可交互组件参考(token + 状态 demo)
|
||||
├── assets/
|
||||
│ ├── restraint.css ← V2.1 共享样式 · 无 V1 legacy alias
|
||||
│ └── shell.js ← sidebar/topbar/Toast/Modal 渲染器
|
||||
└── *.html ← 8 个页面
|
||||
```
|
||||
170
电商AI平台/account.html
Normal file
170
电商AI平台/account.html
Normal file
@ -0,0 +1,170 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>账户 · 流·Studio</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>
|
||||
.acc-grid { display: grid; grid-template-columns: 1.7fr 1fr; gap: 24px; align-items: start; }
|
||||
.balance-banner {
|
||||
background: var(--accent-black);
|
||||
color: var(--accent-white);
|
||||
padding: 28px 32px;
|
||||
margin-bottom: 24px;
|
||||
position: relative;
|
||||
border: 1px solid var(--accent-black);
|
||||
border-radius: var(--r-md);
|
||||
}
|
||||
.balance-banner::before, .balance-banner::after { content: ''; position: absolute; width: 14px; height: 14px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 21' fill='%23e8e8e8'%3E%3Cpath d='M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z'/%3E%3C/svg%3E") no-repeat center; background-size: contain; pointer-events: none; }
|
||||
.balance-banner::before { top: -7px; left: -7px; }
|
||||
.balance-banner::after { bottom: -7px; right: -7px; }
|
||||
.balance-banner .corner-tr, .balance-banner .corner-bl { position: absolute; color: var(--black-alpha-48); font-family: var(--font-mono); font-size: 13px; }
|
||||
.balance-banner .corner-tr { top: -8px; right: -8px; }
|
||||
.balance-banner .corner-bl { bottom: -8px; left: -8px; }
|
||||
.balance-banner .lbl { font-family: var(--font-mono); font-size: 12px; color: rgba(255,255,255,.55); letter-spacing: .04em; }
|
||||
.balance-banner .v { font-size: 42px; font-weight: 700; letter-spacing: -.018em; margin-top: 8px; font-variant-numeric: tabular-nums; }
|
||||
.balance-banner .meta { font-size: 12.5px; color: rgba(255,255,255,.5); margin-top: 8px; font-family: var(--font-mono); letter-spacing: .02em; }
|
||||
.balance-banner .actions { display: flex; gap: 8px; margin-top: 18px; }
|
||||
.balance-banner .btn { background: var(--accent-white); color: var(--accent-black); border-color: var(--accent-white); }
|
||||
.balance-banner .btn:hover { background: var(--background-base); }
|
||||
.balance-banner .btn-ghost { background: transparent; color: var(--accent-white); border: 1px solid rgba(255,255,255,.25); }
|
||||
.balance-banner .btn-ghost:hover { background: rgba(255,255,255,.1); color: var(--accent-white); }
|
||||
|
||||
.recharge-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-top: 12px; }
|
||||
.recharge-card { border: 1px solid var(--border-faint); border-radius: var(--r-md); padding: 18px; text-align: center; cursor: pointer; background: var(--surface); position: relative; }
|
||||
.recharge-card:hover { background: var(--background-lighter); }
|
||||
.recharge-card.selected { border-color: var(--heat); background: var(--heat-12); }
|
||||
.recharge-card.selected::before, .recharge-card.selected::after { content: ''; position: absolute; width: 14px; height: 14px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 21' fill='%23FA5D19'%3E%3Cpath d='M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z'/%3E%3C/svg%3E") no-repeat center; background-size: contain; pointer-events: none; }
|
||||
.recharge-card.selected::before { top: -7px; left: -7px; }
|
||||
.recharge-card.selected::after { bottom: -7px; right: -7px; }
|
||||
.recharge-card .amt { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; }
|
||||
.recharge-card .gift { font-size: 11px; color: var(--black-alpha-48); margin-top: 4px; font-family: var(--font-mono); }
|
||||
.recharge-card .gift.bonus { color: var(--accent-forest); font-weight: 600; }
|
||||
.recharge-card .ribbon { position: absolute; top: -8px; right: 8px; font-family: var(--font-mono); font-size: 9.5px; padding: 1px 6px; background: var(--heat); color: var(--accent-white); letter-spacing: .04em; font-weight: 600; border-radius: var(--r-sm); }
|
||||
|
||||
.pane { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); padding: 20px; margin-bottom: 16px; }
|
||||
.pane h3 { font-size: 14px; font-weight: 600; margin-bottom: 14px; }
|
||||
.pane h3 + .desc { font-size: 12px; color: var(--black-alpha-48); margin-top: -10px; margin-bottom: 14px; font-family: var(--font-mono); letter-spacing: .02em; }
|
||||
|
||||
.bills .neg { color: var(--accent-black); font-variant-numeric: tabular-nums; font-weight: 500; }
|
||||
.bills .pos { color: var(--accent-forest); font-variant-numeric: tabular-nums; font-weight: 500; }
|
||||
.bills .ref { color: var(--black-alpha-48); font-size: 11px; font-family: var(--font-mono); }
|
||||
|
||||
.usage-line { display: flex; justify-content: space-between; padding: 6px 0; font-size: 13px; }
|
||||
.usage-line .v { font-variant-numeric: tabular-nums; color: var(--accent-black); font-weight: 600; }
|
||||
.usage-bar { height: 4px; background: var(--background-lighter); border-radius: 2px; margin: 6px 0 12px; overflow: hidden; }
|
||||
.usage-bar > span { display: block; height: 100%; }
|
||||
|
||||
.rule-list { font-size: 12.5px; color: var(--black-alpha-56); line-height: 1.7; }
|
||||
.rule-list strong { color: var(--accent-black); font-weight: 600; }
|
||||
.rule-list .mono { font-family: var(--font-mono); color: var(--heat); background: var(--heat-12); padding: 1px 5px; font-size: 11.5px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
|
||||
<div class="page-head">
|
||||
<div>
|
||||
<h1>账户</h1>
|
||||
<div class="sub"><span class="mono">// 余额 · 充值 · 消费明细</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="acc-grid">
|
||||
<div>
|
||||
<div class="balance-banner">
|
||||
<span class="corner-tr" aria-hidden></span><span class="corner-bl" aria-hidden></span>
|
||||
<div class="lbl">[ CURRENT BALANCE ]</div>
|
||||
<div class="v">¥327.40</div>
|
||||
<div class="meta">// 本月已消费 ¥162.60 · 可使用约 32 个项目</div>
|
||||
<div class="actions">
|
||||
<button class="btn btn-lg" onclick="Shell.toast('充值', '/billing/topup')">充值</button>
|
||||
<button class="btn btn-ghost btn-lg" onclick="Shell.toast('提取明细', '/billing/export')">提取消费明细</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pane">
|
||||
<h3>快速充值</h3>
|
||||
<div class="desc">// 充值后立刻到账,可开发票</div>
|
||||
<div class="recharge-row">
|
||||
<div class="recharge-card" onclick="Shell.toast('选择 ¥100')"><div class="amt">¥100</div><div class="gift">无赠送</div></div>
|
||||
<div class="recharge-card selected"><span class="ribbon">推荐</span><div class="amt">¥500</div><div class="gift bonus">+ ¥30 赠送</div></div>
|
||||
<div class="recharge-card" onclick="Shell.toast('选择 ¥1000')"><div class="amt">¥1000</div><div class="gift bonus">+ ¥80 赠送</div></div>
|
||||
<div class="recharge-card" onclick="Shell.toast('选择 ¥3000')"><div class="amt">¥3000</div><div class="gift bonus">+ ¥300 赠送</div></div>
|
||||
</div>
|
||||
<div style="display:flex; gap:10px; margin-top:14px;">
|
||||
<input class="input" placeholder="自定义金额(最低 ¥50)" style="flex:1;">
|
||||
<button class="btn btn-primary" onclick="Shell.toast('微信支付', '¥500 · WechatPay')">微信支付 ¥500</button>
|
||||
<button class="btn" onclick="Shell.toast('支付宝', '¥500 · Alipay')">支付宝</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display:flex; align-items:baseline; margin-bottom:12px;">
|
||||
<h2 style="font-size:15px; font-weight:600;">消费明细</h2>
|
||||
<span class="spacer"></span>
|
||||
<div class="hstack">
|
||||
<button class="chip" style="height:28px; font-size:12px;">近 30 天</button>
|
||||
<button class="chip" style="height:28px; font-size:12px;">导出</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="t bills">
|
||||
<thead>
|
||||
<tr><th>时间</th><th>项目 / 类型</th><th>详情</th><th style="text-align:right;">金额</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td class="muted-2 mono" style="font-size:11.5px;">05.09 14:08</td><td>补水面膜 · v3</td><td class="muted">故事板 image-2 · 1 次</td><td style="text-align:right;" class="neg">-¥0.45</td></tr>
|
||||
<tr><td class="muted-2 mono" style="font-size:11.5px;">05.09 14:02</td><td>补水面膜 · v3</td><td class="muted">脚本 LLM · 2.4k tokens</td><td style="text-align:right;" class="neg">-¥0.04</td></tr>
|
||||
<tr><td class="muted-2 mono" style="font-size:11.5px;">05.09 13:38</td><td>补水面膜 · v3</td><td class="muted">基础资产 · 5 张图</td><td style="text-align:right;" class="neg">-¥1.05</td></tr>
|
||||
<tr><td class="muted-2 mono" style="font-size:11.5px;">05.08 18:21</td><td>透真防晒 · 通勤对比</td><td class="muted">视频片段 · 6 镜</td><td style="text-align:right;" class="neg">-¥1.20</td></tr>
|
||||
<tr><td class="muted-2 mono" style="font-size:11.5px;">05.08 11:02</td><td>充值</td><td class="muted">微信支付 · <span class="ref">TX2024050811021Z</span></td><td style="text-align:right;" class="pos">+¥500.00</td></tr>
|
||||
<tr><td class="muted-2 mono" style="font-size:11.5px;">05.07 20:14</td><td>蓝牙耳机 · 开箱</td><td class="muted">视频片段 · 5 镜(1 镜重跑不扣)</td><td style="text-align:right;" class="neg">-¥0.94</td></tr>
|
||||
<tr><td class="muted-2 mono" style="font-size:11.5px;">05.07 15:48</td><td>咖啡冻干 · 早八</td><td class="muted">故事板生成失败 · <span style="color:var(--black-alpha-48);">不扣费</span></td><td style="text-align:right;" class="muted-2">¥0.00</td></tr>
|
||||
<tr><td class="muted-2 mono" style="font-size:11.5px;">05.06 10:30</td><td>瑜伽裤 · 通勤穿搭</td><td class="muted">项目导出 · 1 次</td><td style="text-align:right;" class="neg">-¥3.20</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="pane">
|
||||
<h3>本月消费分布</h3>
|
||||
<div class="usage-line"><span>视频片段(Seedance)</span><span class="v">¥98.40</span></div>
|
||||
<div class="usage-bar"><span style="width:60%; background:var(--heat);"></span></div>
|
||||
|
||||
<div class="usage-line"><span>故事板(image-2)</span><span class="v">¥36.00</span></div>
|
||||
<div class="usage-bar"><span style="width:22%; background:var(--accent-forest);"></span></div>
|
||||
|
||||
<div class="usage-line"><span>基础资产</span><span class="v">¥21.00</span></div>
|
||||
<div class="usage-bar"><span style="width:13%; background:var(--black-alpha-56);"></span></div>
|
||||
|
||||
<div class="usage-line"><span>脚本 LLM</span><span class="v">¥7.20</span></div>
|
||||
<div class="usage-bar"><span style="width:5%; background:var(--black-alpha-48);"></span></div>
|
||||
|
||||
<div class="divider"></div>
|
||||
<div class="usage-line" style="font-weight:600;"><span>合计</span><span class="v">¥162.60</span></div>
|
||||
</div>
|
||||
|
||||
<div class="pane">
|
||||
<h3>扣费规则</h3>
|
||||
<div class="rule-list">
|
||||
<strong>① 失败不扣</strong>:模型超时、内容审核拦截、生成异常一律不扣费。<br>
|
||||
<strong>② 用户重跑不扣首次</strong>:第一次重跑保留原扣费,第二次起按次结算。<br>
|
||||
<strong>③ 仅在你点击 <span class="mono">[ 确认通过 ]</span> 时入账</strong>。<br>
|
||||
<strong>④ 导出不再扣费</strong>,所有 token 已在过程中结算。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pane">
|
||||
<h3>开发票</h3>
|
||||
<div style="font-size:12.5px; color:var(--black-alpha-56); margin-bottom:10px;">本月可开发票额度:<strong style="color:var(--accent-black);">¥162.60</strong></div>
|
||||
<button class="btn" style="width:100%;" onclick="Shell.toast('申请发票', '/billing/invoice')">申请发票</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script src="assets/shell.js"></script>
|
||||
<script>Shell.render({ active: 'account', crumbs: [{ label: '工作台', href: 'index.html' }, { label: '账户' }] });</script>
|
||||
</body>
|
||||
</html>
|
||||
885
电商AI平台/assets/restraint.css
Normal file
885
电商AI平台/assets/restraint.css
Normal file
@ -0,0 +1,885 @@
|
||||
/* ============================================================
|
||||
流·Studio · Restraint V2.1 · Firecrawl-aligned · 纯净版
|
||||
============================================================
|
||||
严格遵循 DESIGN_SPEC_V2.md V2.1 · 不含任何 V1/V2 legacy alias
|
||||
============================================================ */
|
||||
|
||||
/* ============ Web font · Alibaba PuHuiTi 3.0 ============ */
|
||||
@font-face {
|
||||
font-family: 'Alibaba PuHuiTi';
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: local('Alibaba PuHuiTi 3.0'),
|
||||
local('AlibabaPuHuiTi-3-55-Regular'),
|
||||
local('Alibaba PuHuiTi 2.0'),
|
||||
local('AlibabaPuHuiTi-2-55-Regular'),
|
||||
url('https://chinese-fonts-cdn.deno.dev/packages/alibaba_puhuiti/dist/AlibabaPuHuiTi-3-55-Regular/AlibabaPuHuiTi-3-55-Regular.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Alibaba PuHuiTi';
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: local('Alibaba PuHuiTi 3.0 Medium'),
|
||||
local('AlibabaPuHuiTi-3-65-Medium'),
|
||||
local('AlibabaPuHuiTi-2-65-Medium'),
|
||||
url('https://chinese-fonts-cdn.deno.dev/packages/alibaba_puhuiti/dist/AlibabaPuHuiTi-3-65-Medium/AlibabaPuHuiTi-3-65-Medium.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Alibaba PuHuiTi';
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: local('AlibabaPuHuiTi-3-75-SemiBold'),
|
||||
local('AlibabaPuHuiTi-2-75-SemiBold'),
|
||||
url('https://chinese-fonts-cdn.deno.dev/packages/alibaba_puhuiti/dist/AlibabaPuHuiTi-3-75-SemiBold/AlibabaPuHuiTi-3-75-SemiBold.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Alibaba PuHuiTi';
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: local('Alibaba PuHuiTi 3.0 Bold'),
|
||||
local('AlibabaPuHuiTi-3-85-Bold'),
|
||||
local('AlibabaPuHuiTi-2-85-Bold'),
|
||||
url('https://chinese-fonts-cdn.deno.dev/packages/alibaba_puhuiti/dist/AlibabaPuHuiTi-3-85-Bold/AlibabaPuHuiTi-3-85-Bold.woff2') format('woff2');
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
:root {
|
||||
/* ===== Backgrounds (冷灰) ===== */
|
||||
--background-base: #f9f9f9;
|
||||
--background-lighter: #fbfbfb;
|
||||
--surface: #ffffff;
|
||||
--surface-raised: #ffffff;
|
||||
|
||||
/* ===== Borders (冷灰 3 档,语义优先) ===== */
|
||||
--border-faint: #ededed;
|
||||
--border-muted: #e8e8e8;
|
||||
--border-loud: #e6e6e6;
|
||||
|
||||
/* ===== Accent multi-color (5 色信号) ===== */
|
||||
--accent-black: #262626;
|
||||
--accent-white: #ffffff;
|
||||
--accent-amethyst: #9061ff;
|
||||
--accent-bluetron: #2a6dfb;
|
||||
--accent-crimson: #eb3424;
|
||||
--accent-forest: #42c366;
|
||||
--accent-honey: #ecb730;
|
||||
|
||||
/* status 配套底/边 */
|
||||
--forest-bg: rgba(66, 195, 102, .08);
|
||||
--forest-bd: rgba(66, 195, 102, .20);
|
||||
--crimson-bg: rgba(235, 52, 36, .08);
|
||||
--crimson-bd: rgba(235, 52, 36, .20);
|
||||
--honey-bg: rgba(236, 183, 48, .08);
|
||||
--honey-bd: rgba(236, 183, 48, .20);
|
||||
|
||||
/* ===== Heat · 单 hue + 8 档 alpha ===== */
|
||||
--heat: #fa5d19;
|
||||
--heat-90: rgba(250, 93, 25, .90);
|
||||
--heat-40: rgba(250, 93, 25, .40);
|
||||
--heat-20: rgba(250, 93, 25, .20);
|
||||
--heat-16: rgba(250, 93, 25, .16);
|
||||
--heat-12: rgba(250, 93, 25, .12);
|
||||
--heat-8: rgba(250, 93, 25, .08);
|
||||
--heat-4: rgba(250, 93, 25, .04);
|
||||
|
||||
/* ===== Black-alpha 阶梯 (20 档) ===== */
|
||||
--black-alpha-1: rgba(0, 0, 0, .01);
|
||||
--black-alpha-2: rgba(0, 0, 0, .02);
|
||||
--black-alpha-3: rgba(0, 0, 0, .03);
|
||||
--black-alpha-4: rgba(0, 0, 0, .04);
|
||||
--black-alpha-5: rgba(0, 0, 0, .05);
|
||||
--black-alpha-6: rgba(0, 0, 0, .06);
|
||||
--black-alpha-7: rgba(0, 0, 0, .07);
|
||||
--black-alpha-8: rgba(0, 0, 0, .08);
|
||||
--black-alpha-10: rgba(0, 0, 0, .10);
|
||||
--black-alpha-12: rgba(0, 0, 0, .12);
|
||||
--black-alpha-16: rgba(0, 0, 0, .16);
|
||||
--black-alpha-20: rgba(0, 0, 0, .20);
|
||||
--black-alpha-24: rgba(0, 0, 0, .24);
|
||||
--black-alpha-32: rgba(38, 38, 38, .32);
|
||||
--black-alpha-40: rgba(38, 38, 38, .40);
|
||||
--black-alpha-48: rgba(38, 38, 38, .48);
|
||||
--black-alpha-56: rgba(38, 38, 38, .56);
|
||||
--black-alpha-64: rgba(38, 38, 38, .64);
|
||||
--black-alpha-72: rgba(38, 38, 38, .72);
|
||||
--black-alpha-88: rgba(38, 38, 38, .88);
|
||||
|
||||
/* ===== Radius ===== */
|
||||
--r-sm: 4px;
|
||||
--r-md: 8px;
|
||||
--r-pill: 999px;
|
||||
|
||||
/* ===== Font · 关键:--font-mono 必须含 PuHuiTi 中文 fallback ===== */
|
||||
/* Inter / JetBrains Mono 都不含 CJK 字形。
|
||||
字体链按字符级 fallthrough,中文字符会找下一个候选 —— 必须包含 PuHuiTi。 */
|
||||
--font-sans: 'Inter', 'Alibaba PuHuiTi', 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif;
|
||||
--font-inter: 'Inter', system-ui, sans-serif;
|
||||
--font-mono: 'JetBrains Mono', 'Geist Mono', ui-monospace, 'Alibaba PuHuiTi', 'PingFang SC', 'Microsoft YaHei', monospace;
|
||||
|
||||
/* ===== Transition ===== */
|
||||
--t-fast: 100ms ease;
|
||||
--t-base: 200ms ease;
|
||||
--t-slow: 300ms cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
|
||||
/* ===== Shadows ===== */
|
||||
--shadow-cta:
|
||||
inset 0 -4px 8px rgba(250, 93, 25, .20),
|
||||
0 1px 1px rgba(250, 93, 25, .12),
|
||||
0 2px 4px rgba(250, 93, 25, .10),
|
||||
0 .5px .5px rgba(250, 93, 25, .16);
|
||||
--shadow-cta-hover:
|
||||
inset 0 -4px 8px rgba(250, 93, 25, .20),
|
||||
0 1px 1px rgba(250, 93, 25, .16),
|
||||
0 4px 8px rgba(250, 93, 25, .20),
|
||||
0 .5px .5px rgba(250, 93, 25, .16);
|
||||
--shadow-cta-active:
|
||||
inset 0 -4px 8px rgba(250, 93, 25, .28),
|
||||
0 1px 2px rgba(250, 93, 25, .16);
|
||||
--shadow-floating: 0 4px 20px rgba(21, 20, 15, .06);
|
||||
}
|
||||
|
||||
::selection { background: var(--heat-20); color: var(--heat); }
|
||||
|
||||
html, body {
|
||||
background: var(--background-base);
|
||||
color: var(--accent-black);
|
||||
font-family: var(--font-sans);
|
||||
font-size: 14px;
|
||||
line-height: 1.65;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
a { color: inherit; text-decoration: none; }
|
||||
button { font: inherit; cursor: pointer; border: 0; background: none; color: inherit; }
|
||||
input, textarea, select { font: inherit; color: inherit; outline: none; }
|
||||
img, svg, video { display: block; max-width: 100%; }
|
||||
|
||||
.num, .tnum { font-variant-numeric: tabular-nums; }
|
||||
.mono { font-family: var(--font-mono); }
|
||||
.muted { color: var(--black-alpha-56); }
|
||||
.muted-2 { color: var(--black-alpha-48); }
|
||||
.spacer { flex: 1; }
|
||||
.hstack { display: flex; align-items: center; gap: 8px; }
|
||||
.vstack { display: flex; flex-direction: column; gap: 8px; }
|
||||
.divider { height: 1px; background: var(--border-faint); margin: 16px 0; }
|
||||
|
||||
/* ─── App shell ─── */
|
||||
.app { display: grid; grid-template-columns: 248px 1fr; min-height: 100vh; }
|
||||
|
||||
/* ─── Sidebar ─── */
|
||||
aside.sidebar {
|
||||
padding: 22px 16px;
|
||||
border-right: 1px solid var(--border-faint);
|
||||
background: var(--background-base);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.brand { display: flex; align-items: center; gap: 10px; padding: 6px 8px 16px; }
|
||||
.flame { width: 22px; height: 22px; color: var(--heat); }
|
||||
.flame svg { width: 100%; height: 100%; }
|
||||
.brand .name { font-weight: 600; font-size: 18px; letter-spacing: -.012em; color: var(--accent-black); }
|
||||
|
||||
/* sidebar search · Ctrl K Inter Bold 平铺 */
|
||||
.search-box {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
padding: 9px 12px;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
color: var(--black-alpha-48);
|
||||
margin-bottom: 18px;
|
||||
cursor: text;
|
||||
transition: border-color var(--t-base);
|
||||
}
|
||||
.search-box:hover { border-color: var(--black-alpha-24); }
|
||||
.search-box:focus-within { border-color: var(--heat-40); box-shadow: inset 0 0 0 1px var(--heat-40); }
|
||||
.search-box svg { width: 14px; height: 14px; flex-shrink: 0; color: var(--black-alpha-56); }
|
||||
.search-box input {
|
||||
flex: 1; min-width: 0;
|
||||
border: 0; background: transparent;
|
||||
font-size: 13.5px; color: var(--accent-black);
|
||||
padding: 0;
|
||||
}
|
||||
.search-box input::placeholder { color: var(--black-alpha-48); }
|
||||
.search-box .kbd {
|
||||
margin-left: auto;
|
||||
flex-shrink: 0;
|
||||
white-space: nowrap;
|
||||
font-family: var(--font-inter);
|
||||
font-weight: 700;
|
||||
font-size: 11px;
|
||||
color: var(--black-alpha-48);
|
||||
letter-spacing: .02em;
|
||||
}
|
||||
|
||||
.nav-section {
|
||||
font-size: 11px; color: var(--black-alpha-48);
|
||||
padding: 16px 12px 8px;
|
||||
letter-spacing: .04em;
|
||||
font-weight: 500;
|
||||
/* 中文标签用 sans 字体,不用 mono + uppercase */
|
||||
}
|
||||
nav { display: flex; flex-direction: column; gap: 2px; }
|
||||
nav a {
|
||||
display: flex; align-items: center; gap: 11px;
|
||||
padding: 9px 12px;
|
||||
color: var(--black-alpha-56);
|
||||
font-size: 13.5px; font-weight: 500;
|
||||
border-radius: var(--r-md);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: background var(--t-base), color var(--t-base);
|
||||
}
|
||||
nav a:hover { background: var(--black-alpha-4); color: var(--accent-black); }
|
||||
nav a.active { background: var(--heat-12); color: var(--heat); }
|
||||
nav a svg { width: 14px; height: 14px; opacity: .85; }
|
||||
nav a.active svg { opacity: 1; }
|
||||
nav a .pill-mini {
|
||||
margin-left: auto;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 9.5px; font-weight: 600;
|
||||
padding: 2px 7px;
|
||||
background: var(--surface);
|
||||
color: var(--black-alpha-48);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-pill);
|
||||
letter-spacing: .04em;
|
||||
}
|
||||
nav a.disabled { color: var(--black-alpha-32); cursor: not-allowed; }
|
||||
nav a.disabled:hover { background: transparent; color: var(--black-alpha-32); }
|
||||
.aside-foot { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--border-faint); }
|
||||
.user {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
padding: 8px 10px;
|
||||
border-radius: var(--r-md);
|
||||
cursor: pointer;
|
||||
transition: background var(--t-base);
|
||||
}
|
||||
.user:hover { background: var(--black-alpha-4); }
|
||||
.user .av {
|
||||
width: 26px; height: 26px;
|
||||
border-radius: 6px;
|
||||
background: var(--accent-black);
|
||||
color: var(--accent-white);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-weight: 600; font-size: 11px;
|
||||
}
|
||||
.user .em { font-size: 13px; color: var(--accent-black); }
|
||||
|
||||
/* ─── Main + grid background ─── */
|
||||
main { position: relative; overflow: hidden; background: var(--background-base); }
|
||||
.grid-bg {
|
||||
position: absolute; inset: 0; pointer-events: none;
|
||||
background-image:
|
||||
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><g stroke='%23c8c8c8' stroke-width='1' fill='none'><path d='M-5 0 L5 0 M0 -5 L0 5'/><path d='M235 0 L245 0 M240 -5 L240 5'/><path d='M-5 240 L5 240 M0 235 L0 245'/><path d='M235 240 L245 240 M240 235 L240 245'/></g></svg>"),
|
||||
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='60' height='60'><circle cx='60' cy='60' r='0.9' fill='%23d8d8d8'/></svg>"),
|
||||
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><g stroke='%23ebebeb' stroke-width='1' fill='none' stroke-dasharray='1.5 4'><path d='M240 0 L240 240'/><path d='M0 240 L240 240'/></g></svg>");
|
||||
background-size: 240px 240px, 60px 60px, 240px 240px;
|
||||
mask-image: radial-gradient(ellipse 95% 80% at 50% 35%, #000 25%, transparent 95%);
|
||||
-webkit-mask-image: radial-gradient(ellipse 95% 80% at 50% 35%, #000 25%, transparent 95%);
|
||||
}
|
||||
.scatter {
|
||||
position: absolute;
|
||||
font-family: var(--font-mono); font-size: 8.5px; line-height: 1.05;
|
||||
color: var(--black-alpha-20); white-space: pre; pointer-events: none;
|
||||
opacity: .85; letter-spacing: .04em;
|
||||
}
|
||||
.tag-corner {
|
||||
position: absolute;
|
||||
color: var(--black-alpha-48);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10.5px; letter-spacing: .06em;
|
||||
pointer-events: none; opacity: .85; z-index: 1;
|
||||
}
|
||||
.sq-mark { position: absolute; width: 5px; height: 5px; background: var(--black-alpha-24); pointer-events: none; }
|
||||
|
||||
/* ─── Topbar ─── */
|
||||
.topbar {
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
padding: 14px 28px;
|
||||
border-bottom: 1px solid var(--border-faint);
|
||||
background: var(--background-base);
|
||||
position: relative; z-index: 2;
|
||||
}
|
||||
.crumbs { display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--black-alpha-48); }
|
||||
.crumbs .sep { color: var(--black-alpha-32); }
|
||||
.crumbs .here { color: var(--accent-black); font-weight: 500; }
|
||||
.crumbs a:hover { color: var(--accent-black); }
|
||||
.topbar .right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
|
||||
.balance-chip {
|
||||
display: inline-flex; align-items: center; gap: 7px;
|
||||
height: 36px;
|
||||
padding: 0 14px 0 12px;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-pill);
|
||||
font-size: 13px;
|
||||
color: var(--black-alpha-56);
|
||||
cursor: pointer;
|
||||
transition: background var(--t-base), border-color var(--t-base);
|
||||
}
|
||||
.balance-chip:hover { background: var(--black-alpha-4); border-color: var(--black-alpha-24); }
|
||||
.balance-chip strong { color: var(--accent-black); font-weight: 600; font-variant-numeric: tabular-nums; }
|
||||
.balance-chip svg { width: 13px; height: 13px; color: var(--heat); }
|
||||
.icon-btn {
|
||||
width: 36px; height: 36px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
color: var(--black-alpha-56);
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
transition: background var(--t-base), border-color var(--t-base), color var(--t-base);
|
||||
}
|
||||
.icon-btn:hover { background: var(--black-alpha-4); color: var(--accent-black); border-color: var(--black-alpha-24); }
|
||||
.icon-btn svg { width: 15px; height: 15px; }
|
||||
.icon-btn .dot-noti {
|
||||
position: absolute; top: 8px; right: 9px;
|
||||
width: 7px; height: 7px; border-radius: 50%;
|
||||
background: var(--heat); border: 1.5px solid var(--surface);
|
||||
}
|
||||
|
||||
/* ─── Content ─── */
|
||||
.content {
|
||||
padding: 48px 56px 72px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
max-width: 1480px;
|
||||
margin: 0 auto;
|
||||
min-height: calc(100vh - 64px);
|
||||
}
|
||||
|
||||
.content > .corner-mark { display: none; }
|
||||
.page-head {
|
||||
display: flex; align-items: flex-start; justify-content: space-between;
|
||||
margin-bottom: 36px; gap: 16px; flex-wrap: wrap;
|
||||
}
|
||||
.page-head h1 {
|
||||
font-size: 28px; font-weight: 600; letter-spacing: -.02em; line-height: 1.25;
|
||||
color: var(--accent-black);
|
||||
}
|
||||
.page-head .sub {
|
||||
font-size: 14px; color: var(--black-alpha-56);
|
||||
margin-top: 10px;
|
||||
display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
|
||||
}
|
||||
.page-head .sub .mono { font-family: var(--font-mono); font-size: 11.5px; color: var(--black-alpha-48); letter-spacing: .04em; }
|
||||
.page-head .actions { display: flex; gap: 10px; align-items: center; }
|
||||
|
||||
.section-h { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 14px; }
|
||||
.section-h h2 { font-size: 16px; font-weight: 600; letter-spacing: -.01em; color: var(--accent-black); }
|
||||
.section-h .more {
|
||||
font-family: var(--font-mono); font-size: 11.5px;
|
||||
color: var(--black-alpha-48); letter-spacing: .04em;
|
||||
cursor: pointer;
|
||||
transition: color var(--t-base);
|
||||
}
|
||||
.section-h .more:hover { color: var(--heat); }
|
||||
|
||||
/* ─── Buttons · 统一高度 36 / 8 px 圆角 / 真 1px border / hover bg 切换 ─── */
|
||||
.btn {
|
||||
display: inline-flex; align-items: center; justify-content: center; gap: 6px;
|
||||
height: 36px;
|
||||
padding: 0 16px;
|
||||
border-radius: var(--r-md);
|
||||
font-size: 13px; font-weight: 500;
|
||||
background: var(--surface);
|
||||
color: var(--accent-black);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
font-family: inherit;
|
||||
border: 1px solid var(--black-alpha-12);
|
||||
transition: background var(--t-base), border-color var(--t-base), transform var(--t-fast);
|
||||
}
|
||||
.btn:hover { background: var(--black-alpha-4); border-color: var(--black-alpha-24); }
|
||||
.btn:active { background: var(--black-alpha-7); transform: scale(.99); }
|
||||
.btn:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--background-base), 0 0 0 4px var(--heat-40); }
|
||||
.btn:disabled, .btn.disabled {
|
||||
color: var(--black-alpha-32);
|
||||
background: var(--black-alpha-5);
|
||||
border-color: var(--black-alpha-12);
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
.btn:disabled:hover, .btn.disabled:hover {
|
||||
background: var(--black-alpha-5);
|
||||
border-color: var(--black-alpha-12);
|
||||
}
|
||||
.btn svg { width: 13px; height: 13px; }
|
||||
|
||||
.btn-primary {
|
||||
background: var(--heat);
|
||||
color: var(--accent-white);
|
||||
border-color: var(--heat);
|
||||
font-weight: 600;
|
||||
/* 继承 .btn 的 height: 36px / padding: 0 16px */
|
||||
box-shadow: var(--shadow-cta);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: var(--heat);
|
||||
border-color: var(--heat);
|
||||
box-shadow: var(--shadow-cta-hover);
|
||||
}
|
||||
.btn-primary:active {
|
||||
background: var(--heat);
|
||||
transform: scale(.995);
|
||||
box-shadow: var(--shadow-cta-active);
|
||||
}
|
||||
.btn-primary:disabled, .btn-primary.disabled {
|
||||
background: var(--heat-40);
|
||||
color: var(--accent-white);
|
||||
border-color: var(--heat-40);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
background: transparent;
|
||||
border-color: transparent;
|
||||
color: var(--black-alpha-56);
|
||||
}
|
||||
.btn-ghost:hover { background: var(--black-alpha-4); border-color: transparent; color: var(--accent-black); }
|
||||
.btn-ghost:active { background: var(--black-alpha-7); }
|
||||
|
||||
.btn-sm { height: 28px; padding: 0 12px; font-size: 12px; border-radius: var(--r-md); }
|
||||
.btn-lg { height: 40px; padding: 0 20px; font-size: 13.5px; }
|
||||
|
||||
/* ─── Pills ─── */
|
||||
.pill {
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: var(--r-pill);
|
||||
font-size: 11.5px; font-weight: 500;
|
||||
border: 1px solid var(--border-faint);
|
||||
background: var(--surface);
|
||||
color: var(--black-alpha-56);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.pill.info { background: var(--heat-12); color: var(--heat); border-color: var(--heat-20); }
|
||||
.pill.ok { background: var(--forest-bg); color: var(--accent-forest); border-color: var(--forest-bd); }
|
||||
.pill.err { background: var(--crimson-bg); color: var(--accent-crimson); border-color: var(--crimson-bd); }
|
||||
.pill.neutral { background: var(--black-alpha-4); color: var(--black-alpha-56); border-color: var(--border-faint); }
|
||||
.pill .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
|
||||
|
||||
/* ─── Cards / containers · V2.1 统一 8 px 圆角 ─── */
|
||||
.card-hard {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
position: relative;
|
||||
}
|
||||
/* V2.1 spec §5.3 · 容器四角准星 · SVG 圆弧内凹(22×21 viewBox) */
|
||||
.card-hard.with-corners::before, .card-hard.with-corners::after,
|
||||
.with-corners .corner-tr, .with-corners .corner-bl {
|
||||
content: ''; position: absolute;
|
||||
width: 14px; height: 14px;
|
||||
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 21' fill='%23e8e8e8'%3E%3Cpath d='M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z'/%3E%3C/svg%3E") no-repeat center;
|
||||
background-size: contain;
|
||||
pointer-events: none;
|
||||
}
|
||||
.card-hard.with-corners::before { top: -7px; left: -7px; }
|
||||
.card-hard.with-corners::after { bottom: -7px; right: -7px; }
|
||||
.with-corners .corner-tr { top: -7px; right: -7px; }
|
||||
.with-corners .corner-bl { bottom: -7px; left: -7px; }
|
||||
|
||||
/* ─── Stats (KPI bar) ─── */
|
||||
.stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 0;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
position: relative;
|
||||
margin-bottom: 36px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.stat {
|
||||
padding: 24px 28px;
|
||||
border-right: 1px solid var(--border-faint);
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
transition: background var(--t-base);
|
||||
}
|
||||
.stat:hover { background: var(--black-alpha-4); }
|
||||
.stat:last-child { border-right: 0; }
|
||||
.stat .lbl {
|
||||
font-size: 12.5px; color: var(--black-alpha-48);
|
||||
font-weight: 500; display: flex; align-items: center; gap: 8px;
|
||||
}
|
||||
.stat .lbl .badge {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px; color: var(--black-alpha-48);
|
||||
background: var(--black-alpha-4);
|
||||
padding: 1px 7px;
|
||||
border-radius: var(--r-sm);
|
||||
border: 1px solid var(--border-faint);
|
||||
letter-spacing: .04em;
|
||||
}
|
||||
.stat .v {
|
||||
font-size: 32px; font-weight: 600; letter-spacing: -.02em;
|
||||
line-height: 1.1; margin-top: 14px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
color: var(--accent-black);
|
||||
}
|
||||
.stat .v small { font-size: 15px; color: var(--black-alpha-48); font-weight: 500; margin-left: 2px; }
|
||||
.stat .delta {
|
||||
font-family: var(--font-mono); font-size: 11px;
|
||||
margin-top: 10px; color: var(--black-alpha-48); letter-spacing: .02em;
|
||||
}
|
||||
.stat .delta.up { color: var(--accent-forest); }
|
||||
.stat .bar { height: 5px; background: var(--black-alpha-7); border-radius: 3px; margin-top: 14px; overflow: hidden; }
|
||||
.stat .bar > span { display: block; height: 100%; background: var(--heat); border-radius: 3px; }
|
||||
.stat .sub {
|
||||
font-family: var(--font-mono); font-size: 10.5px;
|
||||
color: var(--black-alpha-48); margin-top: 10px; letter-spacing: .02em;
|
||||
}
|
||||
|
||||
/* ─── Form fields ─── */
|
||||
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 18px; }
|
||||
.field-label { font-size: 13px; font-weight: 500; color: var(--accent-black); }
|
||||
.field-label .req { color: var(--accent-crimson); margin-left: 2px; }
|
||||
.field-hint { font-size: 12px; color: var(--black-alpha-48); }
|
||||
.input, .textarea, .select {
|
||||
height: 36px;
|
||||
padding: 0 14px;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--black-alpha-12);
|
||||
border-radius: var(--r-md);
|
||||
font-size: 13.5px;
|
||||
width: 100%;
|
||||
font-family: inherit;
|
||||
color: var(--accent-black);
|
||||
transition: border-color var(--t-base), box-shadow var(--t-base), background var(--t-base);
|
||||
}
|
||||
.input:hover, .textarea:hover, .select:hover { border-color: var(--black-alpha-24); }
|
||||
.input:focus, .textarea:focus, .select:focus {
|
||||
border-color: var(--heat-40);
|
||||
box-shadow: inset 0 0 0 1px var(--heat-40);
|
||||
}
|
||||
.input::placeholder, .textarea::placeholder { color: var(--black-alpha-48); }
|
||||
.input:disabled, .textarea:disabled, .select:disabled {
|
||||
background: var(--black-alpha-5);
|
||||
color: var(--black-alpha-32);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.textarea { height: auto; min-height: 88px; padding: 12px 14px; line-height: 1.6; resize: vertical; }
|
||||
.select {
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 16 16' fill='none'><path d='M4 6l4 4 4-4' stroke='%237a7a7a' stroke-width='1.4'/></svg>");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 12px center;
|
||||
padding-right: 32px;
|
||||
}
|
||||
|
||||
/* ─── Tabs ─── */
|
||||
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border-faint); margin-bottom: 20px; }
|
||||
.tab {
|
||||
padding: 10px 14px; font-size: 13px;
|
||||
color: var(--black-alpha-56);
|
||||
border-bottom: 2px solid transparent;
|
||||
margin-bottom: -1px;
|
||||
cursor: pointer;
|
||||
font-weight: 500; user-select: none;
|
||||
transition: color var(--t-base), background var(--t-base);
|
||||
border-radius: var(--r-md) var(--r-md) 0 0;
|
||||
}
|
||||
.tab:hover { color: var(--accent-black); background: var(--black-alpha-4); }
|
||||
.tab.active { color: var(--accent-black); border-bottom-color: var(--heat); }
|
||||
.tab .count {
|
||||
font-family: var(--font-mono); font-size: 10.5px;
|
||||
color: var(--black-alpha-48); margin-left: 6px;
|
||||
padding: 1px 7px;
|
||||
background: var(--black-alpha-4);
|
||||
border-radius: var(--r-sm); letter-spacing: .04em;
|
||||
}
|
||||
.tab.active .count { background: var(--heat-12); color: var(--heat); }
|
||||
|
||||
/* ─── Filter chips · 统一高度 36 px 与 .btn / .input 对齐 ─── */
|
||||
.chip {
|
||||
height: 36px; padding: 0 14px;
|
||||
border: 1px solid var(--border-faint);
|
||||
background: var(--surface);
|
||||
border-radius: var(--r-md);
|
||||
font-size: 13px;
|
||||
color: var(--black-alpha-56);
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: background var(--t-base), border-color var(--t-base), color var(--t-base);
|
||||
}
|
||||
.chip:hover { background: var(--black-alpha-4); border-color: var(--black-alpha-24); color: var(--accent-black); }
|
||||
.chip.active { border-color: var(--heat-40); color: var(--heat); background: var(--heat-12); }
|
||||
.chip svg { width: 12px; height: 12px; }
|
||||
|
||||
/* ─── Toolbar ─── */
|
||||
.toolbar { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; flex-wrap: wrap; }
|
||||
.toolbar .search-inline {
|
||||
position: relative; flex: 1; max-width: 360px;
|
||||
}
|
||||
.toolbar .search-inline svg {
|
||||
position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
|
||||
color: var(--black-alpha-56); width: 14px; height: 14px;
|
||||
z-index: 2; pointer-events: none;
|
||||
}
|
||||
.toolbar .search-inline input { padding-left: 36px; }
|
||||
|
||||
/* ─── Progress (5 段流水线 · V2.1 语义色 + 脉动) ─── */
|
||||
.prog { display: flex; gap: 3px; }
|
||||
.prog span {
|
||||
width: 18px; height: 5px; border-radius: 2px;
|
||||
background: var(--black-alpha-8);
|
||||
transition: background var(--t-base);
|
||||
}
|
||||
.prog span.done { background: var(--accent-forest); }
|
||||
.prog span.cur {
|
||||
background: var(--heat);
|
||||
animation: prog-pulse 1.4s ease-in-out infinite;
|
||||
}
|
||||
.prog span.fail { background: var(--accent-crimson); }
|
||||
@keyframes prog-pulse {
|
||||
0%, 100% { opacity: 1; transform: scaleY(1); }
|
||||
50% { opacity: .55; transform: scaleY(.7); }
|
||||
}
|
||||
|
||||
/* ─── Table ─── */
|
||||
table.t {
|
||||
width: 100%; border-collapse: collapse;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
overflow: hidden;
|
||||
}
|
||||
table.t thead th {
|
||||
text-align: left;
|
||||
font-size: 11.5px;
|
||||
font-weight: 500;
|
||||
color: var(--black-alpha-48);
|
||||
padding: 14px 16px;
|
||||
background: var(--black-alpha-3);
|
||||
border-bottom: 1px solid var(--border-faint);
|
||||
letter-spacing: .04em;
|
||||
text-transform: uppercase;
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
table.t tbody td {
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid var(--border-faint);
|
||||
font-size: 13px;
|
||||
vertical-align: middle;
|
||||
color: var(--accent-black);
|
||||
}
|
||||
table.t tbody tr:last-child td { border-bottom: 0; }
|
||||
table.t tbody tr { cursor: pointer; transition: background var(--t-base); }
|
||||
table.t tbody tr:hover { background: var(--black-alpha-4); }
|
||||
|
||||
/* ─── Placeholder thumb ─── */
|
||||
.placeholder {
|
||||
background:
|
||||
repeating-linear-gradient(135deg, rgba(0,0,0,0.025) 0 1px, transparent 1px 12px),
|
||||
var(--black-alpha-4);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
display: grid; place-items: center;
|
||||
color: var(--black-alpha-48);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px;
|
||||
letter-spacing: .04em;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
padding: 6px;
|
||||
}
|
||||
.placeholder .ph-frame {
|
||||
background: rgba(255, 255, 255, .92);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-sm);
|
||||
padding: 3px 8px;
|
||||
font-size: 10.5px;
|
||||
color: var(--black-alpha-56);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* ─── Toast ─── */
|
||||
.toast {
|
||||
position: fixed; bottom: 24px; right: 24px;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
padding: 14px 18px;
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
box-shadow: var(--shadow-floating);
|
||||
transform: translateX(420px);
|
||||
transition: transform var(--t-slow);
|
||||
z-index: 1000;
|
||||
min-width: 260px;
|
||||
}
|
||||
.toast.show { transform: translateX(0); }
|
||||
.toast .ic-t {
|
||||
width: 26px; height: 26px;
|
||||
background: var(--heat-12);
|
||||
color: var(--heat);
|
||||
border-radius: var(--r-md);
|
||||
display: grid; place-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.toast .ic-t svg { width: 13px; height: 13px; }
|
||||
.toast .txt { font-size: 13px; color: var(--accent-black); font-weight: 500; }
|
||||
.toast .txt .mono {
|
||||
font-family: var(--font-mono); font-size: 11px;
|
||||
color: var(--black-alpha-48); display: block; margin-top: 2px;
|
||||
letter-spacing: .04em; font-weight: 400;
|
||||
}
|
||||
|
||||
/* ─── Modal ─── */
|
||||
.modal-bg {
|
||||
position: fixed; inset: 0;
|
||||
background: rgba(21, 20, 15, .42);
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
display: none; align-items: center; justify-content: center;
|
||||
z-index: 999;
|
||||
opacity: 0;
|
||||
transition: opacity .2s;
|
||||
}
|
||||
.modal-bg.show { display: flex; opacity: 1; }
|
||||
.modal {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
max-width: 480px; width: 90%;
|
||||
position: relative;
|
||||
transform: scale(.96);
|
||||
transition: transform .25s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
.modal-bg.show .modal { transform: scale(1); }
|
||||
.modal::before, .modal::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 14px; height: 14px;
|
||||
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 21' fill='%23e8e8e8'%3E%3Cpath d='M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z'/%3E%3C/svg%3E") no-repeat center;
|
||||
background-size: contain;
|
||||
pointer-events: none;
|
||||
color: var(--black-alpha-48);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 13px; line-height: 1;
|
||||
}
|
||||
.modal::before { top: -7px; left: -7px; }
|
||||
.modal::after { bottom: -7px; right: -7px; }
|
||||
.modal .corner-tr, .modal .corner-bl {
|
||||
position: absolute;
|
||||
width: 14px; height: 14px;
|
||||
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 21' fill='%23e8e8e8'%3E%3Cpath d='M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z'/%3E%3C/svg%3E") no-repeat center;
|
||||
background-size: contain;
|
||||
pointer-events: none;
|
||||
}
|
||||
.modal .corner-tr { top: -7px; right: -7px; }
|
||||
.modal .corner-bl { bottom: -7px; left: -7px; }
|
||||
.modal-h {
|
||||
padding: 22px 24px 16px;
|
||||
border-bottom: 1px solid var(--border-faint);
|
||||
display: flex; align-items: center; gap: 14px;
|
||||
}
|
||||
.modal-h .ic-m {
|
||||
width: 36px; height: 36px;
|
||||
background: var(--heat-12);
|
||||
color: var(--heat);
|
||||
border-radius: var(--r-md);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.modal-h .ic-m svg { width: 17px; height: 17px; }
|
||||
.modal-h .ti { font-size: 16px; font-weight: 600; line-height: 1.4; color: var(--accent-black); }
|
||||
.modal-h .ti span {
|
||||
display: block; font-family: var(--font-mono); font-size: 11px;
|
||||
color: var(--black-alpha-48); font-weight: 400; margin-top: 4px; letter-spacing: .04em;
|
||||
}
|
||||
.modal-b { padding: 20px 24px; font-size: 13.5px; color: var(--black-alpha-72); line-height: 1.75; }
|
||||
.modal-b .mono-acc {
|
||||
font-family: var(--font-mono); color: var(--heat);
|
||||
background: var(--heat-12); padding: 2px 6px;
|
||||
font-size: 11.5px; border-radius: var(--r-sm);
|
||||
}
|
||||
.modal-f {
|
||||
padding: 16px 24px;
|
||||
border-top: 1px solid var(--border-faint);
|
||||
display: flex; justify-content: flex-end; gap: 10px;
|
||||
}
|
||||
|
||||
/* ─── Drawer ─── */
|
||||
.drawer-bg {
|
||||
position: fixed; inset: 0;
|
||||
background: rgba(21, 20, 15, .32);
|
||||
display: none;
|
||||
z-index: 90;
|
||||
}
|
||||
.drawer-bg.show { display: block; }
|
||||
.drawer {
|
||||
position: fixed; right: 0; top: 0; bottom: 0;
|
||||
width: 540px; max-width: 100vw;
|
||||
background: var(--surface);
|
||||
border-left: 1px solid var(--border-faint);
|
||||
z-index: 95;
|
||||
transform: translateX(100%);
|
||||
transition: transform .25s cubic-bezier(.32, .72, 0, 1);
|
||||
display: flex; flex-direction: column;
|
||||
box-shadow: -4px 0 24px rgba(21, 20, 15, .04);
|
||||
}
|
||||
.drawer.show { transform: translateX(0); }
|
||||
.drawer-h {
|
||||
padding: 20px 24px;
|
||||
border-bottom: 1px solid var(--border-faint);
|
||||
display: flex; align-items: center;
|
||||
}
|
||||
.drawer-h h3 { font-size: 16px; font-weight: 600; color: var(--accent-black); }
|
||||
.drawer-h .x {
|
||||
margin-left: auto; width: 32px; height: 32px;
|
||||
border-radius: var(--r-md);
|
||||
display: grid; place-items: center;
|
||||
color: var(--black-alpha-56); cursor: pointer;
|
||||
transition: background var(--t-base);
|
||||
}
|
||||
.drawer-h .x:hover { background: var(--black-alpha-4); color: var(--accent-black); }
|
||||
.drawer-b { padding: 24px; overflow-y: auto; flex: 1; }
|
||||
.drawer-f {
|
||||
padding: 16px 24px;
|
||||
border-top: 1px solid var(--border-faint);
|
||||
display: flex; gap: 10px; justify-content: flex-end;
|
||||
background: var(--background-lighter);
|
||||
}
|
||||
|
||||
/* ─── Scrollbar ─── */
|
||||
::-webkit-scrollbar { width: 8px; height: 8px; }
|
||||
::-webkit-scrollbar-track { background: transparent; }
|
||||
::-webkit-scrollbar-thumb { background: var(--black-alpha-12); border-radius: 4px; }
|
||||
::-webkit-scrollbar-thumb:hover { background: var(--black-alpha-24); }
|
||||
|
||||
/* ─── Responsive ─── */
|
||||
@media (max-width: 1100px) {
|
||||
.app { grid-template-columns: 1fr; }
|
||||
aside.sidebar { display: none; }
|
||||
.stats { grid-template-columns: repeat(2, 1fr); }
|
||||
.stat:nth-child(2) { border-right: 0; }
|
||||
.stat:nth-child(1), .stat:nth-child(2) { border-bottom: 1px solid var(--border-faint); }
|
||||
.content { padding: 28px 24px 48px; }
|
||||
}
|
||||
|
||||
/* ─── Spinner ─── */
|
||||
.spinner {
|
||||
width: 18px; height: 18px;
|
||||
border: 2px solid var(--border-faint);
|
||||
border-top-color: var(--heat);
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
195
电商AI平台/assets/shell.js
Normal file
195
电商AI平台/assets/shell.js
Normal file
@ -0,0 +1,195 @@
|
||||
/* ============================================================
|
||||
流·Studio · Shell renderer V2.1
|
||||
渲染 sidebar / topbar / 网格背景装饰 / Toast / Modal helpers
|
||||
每个页面调用 Shell.render({ active, crumbs, balance, topActions })
|
||||
|
||||
V2.1 变化:
|
||||
- sidebar 搜索 ⌘K → "Ctrl K" Inter Bold 平铺(无 kbd 边框)
|
||||
============================================================ */
|
||||
|
||||
const NAV = [
|
||||
{
|
||||
id: 'dashboard', label: '工作台', href: 'index.html',
|
||||
icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M3 12 12 3l9 9"/><path d="M5 10v10h14V10"/></svg>'
|
||||
},
|
||||
{
|
||||
id: 'products', label: '商品库', href: 'products.html', badge: '12',
|
||||
icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><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>'
|
||||
},
|
||||
{
|
||||
id: 'projects', label: '视频项目', href: 'projects.html',
|
||||
icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="4" width="18" height="16"/><path d="M7 4v16M16 4v16M3 9h18M3 15h18"/></svg>'
|
||||
},
|
||||
{
|
||||
id: 'library', label: '资产库', href: 'library.html',
|
||||
icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="4" width="6" height="16"/><rect x="11" y="4" width="4" height="16"/><rect x="17" y="6" width="4" height="14"/></svg>'
|
||||
},
|
||||
{
|
||||
id: 'account', label: '账户', href: 'account.html',
|
||||
icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="6" width="18" height="13" rx="2"/><path d="M3 10h18M16 14h2"/></svg>'
|
||||
},
|
||||
{
|
||||
id: 'settings', label: '设置', href: '#',
|
||||
icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8 2 2 0 0 1-2.8 2.8 1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5 2 2 0 0 1-4 0 1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3 2 2 0 0 1-2.8-2.8 1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1 2 2 0 0 1 0-4 1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8 2 2 0 0 1 2.8-2.8 1.7 1.7 0 0 0 1.8.3 1.7 1.7 0 0 0 1-1.5 2 2 0 0 1 4 0 1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3 2 2 0 0 1 2.8 2.8 1.7 1.7 0 0 0-.3 1.8 1.7 1.7 0 0 0 1.5 1 2 2 0 0 1 0 4 1.7 1.7 0 0 0-1.5 1.1Z"/></svg>'
|
||||
}
|
||||
];
|
||||
|
||||
const TEAM_NAV = {
|
||||
label: '团队', icon:
|
||||
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="9" cy="8" r="3"/><circle cx="17" cy="9" r="2.5"/><path d="M3 19c0-3 2.7-5 6-5s6 2 6 5M14 19c.5-2.4 2.4-4 5-4 .8 0 1.5.2 2 .5"/></svg>',
|
||||
badge: 'V1.5'
|
||||
};
|
||||
|
||||
window.Shell = {
|
||||
render({ active = '', crumbs = [], balance = '¥327.40', topActions = '' } = {}) {
|
||||
const navHtml = NAV.map(n => `
|
||||
<a href="${n.href}" class="${active === n.id ? 'active' : ''}">
|
||||
${n.icon}
|
||||
<span>${n.label}</span>
|
||||
${n.badge ? `<span class="pill-mini">${n.badge}</span>` : ''}
|
||||
</a>
|
||||
`).join('');
|
||||
|
||||
const sidebar = `
|
||||
<aside class="sidebar">
|
||||
<div class="brand">
|
||||
<div class="flame"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2c1 3 4 5 4 9a4 4 0 0 1-4 4 4 4 0 0 1-4-4 5 5 0 0 1 1.5-3.5C10.5 6 11.5 4 12 2zm-1 13c0 2 1 3 1 5 1-1 3-2 3-5 0-1.5-1-2-2-3-1 1-2 2-2 3z"/></svg></div>
|
||||
<div><div class="name">流·Studio</div></div>
|
||||
</div>
|
||||
<div class="search-box" onclick="document.getElementById('global-search').focus()">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<input id="global-search" placeholder="搜索"/>
|
||||
<span class="kbd">Ctrl K</span>
|
||||
</div>
|
||||
<div class="nav-section">主要</div>
|
||||
<nav>${navHtml}</nav>
|
||||
<div class="nav-section">协作</div>
|
||||
<nav>
|
||||
<a class="disabled" title="V1.5 上线,敬请期待">
|
||||
${TEAM_NAV.icon}
|
||||
<span>${TEAM_NAV.label}</span>
|
||||
<span class="pill-mini">${TEAM_NAV.badge}</span>
|
||||
</a>
|
||||
</nav>
|
||||
<div class="aside-foot">
|
||||
<div class="user" onclick="Shell.toast('账户菜单', 'li@shop.com')">
|
||||
<div class="av">李</div>
|
||||
<div class="em">小李的店</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
`;
|
||||
|
||||
const crumbHtml = crumbs.length ? `
|
||||
<div class="crumbs">
|
||||
${crumbs.map((c, i) => {
|
||||
const last = i === crumbs.length - 1;
|
||||
const sep = i > 0 ? '<span class="sep">/</span>' : '';
|
||||
if (last) return `${sep}<span class="here">${c.label}</span>`;
|
||||
return `${sep}<a href="${c.href || '#'}">${c.label}</a>`;
|
||||
}).join('')}
|
||||
</div>
|
||||
` : '';
|
||||
|
||||
const topbar = `
|
||||
<header class="topbar">
|
||||
${crumbHtml}
|
||||
<div class="right">
|
||||
<span class="balance-chip" onclick="location.href='account.html'">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><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>
|
||||
余额 <strong>${balance}</strong>
|
||||
</span>
|
||||
<button class="icon-btn" onclick="Shell.toast('通知中心', '3 条未读')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9M10 21a2 2 0 0 0 4 0"/></svg>
|
||||
<span class="dot-noti"></span>
|
||||
</button>
|
||||
${topActions}
|
||||
</div>
|
||||
</header>
|
||||
`;
|
||||
|
||||
const decorations = `
|
||||
<div class="grid-bg"></div>
|
||||
<pre class="scatter" style="top:96px;left:280px"> · · +
|
||||
· +XX+
|
||||
+XXXX·
|
||||
+X· </pre>
|
||||
<pre class="scatter" style="top:340px;right:96px">+ · ·
|
||||
XX· ·
|
||||
·XXXX·+
|
||||
·++· </pre>
|
||||
<pre class="scatter" style="bottom:160px;left:42%"> · +
|
||||
+·XX·
|
||||
·X+ ·
|
||||
· </pre>
|
||||
<pre class="scatter" style="top:580px;left:60px"> +X·
|
||||
·XX·
|
||||
+·X·+</pre>
|
||||
<span class="sq-mark" style="top:238px;left:478px"></span>
|
||||
<span class="sq-mark" style="top:478px;left:1198px"></span>
|
||||
<span class="sq-mark" style="bottom:300px;left:238px"></span>
|
||||
<span class="sq-mark" style="top:718px;right:240px"></span>
|
||||
<span class="tag-corner" style="top:158px;left:34px">[ 200 OK ]</span>
|
||||
<span class="tag-corner" style="top:158px;right:34px">[ /v2 ]</span>
|
||||
<span class="tag-corner" style="bottom:36px;left:34px">[ .MP4 · 9:16 ]</span>
|
||||
<span class="tag-corner" style="bottom:36px;right:34px">[ STUDIO ]</span>
|
||||
`;
|
||||
|
||||
const toastHtml = `
|
||||
<div class="toast" id="__toast">
|
||||
<div class="ic-t"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg></div>
|
||||
<div class="txt" id="__toast-txt">操作成功<span class="mono">[ 200 OK ]</span></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 装订线 SVG 准星 · V2.1 签名元素(圆弧内凹的"+")
|
||||
const cornerSvg = `<path d="M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z" fill="currentColor"/>`;
|
||||
const cornerMarks = `
|
||||
<span class="corner-mark tl"><svg viewBox="0 0 22 21" fill="none">${cornerSvg}</svg></span>
|
||||
<span class="corner-mark tr"><svg viewBox="0 0 22 21" fill="none">${cornerSvg}</svg></span>
|
||||
<span class="corner-mark bl"><svg viewBox="0 0 22 21" fill="none">${cornerSvg}</svg></span>
|
||||
<span class="corner-mark br"><svg viewBox="0 0 22 21" fill="none">${cornerSvg}</svg></span>
|
||||
`;
|
||||
|
||||
const app = document.createElement('div');
|
||||
app.className = 'app';
|
||||
app.innerHTML = sidebar + `<main>${decorations}${topbar}<div class="content" id="page-content">${cornerMarks}</div></main>`;
|
||||
|
||||
const src = document.getElementById('page');
|
||||
document.body.prepend(app);
|
||||
if (src) {
|
||||
// 把页面 body 内容追加到 .content,保留 4 个 corner-mark SVG
|
||||
document.getElementById('page-content').insertAdjacentHTML('beforeend', src.innerHTML);
|
||||
src.remove();
|
||||
}
|
||||
document.body.insertAdjacentHTML('beforeend', toastHtml);
|
||||
|
||||
document.addEventListener('keydown', e => {
|
||||
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
|
||||
e.preventDefault();
|
||||
document.getElementById('global-search')?.focus();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
toast(text, mono) {
|
||||
const t = document.getElementById('__toast');
|
||||
const txt = document.getElementById('__toast-txt');
|
||||
if (!t || !txt) return;
|
||||
txt.innerHTML = text + (mono ? `<span class="mono">[ ${mono} ]</span>` : '');
|
||||
t.classList.add('show');
|
||||
clearTimeout(this._tt);
|
||||
this._tt = setTimeout(() => t.classList.remove('show'), 2400);
|
||||
},
|
||||
|
||||
openModal(id) { document.getElementById(id)?.classList.add('show'); },
|
||||
closeModal(id) { document.getElementById(id)?.classList.remove('show'); },
|
||||
openDrawer(id) {
|
||||
document.getElementById(id)?.classList.add('show');
|
||||
document.getElementById(id + '-bg')?.classList.add('show');
|
||||
},
|
||||
closeDrawer(id) {
|
||||
document.getElementById(id)?.classList.remove('show');
|
||||
document.getElementById(id + '-bg')?.classList.remove('show');
|
||||
}
|
||||
};
|
||||
1730
电商AI平台/design-system.html
Normal file
1730
电商AI平台/design-system.html
Normal file
File diff suppressed because it is too large
Load Diff
173
电商AI平台/index.html
Normal file
173
电商AI平台/index.html
Normal file
@ -0,0 +1,173 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>工作台 · 流·Studio</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>
|
||||
.dash-grid { display: grid; grid-template-columns: 1.7fr 1fr; gap: 24px; align-items: start; }
|
||||
.recent-row { display: grid; grid-template-columns: 54px 1fr auto auto auto; align-items: center; gap: 16px; padding: 14px 18px; border-bottom: 1px solid var(--border-faint); cursor: pointer; }
|
||||
.recent-row:last-child { border-bottom: 0; }
|
||||
.recent-row:hover { background: var(--background-lighter); }
|
||||
.recent-row .thumb { width: 54px; height: 70px; border-radius: var(--r-md); }
|
||||
.recent-meta .name { font-weight: 600; font-size: 13.5px; color: var(--accent-black); }
|
||||
.recent-meta .sub { font-size: 12px; color: var(--black-alpha-48); margin-top: 3px; font-family: var(--font-mono); letter-spacing: .01em; }
|
||||
.shortcuts { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
||||
.shortcut { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); padding: 16px; display: flex; align-items: flex-start; gap: 12px; cursor: pointer; transition: background var(--t-base); }
|
||||
.shortcut:hover { background: var(--black-alpha-4); }
|
||||
.shortcut .ic { width: 32px; height: 32px; background: var(--heat-12); color: var(--heat); display: grid; place-items: center; border-radius: var(--r-md); flex-shrink: 0; }
|
||||
.shortcut .ic svg { width: 16px; height: 16px; }
|
||||
.shortcut .t { font-size: 13px; font-weight: 600; }
|
||||
.shortcut .d { font-size: 11.5px; color: var(--black-alpha-48); margin-top: 3px; font-family: var(--font-mono); letter-spacing: .01em; }
|
||||
.tip { background: var(--surface); border: 1px dashed var(--border-faint); padding: 14px 16px; font-size: 12.5px; color: var(--black-alpha-56); line-height: 1.6; border-radius: var(--r-md); }
|
||||
.tip strong { color: var(--accent-black); font-weight: 600; display: block; margin-bottom: 4px; }
|
||||
.tip .mono { font-family: var(--font-mono); color: var(--heat); background: var(--heat-12); padding: 1px 5px; border-radius: var(--r-sm); font-size: 11.5px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
|
||||
<div class="page-head">
|
||||
<div>
|
||||
<h1>欢迎回来,小李</h1>
|
||||
<div class="sub">
|
||||
<span class="mono">// 05.14 · 周三</span>
|
||||
<span>·</span>
|
||||
<span>你有 <b style="color:var(--accent-black)">3 个项目</b> 正在进行中</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a class="btn" href="products.html">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>
|
||||
新建商品
|
||||
</a>
|
||||
<a class="btn btn-primary btn-lg" href="projects-new.html">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>
|
||||
新建项目
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats with-corners">
|
||||
<span class="corner-tr" aria-hidden></span><span class="corner-bl" aria-hidden></span>
|
||||
<a class="stat" href="projects.html">
|
||||
<div class="lbl">总项目 <span class="badge">ALL</span></div>
|
||||
<div class="v">12</div>
|
||||
<div class="delta up"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19V5M5 12l7-7 7 7"/></svg> 本月 +3</div>
|
||||
</a>
|
||||
<a class="stat" href="projects.html">
|
||||
<div class="lbl">进行中 <span class="badge">WIP</span></div>
|
||||
<div class="v">3</div>
|
||||
<div class="delta">2 个待审核</div>
|
||||
</a>
|
||||
<a class="stat" href="projects.html">
|
||||
<div class="lbl">本月成片 <span class="badge">DONE</span></div>
|
||||
<div class="v">8</div>
|
||||
<div class="delta up"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19V5M5 12l7-7 7 7"/></svg> 较上月 +33%</div>
|
||||
</a>
|
||||
<a class="stat" href="account.html">
|
||||
<div class="lbl">余额 <span class="badge">¥</span></div>
|
||||
<div class="v">¥327<small>.40</small></div>
|
||||
<div class="bar"><span style="width:33%"></span></div>
|
||||
<div class="sub">已用 ¥162.60 / ¥500</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="dash-grid">
|
||||
<div>
|
||||
<div class="section-h">
|
||||
<h2>最近项目</h2>
|
||||
<a class="more" href="projects.html">[ ALL · 12 ] <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:middle;"><path d="M5 12h14M12 5l7 7-7 7"/></svg></a>
|
||||
</div>
|
||||
<div class="card-hard">
|
||||
<a class="recent-row" href="pipeline.html#stage-3">
|
||||
<div class="placeholder thumb"><span class="ph-frame">9:16</span></div>
|
||||
<div class="recent-meta">
|
||||
<div class="name">补水面膜 · 痛点种草</div>
|
||||
<div class="sub">补水面膜 / AI 全生 / 6 镜</div>
|
||||
</div>
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="cur"></span><span></span><span></span></div>
|
||||
<span class="pill info"><span class="dot"></span>故事板 待确认</span>
|
||||
<span class="btn btn-sm">继续</span>
|
||||
</a>
|
||||
<a class="recent-row" href="pipeline.html#stage-5">
|
||||
<div class="placeholder thumb"><span class="ph-frame">9:16</span></div>
|
||||
<div class="recent-meta">
|
||||
<div class="name">蓝牙耳机 · 开箱测评</div>
|
||||
<div class="sub">南卡 Lite Pro / 自带脚本 / 5 镜</div>
|
||||
</div>
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span></div>
|
||||
<span class="pill ok"><span class="dot"></span>已完成</span>
|
||||
<span class="btn btn-sm">打开</span>
|
||||
</a>
|
||||
<a class="recent-row" href="pipeline.html#stage-2">
|
||||
<div class="placeholder thumb"><span class="ph-frame">9:16</span></div>
|
||||
<div class="recent-meta">
|
||||
<div class="name">速食牛肉面 · 一句话主题</div>
|
||||
<div class="sub">滋啦速食 / 一句话 / 4 镜</div>
|
||||
</div>
|
||||
<div class="prog"><span class="done"></span><span class="cur"></span><span></span><span></span><span></span></div>
|
||||
<span class="pill info"><span class="dot"></span>资产生成中</span>
|
||||
<span class="btn btn-sm">继续</span>
|
||||
</a>
|
||||
<a class="recent-row" href="pipeline.html#stage-4">
|
||||
<div class="placeholder thumb"><span class="ph-frame">9:16</span></div>
|
||||
<div class="recent-meta">
|
||||
<div class="name">防晒霜 · 对比展示</div>
|
||||
<div class="sub">透真防晒 / AI 全生 / 6 镜</div>
|
||||
</div>
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="cur"></span><span></span></div>
|
||||
<span class="pill info"><span class="dot"></span>视频生成 4/6</span>
|
||||
<span class="btn btn-sm">继续</span>
|
||||
</a>
|
||||
<a class="recent-row" href="pipeline.html#stage-3">
|
||||
<div class="placeholder thumb"><span class="ph-frame">9:16</span></div>
|
||||
<div class="recent-meta">
|
||||
<div class="name">咖啡冻干粉 · 剧情带货</div>
|
||||
<div class="sub">三顿半同款 / 一句话 / 5 镜</div>
|
||||
</div>
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="fail"></span><span></span><span></span></div>
|
||||
<span class="pill err"><span class="dot"></span>故事板失败</span>
|
||||
<span class="btn btn-sm">查看</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display:flex;flex-direction:column;gap:24px">
|
||||
<div>
|
||||
<div class="section-h"><h2>快捷入口</h2><span class="more">[ /shortcuts ]</span></div>
|
||||
<div class="shortcuts">
|
||||
<a class="shortcut" href="products.html">
|
||||
<div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="m3 7 9-4 9 4-9 4-9-4z"/><path d="m3 12 9 4 9-4"/></svg></div>
|
||||
<div><div class="t">商品库</div><div class="d">12 SKU</div></div>
|
||||
</a>
|
||||
<a class="shortcut" href="library.html">
|
||||
<div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="6" height="16"/><rect x="11" y="4" width="4" height="16"/><rect x="17" y="6" width="4" height="14"/></svg></div>
|
||||
<div><div class="t">资产库</div><div class="d">人 8 · 景 14 · 片 8</div></div>
|
||||
</a>
|
||||
<a class="shortcut" href="account.html">
|
||||
<div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><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 class="t">充值</div><div class="d">¥327.40</div></div>
|
||||
</a>
|
||||
<a class="shortcut" href="projects.html">
|
||||
<div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16"/><path d="M7 4v16M16 4v16M3 9h18M3 15h18"/></svg></div>
|
||||
<div><div class="t">所有项目</div><div class="d">12 个</div></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="section-h"><h2>提示</h2><span class="more">[ FAQ ]</span></div>
|
||||
<div class="tip">
|
||||
<strong>扣费规则</strong>
|
||||
生成失败、超时、用户重跑 — 均不扣费。仅在你点 <span class="mono">[ 确认通过 ]</span> 时按 token 实际结算。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script src="assets/shell.js"></script>
|
||||
<script>Shell.render({ active: 'dashboard', crumbs: [{ label: '工作台' }] });</script>
|
||||
</body>
|
||||
</html>
|
||||
120
电商AI平台/library.html
Normal file
120
电商AI平台/library.html
Normal file
@ -0,0 +1,120 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>资产库 · 流·Studio</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>
|
||||
.asset-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px; }
|
||||
.asset-card { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); cursor: pointer; transition: background .15s; }
|
||||
.asset-card:hover { background: var(--background-lighter); border-color: var(--black-alpha-48); }
|
||||
.asset-thumb { aspect-ratio: 1; }
|
||||
.asset-card.video .asset-thumb { aspect-ratio: 9/16; max-height: 280px; }
|
||||
.asset-body { padding: 12px 14px; }
|
||||
.asset-name { font-size: 13px; font-weight: 600; }
|
||||
.asset-meta { font-size: 11px; color: var(--black-alpha-48); margin-top: 3px; font-family: var(--font-mono); letter-spacing: .02em; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
|
||||
<div class="page-head">
|
||||
<div>
|
||||
<h1>资产库</h1>
|
||||
<div class="sub"><span class="mono">// 跨项目复用 · 人 8 · 景 14 · 商 12 · 片 8</span></div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" onclick="Shell.toast('上传资产', '/library/upload')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 5v14M5 12h14"/></svg>
|
||||
上传资产
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tabs">
|
||||
<div class="tab active">人物 <span class="count">8</span></div>
|
||||
<div class="tab">场景 <span class="count">14</span></div>
|
||||
<div class="tab">商品图 <span class="count">12</span></div>
|
||||
<div class="tab">成片 <span class="count">8</span></div>
|
||||
<div class="tab">我的上传 <span class="count">3</span></div>
|
||||
</div>
|
||||
|
||||
<div class="toolbar">
|
||||
<div class="search-inline">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<input class="input" placeholder="搜索人物特征">
|
||||
</div>
|
||||
<button class="chip active">全部 <span class="mono" style="opacity:.7">8</span></button>
|
||||
<button class="chip">女性</button>
|
||||
<button class="chip">男性</button>
|
||||
<button class="chip">25-30 岁</button>
|
||||
<button class="chip">都市白领</button>
|
||||
<span class="spacer"></span>
|
||||
<button class="chip">最近使用 <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M4 6l4 4 4-4"/></svg></button>
|
||||
</div>
|
||||
|
||||
<div class="asset-grid">
|
||||
<div class="asset-card" onclick="Shell.toast('查看资产', '林夕')">
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">林夕 · 都市白领</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">林夕</div>
|
||||
<div class="asset-meta">女 · 25-30 · 用过 4 次</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="asset-card" onclick="Shell.toast('查看资产', '阿楠')">
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">阿楠 · 同事女</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">阿楠</div>
|
||||
<div class="asset-meta">女 · 25-30 · 用过 2 次</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="asset-card" onclick="Shell.toast('查看资产', '小七')">
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">小七 · 学生女</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">小七</div>
|
||||
<div class="asset-meta">女 · 18-22 · 用过 3 次</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="asset-card" onclick="Shell.toast('查看资产', '阿杰')">
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">阿杰 · 通勤男</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">阿杰</div>
|
||||
<div class="asset-meta">男 · 28-35 · 用过 2 次</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="asset-card" onclick="Shell.toast('查看资产', '王姐')">
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">妈妈 · 居家</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">妈妈 · 王姐</div>
|
||||
<div class="asset-meta">女 · 38-45 · 用过 1 次</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="asset-card" onclick="Shell.toast('查看资产', '阿强')">
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">阿强 · 健身男</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">阿强</div>
|
||||
<div class="asset-meta">男 · 22-28 · 用过 2 次</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="asset-card" onclick="Shell.toast('查看资产', '小苏')">
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">研究生 · 文艺女</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">小苏</div>
|
||||
<div class="asset-meta">女 · 22-26 · 用过 1 次</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="asset-card" onclick="Shell.toast('查看资产', '闺蜜组合')">
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">闺蜜组合 · 双人</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">闺蜜组合</div>
|
||||
<div class="asset-meta">双人 · 25-30 · 用过 1 次</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script src="assets/shell.js"></script>
|
||||
<script>Shell.render({ active: 'library', crumbs: [{ label: '工作台', href: 'index.html' }, { label: '资产库' }] });</script>
|
||||
</body>
|
||||
</html>
|
||||
784
电商AI平台/pipeline.html
Normal file
784
电商AI平台/pipeline.html
Normal file
@ -0,0 +1,784 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>补水面膜 · v3 · 流水线 · 流·Studio</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>
|
||||
/* ─── Project header ─── */
|
||||
.proj-head { display: flex; justify-content: space-between; gap: 16px; margin-bottom: 22px; align-items: flex-start; }
|
||||
.proj-head h1 { font-size: 20px; font-weight: 700; letter-spacing: -.012em; }
|
||||
|
||||
/* ─── Stepper ─── */
|
||||
.stepper { display: flex; align-items: center; gap: 0; margin-bottom: 28px; padding: 14px 18px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); position: relative; }
|
||||
.stepper::before, .stepper::after { content: ''; position: absolute; width: 14px; height: 14px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 21' fill='%23e8e8e8'%3E%3Cpath d='M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z'/%3E%3C/svg%3E") no-repeat center; background-size: contain; pointer-events: none; }
|
||||
.stepper::before { top: -7px; left: -7px; }
|
||||
.stepper::after { bottom: -7px; right: -7px; }
|
||||
.stepper .corner-tr, .stepper .corner-bl { position: absolute; width: 14px; height: 14px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 21' fill='%23e8e8e8'%3E%3Cpath d='M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z'/%3E%3C/svg%3E") no-repeat center; background-size: contain; pointer-events: none; }
|
||||
.stepper .corner-tr { top: -7px; right: -7px; }
|
||||
.stepper .corner-bl { bottom: -7px; left: -7px; }
|
||||
.stage-step { display: flex; align-items: center; gap: 10px; padding: 6px 0; cursor: pointer; user-select: none; }
|
||||
.stage-step .num { width: 26px; height: 26px; display: grid; place-items: center; font-family: var(--font-mono); font-size: 12px; font-weight: 600; border: 1px solid var(--border-faint); border-radius: var(--r-sm); background: var(--surface); color: var(--black-alpha-48); flex-shrink: 0; }
|
||||
.stage-step.done .num { background: var(--accent-black); border-color: var(--accent-black); color: var(--accent-white); }
|
||||
.stage-step.active .num { background: var(--heat); border-color: var(--heat); color: var(--accent-white); }
|
||||
.stage-step.locked { opacity: .5; cursor: not-allowed; }
|
||||
.stage-step .lbl { font-size: 13px; font-weight: 500; color: var(--black-alpha-56); }
|
||||
.stage-step.active .lbl { color: var(--accent-black); font-weight: 600; }
|
||||
.stage-step .st { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); margin-left: 4px; padding: 1px 6px; background: var(--background-lighter); border: 1px solid var(--border-faint); border-radius: var(--r-sm); letter-spacing: .04em; }
|
||||
.stage-step.active .st { background: var(--heat-12); color: var(--heat); border-color: var(--heat-20); }
|
||||
.stage-line { flex: 1; height: 1px; background: var(--border-faint); margin: 0 14px; min-width: 30px; }
|
||||
.stage-line.done { background: var(--accent-black); }
|
||||
|
||||
/* ─── Stage panes ─── */
|
||||
.stage { display: none; }
|
||||
.stage.active { display: block; }
|
||||
|
||||
/* Common pane */
|
||||
.pane { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); }
|
||||
.pane-h { display: flex; align-items: center; gap: 8px; padding: 14px 18px; border-bottom: 1px solid var(--border-faint); }
|
||||
.pane-h strong { font-size: 14px; font-weight: 600; }
|
||||
|
||||
/* Stage foot */
|
||||
.stage-foot { display: flex; justify-content: space-between; align-items: center; padding: 18px 0 0; margin-top: 18px; border-top: 1px solid var(--border-faint); }
|
||||
.stage-foot .info { font-size: 12.5px; color: var(--black-alpha-56); }
|
||||
.stage-foot .info .mono { font-family: var(--font-mono); color: var(--black-alpha-48); font-size: 11.5px; letter-spacing: .02em; }
|
||||
|
||||
/* === STAGE 1 · 脚本 === */
|
||||
.stage-script { display: grid; grid-template-columns: 1fr 1.2fr; gap: 16px; min-height: 560px; }
|
||||
|
||||
.chat-pane { display: flex; flex-direction: column; }
|
||||
.chat-body { padding: 16px 18px; flex: 1; overflow-y: auto; max-height: 460px; display: flex; flex-direction: column; gap: 14px; }
|
||||
.msg .bubble { max-width: 90%; padding: 10px 14px; font-size: 13px; line-height: 1.6; border: 1px solid var(--border-faint); border-radius: var(--r-md); }
|
||||
.msg.ai .bubble { background: var(--surface); }
|
||||
.msg.user { display: flex; flex-direction: column; align-items: flex-end; }
|
||||
.msg.user .bubble { background: var(--heat-12); color: var(--accent-black); border-color: var(--heat-20); }
|
||||
.msg .time { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); margin-top: 4px; letter-spacing: .02em; }
|
||||
.msg .actions { display: flex; gap: 6px; margin-top: 6px; }
|
||||
.ai-avatar { width: 26px; height: 26px; background: var(--heat); color: var(--accent-white); display: grid; place-items: center; font-size: 11px; font-weight: 700; border: 1px solid var(--heat); border-radius: 50%; }
|
||||
.del { text-decoration: line-through; color: var(--black-alpha-48); }
|
||||
.ins { background: var(--forest-bg); color: var(--accent-forest); padding: 0 3px; }
|
||||
.chat-input { padding: 14px 18px; border-top: 1px solid var(--border-faint); }
|
||||
|
||||
.shot-list { display: flex; flex-direction: column; }
|
||||
.shots-body { padding: 12px 16px; flex: 1; overflow-y: auto; max-height: 540px; display: flex; flex-direction: column; gap: 10px; }
|
||||
.shot-card { background: var(--background-base); border: 1px solid var(--border-faint); border-radius: var(--r-md); padding: 12px 14px; }
|
||||
.shot-card.highlight { border-color: var(--heat); background: var(--heat-12); }
|
||||
.shot-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
|
||||
.shot-num { width: 22px; height: 22px; background: var(--accent-black); color: var(--accent-white); display: grid; place-items: center; font-family: var(--font-mono); font-size: 11px; font-weight: 700; border-radius: var(--r-sm); }
|
||||
.shot-time { font-family: var(--font-mono); font-size: 11px; color: var(--black-alpha-48); padding: 2px 6px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-sm); }
|
||||
.shot-row { display: grid; grid-template-columns: 36px 1fr; gap: 8px; padding: 4px 0; }
|
||||
.shot-k { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); padding-top: 2px; letter-spacing: .04em; }
|
||||
.shot-v { font-size: 12.5px; color: var(--accent-black); line-height: 1.55; }
|
||||
.icon-mini-btn { width: 24px; height: 24px; display: grid; place-items: center; color: var(--black-alpha-48); background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-sm); cursor: pointer; font-size: 14px; }
|
||||
.icon-mini-btn:hover { color: var(--heat); border-color: var(--heat); }
|
||||
|
||||
/* === STAGE 2 · 基础资产 === */
|
||||
.stage-assets { display: grid; grid-template-columns: 200px 1fr; gap: 24px; }
|
||||
.asset-side .ttab { padding: 10px 12px; font-size: 13px; cursor: pointer; display: flex; align-items: center; gap: 8px; border: 1px solid transparent; border-radius: var(--r-md); }
|
||||
.asset-side .ttab:hover { background: var(--background-lighter); }
|
||||
.asset-side .ttab.active { background: var(--heat-12); color: var(--heat); border-color: var(--heat-20); font-weight: 600; }
|
||||
.asset-side .ttab .num { font-family: var(--font-mono); font-size: 11px; color: var(--black-alpha-48); margin-left: auto; }
|
||||
.asset-side .ttab.active .num { color: var(--heat); }
|
||||
.asset-side .info { font-size: 12px; color: var(--black-alpha-48); padding: 14px 12px; line-height: 1.6; margin-top: 14px; border-top: 1px solid var(--border-faint); }
|
||||
.asset-side .info strong { color: var(--black-alpha-56); display: block; }
|
||||
.asset-side .info .mono { font-family: var(--font-mono); }
|
||||
|
||||
.asset-grid-2 { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
|
||||
.asset-card-2 { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); }
|
||||
.asset-card-2 .thumb-2 { aspect-ratio: 1; }
|
||||
.asset-card-2 .body-2 { padding: 12px 14px; }
|
||||
.prompt-box { background: var(--background-base); border: 1px solid var(--border-faint); border-radius: var(--r-sm); padding: 10px 12px; font-size: 12px; color: var(--black-alpha-56); margin-top: 8px; line-height: 1.55; font-family: var(--font-mono); letter-spacing: .01em; }
|
||||
.fail-icon { width: 28px; height: 28px; background: var(--accent-crimson); color: var(--accent-white); display: grid; place-items: center; font-weight: 700; font-size: 16px; border-radius: 50%; }
|
||||
|
||||
/* === STAGE 3 · 故事板 === */
|
||||
.stage-storyboard { display: grid; grid-template-columns: 1.7fr 1fr; gap: 16px; align-items: start; }
|
||||
.sb-canvas { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); }
|
||||
.sb-row { display: grid; grid-template-columns: 60px 1fr 1fr; gap: 0; border-bottom: 1px solid var(--border-faint); }
|
||||
.sb-row:last-child { border-bottom: 0; }
|
||||
.sb-row.head { background: var(--background-lighter); font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); letter-spacing: .04em; text-transform: uppercase; }
|
||||
.sb-row.head > div { padding: 10px 14px; }
|
||||
.sb-num { padding: 14px; font-family: var(--font-mono); font-size: 14px; font-weight: 700; color: var(--accent-black); border-right: 1px solid var(--border-faint); }
|
||||
.sb-num .t { display: block; font-size: 10.5px; color: var(--black-alpha-48); font-weight: 400; margin-top: 4px; letter-spacing: .02em; }
|
||||
.sb-img { padding: 10px; border-right: 1px solid var(--border-faint); }
|
||||
.sb-img .placeholder { aspect-ratio: 16/9; }
|
||||
.sb-text { padding: 14px; display: flex; flex-direction: column; gap: 6px; }
|
||||
.sb-text .meta { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); letter-spacing: .04em; }
|
||||
.sb-text .dialog { font-size: 12.5px; color: var(--accent-black); line-height: 1.55; }
|
||||
.sb-text .sfx { font-size: 11.5px; color: var(--black-alpha-48); }
|
||||
|
||||
.sb-side .pane { padding: 18px; }
|
||||
.prompt-edit { background: var(--background-base); border: 1px solid var(--border-faint); border-radius: var(--r-md); padding: 12px 14px; font-family: var(--font-mono); font-size: 11.5px; line-height: 1.7; color: var(--black-alpha-56); white-space: pre-wrap; min-height: 200px; outline: none; letter-spacing: .01em; }
|
||||
.prompt-edit:focus { border-color: var(--heat); box-shadow: 0 0 0 3px var(--heat-12); }
|
||||
.asset-tag { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; background: var(--background-lighter); border: 1px solid var(--border-faint); border-radius: var(--r-pill); font-size: 11.5px; }
|
||||
.asset-tag .dotc { width: 14px; height: 14px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: 50%; }
|
||||
|
||||
/* === STAGE 4 · 视频片段 === */
|
||||
.queue-bar { display: flex; align-items: center; gap: 16px; padding: 14px 18px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); margin-bottom: 18px; }
|
||||
.queue-bar .bar-wrap { flex: 1; height: 6px; background: var(--background-lighter); overflow: hidden; }
|
||||
.queue-bar .bar-wrap > span { display: block; height: 100%; background: var(--heat); }
|
||||
|
||||
.video-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 14px; }
|
||||
.video-card { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); }
|
||||
.video-thumb { aspect-ratio: 9/16; max-height: 320px; position: relative; border-radius: var(--r-md) var(--r-md) 0 0; }
|
||||
.video-thumb .play { position: absolute; inset: 0; display: grid; place-items: center; background: rgba(0,0,0,0.05); cursor: pointer; opacity: 0; transition: opacity .15s; }
|
||||
.video-thumb:hover .play { opacity: 1; }
|
||||
.video-thumb .btn-play { width: 36px; height: 36px; background: rgba(0,0,0,.7); color: var(--accent-white); border-radius: 50%; display: grid; place-items: center; }
|
||||
.video-card .body { padding: 10px 12px; }
|
||||
|
||||
/* === STAGE 5 · 编辑器 === */
|
||||
.editor { display: grid; grid-template-columns: 1fr 280px; grid-template-rows: 1fr auto; gap: 0; height: 580px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); }
|
||||
.editor-preview { padding: 16px; border-right: 1px solid var(--border-faint); border-bottom: 1px solid var(--border-faint); display: flex; flex-direction: column; gap: 12px; }
|
||||
.editor-preview .canvas { flex: 1; aspect-ratio: 9/16; max-height: 380px; margin: 0 auto; background:
|
||||
repeating-linear-gradient(135deg, rgba(0,0,0,0.03) 0 1px, transparent 1px 12px),
|
||||
var(--background-lighter);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
display: grid; place-items: center;
|
||||
color: var(--black-alpha-48);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 12px; }
|
||||
.editor-preview .controls { display: flex; align-items: center; gap: 8px; justify-content: center; }
|
||||
.ctl-btn { width: 36px; height: 36px; border: 1px solid var(--border-faint); background: var(--surface); color: var(--black-alpha-56); border-radius: var(--r-md); display: grid; place-items: center; cursor: pointer; transition: background var(--t-base), border-color var(--t-base), color var(--t-base); }
|
||||
.ctl-btn:hover { color: var(--heat); border-color: var(--heat-40); background: var(--heat-12); }
|
||||
|
||||
.editor-props { padding: 16px; border-bottom: 1px solid var(--border-faint); overflow-y: auto; }
|
||||
.props-tabs { display: flex; gap: 0; margin-bottom: 14px; border-bottom: 1px solid var(--border-faint); }
|
||||
.props-tabs > div { padding: 8px 12px; font-size: 12.5px; color: var(--black-alpha-56); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; }
|
||||
.props-tabs > div.active { color: var(--heat); border-bottom-color: var(--heat); font-weight: 600; }
|
||||
.style-swatch { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
|
||||
.swatch-card { padding: 10px; border: 1px solid var(--border-faint); border-radius: var(--r-md); cursor: pointer; }
|
||||
.swatch-card:hover { background: var(--background-lighter); }
|
||||
.swatch-card.selected { border-color: var(--heat); background: var(--heat-12); }
|
||||
.swatch-card .demo { font-size: 12px; padding: 6px 8px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-sm); margin-bottom: 4px; text-align: center; }
|
||||
.swatch-card .demo.b { background: var(--accent-black); color: var(--accent-white); font-family: serif; }
|
||||
.swatch-card .demo.c { color: var(--heat); -webkit-text-stroke: 0.5px var(--accent-black); }
|
||||
.swatch-card .demo.d { background: var(--accent-honey); color: var(--accent-black); font-weight: 700; }
|
||||
.swatch-card .nm { font-size: 11px; color: var(--black-alpha-48); font-family: var(--font-mono); letter-spacing: .02em; }
|
||||
.props-row { display: flex; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--border-faint); font-size: 12.5px; }
|
||||
.props-row:last-child { border-bottom: 0; }
|
||||
.props-row .k { color: var(--black-alpha-48); flex: 1; font-family: var(--font-mono); font-size: 11px; letter-spacing: .02em; }
|
||||
.input-mini { width: 90px; padding: 0 10px; height: 28px; font-size: 12px; border-radius: var(--r-md); background: var(--surface); border: 1px solid var(--black-alpha-12); }
|
||||
|
||||
.timeline { grid-column: 1 / -1; padding: 14px 16px; background: var(--background-base); }
|
||||
.tl-toolbar { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid var(--border-faint); }
|
||||
.tl-ruler { display: grid; grid-template-columns: 80px 1fr; align-items: center; padding: 4px 0; font-size: 10.5px; }
|
||||
.tl-ruler .l { font-family: var(--font-mono); color: var(--black-alpha-48); padding-left: 4px; }
|
||||
.tl-ruler .ticks { display: flex; justify-content: space-between; font-family: var(--font-mono); color: var(--black-alpha-48); padding: 0 4px; letter-spacing: .04em; }
|
||||
.tl-track { display: grid; grid-template-columns: 80px 1fr; align-items: center; gap: 0; padding: 6px 0; }
|
||||
.tl-track .label { font-size: 11.5px; color: var(--black-alpha-56); display: flex; align-items: center; gap: 6px; padding-left: 4px; }
|
||||
.tl-track .label .dot { width: 8px; height: 8px; }
|
||||
.tl-track .lane { display: flex; gap: 2px; height: 30px; position: relative; }
|
||||
.clip { padding: 0 8px; font-size: 11px; display: flex; align-items: center; cursor: pointer; overflow: hidden; white-space: nowrap; user-select: none; }
|
||||
.clip.video { background: var(--heat-12); border: 1px solid var(--heat-40); color: var(--heat); }
|
||||
.clip.video.selected { background: var(--heat); color: var(--accent-white); border-color: var(--heat); }
|
||||
.clip.subtitle { background: var(--forest-bg); border: 1px solid var(--forest-bd); color: var(--accent-forest); }
|
||||
.clip.bgm { background: rgba(144, 97, 255, 0.10); border: 1px solid rgba(144, 97, 255, 0.30); color: var(--accent-amethyst); }
|
||||
.clip .num { font-family: var(--font-mono); font-weight: 700; margin-right: 6px; opacity: .7; }
|
||||
.playhead { position: absolute; top: -16px; bottom: -54px; width: 1px; background: var(--heat); pointer-events: none; }
|
||||
.playhead::before { content: ''; position: absolute; top: -2px; left: -4px; width: 9px; height: 9px; background: var(--heat); transform: rotate(45deg); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
|
||||
<!-- Project header -->
|
||||
<div class="proj-head">
|
||||
<div style="display:flex; gap:14px; align-items:center;">
|
||||
<div class="placeholder" style="width:42px;height:54px;"><span class="ph-frame">9:16</span></div>
|
||||
<div>
|
||||
<div style="display:flex; gap:8px; align-items:center;">
|
||||
<h1>补水面膜 · 痛点种草 · v3</h1>
|
||||
<span class="pill info"><span class="dot"></span>进行中</span>
|
||||
</div>
|
||||
<div class="muted-2 mono" style="font-size:11.5px; margin-top:4px; letter-spacing:.02em;">// 透真补水面膜 · AI 全生 · 6 镜 · 0-15s · 9:16</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hstack">
|
||||
<button class="btn btn-ghost btn-sm" onclick="Shell.toast('分享', '/projects/p3/share')">分享</button>
|
||||
<button class="btn btn-sm" onclick="Shell.toast('已复制项目', '补水面膜 · v4')">复制项目</button>
|
||||
<button class="btn btn-sm" onclick="Shell.toast('归档项目', '/projects/p3/archive')">归档</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stage stepper -->
|
||||
<div class="stepper">
|
||||
<span class="corner-tr" aria-hidden></span><span class="corner-bl" aria-hidden></span>
|
||||
<a class="stage-step done" data-stage="1" href="#stage-1"><div class="num">1</div><div class="lbl">脚本</div><div class="st">已确认</div></a>
|
||||
<div class="stage-line done"></div>
|
||||
<a class="stage-step done" data-stage="2" href="#stage-2"><div class="num">2</div><div class="lbl">基础资产</div><div class="st">已确认</div></a>
|
||||
<div class="stage-line done"></div>
|
||||
<a class="stage-step active" data-stage="3" href="#stage-3"><div class="num">3</div><div class="lbl">故事板</div><div class="st">待确认</div></a>
|
||||
<div class="stage-line"></div>
|
||||
<a class="stage-step" data-stage="4" href="#stage-4"><div class="num">4</div><div class="lbl">视频片段</div><div class="st">未开始</div></a>
|
||||
<div class="stage-line"></div>
|
||||
<a class="stage-step" data-stage="5" href="#stage-5"><div class="num">5</div><div class="lbl">拼接导出</div><div class="st">未开始</div></a>
|
||||
</div>
|
||||
|
||||
<!-- ============= STAGE 1 · 脚本 ============= -->
|
||||
<section class="stage" data-stage-pane="1">
|
||||
<div class="stage-script">
|
||||
<div class="pane chat-pane">
|
||||
<div class="pane-h">
|
||||
<div class="ai-avatar">AI</div>
|
||||
<strong>脚本助手</strong>
|
||||
<span class="muted-2 mono" style="font-size:11px;">· GPT-4o</span>
|
||||
<span class="spacer"></span>
|
||||
<button class="btn btn-ghost btn-sm" onclick="Shell.toast('已清空对话')">清空对话</button>
|
||||
</div>
|
||||
<div class="chat-body">
|
||||
<div class="msg ai">
|
||||
<div style="display:flex; gap:10px; align-items:flex-start;">
|
||||
<div class="ai-avatar" style="margin-top:2px;">AI</div>
|
||||
<div class="bubble">根据 <strong>透真补水面膜</strong> 和"痛点种草"风格,我先生成了一版 6 镜的脚本,主线是"加班党的深夜急救"。你可以直接编辑右侧的镜头,或者让我重写某一镜。</div>
|
||||
</div>
|
||||
<div class="time" style="margin-left:36px;">14:02</div>
|
||||
</div>
|
||||
<div class="msg user">
|
||||
<div class="bubble">第 4 镜对白太硬了,能不能更口语化?</div>
|
||||
<div class="time">14:05</div>
|
||||
</div>
|
||||
<div class="msg ai">
|
||||
<div style="display:flex; gap:10px; align-items:flex-start;">
|
||||
<div class="ai-avatar" style="margin-top:2px;">AI</div>
|
||||
<div>
|
||||
<div class="bubble">把 "<span class="del">补水力极强,锁水持久</span>" 改成 "<span class="ins">真的,敷完第二天起来脸是软的,不是绷着的</span>",更像真实分享。已替换右侧第 4 镜,确认要的话点 [接受]。</div>
|
||||
<div class="actions">
|
||||
<button class="btn btn-sm" onclick="Shell.toast('已接受改动', 'shot-4')">接受</button>
|
||||
<button class="btn btn-ghost btn-sm" onclick="Shell.toast('再来一版')">再来一版</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="time" style="margin-left:36px;">14:05</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-input">
|
||||
<textarea class="textarea" placeholder="对脚本的修改诉求 · 比如:让第 5 镜更夸张一点、整体加 1 镜结尾……" rows="2"></textarea>
|
||||
<div class="hstack" style="margin-top:8px;">
|
||||
<button class="btn btn-ghost btn-sm">↻ 整体重写</button>
|
||||
<span class="spacer"></span>
|
||||
<button class="btn btn-primary" onclick="Shell.toast('已发送', 'POST /chat')">发送 ⌘↵</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pane shot-list">
|
||||
<div class="pane-h">
|
||||
<strong>镜头脚本</strong>
|
||||
<span class="muted-2 mono" style="font-size:11px;">· 6 镜 · 0-15s</span>
|
||||
<span class="spacer"></span>
|
||||
<button class="btn btn-ghost btn-sm" onclick="Shell.toast('已加一镜')">+ 加一镜</button>
|
||||
</div>
|
||||
<div class="shots-body">
|
||||
<div class="shot-card">
|
||||
<div class="shot-head"><div class="shot-num">1</div><div class="shot-time">0-2s</div><span class="spacer"></span><button class="icon-mini-btn" title="重写">↻</button></div>
|
||||
<div class="shot-row"><span class="shot-k">画面</span><div class="shot-v">深夜的办公桌,电脑屏幕亮着,女主对着镜子叹气,皮肤干燥起皮特写。</div></div>
|
||||
<div class="shot-row"><span class="shot-k">对白</span><div class="shot-v">(叹气)"加班三天,脸已经不能看了……"</div></div>
|
||||
</div>
|
||||
<div class="shot-card">
|
||||
<div class="shot-head"><div class="shot-num">2</div><div class="shot-time">2-5s</div><span class="spacer"></span><button class="icon-mini-btn">↻</button></div>
|
||||
<div class="shot-row"><span class="shot-k">画面</span><div class="shot-v">女主从抽屉拿出补水面膜,包装特写,光线柔和。</div></div>
|
||||
<div class="shot-row"><span class="shot-k">对白</span><div class="shot-v">"还好我有这个 —— 透真玻尿酸面膜。"</div></div>
|
||||
</div>
|
||||
<div class="shot-card">
|
||||
<div class="shot-head"><div class="shot-num">3</div><div class="shot-time">5-8s</div><span class="spacer"></span><button class="icon-mini-btn">↻</button></div>
|
||||
<div class="shot-row"><span class="shot-k">画面</span><div class="shot-v">面膜布展开,30g 精华液从布上滴落特写,慢镜头。</div></div>
|
||||
<div class="shot-row"><span class="shot-k">对白</span><div class="shot-v">"30g 精华液,一片顶三片的量。"</div></div>
|
||||
</div>
|
||||
<div class="shot-card highlight">
|
||||
<div class="shot-head"><div class="shot-num">4</div><div class="shot-time">8-11s</div><span class="pill info" style="margin-left:6px;"><span class="dot"></span>刚改</span><span class="spacer"></span><button class="icon-mini-btn">↻</button></div>
|
||||
<div class="shot-row"><span class="shot-k">画面</span><div class="shot-v">女主敷面膜,闭眼平躺,灯光暖。床头闹钟显示 23:41。</div></div>
|
||||
<div class="shot-row"><span class="shot-k">对白</span><div class="shot-v">"真的,敷完第二天起来脸是软的,不是绷着的。"</div></div>
|
||||
</div>
|
||||
<div class="shot-card">
|
||||
<div class="shot-head"><div class="shot-num">5</div><div class="shot-time">11-13s</div><span class="spacer"></span><button class="icon-mini-btn">↻</button></div>
|
||||
<div class="shot-row"><span class="shot-k">画面</span><div class="shot-v">第二天早上,女主对镜化妆,皮肤透亮,状态饱满。</div></div>
|
||||
<div class="shot-row"><span class="shot-k">对白</span><div class="shot-v">"早上化妆都能看出来,不假吹。"</div></div>
|
||||
</div>
|
||||
<div class="shot-card">
|
||||
<div class="shot-head"><div class="shot-num">6</div><div class="shot-time">13-15s</div><span class="spacer"></span><button class="icon-mini-btn">↻</button></div>
|
||||
<div class="shot-row"><span class="shot-k">画面</span><div class="shot-v">面膜产品大图,价格标签 "5 片装 ¥39.9",购物车浮动按钮。</div></div>
|
||||
<div class="shot-row"><span class="shot-k">对白</span><div class="shot-v">"618 五片才 39.9,囤起来。"</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stage-foot">
|
||||
<div class="info"><span class="mono">[ LLM 用量 ~2.4k tokens · ¥0.04 ]</span></div>
|
||||
<div class="hstack">
|
||||
<button class="btn" onclick="Shell.toast('重新生成', 'POST /script/regen')"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12a8 8 0 0 1 14-5.5L21 9"/><path d="M21 4v5h-5"/><path d="M20 12a8 8 0 0 1-14 5.5L3 15"/><path d="M3 20v-5h5"/></svg> 重新生成全部</button>
|
||||
<button class="btn btn-primary btn-lg" onclick="location.hash='#stage-2'">确认脚本,进入下一步 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============= STAGE 2 · 基础资产 ============= -->
|
||||
<section class="stage" data-stage-pane="2">
|
||||
<div class="stage-assets">
|
||||
<div class="asset-side">
|
||||
<div class="ttab active"><span>人物</span><span class="num">2/2</span></div>
|
||||
<div class="ttab"><span>场景</span><span class="num">3/3</span></div>
|
||||
<div class="ttab"><span>商品</span><span class="num">3 张</span></div>
|
||||
<div class="info">
|
||||
基础资产是后续故事板的素材。生成后可以单独修改提示词重跑,或上传你已有的图替换。
|
||||
<br><br>
|
||||
<strong class="mono">// 人物 +¥0.20/张</strong>
|
||||
<strong class="mono">// 场景 +¥0.15/张</strong>
|
||||
<span style="color:var(--black-alpha-48);">商品图无成本(直接复用商品库)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="hstack" style="margin-bottom:14px;">
|
||||
<h3 style="font-size:15px; font-weight:600;">人物 · 2 个</h3>
|
||||
<span class="spacer"></span>
|
||||
<button class="btn btn-ghost btn-sm">从我的资产库选</button>
|
||||
<button class="btn btn-sm" onclick="Shell.toast('+ 新增人物')">+ 新增人物</button>
|
||||
</div>
|
||||
|
||||
<div class="asset-grid-2">
|
||||
<div class="asset-card-2">
|
||||
<div class="placeholder thumb-2"><span class="ph-frame">林夕 · 都市白领</span></div>
|
||||
<div class="body-2">
|
||||
<div class="hstack"><strong style="font-size:13.5px;">主角 · 林夕</strong><span class="spacer"></span><span class="pill ok"><span class="dot"></span>已确认</span></div>
|
||||
<div class="prompt-box">25-30 岁都市白领,长发,穿宽松米色家居服,温柔但带点疲倦感,肤色偏黄/略干。</div>
|
||||
<div class="hstack" style="margin-top:10px;">
|
||||
<button class="btn btn-ghost btn-sm">改提示词</button>
|
||||
<button class="btn btn-ghost btn-sm">↻ 重跑</button>
|
||||
<span class="spacer"></span>
|
||||
<button class="btn btn-ghost btn-sm">⤓ 上传替换</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="asset-card-2">
|
||||
<div class="placeholder thumb-2">
|
||||
<div style="display:flex; flex-direction:column; gap:8px; align-items:center;">
|
||||
<div class="spinner"></div>
|
||||
<span class="ph-frame">生成中 · 约 8s</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="body-2">
|
||||
<div class="hstack"><strong style="font-size:13.5px;">朋友/同事 · 阿楠</strong><span class="spacer"></span><span class="pill info"><span class="dot"></span>生成中</span></div>
|
||||
<div class="prompt-box">25-30 岁同龄女性,短发,穿白色衬衫,妆容精致皮肤好,作为对比。</div>
|
||||
<div class="hstack" style="margin-top:10px;">
|
||||
<button class="btn btn-ghost btn-sm" disabled>改提示词</button>
|
||||
<button class="btn btn-ghost btn-sm" disabled>↻ 重跑</button>
|
||||
<span class="spacer"></span>
|
||||
<button class="btn btn-ghost btn-sm" disabled>⤓ 上传替换</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hstack" style="margin:28px 0 14px;">
|
||||
<h3 style="font-size:15px; font-weight:600;">场景 · 3 个</h3>
|
||||
<span class="spacer"></span>
|
||||
<button class="btn btn-ghost btn-sm">从我的资产库选</button>
|
||||
<button class="btn btn-sm">+ 新增场景</button>
|
||||
</div>
|
||||
|
||||
<div class="asset-grid-2">
|
||||
<div class="asset-card-2">
|
||||
<div class="placeholder thumb-2"><span class="ph-frame">深夜办公桌</span></div>
|
||||
<div class="body-2">
|
||||
<div class="hstack"><strong style="font-size:13.5px;">深夜办公桌</strong><span class="spacer"></span><span class="pill ok"><span class="dot"></span>已确认</span></div>
|
||||
<div class="prompt-box">深夜居家办公环境,木质书桌,台灯暖光,电脑屏幕亮着,背景虚化。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="asset-card-2">
|
||||
<div class="placeholder thumb-2"><span class="ph-frame">床头特写</span></div>
|
||||
<div class="body-2">
|
||||
<div class="hstack"><strong style="font-size:13.5px;">卧室床头</strong><span class="spacer"></span><span class="pill ok"><span class="dot"></span>已确认</span></div>
|
||||
<div class="prompt-box">米白色床品,木质床头柜,闹钟显示晚间时间,氛围温柔安静。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="asset-card-2">
|
||||
<div class="placeholder thumb-2">
|
||||
<div style="display:flex; flex-direction:column; gap:6px; align-items:center;">
|
||||
<div class="fail-icon">!</div>
|
||||
<span class="ph-frame">生成失败</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="body-2">
|
||||
<div class="hstack"><strong style="font-size:13.5px;">通勤地铁</strong><span class="spacer"></span><span class="pill err"><span class="dot"></span>失败</span></div>
|
||||
<div class="prompt-box">早高峰地铁车厢,光线偏冷,年轻通勤族,氛围紧张。</div>
|
||||
<div class="muted-2" style="font-size:12px; margin-top:6px; display:flex; align-items:center; gap:6px;"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="color:var(--accent-crimson); flex-shrink:0;"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>提示词被安全审核拦截,请调整后重试(不扣费)</div>
|
||||
<div class="hstack" style="margin-top:8px;">
|
||||
<button class="btn btn-sm">改提示词</button>
|
||||
<button class="btn btn-ghost btn-sm">↻ 重跑</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stage-foot">
|
||||
<div class="info"><span class="mono">[ 已确认 ¥0.85 · 待生成 ¥0.20 · 失败 ¥0(不扣) ]</span></div>
|
||||
<div class="hstack">
|
||||
<button class="btn" onclick="location.hash='#stage-1'">← 返回脚本</button>
|
||||
<button class="btn btn-primary btn-lg" disabled>1 个资产生成中 · 等待</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============= STAGE 3 · 故事板 ============= -->
|
||||
<section class="stage active" data-stage-pane="3">
|
||||
<div class="stage-storyboard">
|
||||
<div class="sb-canvas">
|
||||
<div class="sb-row head">
|
||||
<div>镜号</div><div>画面</div><div>机位 / 对白 / 音效</div>
|
||||
</div>
|
||||
<div class="sb-row">
|
||||
<div class="sb-num">1<span class="t">0-2s</span></div>
|
||||
<div class="sb-img"><div class="placeholder"><span class="ph-frame">深夜办公桌 · 女主对镜叹气 · 暖光</span></div></div>
|
||||
<div class="sb-text">
|
||||
<div class="meta">中景 / 固定机位</div>
|
||||
<div class="dialog">"加班三天,脸已经不能看了……"</div>
|
||||
<div class="sfx">SFX:键盘声 + 远处空调嗡鸣</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-row">
|
||||
<div class="sb-num">2<span class="t">2-5s</span></div>
|
||||
<div class="sb-img"><div class="placeholder"><span class="ph-frame">面膜包装特写 · 抽屉光线柔和</span></div></div>
|
||||
<div class="sb-text">
|
||||
<div class="meta">特写 / 缓推</div>
|
||||
<div class="dialog">"还好我有这个 —— 透真玻尿酸面膜。"</div>
|
||||
<div class="sfx">SFX:抽屉滑动声</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-row">
|
||||
<div class="sb-num">3<span class="t">5-8s</span></div>
|
||||
<div class="sb-img"><div class="placeholder"><span class="ph-frame">面膜布展开 · 30g 精华滴落 · 慢动作</span></div></div>
|
||||
<div class="sb-text">
|
||||
<div class="meta">微距 / 慢镜头</div>
|
||||
<div class="dialog">"30g 精华液,一片顶三片的量。"</div>
|
||||
<div class="sfx">SFX:水滴慢速回弹</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-row">
|
||||
<div class="sb-num">4<span class="t">8-11s</span></div>
|
||||
<div class="sb-img"><div class="placeholder"><span class="ph-frame">女主敷面膜平躺 · 闹钟 23:41</span></div></div>
|
||||
<div class="sb-text">
|
||||
<div class="meta">中近景 / 固定</div>
|
||||
<div class="dialog">"敷完第二天起来脸是软的,不是绷着的。"</div>
|
||||
<div class="sfx">SFX:呼吸声 + 窗外风声</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-row">
|
||||
<div class="sb-num">5<span class="t">11-13s</span></div>
|
||||
<div class="sb-img"><div class="placeholder"><span class="ph-frame">早晨化妆台 · 女主对镜上妆 · 透亮</span></div></div>
|
||||
<div class="sb-text">
|
||||
<div class="meta">中景 / 固定</div>
|
||||
<div class="dialog">"早上化妆都能看出来,不假吹。"</div>
|
||||
<div class="sfx">SFX:化妆刷轻扫声</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-row">
|
||||
<div class="sb-num">6<span class="t">13-15s</span></div>
|
||||
<div class="sb-img"><div class="placeholder"><span class="ph-frame">产品大图 · 价格 5片¥39.9 · 购物车</span></div></div>
|
||||
<div class="sb-text">
|
||||
<div class="meta">产品定格 / 静止</div>
|
||||
<div class="dialog">"618 五片才 39.9,囤起来。"</div>
|
||||
<div class="sfx">SFX:清脆叮咚音效</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sb-side">
|
||||
<div class="pane">
|
||||
<div class="hstack" style="margin-bottom:10px;">
|
||||
<strong style="font-size:14px;">故事板</strong>
|
||||
<span class="spacer"></span>
|
||||
<span class="pill ok"><span class="dot"></span>已生成</span>
|
||||
</div>
|
||||
<div class="muted-2" style="font-size:12px; line-height:1.55; margin-bottom:14px;">
|
||||
整张故事板由 image-2 一次性输出,包含画面 + 镜头说明。如需修改请编辑下方提示词整张重跑(不能局部改)。
|
||||
</div>
|
||||
|
||||
<div class="muted mono" style="font-size:11px; font-weight:500; margin-bottom:6px; letter-spacing:.04em;">// 视觉提示词</div>
|
||||
<div class="prompt-edit" contenteditable="true">风格:日系小清新短视频,暖色调,午夜→清晨光线变化。
|
||||
镜头列表(6 镜,0-15s):
|
||||
1. 中景 · 深夜办公桌女主对镜叹气
|
||||
2. 特写 · 面膜包装从抽屉拿出
|
||||
3. 微距 · 面膜布展开 + 精华液滴落慢镜
|
||||
4. 中近景 · 女主敷面膜平躺,床头闹钟 23:41
|
||||
5. 中景 · 早晨化妆台 + 女主透亮上妆
|
||||
6. 产品定格 · 面膜盒 + 价格标签 ¥39.9
|
||||
人物:林夕(参考 R1)
|
||||
场景:深夜办公桌(S1) + 卧室床头(S2)
|
||||
要求:表格化布局,每镜含画面 + 文字说明</div>
|
||||
|
||||
<div class="hstack" style="margin-top:12px;">
|
||||
<button class="btn btn-sm" onclick="Shell.toast('整张重跑', 'POST /storyboard/regen ¥0.45')">↻ 整张重跑</button>
|
||||
<span class="spacer"></span>
|
||||
<span class="muted-2 mono" style="font-size:11px;">~¥0.45</span>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="muted mono" style="font-size:11px; font-weight:500; margin-bottom:8px; letter-spacing:.04em;">// 绑定的资产</div>
|
||||
<div style="display:flex; gap:6px; flex-wrap:wrap;">
|
||||
<span class="asset-tag"><span class="dotc"></span>林夕(人物)</span>
|
||||
<span class="asset-tag"><span class="dotc"></span>深夜办公桌(场景)</span>
|
||||
<span class="asset-tag"><span class="dotc"></span>卧室床头(场景)</span>
|
||||
<span class="asset-tag"><span class="dotc"></span>面膜盒(商品)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stage-foot">
|
||||
<div class="info"><span class="mono">[ image-2 一次 ¥0.45 · 累计 ¥1.50 ]</span></div>
|
||||
<div class="hstack">
|
||||
<button class="btn" onclick="location.hash='#stage-2'"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg> 返回资产</button>
|
||||
<button class="btn btn-primary btn-lg" onclick="location.hash='#stage-4'">确认故事板,开始生成视频片段 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============= STAGE 4 · 视频片段 ============= -->
|
||||
<section class="stage" data-stage-pane="4">
|
||||
<div class="queue-bar">
|
||||
<div>
|
||||
<div style="font-size:14px; font-weight:600;">视频生成中 · 4 / 6 完成</div>
|
||||
<div class="muted-2 mono" style="font-size:11px; margin-top:3px; letter-spacing:.02em;">// 每镜 Seedance 调用 ~30s · 预计还需 1 分钟</div>
|
||||
</div>
|
||||
<div class="bar-wrap"><span style="width:67%"></span></div>
|
||||
<span class="muted mono" style="font-size:12px;">67%</span>
|
||||
<button class="btn btn-sm" onclick="Shell.toast('全部重跑', 'POST /video/regen-all')">↻ 全部重跑</button>
|
||||
</div>
|
||||
|
||||
<div class="video-grid">
|
||||
<div class="video-card">
|
||||
<div class="placeholder video-thumb">
|
||||
<span class="ph-frame">镜 1 · 0-2s</span>
|
||||
<div class="play"><div class="btn-play"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M5 4l6 4-6 4z" fill="currentColor"/></svg></div></div>
|
||||
</div>
|
||||
<div class="body">
|
||||
<div class="hstack"><strong style="font-size:13px;">镜 1 · 深夜办公桌</strong><span class="spacer"></span><span class="pill ok"><span class="dot"></span>完成</span></div>
|
||||
<div class="muted-2 mono" style="font-size:11px; margin-top:4px;">2.0s · 1080×1920 · ¥0.18</div>
|
||||
<div class="hstack" style="margin-top:8px;">
|
||||
<button class="btn btn-ghost btn-sm">↻ 重跑</button>
|
||||
<button class="btn btn-ghost btn-sm">⤓ 下载</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="video-card">
|
||||
<div class="placeholder video-thumb">
|
||||
<span class="ph-frame">镜 2 · 2-5s</span>
|
||||
<div class="play"><div class="btn-play"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M5 4l6 4-6 4z" fill="currentColor"/></svg></div></div>
|
||||
</div>
|
||||
<div class="body">
|
||||
<div class="hstack"><strong style="font-size:13px;">镜 2 · 面膜包装</strong><span class="spacer"></span><span class="pill ok"><span class="dot"></span>完成</span></div>
|
||||
<div class="muted-2 mono" style="font-size:11px; margin-top:4px;">3.0s · 1080×1920 · ¥0.22</div>
|
||||
<div class="hstack" style="margin-top:8px;">
|
||||
<button class="btn btn-ghost btn-sm">↻ 重跑</button>
|
||||
<button class="btn btn-ghost btn-sm">⤓ 下载</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="video-card">
|
||||
<div class="placeholder video-thumb">
|
||||
<span class="ph-frame">镜 3 · 5-8s</span>
|
||||
<div class="play"><div class="btn-play"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M5 4l6 4-6 4z" fill="currentColor"/></svg></div></div>
|
||||
</div>
|
||||
<div class="body">
|
||||
<div class="hstack"><strong style="font-size:13px;">镜 3 · 精华液微距</strong><span class="spacer"></span><span class="pill ok"><span class="dot"></span>完成</span></div>
|
||||
<div class="muted-2 mono" style="font-size:11px; margin-top:4px;">3.0s · 1080×1920 · ¥0.22</div>
|
||||
<div class="hstack" style="margin-top:8px;">
|
||||
<button class="btn btn-ghost btn-sm">↻ 重跑</button>
|
||||
<button class="btn btn-ghost btn-sm">⤓ 下载</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="video-card">
|
||||
<div class="placeholder video-thumb">
|
||||
<span class="ph-frame">镜 4 · 8-11s</span>
|
||||
<div class="play"><div class="btn-play"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M5 4l6 4-6 4z" fill="currentColor"/></svg></div></div>
|
||||
</div>
|
||||
<div class="body">
|
||||
<div class="hstack"><strong style="font-size:13px;">镜 4 · 敷面膜平躺</strong><span class="spacer"></span><span class="pill ok"><span class="dot"></span>完成</span></div>
|
||||
<div class="muted-2 mono" style="font-size:11px; margin-top:4px;">3.0s · 1080×1920 · ¥0.22</div>
|
||||
<div class="hstack" style="margin-top:8px;">
|
||||
<button class="btn btn-ghost btn-sm">↻ 重跑</button>
|
||||
<button class="btn btn-ghost btn-sm">⤓ 下载</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="video-card">
|
||||
<div class="placeholder video-thumb">
|
||||
<div style="display:flex; flex-direction:column; gap:8px; align-items:center;">
|
||||
<div class="spinner"></div>
|
||||
<span class="ph-frame">镜 5 · 生成中 18s</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="body">
|
||||
<div class="hstack"><strong style="font-size:13px;">镜 5 · 化妆台</strong><span class="spacer"></span><span class="pill info"><span class="dot"></span>生成中</span></div>
|
||||
<div class="muted-2 mono" style="font-size:11px; margin-top:4px;">2.0s · 排队中 · ~¥0.18</div>
|
||||
<div class="hstack" style="margin-top:8px;">
|
||||
<button class="btn btn-ghost btn-sm" disabled>↻ 重跑</button>
|
||||
<button class="btn btn-ghost btn-sm" disabled>⤓ 下载</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="video-card">
|
||||
<div class="placeholder video-thumb"><span class="ph-frame">镜 6 · 排队</span></div>
|
||||
<div class="body">
|
||||
<div class="hstack"><strong style="font-size:13px;">镜 6 · 产品定格</strong><span class="spacer"></span><span class="pill neutral"><span class="dot"></span>排队中</span></div>
|
||||
<div class="muted-2 mono" style="font-size:11px; margin-top:4px;">2.0s · 等待中 · ~¥0.18</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stage-foot">
|
||||
<div class="info"><span class="mono">[ 已确认 ¥0.84 · 待生成 ¥0.36 · 累计 ¥2.34 ]</span></div>
|
||||
<div class="hstack">
|
||||
<button class="btn" onclick="location.hash='#stage-3'">← 返回故事板</button>
|
||||
<button class="btn btn-primary btn-lg" disabled>2 镜生成中 · 等待</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============= STAGE 5 · 拼接编辑器 ============= -->
|
||||
<section class="stage" data-stage-pane="5">
|
||||
<div class="editor">
|
||||
<div class="editor-preview">
|
||||
<div class="canvas">9:16 预览 · 1080×1920</div>
|
||||
<div class="controls">
|
||||
<button class="ctl-btn" title="上一帧"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M3 3v10l4-5zM9 3v10l4-5z" fill="currentColor"/></svg></button>
|
||||
<button class="ctl-btn" title="播放" onclick="Shell.toast('播放', '00:08.42 / 00:15.00')"><svg width="16" height="16" viewBox="0 0 16 16"><path d="M5 4l7 4-7 4z" fill="currentColor"/></svg></button>
|
||||
<button class="ctl-btn" title="下一帧"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M13 3v10l-4-5zM7 3v10l-4-5z" fill="currentColor"/></svg></button>
|
||||
<span class="muted mono" style="font-size:12px; margin-left:8px;">00:08.42 / 00:15.00</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editor-props">
|
||||
<div class="props-tabs">
|
||||
<div class="active">字幕</div>
|
||||
<div>转场</div>
|
||||
<div>BGM</div>
|
||||
</div>
|
||||
<div class="muted mono" style="font-size:11px; font-weight:500; margin-bottom:8px; letter-spacing:.04em;">// 字幕样式</div>
|
||||
<div class="style-swatch">
|
||||
<div class="swatch-card selected"><div class="demo">真实分享</div><div class="nm">朴素白底</div></div>
|
||||
<div class="swatch-card"><div class="demo b">真实分享</div><div class="nm">影视黑底</div></div>
|
||||
<div class="swatch-card"><div class="demo c">真实分享</div><div class="nm">手写描边</div></div>
|
||||
<div class="swatch-card"><div class="demo d">真实分享</div><div class="nm">综艺暖黄</div></div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="muted mono" style="font-size:11px; font-weight:500; margin-bottom:8px; letter-spacing:.04em;">// 当前选中(镜 4)</div>
|
||||
<div class="props-row"><span class="k">起始</span><input class="input-mini" value="00:08.00"></div>
|
||||
<div class="props-row"><span class="k">时长</span><input class="input-mini" value="3.00s"></div>
|
||||
<div class="props-row"><span class="k">音量</span><input class="input-mini" value="100"></div>
|
||||
<div class="props-row"><span class="k">速度</span><input class="input-mini" value="1.0x"></div>
|
||||
<div class="props-row"><span class="k">入场</span><span class="mono" style="font-size:11.5px;">交叉淡化</span></div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="muted mono" style="font-size:11px; font-weight:500; margin-bottom:8px; letter-spacing:.04em;">// BGM</div>
|
||||
<div class="props-row" style="border-bottom:0;">
|
||||
<span style="font-size:12px; flex:1;">温柔治愈钢琴 · 0:42</span>
|
||||
<button class="btn btn-ghost btn-sm">替换</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline">
|
||||
<div class="tl-toolbar">
|
||||
<button class="btn btn-ghost btn-sm">↶</button>
|
||||
<button class="btn btn-ghost btn-sm">↷</button>
|
||||
<span class="muted-2" style="font-size:12px;">|</span>
|
||||
<button class="btn btn-ghost btn-sm">分割</button>
|
||||
<button class="btn btn-ghost btn-sm">复制</button>
|
||||
<button class="btn btn-ghost btn-sm">删除</button>
|
||||
<span class="spacer"></span>
|
||||
<span class="muted mono" style="font-size:11px;">缩放</span>
|
||||
<input type="range" min="50" max="200" value="100" style="width:120px;">
|
||||
</div>
|
||||
|
||||
<div class="tl-ruler">
|
||||
<div class="l">// time</div>
|
||||
<div class="ticks">
|
||||
<span>0s</span><span>2s</span><span>5s</span><span>8s</span><span>11s</span><span>13s</span><span>15s</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tl-track">
|
||||
<div class="label"><span class="dot" style="background:var(--heat);"></span>视频</div>
|
||||
<div class="lane">
|
||||
<div class="clip video" style="flex:2;"><span class="num">1</span> 深夜办公桌</div>
|
||||
<div class="clip video" style="flex:3;"><span class="num">2</span> 面膜包装</div>
|
||||
<div class="clip video" style="flex:3;"><span class="num">3</span> 精华液微距</div>
|
||||
<div class="clip video selected" style="flex:3;"><span class="num">4</span> 敷面膜平躺</div>
|
||||
<div class="clip video" style="flex:2;"><span class="num">5</span> 化妆台</div>
|
||||
<div class="clip video" style="flex:2;"><span class="num">6</span> 产品定格</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tl-track">
|
||||
<div class="label"><span class="dot" style="background:var(--accent-forest);"></span>字幕</div>
|
||||
<div class="lane" style="position:relative;">
|
||||
<div class="clip subtitle" style="flex:2;">加班三天 脸已经不能看了…</div>
|
||||
<div class="clip subtitle" style="flex:3;">还好我有这个 透真玻尿酸面膜</div>
|
||||
<div class="clip subtitle" style="flex:3;">30g 精华 一片顶三片</div>
|
||||
<div class="clip subtitle" style="flex:3;">敷完起来脸是软的</div>
|
||||
<div class="clip subtitle" style="flex:2;">化妆都能看出来</div>
|
||||
<div class="clip subtitle" style="flex:2;">5 片 ¥39.9 囤起来</div>
|
||||
<div class="playhead" style="left:56%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tl-track">
|
||||
<div class="label"><span class="dot" style="background:var(--accent-amethyst);"></span>BGM</div>
|
||||
<div class="lane">
|
||||
<div class="clip bgm" style="flex:15;">温柔治愈钢琴 · 0:42(循环 1 次,淡入淡出)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stage-foot">
|
||||
<div class="info"><span class="mono">[ 合成预估 ~30s · 不消耗 token ]</span></div>
|
||||
<div class="hstack">
|
||||
<button class="btn" onclick="location.hash='#stage-4'"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg> 返回片段</button>
|
||||
<button class="btn" onclick="Shell.toast('已保存草稿', '/projects/p3/draft')">保存草稿</button>
|
||||
<button class="btn btn-primary btn-lg" onclick="Shell.toast('开始导出', 'POST /export · 1080P 9:16')">导出 MP4 · 1080P 9:16 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 4v12m0 0l-5-5m5 5l5-5M4 20h16"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
<script src="assets/shell.js"></script>
|
||||
<script>
|
||||
Shell.render({
|
||||
active: 'projects',
|
||||
crumbs: [{ label: '工作台', href: 'index.html' }, { label: '视频项目', href: 'projects.html' }, { label: '补水面膜 · v3' }]
|
||||
});
|
||||
|
||||
// hash routing
|
||||
function activateStage(n) {
|
||||
document.querySelectorAll('.stage').forEach(s => s.classList.remove('active'));
|
||||
document.querySelector(`[data-stage-pane="${n}"]`)?.classList.add('active');
|
||||
|
||||
document.querySelectorAll('.stage-step').forEach(s => {
|
||||
s.classList.remove('active');
|
||||
if (+s.dataset.stage === +n) s.classList.add('active');
|
||||
});
|
||||
|
||||
// update top breadcrumb fragment indicator with shell.toast
|
||||
const stageNames = { 1:'脚本', 2:'基础资产', 3:'故事板', 4:'视频片段', 5:'拼接导出' };
|
||||
Shell.toast('进入 Stage ' + n + ' · ' + stageNames[n], 'pipeline#stage-' + n);
|
||||
}
|
||||
function readHash() {
|
||||
const m = location.hash.match(/stage-(\d)/);
|
||||
if (m) activateStage(+m[1]);
|
||||
}
|
||||
window.addEventListener('hashchange', readHash);
|
||||
readHash();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
1594
电商AI平台/product-create.html
Normal file
1594
电商AI平台/product-create.html
Normal file
File diff suppressed because it is too large
Load Diff
128
电商AI平台/products.html
Normal file
128
电商AI平台/products.html
Normal file
@ -0,0 +1,128 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>商品库 · 流·Studio</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>
|
||||
.product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }
|
||||
.product-card { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); cursor: pointer; transition: background .15s; }
|
||||
.product-card:hover { background: var(--background-lighter); border-color: var(--black-alpha-48); }
|
||||
.product-thumb { aspect-ratio: 1.4 / 1; }
|
||||
.product-body { padding: 14px; }
|
||||
.product-name { font-size: 14px; font-weight: 600; color: var(--accent-black); }
|
||||
.product-meta { font-size: 11.5px; color: var(--black-alpha-48); margin-top: 4px; font-family: var(--font-mono); letter-spacing: .02em; }
|
||||
.product-tags { display: flex; gap: 6px; margin-top: 10px; flex-wrap: wrap; }
|
||||
.tag-chip { font-size: 11px; padding: 2px 9px; background: var(--background-lighter); color: var(--black-alpha-56); border: 1px solid var(--border-faint); border-radius: var(--r-sm); }
|
||||
.product-card.add { border: 1px dashed var(--border-faint); border-radius: var(--r-md); background: transparent; display: grid; place-items: center; min-height: 220px; color: var(--black-alpha-56); gap: 8px; padding: 16px; }
|
||||
.product-card.add:hover { border-color: var(--heat); color: var(--heat); background: var(--heat-12); }
|
||||
.product-card.add .plus-ic { width: 36px; height: 36px; border: 1px solid currentColor; border-radius: var(--r-md); display: grid; place-items: center; }
|
||||
.upload-zone { border: 1px dashed var(--border-faint); border-radius: var(--r-md); padding: 24px; text-align: center; background: var(--background-lighter); color: var(--black-alpha-56); font-size: 13px; }
|
||||
.upload-zone strong { color: var(--heat); font-weight: 600; }
|
||||
.upload-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 10px; }
|
||||
.upload-grid .placeholder { aspect-ratio: 1; }
|
||||
.bullet-list { list-style: none; }
|
||||
.bullet-list li { display: flex; gap: 8px; align-items: center; padding: 10px 12px; background: var(--background-lighter); border: 1px solid var(--border-faint); border-radius: var(--r-sm); margin-bottom: 6px; font-size: 13px; }
|
||||
.bullet-list .num { width: 18px; height: 18px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-sm); font-size: 11px; color: var(--black-alpha-56); display: grid; place-items: center; flex-shrink: 0; font-family: var(--font-mono); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
|
||||
<div class="page-head">
|
||||
<div>
|
||||
<h1>商品库</h1>
|
||||
<div class="sub"><span class="mono">// 12 SKU</span> · 商品信息会作为脚本和资产生成的素材</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a class="btn btn-primary" href="product-create.html">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 5v14M5 12h14"/></svg>
|
||||
新建商品
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toolbar">
|
||||
<div class="search-inline">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<input class="input" placeholder="搜索商品名称、品牌">
|
||||
</div>
|
||||
<button class="chip active">全部 <span class="mono" style="opacity:.7">12</span></button>
|
||||
<button class="chip">美妆个护</button>
|
||||
<button class="chip">数码 3C</button>
|
||||
<button class="chip">食品饮料</button>
|
||||
<button class="chip">服饰</button>
|
||||
<span class="spacer"></span>
|
||||
<button class="chip">最近添加 <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M4 6l4 4 4-4"/></svg></button>
|
||||
</div>
|
||||
|
||||
<div class="product-grid">
|
||||
<div class="product-card" onclick="Shell.toast('打开商品', '透真玻尿酸补水面膜')">
|
||||
<div class="placeholder product-thumb"><span class="ph-frame">补水面膜 · 1200×800</span></div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">透真玻尿酸补水面膜</div>
|
||||
<div class="product-meta">美妆个护 · 3 张图</div>
|
||||
<div class="product-tags"><span class="tag-chip">熬夜党</span><span class="tag-chip">敏感肌</span><span class="tag-chip">¥39.9</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="product-card" onclick="Shell.toast('打开商品', '南卡 Lite Pro')">
|
||||
<div class="placeholder product-thumb"><span class="ph-frame">蓝牙耳机 · 1200×800</span></div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">南卡 Lite Pro 蓝牙耳机</div>
|
||||
<div class="product-meta">数码 3C · 5 张图</div>
|
||||
<div class="product-tags"><span class="tag-chip">通勤</span><span class="tag-chip">运动</span><span class="tag-chip">¥199</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="product-card" onclick="Shell.toast('打开商品', '滋啦速食')">
|
||||
<div class="placeholder product-thumb"><span class="ph-frame">速食牛肉面 · 1200×800</span></div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">滋啦速食牛肉面 · 6 桶装</div>
|
||||
<div class="product-meta">食品饮料 · 4 张图</div>
|
||||
<div class="product-tags"><span class="tag-chip">加班</span><span class="tag-chip">独居</span><span class="tag-chip">¥49.9</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="product-card" onclick="Shell.toast('打开商品', '透真清透防晒')">
|
||||
<div class="placeholder product-thumb"><span class="ph-frame">防晒霜 · 1200×800</span></div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">透真清透物理防晒霜</div>
|
||||
<div class="product-meta">美妆个护 · 4 张图</div>
|
||||
<div class="product-tags"><span class="tag-chip">SPF50</span><span class="tag-chip">通勤</span><span class="tag-chip">¥69</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="product-card" onclick="Shell.toast('打开商品', '三顿半同款')">
|
||||
<div class="placeholder product-thumb"><span class="ph-frame">咖啡冻干粉 · 1200×800</span></div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">三顿半同款冻干咖啡粉</div>
|
||||
<div class="product-meta">食品饮料 · 6 张图</div>
|
||||
<div class="product-tags"><span class="tag-chip">提神</span><span class="tag-chip">早八</span><span class="tag-chip">¥89/24 颗</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="product-card" onclick="Shell.toast('打开商品', '小熊 4L 空气炸锅')">
|
||||
<div class="placeholder product-thumb"><span class="ph-frame">空气炸锅 · 1200×800</span></div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">小熊 4L 可视空气炸锅</div>
|
||||
<div class="product-meta">家电 · 5 张图</div>
|
||||
<div class="product-tags"><span class="tag-chip">小户型</span><span class="tag-chip">健康</span><span class="tag-chip">¥159</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="product-card" onclick="Shell.toast('打开商品', '露露同款瑜伽裤')">
|
||||
<div class="placeholder product-thumb"><span class="ph-frame">瑜伽裤 · 1200×800</span></div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">露露同款裸感瑜伽裤</div>
|
||||
<div class="product-meta">服饰 · 8 张图</div>
|
||||
<div class="product-tags"><span class="tag-chip">健身房</span><span class="tag-chip">通勤</span><span class="tag-chip">¥119</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<a class="product-card add" href="product-create.html">
|
||||
<div class="plus-ic"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 5v14M5 12h14"/></svg></div>
|
||||
<div style="font-size:13px; font-weight:500;">新建商品</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="assets/shell.js"></script>
|
||||
<script>Shell.render({ active: 'products', crumbs: [{ label: '工作台', href: 'index.html' }, { label: '商品库' }] });</script>
|
||||
</body>
|
||||
</html>
|
||||
287
电商AI平台/projects-new.html
Normal file
287
电商AI平台/projects-new.html
Normal file
@ -0,0 +1,287 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>新建项目 · 流·Studio</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>
|
||||
.wizard { display: grid; grid-template-columns: 200px minmax(0, 1fr) 300px; gap: 36px; align-items: start; max-width: 1400px; }
|
||||
@media (max-width: 1180px) { .wizard { grid-template-columns: 200px minmax(0, 1fr); } .wiz-preview { display: none; } }
|
||||
.steps { position: sticky; top: 24px; align-self: start; }
|
||||
.step { display: flex; gap: 12px; padding: 12px 0; position: relative; }
|
||||
.step:not(:last-child)::after { content: ''; position: absolute; left: 11px; top: 36px; width: 1px; height: calc(100% - 24px); background: var(--border-faint); }
|
||||
.step .num { width: 24px; height: 24px; border: 1px solid var(--border-faint); border-radius: var(--r-sm); background: var(--surface); display: grid; place-items: center; font-size: 11px; font-weight: 600; color: var(--black-alpha-48); flex-shrink: 0; z-index: 1; font-family: var(--font-mono); }
|
||||
.step.done .num { background: var(--accent-black); border-color: var(--accent-black); color: var(--accent-white); }
|
||||
.step.active .num { background: var(--heat); border-color: var(--heat); color: var(--accent-white); }
|
||||
.step .label { font-size: 13.5px; font-weight: 500; color: var(--black-alpha-56); padding-top: 2px; }
|
||||
.step .desc { font-size: 11.5px; color: var(--black-alpha-48); padding-top: 3px; line-height: 1.4; font-family: var(--font-mono); letter-spacing: .02em; }
|
||||
.step.active .label { color: var(--accent-black); font-weight: 600; }
|
||||
.step.done .label { color: var(--black-alpha-56); }
|
||||
.step.done:not(:last-child)::after { background: var(--accent-black); }
|
||||
|
||||
.wiz-pane { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); padding: 22px 24px; margin-bottom: 14px; }
|
||||
.wiz-pane.active { padding: 26px 28px; position: relative; }
|
||||
.wiz-pane.active::before, .wiz-pane.active::after { content: ''; position: absolute; width: 14px; height: 14px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 21' fill='%23e8e8e8'%3E%3Cpath d='M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z'/%3E%3C/svg%3E") no-repeat center; background-size: contain; pointer-events: none; }
|
||||
.wiz-pane.active::before { top: -7px; left: -7px; }
|
||||
.wiz-pane.active::after { bottom: -7px; right: -7px; }
|
||||
.wiz-pane.collapsed { padding: 16px 20px; }
|
||||
.wiz-pane-h { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; }
|
||||
.wiz-pane-h h3 { font-size: 14px; font-weight: 600; }
|
||||
.wiz-step-h h2 { font-size: 20px; font-weight: 600; letter-spacing: -.015em; }
|
||||
.wiz-step-h p { font-size: 13px; color: var(--black-alpha-56); margin-top: 6px; }
|
||||
|
||||
.opt-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
|
||||
.opt-row.cols-4 { grid-template-columns: repeat(4, 1fr); }
|
||||
.opt-row.cols-6 { grid-template-columns: repeat(3, 1fr); }
|
||||
@media (min-width: 1280px) { .opt-row.cols-6 { grid-template-columns: repeat(6, 1fr); } }
|
||||
.opt-card { border: 1px solid var(--border-faint); border-radius: var(--r-md); padding: 14px; background: var(--surface); cursor: pointer; position: relative; display: flex; flex-direction: column; min-width: 0; }
|
||||
.opt-card:hover { background: var(--background-lighter); }
|
||||
.opt-card.selected { border-color: var(--heat); background: var(--heat-12); }
|
||||
.opt-card.selected::after { content: ''; position: absolute; top: 8px; right: 10px; width: 16px; height: 16px; background-color: var(--heat); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: center; background-size: 10px 10px; border-radius: var(--r-sm, 4px); }
|
||||
.opt-card h4 { font-size: 13px; font-weight: 600; }
|
||||
.opt-card .sub { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); margin-top: 3px; letter-spacing: .02em; }
|
||||
.opt-card .note { font-size: 11.5px; color: var(--black-alpha-56); margin-top: 6px; line-height: 1.5; }
|
||||
.opt-card .metric { margin-top: auto; padding-top: 10px; font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); letter-spacing: .02em; }
|
||||
.opt-card .metric .val { color: var(--accent-black); font-weight: 500; }
|
||||
.opt-card.selected .metric .val { color: var(--heat); }
|
||||
.opt-card .badge { font-family: var(--font-mono); font-size: 9.5px; padding: 1px 6px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-sm); color: var(--black-alpha-48); display: inline-block; margin-top: 8px; letter-spacing: .04em; align-self: flex-start; }
|
||||
.opt-card.selected .badge { color: var(--heat); border-color: var(--heat-20); }
|
||||
|
||||
.theme-pill { display: inline-flex; gap: 4px; height: 28px; align-items: center; padding: 0 12px; border: 1px solid var(--border-faint); border-radius: 999px; background: var(--surface); font-size: 12.5px; cursor: pointer; color: var(--black-alpha-56); }
|
||||
.theme-pill:hover { background: var(--background-lighter); }
|
||||
.theme-pill.active { background: var(--heat-12); color: var(--heat); border-color: var(--heat-20); font-weight: 600; }
|
||||
|
||||
.reco-bubble { position: relative; margin-top: 10px; padding: 10px 14px; background: var(--heat-12); border: 1px solid var(--heat-20); border-radius: var(--r-md); display: flex; align-items: center; gap: 12px; font-size: 12.5px; color: var(--accent-black); }
|
||||
.reco-bubble::before { content: ''; position: absolute; top: -5px; left: 28px; width: 9px; height: 9px; background: var(--heat-12); border-left: 1px solid var(--heat-20); border-top: 1px solid var(--heat-20); transform: rotate(45deg); }
|
||||
.reco-bubble .ic { color: var(--heat); flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; }
|
||||
.reco-bubble .ic svg, .reco-bubble .dismiss svg { display: block; }
|
||||
.reco-bubble .txt { flex: 1; line-height: 1.5; }
|
||||
.reco-bubble .txt strong { color: var(--heat); font-weight: 600; }
|
||||
.reco-bubble .txt .meta { display: block; font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); margin-top: 2px; letter-spacing: .02em; }
|
||||
.reco-bubble .btn-apply { height: 28px; padding: 0 12px; background: var(--heat); color: var(--accent-white); border: 1px solid var(--heat); border-radius: var(--r-md); font-size: 12px; font-weight: 600; cursor: pointer; flex-shrink: 0; box-shadow: var(--shadow-cta); transition: box-shadow var(--t-base); }
|
||||
.reco-bubble .btn-apply:hover { box-shadow: var(--shadow-cta-hover); }
|
||||
.reco-bubble .dismiss { background: transparent; color: var(--black-alpha-48); border: 0; width: 24px; height: 24px; padding: 0; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; }
|
||||
.reco-bubble .dismiss:hover { color: var(--accent-black); }
|
||||
|
||||
.wiz-foot { display: flex; justify-content: space-between; align-items: center; margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--border-faint); }
|
||||
|
||||
/* preview panel */
|
||||
.wiz-preview { position: sticky; top: 24px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); padding: 18px; }
|
||||
.wiz-preview::before, .wiz-preview::after { content: ''; position: absolute; width: 14px; height: 14px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 21' fill='%23e8e8e8'%3E%3Cpath d='M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z'/%3E%3C/svg%3E") no-repeat center; background-size: contain; pointer-events: none; }
|
||||
.wiz-preview::before { top: -7px; left: -7px; }
|
||||
.wiz-preview::after { bottom: -7px; right: -7px; }
|
||||
.pv-h { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); letter-spacing: .08em; margin-bottom: 12px; text-transform: uppercase; display: flex; justify-content: space-between; }
|
||||
.pv-h .live { display: inline-flex; align-items: center; gap: 5px; color: var(--heat); }
|
||||
.pv-h .live::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--heat); animation: pulse 1.6s ease-in-out infinite; }
|
||||
@keyframes pulse { 0%, 100% { opacity: 1 } 50% { opacity: .35 } }
|
||||
.pv-title { font-size: 14px; font-weight: 600; line-height: 1.3; margin-bottom: 14px; }
|
||||
.pv-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--border-faint); border: 1px solid var(--border-faint); margin-bottom: 14px; }
|
||||
.pv-metric { padding: 10px 12px; background: var(--surface); }
|
||||
.pv-metric .l { font-family: var(--font-mono); font-size: 9.5px; color: var(--black-alpha-48); letter-spacing: .04em; text-transform: uppercase; }
|
||||
.pv-metric .v { font-size: 18px; font-weight: 600; margin-top: 3px; font-variant-numeric: tabular-nums; color: var(--accent-black); }
|
||||
.pv-metric .v small { font-size: 11px; color: var(--black-alpha-48); font-weight: 500; }
|
||||
.pv-metric.accent .v { color: var(--heat); }
|
||||
.pv-section { margin-top: 14px; }
|
||||
.pv-section .lbl { font-family: var(--font-mono); font-size: 9.5px; color: var(--black-alpha-48); letter-spacing: .06em; text-transform: uppercase; margin-bottom: 8px; }
|
||||
.pv-flow { display: flex; flex-wrap: wrap; gap: 4px 0; font-size: 11.5px; color: var(--black-alpha-56); align-items: center; line-height: 1.7; }
|
||||
.pv-flow .node { padding: 2px 7px; background: var(--background-lighter); border: 1px solid var(--border-faint); border-radius: var(--r-sm); color: var(--accent-black); font-weight: 500; }
|
||||
.pv-flow .arrow { color: var(--heat); margin: 0 5px; display: inline-flex; align-items: center; }
|
||||
.pv-flow .arrow svg { display: block; }
|
||||
.pv-list { list-style: none; padding: 0; margin: 0; }
|
||||
.pv-list li { font-size: 11.5px; color: var(--black-alpha-56); padding: 4px 0; display: flex; align-items: center; gap: 6px; }
|
||||
.pv-list li::before { content: ''; width: 11px; height: 11px; flex-shrink: 0; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FA5D19' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12l5 5L20 6'/%3E%3C/svg%3E") no-repeat center; background-size: contain; }
|
||||
.pv-foot { margin-top: 14px; padding-top: 12px; border-top: 1px dashed var(--border-faint); font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); display: flex; justify-content: space-between; }
|
||||
.pv-foot strong { color: var(--accent-black); font-weight: 500; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
|
||||
<div class="page-head">
|
||||
<div>
|
||||
<h1>新建项目</h1>
|
||||
<div class="sub"><span class="mono">// 商品 → 脚本来源 → 配置 → 确认 · 4 步开始生成</span></div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a class="btn btn-ghost" href="projects.html">退出</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wizard">
|
||||
<nav class="steps">
|
||||
<div class="step done"><div class="num"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12l5 5L20 6"/></svg></div><div><div class="label">选择商品</div><div class="desc">透真补水面膜</div></div></div>
|
||||
<div class="step done"><div class="num"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12l5 5L20 6"/></svg></div><div><div class="label">脚本来源</div><div class="desc">AI 全生 · 痛点种草</div></div></div>
|
||||
<div class="step active"><div class="num">3</div><div><div class="label">项目配置</div><div class="desc">名称 · 时长 · 风格</div></div></div>
|
||||
<div class="step"><div class="num">4</div><div><div class="label">确认与计费</div><div class="desc">预估 ¥3.20</div></div></div>
|
||||
</nav>
|
||||
|
||||
<div>
|
||||
<div class="wiz-pane collapsed">
|
||||
<div class="wiz-pane-h">
|
||||
<h3>第 1 步 · 选择商品</h3>
|
||||
<span class="spacer"></span>
|
||||
<button class="btn btn-ghost btn-sm">修改</button>
|
||||
</div>
|
||||
<div class="hstack" style="gap:12px;">
|
||||
<div class="placeholder" style="width:44px;height:56px;"><span class="ph-frame">主图</span></div>
|
||||
<div>
|
||||
<div style="font-weight:600; font-size:13.5px;">透真玻尿酸补水面膜</div>
|
||||
<div class="muted-2 mono" style="font-size:11.5px; margin-top:3px; letter-spacing:.02em;">美妆个护 · ¥39.9 · 3 张图 · 3 个卖点</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wiz-pane collapsed">
|
||||
<div class="wiz-pane-h">
|
||||
<h3>第 2 步 · 脚本来源</h3>
|
||||
<span class="spacer"></span>
|
||||
<button class="btn btn-ghost btn-sm">修改</button>
|
||||
</div>
|
||||
<div class="hstack">
|
||||
<span class="pill info"><span class="dot"></span>AI 全生</span>
|
||||
<span class="muted">主题:</span>
|
||||
<span style="font-size:13px;">熬夜党的急救面膜 · 痛点种草向</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wiz-pane active">
|
||||
<div class="wiz-step-h" style="margin-bottom:18px;">
|
||||
<h2>第 3 步 · 项目配置</h2>
|
||||
<p>这些设置会影响 LLM 生成脚本的方向,确认后会进入流水线第 1 步(脚本生成)。</p>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="field-label">项目名称<span class="req">*</span></label>
|
||||
<input class="input" value="补水面膜 · 痛点种草 · v3">
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="field-label">视频时长<span class="req">*</span></label>
|
||||
<div class="opt-row cols-4">
|
||||
<div class="opt-card"><h4>0-10 秒</h4><div class="sub">3-4 镜</div><div class="note">黄金完播</div><div class="metric">完播 <span class="val">52%</span></div></div>
|
||||
<div class="opt-card selected"><h4>0-15 秒</h4><div class="sub">4-5 镜</div><div class="note">完播率最佳</div><div class="metric">完播 <span class="val">42%</span></div></div>
|
||||
<div class="opt-card"><h4>0-30 秒</h4><div class="sub">6-8 镜</div><div class="note">卖点详解</div><div class="metric">完播 <span class="val">32%</span></div></div>
|
||||
<div class="opt-card"><h4>0-60 秒</h4><div class="sub">10-12 镜</div><div class="note">故事化</div><div class="metric">完播 <span class="val">26%</span></div></div>
|
||||
</div>
|
||||
<div class="field-hint">数据来源:抖音同品类 TOP 视频均值 · 实际镜头数由 LLM 决定</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="field-label">脚本风格</label>
|
||||
<div class="opt-row">
|
||||
<div class="opt-card selected">
|
||||
<h4>痛点种草</h4>
|
||||
<div class="note">用户痛点切入,以「我懂你」的口吻引出产品。</div>
|
||||
<span class="badge">最常用</span>
|
||||
</div>
|
||||
<div class="opt-card">
|
||||
<h4>开箱测评</h4>
|
||||
<div class="note">朋友式分享,从开箱到使用感受娓娓道来。</div>
|
||||
</div>
|
||||
<div class="opt-card">
|
||||
<h4>对比展示</h4>
|
||||
<div class="note">「用前 vs 用后 / 同类 vs 本品」直观呈现。</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="field-label">人物设定</label>
|
||||
<div class="opt-row cols-6">
|
||||
<div class="opt-card"><h4>都市白领女性</h4><div class="sub">25-30 岁</div><div class="metric"><span class="val">大盘消费力</span></div></div>
|
||||
<div class="opt-card"><h4>闺蜜种草</h4><div class="sub">邻家女孩</div><div class="metric"><span class="val">复购最高</span></div></div>
|
||||
<div class="opt-card"><h4>总裁亲选</h4><div class="sub">创始人 IP</div><div class="metric"><span class="val">30 万销额</span></div></div>
|
||||
<div class="opt-card"><h4>专业测评师</h4><div class="sub">垂类达人</div><div class="metric"><span class="val">互动 +30%</span></div></div>
|
||||
<div class="opt-card"><h4>实用宝妈</h4><div class="sub">家庭决策者</div><div class="metric"><span class="val">母婴/家清</span></div></div>
|
||||
<div class="opt-card selected"><h4>学生党</h4><div class="sub">Z 世代 18-24</div><div class="metric"><span class="val">平价快消</span></div></div>
|
||||
</div>
|
||||
|
||||
<div class="reco-bubble">
|
||||
<span class="ic">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M15.09 14c.18-.98.65-1.74 1.41-2.5A4.65 4.65 0 0 0 18 8 6 6 0 0 0 6 8c0 1 .23 2.23 1.5 3.5A4.61 4.61 0 0 1 8.91 14"/></svg>
|
||||
</span>
|
||||
<div class="txt">
|
||||
<span>抖音同人设 TOP 视频更常用 <strong>0-10 秒</strong> + <strong>对比展示</strong></span>
|
||||
<span class="meta">当前 0-15 秒 · 痛点种草 → 推荐换为学生党最优组合</span>
|
||||
</div>
|
||||
<button class="btn-apply">一键套用</button>
|
||||
<button class="dismiss" aria-label="忽略">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 5l14 14M19 5L5 19"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="field-label">关键卖点(可勾选要重点突出的)</label>
|
||||
<div style="display:flex; gap:6px; flex-wrap:wrap;">
|
||||
<span class="theme-pill active"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12l5 5L20 6"/></svg> 透明质酸 + B5</span>
|
||||
<span class="theme-pill active"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12l5 5L20 6"/></svg> 30g 大容量精华</span>
|
||||
<span class="theme-pill">+ 0 香精 0 酒精</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wiz-foot">
|
||||
<button class="btn">← 上一步</button>
|
||||
<div class="hstack">
|
||||
<span class="muted-2 mono" style="font-size:11.5px; letter-spacing:.02em;">// 下一步:确认与计费</span>
|
||||
<a class="btn btn-primary btn-lg" href="pipeline.html#stage-1" onclick="Shell.toast('开始生成项目', 'pipeline#stage-1')">下一步 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Live preview ── -->
|
||||
<aside class="wiz-preview">
|
||||
<div class="pv-h">
|
||||
<span>实时预估</span>
|
||||
<span class="live">LIVE</span>
|
||||
</div>
|
||||
<div class="pv-title">补水面膜 · 痛点种草 · v3</div>
|
||||
|
||||
<div class="pv-metrics">
|
||||
<div class="pv-metric"><div class="l">镜头</div><div class="v">4-5<small>镜</small></div></div>
|
||||
<div class="pv-metric accent"><div class="l">预估完播</div><div class="v">42<small>%</small></div></div>
|
||||
<div class="pv-metric"><div class="l">预估转化</div><div class="v">1.8<small>%</small></div></div>
|
||||
<div class="pv-metric"><div class="l">预估成本</div><div class="v">¥3.20</div></div>
|
||||
</div>
|
||||
|
||||
<div class="pv-section">
|
||||
<div class="lbl">人设 · 风格</div>
|
||||
<ul class="pv-list">
|
||||
<li>学生党 · Z 世代 18-24</li>
|
||||
<li>痛点种草 · 完播率最佳</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="pv-section">
|
||||
<div class="lbl">脚本走向</div>
|
||||
<div class="pv-flow">
|
||||
<span style="display:inline-flex; align-items:center;"><span class="node">痛点</span><span class="arrow"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span></span>
|
||||
<span style="display:inline-flex; align-items:center;"><span class="node">共鸣</span><span class="arrow"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span></span>
|
||||
<span style="display:inline-flex; align-items:center;"><span class="node">产品</span><span class="arrow"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span></span>
|
||||
<span style="display:inline-flex; align-items:center;"><span class="node">效果</span><span class="arrow"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span></span>
|
||||
<span class="node">引导</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pv-section">
|
||||
<div class="lbl">突出卖点</div>
|
||||
<ul class="pv-list">
|
||||
<li>透明质酸 + B5</li>
|
||||
<li>30g 大容量精华</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="pv-foot">
|
||||
<span>v3 · Restraint</span>
|
||||
<strong>就绪</strong>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script src="assets/shell.js"></script>
|
||||
<script>Shell.render({ active: 'projects', crumbs: [{ label: '工作台', href: 'index.html' }, { label: '视频项目', href: 'projects.html' }, { label: '新建项目' }] });</script>
|
||||
</body>
|
||||
</html>
|
||||
523
电商AI平台/projects.html
Normal file
523
电商AI平台/projects.html
Normal file
@ -0,0 +1,523 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>视频项目 · 流·Studio</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>
|
||||
/* ─── List view ─── */
|
||||
.proj-name-cell { display: flex; align-items: center; gap: 12px; }
|
||||
.proj-thumb { width: 40px; height: 52px; flex-shrink: 0; border-radius: var(--r-md); }
|
||||
.proj-name { font-weight: 600; color: var(--accent-black); font-size: 13.5px; }
|
||||
.proj-sub { font-size: 11.5px; color: var(--black-alpha-48); margin-top: 3px; font-family: var(--font-mono); letter-spacing: .02em; }
|
||||
.row-action { display: flex; gap: 4px; visibility: hidden; }
|
||||
table.t tbody tr:hover .row-action { visibility: visible; }
|
||||
.row-action a { width: 28px; height: 28px; display: grid; place-items: center; color: var(--black-alpha-56); border-radius: var(--r-md); }
|
||||
.row-action a:hover { background: var(--surface); color: var(--heat); border: 1px solid var(--border-faint); }
|
||||
|
||||
/* ─── View toggle ─── */
|
||||
.view-toggle { display: inline-flex; border: 1px solid var(--border-faint); border-radius: var(--r-md); overflow: hidden; }
|
||||
.view-toggle button { padding: 0 14px; background: var(--surface); color: var(--black-alpha-56); font-size: 13px; border-right: 1px solid var(--border-faint); border-radius: 0; height: 36px; cursor: pointer; font-family: inherit; display: flex; align-items: center; gap: 6px; transition: background var(--t-base), color var(--t-base); }
|
||||
.view-toggle button:last-child { border-right: 0; }
|
||||
.view-toggle button:hover { background: var(--background-lighter); color: var(--accent-black); }
|
||||
.view-toggle button.active { background: var(--heat-12); color: var(--heat); font-weight: 600; }
|
||||
.view-toggle button svg { width: 13px; height: 13px; }
|
||||
|
||||
/* ─── Grid view ─── */
|
||||
.proj-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }
|
||||
.proj-card { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); cursor: pointer; transition: background .15s; display: flex; flex-direction: column; }
|
||||
.proj-card:hover { background: var(--background-lighter); border-color: var(--black-alpha-48); }
|
||||
.proj-card .card-thumb { aspect-ratio: 9/16; max-height: 280px; border-radius: var(--r-md) var(--r-md) 0 0; }
|
||||
.proj-card .card-body { padding: 14px; display: flex; flex-direction: column; gap: 10px; flex: 1; }
|
||||
.proj-card .card-name { font-size: 13.5px; font-weight: 600; color: var(--accent-black); line-height: 1.4; }
|
||||
.proj-card .card-sub { font-size: 11.5px; color: var(--black-alpha-48); font-family: var(--font-mono); letter-spacing: .02em; }
|
||||
.proj-card .card-foot { display: flex; align-items: center; justify-content: space-between; padding-top: 10px; border-top: 1px solid var(--border-faint); margin-top: auto; }
|
||||
.proj-card .card-time { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); letter-spacing: .02em; }
|
||||
|
||||
/* ─── Empty state ─── */
|
||||
.empty-state {
|
||||
background: var(--surface);
|
||||
border: 1px dashed var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
padding: 80px 40px;
|
||||
text-align: center;
|
||||
color: var(--black-alpha-56);
|
||||
display: none;
|
||||
}
|
||||
.empty-state.show { display: block; }
|
||||
.empty-state .ic-empty {
|
||||
width: 48px; height: 48px;
|
||||
margin: 0 auto 14px;
|
||||
background: var(--background-lighter);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
display: grid; place-items: center;
|
||||
color: var(--black-alpha-48);
|
||||
}
|
||||
.empty-state h3 { font-size: 14px; font-weight: 600; color: var(--accent-black); margin-bottom: 6px; }
|
||||
.empty-state p { font-size: 12.5px; color: var(--black-alpha-48); font-family: var(--font-mono); letter-spacing: .02em; }
|
||||
|
||||
/* ─── Result count ─── */
|
||||
.result-meta {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
color: var(--black-alpha-48);
|
||||
margin-bottom: 14px;
|
||||
letter-spacing: .04em;
|
||||
}
|
||||
.result-meta .count { color: var(--heat); font-weight: 600; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
|
||||
<div class="page-head">
|
||||
<div>
|
||||
<h1>视频项目</h1>
|
||||
<div class="sub"><span class="mono">// 12 个 · 3 进行中 · 8 完成 · 1 失败</span></div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a class="btn btn-primary btn-lg" href="projects-new.html">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 5v14M5 12h14"/></svg>
|
||||
新建项目
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tabs" id="status-tabs">
|
||||
<div class="tab active" data-filter="all">全部 <span class="count">12</span></div>
|
||||
<div class="tab" data-filter="wip">进行中 <span class="count">3</span></div>
|
||||
<div class="tab" data-filter="done">已完成 <span class="count">8</span></div>
|
||||
<div class="tab" data-filter="fail">失败 <span class="count">1</span></div>
|
||||
</div>
|
||||
|
||||
<div class="toolbar">
|
||||
<div class="search-inline">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<input class="input" id="search-input" placeholder="搜索项目名称、商品">
|
||||
</div>
|
||||
<button class="chip" onclick="Shell.toast('商品筛选', '/filter/product')">商品 <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M4 6l4 4 4-4"/></svg></button>
|
||||
<button class="chip" onclick="Shell.toast('脚本来源筛选', '/filter/source')">脚本来源 <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M4 6l4 4 4-4"/></svg></button>
|
||||
<button class="chip" onclick="Shell.toast('时间筛选', '/filter/date')">创建时间 <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M4 6l4 4 4-4"/></svg></button>
|
||||
<span class="spacer"></span>
|
||||
<div class="view-toggle">
|
||||
<button id="view-grid" data-view="grid">
|
||||
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2" y="2" width="5" height="5"/><rect x="9" y="2" width="5" height="5"/><rect x="2" y="9" width="5" height="5"/><rect x="9" y="9" width="5" height="5"/></svg>
|
||||
网格
|
||||
</button>
|
||||
<button id="view-list" class="active" data-view="list">
|
||||
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 4h12M2 8h12M2 12h12"/></svg>
|
||||
列表
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="result-meta" id="result-meta">// 显示 <span class="count">12</span> / 12 个项目</div>
|
||||
|
||||
<!-- ============= LIST VIEW ============= -->
|
||||
<div id="list-view">
|
||||
<table class="t">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:32%">项目</th>
|
||||
<th>商品</th>
|
||||
<th>脚本来源</th>
|
||||
<th style="width:200px">进度</th>
|
||||
<th>状态</th>
|
||||
<th style="width:120px">更新于</th>
|
||||
<th style="width:60px"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="list-tbody">
|
||||
<tr data-status="wip" data-name="补水面膜 痛点种草" onclick="location.href='pipeline.html#stage-3'">
|
||||
<td>
|
||||
<div class="proj-name-cell">
|
||||
<div class="placeholder proj-thumb"><span class="ph-frame">9:16</span></div>
|
||||
<div><div class="proj-name">补水面膜 · 痛点种草 · v3</div><div class="proj-sub">6 镜 · 0-15s</div></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>透真补水面膜</td>
|
||||
<td><span class="muted">AI 全生</span></td>
|
||||
<td>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="cur"></span><span></span><span></span></div>
|
||||
<span class="muted-2 mono" style="font-size:11px;">3/5</span>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="pill info"><span class="dot"></span>故事板 待确认</span></td>
|
||||
<td class="muted-2">12 分钟前</td>
|
||||
<td>
|
||||
<div class="row-action">
|
||||
<a href="pipeline.html#stage-3" onclick="event.stopPropagation()" title="继续"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M5 4l6 4-6 4z" fill="currentColor"/></svg></a>
|
||||
<a onclick="event.stopPropagation();Shell.toast('更多操作')"><svg width="14" height="14" viewBox="0 0 16 16"><circle cx="3" cy="8" r="1.2" fill="currentColor"/><circle cx="8" cy="8" r="1.2" fill="currentColor"/><circle cx="13" cy="8" r="1.2" fill="currentColor"/></svg></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-status="wip" data-name="速食牛肉面 加班治愈" onclick="location.href='pipeline.html#stage-2'">
|
||||
<td>
|
||||
<div class="proj-name-cell">
|
||||
<div class="placeholder proj-thumb"><span class="ph-frame">9:16</span></div>
|
||||
<div><div class="proj-name">速食牛肉面 · 加班治愈</div><div class="proj-sub">4 镜 · 0-12s</div></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>滋啦速食 · 6 桶装</td>
|
||||
<td><span class="muted">一句话主题</span></td>
|
||||
<td>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="cur"></span><span></span><span></span><span></span></div>
|
||||
<span class="muted-2 mono" style="font-size:11px;">2/5</span>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="pill info"><span class="dot"></span>资产生成中</span></td>
|
||||
<td class="muted-2">37 分钟前</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr data-status="wip" data-name="透真防晒 通勤对比" onclick="location.href='pipeline.html#stage-4'">
|
||||
<td>
|
||||
<div class="proj-name-cell">
|
||||
<div class="placeholder proj-thumb"><span class="ph-frame">9:16</span></div>
|
||||
<div><div class="proj-name">透真防晒 · 通勤对比</div><div class="proj-sub">6 镜 · 0-18s</div></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>透真清透防晒霜</td>
|
||||
<td><span class="muted">AI 全生</span></td>
|
||||
<td>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="cur"></span><span></span></div>
|
||||
<span class="muted-2 mono" style="font-size:11px;">4/5</span>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="pill info"><span class="dot"></span>视频生成 4/6</span></td>
|
||||
<td class="muted-2">2 小时前</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr data-status="fail" data-name="咖啡冻干 早八剧情" onclick="location.href='pipeline.html#stage-3'">
|
||||
<td>
|
||||
<div class="proj-name-cell">
|
||||
<div class="placeholder proj-thumb"><span class="ph-frame">9:16</span></div>
|
||||
<div><div class="proj-name">咖啡冻干 · 早八剧情</div><div class="proj-sub">5 镜 · 0-15s</div></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>三顿半同款冻干</td>
|
||||
<td><span class="muted">一句话主题</span></td>
|
||||
<td>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="fail"></span><span></span><span></span></div>
|
||||
<span class="muted-2 mono" style="font-size:11px;">3/5</span>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="pill err"><span class="dot"></span>故事板生成失败</span></td>
|
||||
<td class="muted-2">昨天 18:42</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr data-status="done" data-name="蓝牙耳机 开箱测评" onclick="location.href='pipeline.html#stage-5'">
|
||||
<td>
|
||||
<div class="proj-name-cell">
|
||||
<div class="placeholder proj-thumb"><span class="ph-frame">9:16</span></div>
|
||||
<div><div class="proj-name">蓝牙耳机 · 开箱测评</div><div class="proj-sub">5 镜 · 0-15s</div></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>南卡 Lite Pro</td>
|
||||
<td><span class="muted">自带脚本</span></td>
|
||||
<td>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span></div>
|
||||
<span class="muted-2 mono" style="font-size:11px;">5/5</span>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="pill ok"><span class="dot"></span>已完成</span></td>
|
||||
<td class="muted-2">5 月 7 日</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr data-status="done" data-name="瑜伽裤 通勤穿搭" onclick="location.href='pipeline.html#stage-5'">
|
||||
<td>
|
||||
<div class="proj-name-cell">
|
||||
<div class="placeholder proj-thumb"><span class="ph-frame">9:16</span></div>
|
||||
<div><div class="proj-name">瑜伽裤 · 通勤穿搭</div><div class="proj-sub">5 镜 · 0-15s</div></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>露露同款瑜伽裤</td>
|
||||
<td><span class="muted">AI 全生</span></td>
|
||||
<td>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span></div>
|
||||
<span class="muted-2 mono" style="font-size:11px;">5/5</span>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="pill ok"><span class="dot"></span>已完成</span></td>
|
||||
<td class="muted-2">5 月 6 日</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr data-status="done" data-name="空气炸锅 小户型" onclick="location.href='pipeline.html#stage-5'">
|
||||
<td>
|
||||
<div class="proj-name-cell">
|
||||
<div class="placeholder proj-thumb"><span class="ph-frame">9:16</span></div>
|
||||
<div><div class="proj-name">空气炸锅 · 小户型</div><div class="proj-sub">4 镜 · 0-12s</div></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>小熊 4L 空气炸锅</td>
|
||||
<td><span class="muted">一句话主题</span></td>
|
||||
<td>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span></div>
|
||||
<span class="muted-2 mono" style="font-size:11px;">5/5</span>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="pill ok"><span class="dot"></span>已完成</span></td>
|
||||
<td class="muted-2">5 月 4 日</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr data-status="archived" data-name="补水面膜 痛点种草 v1" onclick="location.href='pipeline.html#stage-5'">
|
||||
<td>
|
||||
<div class="proj-name-cell">
|
||||
<div class="placeholder proj-thumb"><span class="ph-frame">9:16</span></div>
|
||||
<div><div class="proj-name">补水面膜 · 痛点种草 · v1</div><div class="proj-sub">6 镜 · 0-15s</div></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>透真补水面膜</td>
|
||||
<td><span class="muted">AI 全生</span></td>
|
||||
<td>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span></div>
|
||||
<span class="muted-2 mono" style="font-size:11px;">5/5</span>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="pill neutral"><span class="dot"></span>已归档</span></td>
|
||||
<td class="muted-2">4 月 28 日</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- ============= GRID VIEW ============= -->
|
||||
<div id="grid-view" style="display:none;">
|
||||
<div class="proj-grid" id="grid-body">
|
||||
<div class="proj-card" data-status="wip" data-name="补水面膜 痛点种草" onclick="location.href='pipeline.html#stage-3'">
|
||||
<div class="placeholder card-thumb"><span class="ph-frame">9:16 · 镜 3/6</span></div>
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<div class="card-name">补水面膜 · 痛点种草 · v3</div>
|
||||
<div class="card-sub" style="margin-top:4px;">透真补水面膜 · 6 镜</div>
|
||||
</div>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="cur"></span><span></span><span></span></div>
|
||||
<span class="muted-2 mono" style="font-size:10.5px;">3/5</span>
|
||||
</div>
|
||||
<div class="card-foot">
|
||||
<span class="pill info"><span class="dot"></span>故事板 待确认</span>
|
||||
<span class="card-time">12 分钟前</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="proj-card" data-status="wip" data-name="速食牛肉面 加班治愈" onclick="location.href='pipeline.html#stage-2'">
|
||||
<div class="placeholder card-thumb"><span class="ph-frame">9:16 · 镜 2/4</span></div>
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<div class="card-name">速食牛肉面 · 加班治愈</div>
|
||||
<div class="card-sub" style="margin-top:4px;">滋啦速食 · 4 镜</div>
|
||||
</div>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="cur"></span><span></span><span></span><span></span></div>
|
||||
<span class="muted-2 mono" style="font-size:10.5px;">2/5</span>
|
||||
</div>
|
||||
<div class="card-foot">
|
||||
<span class="pill info"><span class="dot"></span>资产生成中</span>
|
||||
<span class="card-time">37 分钟前</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="proj-card" data-status="wip" data-name="透真防晒 通勤对比" onclick="location.href='pipeline.html#stage-4'">
|
||||
<div class="placeholder card-thumb"><span class="ph-frame">9:16 · 镜 4/6</span></div>
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<div class="card-name">透真防晒 · 通勤对比</div>
|
||||
<div class="card-sub" style="margin-top:4px;">透真清透防晒霜 · 6 镜</div>
|
||||
</div>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="cur"></span><span></span></div>
|
||||
<span class="muted-2 mono" style="font-size:10.5px;">4/5</span>
|
||||
</div>
|
||||
<div class="card-foot">
|
||||
<span class="pill info"><span class="dot"></span>视频 4/6</span>
|
||||
<span class="card-time">2 小时前</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="proj-card" data-status="fail" data-name="咖啡冻干 早八剧情" onclick="location.href='pipeline.html#stage-3'">
|
||||
<div class="placeholder card-thumb"><span class="ph-frame">9:16 · 镜 3/5</span></div>
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<div class="card-name">咖啡冻干 · 早八剧情</div>
|
||||
<div class="card-sub" style="margin-top:4px;">三顿半同款 · 5 镜</div>
|
||||
</div>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="fail"></span><span></span><span></span></div>
|
||||
<span class="muted-2 mono" style="font-size:10.5px;">3/5</span>
|
||||
</div>
|
||||
<div class="card-foot">
|
||||
<span class="pill err"><span class="dot"></span>故事板失败</span>
|
||||
<span class="card-time">昨天 18:42</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="proj-card" data-status="done" data-name="蓝牙耳机 开箱测评" onclick="location.href='pipeline.html#stage-5'">
|
||||
<div class="placeholder card-thumb"><span class="ph-frame">9:16 · 5/5 ✓</span></div>
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<div class="card-name">蓝牙耳机 · 开箱测评</div>
|
||||
<div class="card-sub" style="margin-top:4px;">南卡 Lite Pro · 5 镜</div>
|
||||
</div>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span></div>
|
||||
<span class="muted-2 mono" style="font-size:10.5px;">5/5</span>
|
||||
</div>
|
||||
<div class="card-foot">
|
||||
<span class="pill ok"><span class="dot"></span>已完成</span>
|
||||
<span class="card-time">5 月 7 日</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="proj-card" data-status="done" data-name="瑜伽裤 通勤穿搭" onclick="location.href='pipeline.html#stage-5'">
|
||||
<div class="placeholder card-thumb"><span class="ph-frame">9:16 · 5/5 ✓</span></div>
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<div class="card-name">瑜伽裤 · 通勤穿搭</div>
|
||||
<div class="card-sub" style="margin-top:4px;">露露同款 · 5 镜</div>
|
||||
</div>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span></div>
|
||||
<span class="muted-2 mono" style="font-size:10.5px;">5/5</span>
|
||||
</div>
|
||||
<div class="card-foot">
|
||||
<span class="pill ok"><span class="dot"></span>已完成</span>
|
||||
<span class="card-time">5 月 6 日</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="proj-card" data-status="done" data-name="空气炸锅 小户型" onclick="location.href='pipeline.html#stage-5'">
|
||||
<div class="placeholder card-thumb"><span class="ph-frame">9:16 · 5/5 ✓</span></div>
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<div class="card-name">空气炸锅 · 小户型</div>
|
||||
<div class="card-sub" style="margin-top:4px;">小熊 4L · 4 镜</div>
|
||||
</div>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span></div>
|
||||
<span class="muted-2 mono" style="font-size:10.5px;">5/5</span>
|
||||
</div>
|
||||
<div class="card-foot">
|
||||
<span class="pill ok"><span class="dot"></span>已完成</span>
|
||||
<span class="card-time">5 月 4 日</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="proj-card" data-status="archived" data-name="补水面膜 痛点种草 v1" onclick="location.href='pipeline.html#stage-5'">
|
||||
<div class="placeholder card-thumb"><span class="ph-frame">9:16 · 5/5 ✓</span></div>
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<div class="card-name">补水面膜 · 痛点种草 · v1</div>
|
||||
<div class="card-sub" style="margin-top:4px;">透真补水面膜 · 6 镜</div>
|
||||
</div>
|
||||
<div class="hstack">
|
||||
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span></div>
|
||||
<span class="muted-2 mono" style="font-size:10.5px;">5/5</span>
|
||||
</div>
|
||||
<div class="card-foot">
|
||||
<span class="pill neutral"><span class="dot"></span>已归档</span>
|
||||
<span class="card-time">4 月 28 日</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Empty state -->
|
||||
<div class="empty-state" id="empty">
|
||||
<div class="ic-empty">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
</div>
|
||||
<h3>没有匹配的项目</h3>
|
||||
<p>// 试试切换 tab 或修改搜索词</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script src="assets/shell.js"></script>
|
||||
<script>
|
||||
Shell.render({ active: 'projects', crumbs: [{ label: '工作台', href: 'index.html' }, { label: '视频项目' }] });
|
||||
|
||||
// ============== Tab + search filter + view toggle ==============
|
||||
const state = { filter: 'all', view: 'list', search: '' };
|
||||
const TOTAL = 8; // 实际渲染的样本数
|
||||
|
||||
function applyFilter() {
|
||||
const isList = state.view === 'list';
|
||||
document.getElementById('list-view').style.display = isList ? '' : 'none';
|
||||
document.getElementById('grid-view').style.display = isList ? 'none' : '';
|
||||
|
||||
const items = document.querySelectorAll(isList ? '#list-tbody tr' : '.proj-card');
|
||||
let visible = 0;
|
||||
items.forEach(el => {
|
||||
const status = el.dataset.status || '';
|
||||
const name = (el.dataset.name || '').toLowerCase();
|
||||
const matchFilter = state.filter === 'all' || status.split(' ').includes(state.filter);
|
||||
const matchSearch = !state.search || name.includes(state.search.toLowerCase());
|
||||
const show = matchFilter && matchSearch;
|
||||
el.style.display = show ? '' : 'none';
|
||||
if (show) visible++;
|
||||
});
|
||||
|
||||
// empty state
|
||||
const empty = document.getElementById('empty');
|
||||
if (visible === 0) {
|
||||
empty.classList.add('show');
|
||||
document.getElementById('list-view').style.display = 'none';
|
||||
document.getElementById('grid-view').style.display = 'none';
|
||||
} else {
|
||||
empty.classList.remove('show');
|
||||
}
|
||||
|
||||
// result meta
|
||||
document.getElementById('result-meta').innerHTML = `// 显示 <span class="count">${visible}</span> / ${TOTAL} 个项目`;
|
||||
}
|
||||
|
||||
// Tab clicks
|
||||
document.querySelectorAll('#status-tabs .tab').forEach(t => {
|
||||
t.addEventListener('click', () => {
|
||||
document.querySelectorAll('#status-tabs .tab').forEach(x => x.classList.remove('active'));
|
||||
t.classList.add('active');
|
||||
state.filter = t.dataset.filter;
|
||||
applyFilter();
|
||||
Shell.toast('筛选: ' + t.textContent.trim().split(' ')[0], 'filter=' + state.filter);
|
||||
});
|
||||
});
|
||||
|
||||
// View toggle
|
||||
document.querySelectorAll('.view-toggle button').forEach(b => {
|
||||
b.addEventListener('click', () => {
|
||||
document.querySelectorAll('.view-toggle button').forEach(x => x.classList.remove('active'));
|
||||
b.classList.add('active');
|
||||
state.view = b.dataset.view;
|
||||
applyFilter();
|
||||
Shell.toast('视图切换: ' + (state.view === 'list' ? '列表' : '网格'), 'view=' + state.view);
|
||||
});
|
||||
});
|
||||
|
||||
// Search
|
||||
document.getElementById('search-input').addEventListener('input', e => {
|
||||
state.search = e.target.value.trim();
|
||||
applyFilter();
|
||||
});
|
||||
|
||||
applyFilter();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user