All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 7s
- model-photo / platform-cover · 头部 toolbar 落地: 时间 / 模特(平台) chip 下拉 + 折叠搜索 - model-photo / platform-cover · 图片卡片样式同步图片创作 (.io-cell): bg / hover / .gen 脉冲 / .err 红框 - model-photo / platform-cover · 单图 hover overlay: 再次生成 + 下载 + 更多(加入资产库/删除) - model-photo / platform-cover · 批次底栏: 再次生成图标统一 + 更多 menu(全部加入资产库/删除该批) - model-photo · 修 TDZ bug: renderModelMini 调用挪到 MODELS 声明后, 解决整页崩溃 - model-photo · 去掉冗余 pv-summary, 商品自动选最近编辑, task 写入 name 字段 - image-optimize · 单图右上加再次生成图标, 加入 fs-image-tasks-image 与任务中心打通 - image-optimize · 输入区拆 3 行: + 在顶 / textarea 满宽 / 发送在底栏右; 参考图缩略与加号同 64×64 - asset-factory · 任务中心加时间 chip + image 类型 + 跳转表; 删冗余类型列 - pipeline · stage2 商品卡换商品库风格 + AI 生成三视图主 CTA + .tri-missing-badge[hidden] CSS 修复
1731 lines
103 KiB
HTML
1731 lines
103 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>流·Studio 设计系统 V2 · Interactive</title>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||
<style>
|
||
/* ============================================================
|
||
Alibaba PuHuiTi 3.0 · 阿里巴巴普惠体 · 中文 web 字体
|
||
优先用 chinese-fonts-cdn 上的 woff2(已切片优化加载快)
|
||
失败回退到本地安装 → 系统 PingFang SC / Microsoft YaHei
|
||
============================================================ */
|
||
@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');
|
||
}
|
||
|
||
:root{
|
||
/* ============================================================
|
||
Color system V2.1 · Firecrawl-aligned
|
||
Reference: _design_src/firecrawl_playground_spec.md
|
||
============================================================ */
|
||
|
||
/* ===== Backgrounds (cold gray, no warm tint) ===== */
|
||
--background-base: #f9f9f9; /* page bg */
|
||
--background-lighter: #fbfbfb; /* container bg / hover plate */
|
||
--surface: #ffffff; /* card */
|
||
--surface-raised: #ffffff; /* modal / popover */
|
||
|
||
/* ===== Borders (3 levels, near-identical, semantic only) ===== */
|
||
--border-faint: #ededed; /* default 1px */
|
||
--border-muted: #e8e8e8;
|
||
--border-loud: #e6e6e6;
|
||
|
||
/* ===== Accent multi-color (Firecrawl 5-color signal palette) ===== */
|
||
--accent-black: #262626; /* primary foreground (not pure black) */
|
||
--accent-white: #ffffff;
|
||
--accent-amethyst: #9061ff; /* code / property */
|
||
--accent-bluetron: #2a6dfb; /* info */
|
||
--accent-crimson: #eb3424; /* error */
|
||
--accent-forest: #42c366; /* success */
|
||
--accent-honey: #ecb730; /* warning */
|
||
|
||
/* ===== Heat · single hue + 8 alpha levels (no hue shift on hover) ===== */
|
||
--heat: #fa5d19; /* 100% · main CTA */
|
||
--heat-90: rgba(250, 93, 25, .90);
|
||
--heat-40: rgba(250, 93, 25, .40); /* ring / edge */
|
||
--heat-20: rgba(250, 93, 25, .20); /* pill border / selection */
|
||
--heat-16: rgba(250, 93, 25, .16);
|
||
--heat-12: rgba(250, 93, 25, .12); /* tint bg */
|
||
--heat-8: rgba(250, 93, 25, .08);
|
||
--heat-4: rgba(250, 93, 25, .04);
|
||
|
||
/* ===== Black-alpha (20 levels · 0–24 uses #000, 32+ uses accent-black) ===== */
|
||
--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); /* hover bg */
|
||
--black-alpha-5: rgba(0, 0, 0, .05);
|
||
--black-alpha-6: rgba(0, 0, 0, .06);
|
||
--black-alpha-7: rgba(0, 0, 0, .07); /* active bg */
|
||
--black-alpha-8: rgba(0, 0, 0, .08);
|
||
--black-alpha-10: rgba(0, 0, 0, .10);
|
||
--black-alpha-12: rgba(0, 0, 0, .12); /* inside-border / disabled fg */
|
||
--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); /* placeholder */
|
||
--black-alpha-56: rgba(38, 38, 38, .56); /* secondary / inactive tab */
|
||
--black-alpha-64: rgba(38, 38, 38, .64); /* description */
|
||
--black-alpha-72: rgba(38, 38, 38, .72);
|
||
--black-alpha-88: rgba(38, 38, 38, .88);
|
||
|
||
/* ===== Legacy aliases (V2 names → V2.1 tokens, for backward compat) ===== */
|
||
--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);
|
||
|
||
/* ===== Radius ===== */
|
||
--r-sm: 4px;
|
||
--r-md: 8px;
|
||
--r-pill: 999px;
|
||
|
||
/* ===== Font ===== */
|
||
/* 混排策略:Inter 列首 → 英文/数字/符号用 Inter(Inter 不含 CJK)
|
||
→ 中文自动 fallthrough 到 Alibaba PuHuiTi → 兜底系统中文 */
|
||
--font-sans: 'Inter', 'Alibaba PuHuiTi', 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif;
|
||
--font-mono: 'JetBrains Mono', 'Geist Mono', ui-monospace, monospace;
|
||
/* Inter 系列 · 独立 token,给 Ctrl K / 全英文徽标这种"强制纯英文"场景用 */
|
||
--font-inter: 'Inter', system-ui, sans-serif;
|
||
|
||
/* ===== Transition ===== */
|
||
--t-fast: 100ms ease;
|
||
--t-base: 200ms ease;
|
||
--t-slow: 300ms cubic-bezier(0.34, 1.56, 0.64, 1);
|
||
}
|
||
|
||
::selection{ background: var(--heat-20); color: var(--heat); }
|
||
|
||
*,*::before,*::after{box-sizing:border-box}
|
||
html,body{margin:0;padding:0}
|
||
body{
|
||
font-family:var(--font-sans);
|
||
font-size:14px;
|
||
color:var(--ink);
|
||
background:var(--bg);
|
||
line-height:1.65;
|
||
-webkit-font-smoothing:antialiased;
|
||
-moz-osx-font-smoothing:grayscale;
|
||
text-rendering:optimizeLegibility;
|
||
}
|
||
|
||
/* === Layout: sidebar + main === */
|
||
.layout{display:grid;grid-template-columns:248px 1fr;min-height:100vh}
|
||
.sidebar{
|
||
position:sticky;top:0;height:100vh;
|
||
border-right:1px solid var(--border-faint);
|
||
background:var(--card);
|
||
padding:40px 28px;
|
||
overflow-y:auto;
|
||
}
|
||
.sidebar h1{
|
||
font-size:17px;font-weight:600;letter-spacing:-.01em;
|
||
margin:0 0 6px;line-height:1.4;
|
||
}
|
||
.sidebar .mono-sub{
|
||
font-family:var(--font-mono);font-size:10.5px;color:var(--ink-alpha-48);
|
||
letter-spacing:.04em;margin-bottom:32px;
|
||
}
|
||
.nav-list{list-style:none;padding:0;margin:0}
|
||
.nav-list li{margin:0}
|
||
.nav-list a{
|
||
display:block;padding:8px 12px;
|
||
font-size:13px;color:var(--ink-alpha-64);
|
||
text-decoration:none;border-radius:var(--r-md);
|
||
transition:background var(--t-base),color var(--t-base);
|
||
}
|
||
.nav-list a:hover{background:var(--ink-alpha-4);color:var(--ink)}
|
||
.nav-list a.active{background:var(--heat-12);color:var(--heat)}
|
||
.nav-list .nav-group{
|
||
font-family:var(--font-mono);font-size:10px;
|
||
letter-spacing:.06em;color:var(--ink-alpha-32);
|
||
margin:24px 0 8px;padding:0 12px;text-transform:uppercase;
|
||
}
|
||
|
||
.main{padding:72px 80px 120px;max-width:1280px}
|
||
.main > section{margin-bottom:104px;scroll-margin-top:32px}
|
||
.main > section:last-child{margin-bottom:0}
|
||
|
||
.section-head{margin-bottom:44px;border-bottom:1px solid var(--border-faint);padding-bottom:28px}
|
||
.section-head .mono-tag{
|
||
display:inline-block;font-family:var(--font-mono);font-size:11px;
|
||
color:var(--ink-alpha-48);letter-spacing:.06em;margin-bottom:14px;
|
||
}
|
||
.section-head h2{
|
||
font-size:28px;font-weight:500;letter-spacing:-.02em;margin:0 0 12px;line-height:1.25;
|
||
}
|
||
.section-head p{
|
||
font-size:14px;color:var(--ink-alpha-64);margin:0;max-width:720px;line-height:1.75;
|
||
}
|
||
|
||
.subsection{margin-bottom:64px}
|
||
.subsection h3{
|
||
font-size:16px;font-weight:500;letter-spacing:-.01em;margin:0 0 22px;
|
||
display:flex;align-items:center;gap:12px;line-height:1.4;
|
||
}
|
||
.subsection h3 .mono-num{
|
||
font-family:var(--font-mono);font-size:11px;color:var(--ink-alpha-32);
|
||
font-weight:400;letter-spacing:.04em;
|
||
}
|
||
|
||
.subsection p.lead{
|
||
font-size:13px;color:var(--ink-alpha-56);margin:0 0 22px;line-height:1.8;max-width:720px;
|
||
}
|
||
|
||
/* === Mono helper === */
|
||
.mono{font-family:var(--font-mono);font-size:11.5px;letter-spacing:.04em;color:var(--ink-alpha-56)}
|
||
.kbd{
|
||
display:inline-flex;align-items:center;gap:3px;
|
||
font-family:var(--font-mono);font-size:10.5px;line-height:1;
|
||
background:var(--background-lighter);border:1px solid var(--border-faint);
|
||
border-radius:var(--r-sm);padding:3px 6px;color:var(--black-alpha-64);
|
||
letter-spacing:.04em;
|
||
}
|
||
.kbd svg{display:block;width:10px;height:10px;flex-shrink:0}
|
||
|
||
/* === Hero === */
|
||
.hero{
|
||
position:relative;
|
||
border:1px solid var(--border-faint);
|
||
background:var(--card);
|
||
border-radius:var(--r-md);
|
||
padding:52px 56px;margin-bottom:72px;overflow:hidden;
|
||
}
|
||
.hero .badge{
|
||
display:inline-flex;align-items:center;gap:6px;
|
||
font-family:var(--font-mono);font-size:11px;color:var(--heat);
|
||
background:var(--heat-12);border:1px solid var(--heat-20);
|
||
border-radius:var(--r-pill);padding:4px 11px;letter-spacing:.04em;
|
||
margin-bottom:20px;
|
||
}
|
||
.hero h1{font-size:36px;font-weight:500;letter-spacing:-.024em;margin:0 0 14px;line-height:1.2}
|
||
.hero p{font-size:15px;color:var(--ink-alpha-64);margin:0;line-height:1.75;max-width:680px}
|
||
.hero .meta{display:flex;gap:16px;margin-top:24px;font-family:var(--font-mono);font-size:11px;color:var(--ink-alpha-48);letter-spacing:.04em}
|
||
|
||
/* === Inside-border core utility === */
|
||
.inside-border{position:relative}
|
||
.inside-border::before{
|
||
content:'';position:absolute;inset:0;
|
||
border:1px solid var(--ink-alpha-12);
|
||
border-radius:inherit;pointer-events:none;
|
||
transition:opacity var(--t-base),border-color var(--t-base);
|
||
}
|
||
|
||
/* === Color tokens grid === */
|
||
.swatch-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:14px}
|
||
.swatch{
|
||
background:var(--card);border-radius:var(--r-md);overflow:hidden;
|
||
cursor:pointer;transition:transform var(--t-fast);
|
||
}
|
||
.swatch:hover{transform:translateY(-1px)}
|
||
.swatch .chip{height:76px;position:relative;border-bottom:1px solid var(--border-faint)}
|
||
.swatch .chip.with-grid{
|
||
background-image:
|
||
linear-gradient(45deg,#dcdcdc 25%,transparent 25%),
|
||
linear-gradient(-45deg,#dcdcdc 25%,transparent 25%),
|
||
linear-gradient(45deg,transparent 75%,#dcdcdc 75%),
|
||
linear-gradient(-45deg,transparent 75%,#dcdcdc 75%);
|
||
background-color:#f5f5f5;
|
||
background-size:12px 12px;background-position:0 0,0 6px,6px -6px,-6px 0;
|
||
}
|
||
.swatch .meta-row{padding:14px 14px;border:1px solid var(--border-faint);border-top:0;border-radius:0 0 var(--r-md) var(--r-md)}
|
||
.swatch .name{font-family:var(--font-mono);font-size:11.5px;color:var(--ink);font-weight:500;letter-spacing:.02em;line-height:1.5}
|
||
.swatch .val{font-family:var(--font-mono);font-size:10.5px;color:var(--ink-alpha-48);margin-top:4px;letter-spacing:.04em;line-height:1.5}
|
||
.swatch .copy{font-family:var(--font-mono);font-size:10px;color:var(--heat);display:none;margin-top:3px}
|
||
.swatch.copied .copy{display:block}
|
||
|
||
/* === Type sample === */
|
||
.type-row{display:grid;grid-template-columns:220px 1fr;gap:28px;align-items:baseline;padding:24px 0;border-bottom:1px solid var(--border-faint)}
|
||
.type-row:last-child{border:0}
|
||
.type-row .meta-col{font-family:var(--font-mono);font-size:11px;color:var(--ink-alpha-48);letter-spacing:.04em;line-height:1.65}
|
||
.type-row .meta-col strong{display:block;color:var(--ink);font-family:var(--font-sans);font-size:13px;font-weight:500;margin-bottom:6px;letter-spacing:0}
|
||
.type-row .sample{color:var(--ink)}
|
||
|
||
/* === Radius scale === */
|
||
.radius-row{display:flex;gap:16px;flex-wrap:wrap;align-items:flex-end}
|
||
.radius-box{display:flex;flex-direction:column;align-items:center;gap:6px}
|
||
.radius-box .box{
|
||
background:var(--card);border:1px solid var(--border-faint);
|
||
width:88px;height:88px;
|
||
display:grid;place-items:center;
|
||
}
|
||
.radius-box .lbl{font-family:var(--font-mono);font-size:10.5px;color:var(--ink-alpha-48);letter-spacing:.04em}
|
||
.radius-box .px{font-family:var(--font-mono);font-size:13px;color:var(--ink);font-weight:500}
|
||
|
||
/* === Icons === */
|
||
.icon-row{display:flex;gap:24px;align-items:flex-end;flex-wrap:wrap}
|
||
.icon-cell{display:flex;flex-direction:column;align-items:center;gap:8px}
|
||
.icon-cell .ic{display:grid;place-items:center;color:var(--ink-alpha-64);background:var(--card);border:1px solid var(--border-faint);border-radius:var(--r-md)}
|
||
.icon-cell svg{display:block}
|
||
.icon-cell .lbl{font-family:var(--font-mono);font-size:10px;color:var(--ink-alpha-48);letter-spacing:.04em}
|
||
|
||
.icon-color-row{display:flex;gap:14px;align-items:center;flex-wrap:wrap}
|
||
.icon-color-row .demo{display:inline-flex;align-items:center;gap:8px;padding:8px 14px;border-radius:var(--r-md);border:1px solid var(--border-faint);background:var(--card);font-size:12.5px}
|
||
.icon-color-row .demo.primary{background:var(--heat);color:#fff;border-color:var(--heat)}
|
||
.icon-color-row .demo.disabled{color:var(--ink-alpha-12)}
|
||
|
||
.icon-box{width:32px;height:32px;border-radius:var(--r-md);background:var(--heat-12);display:grid;place-items:center}
|
||
.icon-box svg{stroke:var(--heat);width:16px;height:16px}
|
||
|
||
/* === Buttons === */
|
||
.btn{
|
||
display:inline-flex;align-items:center;justify-content:center;gap:6px;
|
||
height:32px;padding:0 14px;
|
||
background:var(--card);color:var(--ink);
|
||
font-family:inherit;font-size:13px;font-weight:500;line-height:1;
|
||
border:0;cursor:pointer;
|
||
border-radius:var(--r-md);
|
||
position:relative;outline:none;
|
||
transition:background var(--t-base),transform var(--t-fast),box-shadow var(--t-fast);
|
||
}
|
||
.btn::before{
|
||
content:'';position:absolute;inset:0;
|
||
border:1px solid var(--ink-alpha-12);
|
||
border-radius:inherit;pointer-events:none;
|
||
transition:opacity var(--t-base),border-color var(--t-base);
|
||
}
|
||
.btn:hover{background:var(--ink-alpha-4)}
|
||
.btn:hover::before{opacity:0}
|
||
.btn:active{background:var(--ink-alpha-7);transform:scale(.99)}
|
||
.btn:focus-visible::before{opacity:0}
|
||
.btn:focus-visible{box-shadow:0 0 0 2px var(--bg),0 0 0 4px var(--heat-40)}
|
||
.btn[disabled],.btn.is-disabled{
|
||
background:var(--black-alpha-5);color:var(--black-alpha-32);
|
||
cursor:not-allowed;transform:none;
|
||
}
|
||
.btn[disabled]:hover,.btn.is-disabled:hover{background:var(--black-alpha-5)}
|
||
.btn[disabled]::before,.btn.is-disabled::before,
|
||
.btn[disabled]:hover::before,.btn.is-disabled:hover::before{opacity:1;border-color:var(--black-alpha-12)}
|
||
|
||
.btn-primary{
|
||
background:var(--heat);color:#fff;
|
||
box-shadow:
|
||
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 0.5px 0.5px rgba(250,93,25,.16);
|
||
}
|
||
.btn-primary::before{display:none}
|
||
.btn-primary:hover{
|
||
background:var(--heat);
|
||
box-shadow:
|
||
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 0.5px 0.5px rgba(250,93,25,.16);
|
||
}
|
||
.btn-primary:active{transform:scale(.995);box-shadow:inset 0 -4px 8px rgba(250,93,25,.28),0 1px 2px rgba(250,93,25,.16)}
|
||
.btn-primary[disabled],.btn-primary.is-disabled{
|
||
background:var(--heat-40);color:#fff;box-shadow:none;cursor:not-allowed;
|
||
}
|
||
|
||
.btn-ghost{background:transparent;color:var(--ink-alpha-56)}
|
||
.btn-ghost::before{display:none}
|
||
.btn-ghost:hover{background:var(--ink-alpha-4);color:var(--ink)}
|
||
.btn-ghost:active{background:var(--ink-alpha-7)}
|
||
|
||
.btn-sm{height:28px;padding:0 10px;font-size:12px}
|
||
.btn-lg{height:40px;padding:0 18px;font-size:14px}
|
||
|
||
.btn-row{display:flex;gap:14px;flex-wrap:wrap;align-items:center;margin-bottom:20px}
|
||
.btn-row .state-label{
|
||
font-family:var(--font-mono);font-size:11px;color:var(--ink-alpha-48);
|
||
letter-spacing:.04em;width:96px;flex-shrink:0;
|
||
}
|
||
|
||
/* Force visual states for demo */
|
||
.btn.demo-hover{background:var(--ink-alpha-4)}
|
||
.btn.demo-hover::before{opacity:0}
|
||
.btn.demo-active{background:var(--ink-alpha-7);transform:scale(.99)}
|
||
.btn-primary.demo-hover{
|
||
box-shadow:
|
||
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 0.5px 0.5px rgba(250,93,25,.16);
|
||
}
|
||
.btn-primary.demo-active{transform:scale(.995);box-shadow:inset 0 -4px 8px rgba(250,93,25,.28),0 1px 2px rgba(250,93,25,.16)}
|
||
.btn-ghost.demo-hover{background:var(--ink-alpha-4);color:var(--ink)}
|
||
.btn-ghost.demo-active{background:var(--ink-alpha-7)}
|
||
.btn.demo-focus{box-shadow:0 0 0 2px var(--bg),0 0 0 4px var(--heat-40)}
|
||
.btn.demo-focus::before{opacity:0}
|
||
|
||
/* === Pills === */
|
||
.pill{
|
||
display:inline-flex;align-items:center;gap:6px;
|
||
font-weight:500;border-radius:var(--r-pill);
|
||
position:relative;
|
||
}
|
||
.pill .dot{display:block;border-radius:50%;background:currentColor}
|
||
|
||
.pill-l1{height:28px;padding:0 12px;font-size:13px;gap:8px}
|
||
.pill-l1 .dot{width:8px;height:8px}
|
||
.pill-l2{height:22px;padding:0 10px;font-size:11.5px;gap:6px}
|
||
.pill-l2 .dot{width:6px;height:6px}
|
||
.pill-l3{height:18px;padding:0 8px;font-size:10.5px;gap:5px}
|
||
.pill-l3 .dot{width:5px;height:5px}
|
||
|
||
.pill-info{color:var(--heat);background:var(--heat-12);border:1px solid var(--heat-20)}
|
||
.pill-ok{color:var(--green);background:var(--green-bg);border:1px solid var(--green-bd)}
|
||
.pill-err{color:var(--red);background:var(--red-bg);border:1px solid var(--red-bd)}
|
||
|
||
.pill-row{display:flex;gap:14px;flex-wrap:wrap;align-items:center}
|
||
|
||
/* === Inputs === */
|
||
.field-row{display:grid;grid-template-columns:120px 1fr;gap:20px;align-items:center;margin-bottom:18px}
|
||
.field-row .lbl{font-family:var(--font-mono);font-size:11px;color:var(--ink-alpha-48);letter-spacing:.04em}
|
||
.input{
|
||
width:100%;max-width:380px;height:36px;
|
||
padding:0 14px;background:var(--card);color:var(--ink);
|
||
font-family:inherit;font-size:14px;
|
||
border:0;border-radius:var(--r-md);
|
||
position:relative;outline:none;
|
||
transition:background var(--t-base);
|
||
}
|
||
.input-wrap{position:relative;display:inline-block;max-width:380px;width:100%}
|
||
.input-wrap::before{
|
||
content:'';position:absolute;inset:0;
|
||
border:1px solid var(--ink-alpha-12);
|
||
border-radius:var(--r-md);pointer-events:none;
|
||
transition:border-color var(--t-base),box-shadow var(--t-base);
|
||
}
|
||
.input-wrap:hover::before{border-color:var(--ink-alpha-24)}
|
||
.input-wrap.is-focus::before{border-color:var(--heat-40);box-shadow:inset 0 0 0 1px var(--heat-40)}
|
||
.input-wrap.is-error::before{border-color:var(--red);box-shadow:inset 0 0 0 1px var(--red-bd)}
|
||
.input-wrap.is-error .input{background:var(--red-bg)}
|
||
.input-wrap.is-disabled::before{border-color:var(--black-alpha-12)}
|
||
.input-wrap.is-disabled .input{background:var(--black-alpha-5);color:var(--black-alpha-32);cursor:not-allowed}
|
||
.input-wrap.is-disabled .input::placeholder{color:var(--black-alpha-24)}
|
||
.input::placeholder{color:var(--ink-alpha-48)}
|
||
|
||
.search-wrap{position:relative;max-width:440px}
|
||
.search-wrap .ic-left{
|
||
position:absolute;left:14px;top:50%;transform:translateY(-50%);
|
||
color:var(--black-alpha-56);
|
||
pointer-events:none;
|
||
z-index:2; /* 关键:压在 input bg 之上,否则被白底盖住 */
|
||
display:flex; /* 防止 SVG 行高继承导致偏移 */
|
||
}
|
||
.search-wrap .input{padding-left:42px;padding-right:64px}
|
||
.search-wrap .k{
|
||
position:absolute;right:14px;top:50%;transform:translateY(-50%);
|
||
font-family:var(--font-inter); /* Inter Bold,不再用 mono */
|
||
font-weight:700;
|
||
font-size:11.5px;
|
||
color:var(--black-alpha-56);
|
||
letter-spacing:.02em;
|
||
pointer-events:none;z-index:2;
|
||
line-height:1;
|
||
}
|
||
|
||
/* === Checkbox / Radio / Switch === */
|
||
.ck-row{display:flex;gap:24px;align-items:center;flex-wrap:wrap}
|
||
|
||
.ck{display:inline-flex;align-items:center;gap:10px;cursor:pointer;user-select:none;font-size:14px}
|
||
.ck input{display:none}
|
||
.ck .ck-box{
|
||
width:16px;height:16px;border-radius:var(--r-sm);
|
||
background:var(--card);position:relative;flex-shrink:0;
|
||
transition:background var(--t-base),box-shadow var(--t-base);
|
||
box-shadow:inset 0 0 0 1px var(--ink-alpha-24);
|
||
}
|
||
.ck:hover .ck-box{box-shadow:inset 0 0 0 1px var(--ink-alpha-48)}
|
||
.ck input:checked + .ck-box{
|
||
background:var(--heat);
|
||
box-shadow:inset 0 0 0 1px 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:12px 12px;
|
||
}
|
||
.ck.is-indeterminate .ck-box{
|
||
background:var(--heat);
|
||
box-shadow:inset 0 0 0 1px 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='M5 12h14'/%3E%3C/svg%3E");
|
||
background-repeat:no-repeat;
|
||
background-position:center;
|
||
background-size:12px 12px;
|
||
}
|
||
.ck.is-disabled{opacity:.6;cursor:not-allowed}
|
||
.ck.is-disabled .ck-box{background:var(--bg-soft);box-shadow:inset 0 0 0 1px var(--ink-alpha-12)}
|
||
|
||
.rd{display:inline-flex;align-items:center;gap:10px;cursor:pointer;user-select:none;font-size:14px}
|
||
.rd input{display:none}
|
||
.rd .rd-box{
|
||
width:16px;height:16px;border-radius:50%;
|
||
background:var(--card);position:relative;flex-shrink:0;
|
||
box-shadow:inset 0 0 0 1px var(--ink-alpha-24);
|
||
transition:box-shadow var(--t-base);
|
||
}
|
||
.rd:hover .rd-box{box-shadow:inset 0 0 0 1px var(--ink-alpha-48)}
|
||
.rd input:checked + .rd-box{box-shadow:inset 0 0 0 1px var(--heat)}
|
||
.rd input:checked + .rd-box::after{
|
||
content:'';position:absolute;inset:4px;border-radius:50%;background:var(--heat);
|
||
}
|
||
|
||
.sw{display:inline-flex;align-items:center;gap:12px;cursor:pointer;user-select:none;font-size:14px}
|
||
.sw input{display:none}
|
||
.sw .sw-box{
|
||
width:28px;height:16px;border-radius:var(--r-pill);
|
||
background:var(--ink-alpha-12);position:relative;flex-shrink:0;
|
||
transition:background var(--t-base);
|
||
}
|
||
.sw .sw-box::after{
|
||
content:'';position:absolute;left:2px;top:2px;
|
||
width:12px;height:12px;border-radius:50%;background:#fff;
|
||
transition:left var(--t-base);
|
||
box-shadow:0 1px 2px rgba(21,20,15,.12);
|
||
}
|
||
.sw input:checked + .sw-box{background:var(--heat)}
|
||
.sw input:checked + .sw-box::after{left:14px}
|
||
.sw.is-disabled{opacity:.5;cursor:not-allowed}
|
||
|
||
/* === Tabs === */
|
||
.tabs{border-bottom:1px solid var(--border-faint);display:flex;gap:0;margin-bottom:16px}
|
||
.tab{
|
||
position:relative;background:none;border:0;cursor:pointer;
|
||
height:36px;padding:0 14px;
|
||
font-family:inherit;font-size:13px;font-weight:500;
|
||
color:var(--ink-alpha-56);
|
||
transition:color var(--t-base),background var(--t-base);
|
||
border-radius:var(--r-md) var(--r-md) 0 0;
|
||
}
|
||
.tab:hover{color:var(--ink);background:var(--ink-alpha-4)}
|
||
.tab.is-active{color:var(--ink)}
|
||
.tab.is-active::after{
|
||
content:'';position:absolute;left:0;right:0;bottom:-1px;
|
||
height:2px;background:var(--heat);
|
||
}
|
||
|
||
.subtabs{display:flex;gap:0;margin-bottom:24px}
|
||
.subtab{
|
||
display:inline-flex;align-items:center;gap:6px;
|
||
background:none;border:0;cursor:pointer;
|
||
height:28px;padding:0 10px;
|
||
font-family:inherit;font-size:12px;font-weight:500;
|
||
color:var(--ink-alpha-56);
|
||
transition:color var(--t-base);
|
||
border-radius:var(--r-md);
|
||
}
|
||
.subtab svg{opacity:.6;transition:opacity var(--t-base)}
|
||
.subtab:hover{color:var(--ink)}
|
||
.subtab.is-active{color:var(--ink)}
|
||
.subtab.is-active svg{opacity:1;color:var(--heat)}
|
||
.subtab-divider{width:1px;height:12px;background:var(--ink-alpha-7);margin:0 4px;align-self:center}
|
||
|
||
/* === Card / Shortcut / Tip / Stats === */
|
||
.card{
|
||
background:var(--card);border:1px solid var(--border-faint);
|
||
border-radius:var(--r-md);padding:28px 30px;
|
||
}
|
||
|
||
.shortcut{
|
||
display:flex;align-items:center;gap:16px;
|
||
background:var(--card);border:1px solid var(--border-faint);
|
||
border-radius:var(--r-md);padding:18px 20px;
|
||
cursor:pointer;text-decoration:none;color:inherit;
|
||
transition:background var(--t-base);
|
||
}
|
||
.shortcut:hover{background:var(--ink-alpha-4)}
|
||
.shortcut:active{transform:scale(.99)}
|
||
.shortcut .meta{flex:1;min-width:0}
|
||
.shortcut .title{font-size:14px;font-weight:500;color:var(--ink);margin-bottom:4px;line-height:1.4}
|
||
.shortcut .desc{font-family:var(--font-mono);font-size:11.5px;color:var(--ink-alpha-48);letter-spacing:.04em;line-height:1.5}
|
||
|
||
.tip{
|
||
background:var(--card);border:1px dashed var(--border-loud);
|
||
border-radius:var(--r-md);padding:20px 24px;
|
||
}
|
||
.tip .head{font-size:14px;font-weight:500;margin-bottom:10px;color:var(--ink);line-height:1.4}
|
||
.tip .body{font-size:13px;color:var(--ink-alpha-64);line-height:1.8}
|
||
.tip .mono-code{display:inline-block;padding:2px 8px;background:var(--heat-12);color:var(--heat);font-family:var(--font-mono);font-size:11.5px;border-radius:var(--r-sm);letter-spacing:.04em}
|
||
|
||
.stats{
|
||
background:var(--card);border:1px solid var(--border-faint);
|
||
border-radius:var(--r-md);
|
||
display:grid;grid-template-columns:repeat(4,1fr);
|
||
position:relative;
|
||
}
|
||
.stats .cell{padding:28px 30px;border-right:1px solid var(--border-faint)}
|
||
.stats .cell:last-child{border-right:0}
|
||
.stats .lbl-row{display:flex;align-items:center;gap:10px;margin-bottom:14px}
|
||
.stats .lbl{font-family:var(--font-mono);font-size:11px;color:var(--ink-alpha-48);letter-spacing:.06em;text-transform:uppercase}
|
||
.stats .num{font-size:32px;font-weight:500;letter-spacing:-.02em;font-variant-numeric:tabular-nums;line-height:1.1;color:var(--ink)}
|
||
.stats .num small{font-size:15px;color:var(--ink-alpha-48);font-weight:400}
|
||
.stats .delta{font-family:var(--font-mono);font-size:11.5px;color:var(--ink-alpha-48);margin-top:10px}
|
||
.stats .delta .up{color:var(--green)}
|
||
|
||
/* progress bar segments · 语义色 */
|
||
.prog{display:flex;gap:3px;margin-top:8px}
|
||
.prog span{
|
||
width:18px;height:5px;border-radius:2px;
|
||
background:var(--black-alpha-8);
|
||
display:inline-block;
|
||
transition:background var(--t-base);
|
||
}
|
||
.prog span.done{background:var(--accent-forest)} /* 已完成 = 绿 */
|
||
.prog span.now{
|
||
background:var(--heat); /* 进行中 = 橙 + 脉动 */
|
||
animation:prog-pulse 1.4s ease-in-out infinite;
|
||
}
|
||
.prog span.err{background:var(--accent-crimson)} /* 失败 = 红 */
|
||
@keyframes prog-pulse{
|
||
0%,100%{opacity:1;transform:scaleY(1)}
|
||
50%{opacity:.55;transform:scaleY(.7)}
|
||
}
|
||
|
||
/* === List row === */
|
||
.list-card{background:var(--card);border:1px solid var(--border-faint);border-radius:var(--r-md);overflow:hidden}
|
||
.list-row{
|
||
display:grid;grid-template-columns:56px 1fr auto auto auto;gap:22px;
|
||
align-items:center;padding:20px 24px;
|
||
border-bottom:1px solid var(--border-faint);
|
||
transition:background var(--t-base);
|
||
}
|
||
.list-row:last-child{border-bottom:0}
|
||
.list-row:hover{background:var(--ink-alpha-4)}
|
||
.list-row .thumb{
|
||
width:56px;height:72px;background:var(--bg-soft);
|
||
border:1px solid var(--border-faint);border-radius:var(--r-md);
|
||
display:grid;place-items:center;
|
||
font-family:var(--font-mono);font-size:10.5px;color:var(--ink-alpha-48);letter-spacing:.04em;
|
||
}
|
||
.list-row .meta .ti{font-size:14px;font-weight:500;color:var(--ink);margin-bottom:6px;line-height:1.4}
|
||
.list-row .meta .sub{font-family:var(--font-mono);font-size:11.5px;color:var(--ink-alpha-48);letter-spacing:.02em;line-height:1.5}
|
||
|
||
/* === Toast === */
|
||
.toast-stack{position:fixed;right:24px;bottom:24px;display:flex;flex-direction:column;gap:10px;z-index:1000;pointer-events:none}
|
||
.toast{
|
||
pointer-events:auto;
|
||
display:flex;align-items:center;gap:14px;
|
||
background:var(--card);border:1px solid var(--border-faint);
|
||
border-radius:var(--r-md);padding:16px 20px;min-width:300px;max-width:400px;
|
||
box-shadow:0 4px 20px rgba(21,20,15,.06);
|
||
animation:toastIn var(--t-slow) both;
|
||
}
|
||
.toast.is-leave{animation:toastOut 200ms forwards}
|
||
.toast .ic-box{width:28px;height:28px;border-radius:var(--r-md);background:var(--heat-12);display:grid;place-items:center;flex-shrink:0}
|
||
.toast .ic-box svg{stroke:var(--heat);width:14px;height:14px}
|
||
.toast .ti{font-size:14px;font-weight:500;color:var(--ink);line-height:1.4}
|
||
.toast .sub{font-family:var(--font-mono);font-size:11px;color:var(--ink-alpha-48);letter-spacing:.04em;margin-top:3px}
|
||
@keyframes toastIn{from{transform:translateX(420px);opacity:0}to{transform:translateX(0);opacity:1}}
|
||
@keyframes toastOut{to{transform:translateX(420px);opacity:0}}
|
||
|
||
/* === Modal === */
|
||
.modal-mask{
|
||
position:fixed;inset:0;background:rgba(21,20,15,.42);backdrop-filter:blur(8px);
|
||
display:none;align-items:center;justify-content:center;z-index:900;
|
||
animation:fadeIn 200ms both;
|
||
}
|
||
.modal-mask.is-open{display:flex}
|
||
.modal{
|
||
background:var(--card);border:1px solid var(--border-faint);
|
||
border-radius:var(--r-md);width:460px;position:relative;
|
||
animation:modalIn 250ms cubic-bezier(0.34,1.56,0.64,1) both;
|
||
}
|
||
.modal .corner{position:absolute;width:22px;height:21px;color:var(--border-muted)}
|
||
.modal .corner.tl{top:-10.5px;left:-11px}
|
||
.modal .corner.tr{top:-10.5px;right:-11px;transform:scaleX(-1)}
|
||
.modal .corner.bl{bottom:-10.5px;left:-11px;transform:scaleY(-1)}
|
||
.modal .corner.br{bottom:-10.5px;right:-11px;transform:scale(-1,-1)}
|
||
.modal .head{display:flex;align-items:center;gap:16px;padding:24px 28px;border-bottom:1px solid var(--border-faint)}
|
||
.modal .head .ic-box{width:36px;height:36px;border-radius:var(--r-md);background:var(--heat-12);display:grid;place-items:center;flex-shrink:0}
|
||
.modal .head .ic-box svg{stroke:var(--heat);width:18px;height:18px}
|
||
.modal .head .ti{font-size:16px;font-weight:500;color:var(--ink);letter-spacing:-.01em;line-height:1.4}
|
||
.modal .head .sub{font-family:var(--font-mono);font-size:11px;color:var(--ink-alpha-48);letter-spacing:.04em;margin-top:4px}
|
||
.modal .body{padding:24px 28px;font-size:14px;color:var(--ink-alpha-72);line-height:1.8}
|
||
.modal .foot{display:flex;justify-content:flex-end;gap:12px;padding:18px 28px;border-top:1px solid var(--border-faint)}
|
||
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
|
||
@keyframes modalIn{from{opacity:0;transform:scale(.96)}to{opacity:1;transform:scale(1)}}
|
||
|
||
/* === Container border-x demo === */
|
||
.container-demo{
|
||
position:relative;margin:36px auto 24px;
|
||
max-width:720px;padding:48px 56px;
|
||
background:var(--bg);
|
||
border-left:1px solid var(--border-faint);
|
||
border-right:1px solid var(--border-faint);
|
||
}
|
||
.container-demo .corner{position:absolute;width:22px;height:21px;color:var(--border-muted)}
|
||
.container-demo .corner.tl{top:-10.5px;left:-11px}
|
||
.container-demo .corner.tr{top:-10.5px;right:-11px;transform:scaleX(-1)}
|
||
.container-demo .corner.bl{bottom:-10.5px;left:-11px;transform:scaleY(-1)}
|
||
.container-demo .corner.br{bottom:-10.5px;right:-11px;transform:scale(-1,-1)}
|
||
.container-demo .inner{
|
||
background:var(--card);border:1px solid var(--border-faint);
|
||
border-radius:var(--r-md);padding:24px;
|
||
font-size:13px;color:var(--ink-alpha-72);text-align:center;
|
||
}
|
||
|
||
/* === Mono decoration samples === */
|
||
.mono-sample-row{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px}
|
||
.mono-tag-sample{
|
||
font-family:var(--font-mono);font-size:11px;
|
||
color:var(--ink-alpha-48);background:var(--bg-soft);
|
||
border:1px solid var(--border-faint);
|
||
border-radius:var(--r-sm);padding:3px 8px;letter-spacing:.04em;
|
||
}
|
||
.mono-tag-sample.heat{color:var(--heat);background:var(--heat-12);border-color:var(--heat-20)}
|
||
|
||
/* === Don't / Do === */
|
||
.dodont-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
|
||
.dodont{padding:16px 18px;border-radius:var(--r-md);border:1px solid}
|
||
.dodont .head{font-family:var(--font-mono);font-size:10.5px;letter-spacing:.04em;margin-bottom:10px;display:inline-block;padding:1px 8px;border-radius:var(--r-sm)}
|
||
.dodont.do{border-color:var(--green-bd);background:var(--green-bg)}
|
||
.dodont.do .head{background:var(--green);color:#fff}
|
||
.dodont.dont{border-color:var(--red-bd);background:var(--red-bg)}
|
||
.dodont.dont .head{background:var(--red);color:#fff}
|
||
.dodont .body{font-size:12.5px;line-height:1.7;color:var(--ink-alpha-72)}
|
||
|
||
.dont-list-item{
|
||
display:flex;align-items:flex-start;gap:10px;
|
||
font-size:12.5px;line-height:1.7;color:var(--ink-alpha-72);
|
||
padding:8px 0;border-bottom:1px solid var(--border-faint);
|
||
}
|
||
.dont-list-item:last-child{border-bottom:0}
|
||
.dont-list-item .x{color:var(--red);font-family:var(--font-mono);flex-shrink:0;margin-top:2px}
|
||
|
||
/* Codebox */
|
||
.codebox{
|
||
background:var(--bg-soft);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.65;
|
||
color:var(--ink-alpha-88);overflow-x:auto;letter-spacing:.02em;
|
||
white-space:pre;
|
||
}
|
||
.codebox .c-key{color:var(--heat)}
|
||
.codebox .c-val{color:var(--ink-alpha-64)}
|
||
.codebox .c-comment{color:var(--ink-alpha-32)}
|
||
|
||
/* responsive */
|
||
@media(max-width:980px){
|
||
.layout{grid-template-columns:1fr}
|
||
.sidebar{position:relative;height:auto;border-right:0;border-bottom:1px solid var(--border-faint)}
|
||
.main{padding:32px 24px 64px}
|
||
.stats{grid-template-columns:repeat(2,1fr)}
|
||
.stats .cell:nth-child(2){border-right:0}
|
||
.stats .cell:nth-child(1),.stats .cell:nth-child(2){border-bottom:1px solid var(--border-faint)}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="layout">
|
||
|
||
<!-- ============ SIDEBAR ============ -->
|
||
<aside class="sidebar">
|
||
<h1>流·Studio<br>设计系统</h1>
|
||
<div class="mono-sub">// V2 · 2026-05-15 · INTERACTIVE</div>
|
||
|
||
<ul class="nav-list">
|
||
<li class="nav-group">// FOUNDATION</li>
|
||
<li><a href="#tokens">色彩 Tokens</a></li>
|
||
<li><a href="#type">字体系统</a></li>
|
||
<li><a href="#radius">圆角阶梯</a></li>
|
||
<li><a href="#icons">Icon 系统</a></li>
|
||
|
||
<li class="nav-group">// COMPONENTS</li>
|
||
<li><a href="#buttons">按钮</a></li>
|
||
<li><a href="#pills">胶囊 Pills</a></li>
|
||
<li><a href="#inputs">输入框</a></li>
|
||
<li><a href="#form-controls">表单控件</a></li>
|
||
<li><a href="#tabs">Tab</a></li>
|
||
<li><a href="#cards">卡片 / 快捷入口</a></li>
|
||
<li><a href="#stats">KPI 统计</a></li>
|
||
<li><a href="#list">列表行</a></li>
|
||
<li><a href="#tip">提示框 / 进度</a></li>
|
||
<li><a href="#modal">Modal · 弹窗</a></li>
|
||
<li><a href="#toast">Toast · 通知</a></li>
|
||
|
||
<li class="nav-group">// SIGNATURE</li>
|
||
<li><a href="#container">主容器装订线</a></li>
|
||
<li><a href="#mono-decor">Mono 装饰元素</a></li>
|
||
|
||
<li class="nav-group">// GUARDRAILS</li>
|
||
<li><a href="#dont">Don't List</a></li>
|
||
</ul>
|
||
</aside>
|
||
|
||
<!-- ============ MAIN ============ -->
|
||
<main class="main">
|
||
|
||
<!-- HERO -->
|
||
<div class="hero">
|
||
<span class="badge">// V2 · INTERACTIVE</span>
|
||
<h1>流·Studio 设计系统</h1>
|
||
<p>所有 token、组件、状态的可交互参照。基于 Firecrawl Playground 实测规范校准。 hover / 点击下方组件可看到真实交互反馈。</p>
|
||
<div class="meta">
|
||
<span>[ Restraint · v2.0 ]</span>
|
||
<span>·</span>
|
||
<span>// based on DESIGN_SPEC_V2.md</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §1 COLOR TOKENS -->
|
||
<!-- =========================================== -->
|
||
<section id="tokens">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §1 · COLOR TOKENS · V2.1 · FIRECRAWL-ALIGNED</span>
|
||
<h2>色彩系统</h2>
|
||
<p>V2.1 全面对齐 Firecrawl Playground 实测色板:**冷灰底**(非米白)· **#FA5D19 主橙**(更亮一档)· **20 档 black-alpha 阶梯**(替代 11 档 ink-alpha)· **5 色 accent 多彩点**(amethyst / bluetron / crimson / forest / honey)。点击任何色块复制值。</p>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>表面 / 背景 <span class="mono-num">// 4 档 · 冷灰无色相</span></h3>
|
||
<p class="lead">告别 V2 的暖米白(#FAF9F5),全面切换 Firecrawl 的纯冷灰。<code class="mono" style="background:var(--background-lighter);padding:1px 6px;border-radius:4px">--bg/--bg-soft/--card</code> 作为 legacy 别名仍可用。</p>
|
||
<div class="swatch-grid" data-copy-grid>
|
||
<div class="swatch" data-hex="#f9f9f9"><div class="chip" style="background:#f9f9f9"></div><div class="meta-row"><div class="name">--background-base</div><div class="val">#f9f9f9 · 页面底</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="#fbfbfb"><div class="chip" style="background:#fbfbfb"></div><div class="meta-row"><div class="name">--background-lighter</div><div class="val">#fbfbfb · 容器底</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="#ffffff"><div class="chip with-grid" style="background:#ffffff"></div><div class="meta-row"><div class="name">--surface</div><div class="val">#ffffff · 卡片</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="#ffffff"><div class="chip with-grid" style="background:#ffffff"></div><div class="meta-row"><div class="name">--surface-raised</div><div class="val">#ffffff · Modal</div><div class="copy">copied</div></div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>边框 <span class="mono-num">// 3 档 · 冷灰 · 差距极小靠语义</span></h3>
|
||
<p class="lead">3 档相差只 1–2 个色阶,肉眼几乎看不出。**用语义,不用视觉对比**——80% 场景用 <code class="mono" style="background:var(--background-lighter);padding:1px 6px;border-radius:4px">--border-faint</code>。</p>
|
||
<div class="swatch-grid" data-copy-grid>
|
||
<div class="swatch" data-hex="#ededed"><div class="chip" style="background:#ededed"></div><div class="meta-row"><div class="name">--border-faint</div><div class="val">#ededed · 默认 ★</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="#e8e8e8"><div class="chip" style="background:#e8e8e8"></div><div class="meta-row"><div class="name">--border-muted</div><div class="val">#e8e8e8 · 略深</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="#e6e6e6"><div class="chip" style="background:#e6e6e6"></div><div class="meta-row"><div class="name">--border-loud</div><div class="val">#e6e6e6 · 强分隔</div><div class="copy">copied</div></div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>主橙 Heat <span class="mono-num">// 单 hue #FA5D19 + 8 档 alpha</span></h3>
|
||
<p class="lead">从 V2 砖红 <code class="mono" style="background:var(--background-lighter);padding:1px 6px;border-radius:4px">#E55B26</code> 调亮到 Firecrawl 实测 <code class="mono" style="background:var(--heat-12);color:var(--heat);padding:1px 6px;border-radius:4px">#FA5D19</code>(更红更饱和)。**全靠 alpha 叠加,绝不换 hue。** hover 不再切换到更深的橙,而是用 90% / 16% 这些档位组合。</p>
|
||
<div class="swatch-grid" data-copy-grid>
|
||
<div class="swatch" data-hex="#fa5d19"><div class="chip" style="background:#fa5d19"></div><div class="meta-row"><div class="name">--heat</div><div class="val">#fa5d19 · 100% · CTA ★</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(250,93,25,.90)"><div class="chip" style="background:rgba(250,93,25,.90)"></div><div class="meta-row"><div class="name">--heat-90</div><div class="val">90% · hover</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(250,93,25,.40)"><div class="chip" style="background:rgba(250,93,25,.40)"></div><div class="meta-row"><div class="name">--heat-40</div><div class="val">40% · ring / edge</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(250,93,25,.20)"><div class="chip" style="background:rgba(250,93,25,.20)"></div><div class="meta-row"><div class="name">--heat-20</div><div class="val">20% · pill border / selection</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(250,93,25,.16)"><div class="chip" style="background:rgba(250,93,25,.16)"></div><div class="meta-row"><div class="name">--heat-16</div><div class="val">16% · hover bg</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(250,93,25,.12)"><div class="chip" style="background:rgba(250,93,25,.12)"></div><div class="meta-row"><div class="name">--heat-12</div><div class="val">12% · tint bg</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(250,93,25,.08)"><div class="chip" style="background:rgba(250,93,25,.08)"></div><div class="meta-row"><div class="name">--heat-8</div><div class="val">8%</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(250,93,25,.04)"><div class="chip" style="background:rgba(250,93,25,.04)"></div><div class="meta-row"><div class="name">--heat-4</div><div class="val">4% · 极弱</div><div class="copy">copied</div></div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>Accent 多彩点 <span class="mono-num">// 5 色信号 · 限定语义场景</span></h3>
|
||
<p class="lead">**新增章节 · 取自 Firecrawl 实测**。这 5 色只用于**语义信号**(代码高亮 / info / 状态色),**禁止做大面积装饰**——全场依然只有橙色一个 accent。<code class="mono" style="background:var(--heat-12);color:var(--heat);padding:1px 6px;border-radius:4px">--accent-black</code> 替代 V2 的 <code class="mono" style="background:var(--background-lighter);padding:1px 6px;border-radius:4px">--ink #15140F</code>(更柔和的灰黑)。</p>
|
||
<div class="swatch-grid" data-copy-grid>
|
||
<div class="swatch" data-hex="#262626"><div class="chip" style="background:#262626"></div><div class="meta-row"><div class="name">--accent-black</div><div class="val">#262626 · 主前景</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="#ffffff"><div class="chip with-grid" style="background:#ffffff"></div><div class="meta-row"><div class="name">--accent-white</div><div class="val">#ffffff · 反色文字</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="#9061ff"><div class="chip" style="background:#9061ff"></div><div class="meta-row"><div class="name">--accent-amethyst</div><div class="val">#9061ff · 紫 / code property</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="#2a6dfb"><div class="chip" style="background:#2a6dfb"></div><div class="meta-row"><div class="name">--accent-bluetron</div><div class="val">#2a6dfb · 蓝 / info</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="#eb3424"><div class="chip" style="background:#eb3424"></div><div class="meta-row"><div class="name">--accent-crimson</div><div class="val">#eb3424 · 红 / error ★</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="#42c366"><div class="chip" style="background:#42c366"></div><div class="meta-row"><div class="name">--accent-forest</div><div class="val">#42c366 · 绿 / success ★</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="#ecb730"><div class="chip" style="background:#ecb730"></div><div class="meta-row"><div class="name">--accent-honey</div><div class="val">#ecb730 · 黄 / warning</div><div class="copy">copied</div></div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>Black-Alpha 阶梯 <span class="mono-num">// 20 档 · 替代 V2 的 11 档 ink-alpha</span></h3>
|
||
<p class="lead">**核心工具尺。** 0–24% 用 <code class="mono">rgba(0,0,0,...)</code> 纯黑透明;**32% 起换 <code class="mono">rgba(38,38,38,...)</code>**(即 accent-black 作底)避免叠出"灰中带蓝"——这是 Firecrawl 的细节技巧,我们 1:1 复刻。dark mode 时这套 token 自动翻转为 white-alpha。原 <code class="mono">--ink-alpha-*</code> 全部作为 legacy 别名映射到对应 black-alpha。</p>
|
||
<div class="swatch-grid" data-copy-grid>
|
||
<div class="swatch" data-hex="rgba(0,0,0,.01)"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.01)"></div></div><div class="meta-row"><div class="name">--black-alpha-1</div><div class="val">1%</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(0,0,0,.02)"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.02)"></div></div><div class="meta-row"><div class="name">--black-alpha-2</div><div class="val">2%</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(0,0,0,.03)"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.03)"></div></div><div class="meta-row"><div class="name">--black-alpha-3</div><div class="val">3%</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(0,0,0,.04)"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.04)"></div></div><div class="meta-row"><div class="name">--black-alpha-4</div><div class="val">4% · hover bg ★</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(0,0,0,.05)"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.05)"></div></div><div class="meta-row"><div class="name">--black-alpha-5</div><div class="val">5% · tab 分隔</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(0,0,0,.06)"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.06)"></div></div><div class="meta-row"><div class="name">--black-alpha-6</div><div class="val">6%</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(0,0,0,.07)"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.07)"></div></div><div class="meta-row"><div class="name">--black-alpha-7</div><div class="val">7% · active bg ★</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(0,0,0,.08)"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.08)"></div></div><div class="meta-row"><div class="name">--black-alpha-8</div><div class="val">8%</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(0,0,0,.10)"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.10)"></div></div><div class="meta-row"><div class="name">--black-alpha-10</div><div class="val">10%</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(0,0,0,.12)"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.12)"></div></div><div class="meta-row"><div class="name">--black-alpha-12</div><div class="val">12% · inside-border ★</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(0,0,0,.16)"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.16)"></div></div><div class="meta-row"><div class="name">--black-alpha-16</div><div class="val">16%</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(0,0,0,.20)"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.20)"></div></div><div class="meta-row"><div class="name">--black-alpha-20</div><div class="val">20%</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(0,0,0,.24)"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.24)"></div></div><div class="meta-row"><div class="name">--black-alpha-24</div><div class="val">24%</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(38,38,38,.32)"><div class="chip" style="background:rgba(38,38,38,.32)"></div><div class="meta-row"><div class="name">--black-alpha-32</div><div class="val">32% · base 切换 →</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(38,38,38,.40)"><div class="chip" style="background:rgba(38,38,38,.40)"></div><div class="meta-row"><div class="name">--black-alpha-40</div><div class="val">40%</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(38,38,38,.48)"><div class="chip" style="background:rgba(38,38,38,.48)"></div><div class="meta-row"><div class="name">--black-alpha-48</div><div class="val">48% · 占位字色 ★</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(38,38,38,.56)"><div class="chip" style="background:rgba(38,38,38,.56)"></div><div class="meta-row"><div class="name">--black-alpha-56</div><div class="val">56% · 次级文字 ★</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(38,38,38,.64)"><div class="chip" style="background:rgba(38,38,38,.64)"></div><div class="meta-row"><div class="name">--black-alpha-64</div><div class="val">64% · 描述</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(38,38,38,.72)"><div class="chip" style="background:rgba(38,38,38,.72)"></div><div class="meta-row"><div class="name">--black-alpha-72</div><div class="val">72%</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(38,38,38,.88)"><div class="chip" style="background:rgba(38,38,38,.88)"></div><div class="meta-row"><div class="name">--black-alpha-88</div><div class="val">88% · 近主前景</div><div class="copy">copied</div></div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>状态色 <span class="mono-num">// 用 accent-forest / crimson 作语义</span></h3>
|
||
<p class="lead">V2 的 <code class="mono">--green #3F6B3F</code>(深森林绿)与 <code class="mono">--red #B33A2A</code>(暗砖红)替换为 Firecrawl 的 <code class="mono">--accent-forest #42c366</code> 与 <code class="mono">--accent-crimson #eb3424</code>——更明亮、更接近真实"信号灯"颜色,但仍保持非荧光。</p>
|
||
<div class="swatch-grid" data-copy-grid>
|
||
<div class="swatch" data-hex="#42c366"><div class="chip" style="background:#42c366"></div><div class="meta-row"><div class="name">--green</div><div class="val">#42c366 · 成功(=forest)</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(66,195,102,.08)"><div class="chip" style="background:rgba(66,195,102,.08)"></div><div class="meta-row"><div class="name">--green-bg</div><div class="val">8% · 配套底</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(66,195,102,.20)"><div class="chip" style="background:rgba(66,195,102,.20)"></div><div class="meta-row"><div class="name">--green-bd</div><div class="val">20% · 配套边</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="#eb3424"><div class="chip" style="background:#eb3424"></div><div class="meta-row"><div class="name">--red</div><div class="val">#eb3424 · 失败(=crimson)</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(235,52,36,.08)"><div class="chip" style="background:rgba(235,52,36,.08)"></div><div class="meta-row"><div class="name">--red-bg</div><div class="val">8% · 配套底</div><div class="copy">copied</div></div></div>
|
||
<div class="swatch" data-hex="rgba(235,52,36,.20)"><div class="chip" style="background:rgba(235,52,36,.20)"></div><div class="meta-row"><div class="name">--red-bd</div><div class="val">20% · 配套边</div><div class="copy">copied</div></div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>Selection 选中色 <span class="mono-num">// Firecrawl 签名细节</span></h3>
|
||
<p class="lead">页面内任何文字选中时,底色 <code class="mono" style="background:var(--heat-20);color:var(--heat);padding:1px 6px;border-radius:4px">--heat-20</code> + 字色 <code class="mono" style="color:var(--heat);padding:1px 6px;border-radius:4px">--heat</code>。**试着选中下面这行字看效果:**</p>
|
||
<p style="font-size:14px;line-height:1.7;padding:14px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">本月营收 ¥327,400 较上月增长 33%,有 5 个项目处于"生成中"状态。其中 2 个需要重新调整模特模板。</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §2 TYPOGRAPHY -->
|
||
<!-- =========================================== -->
|
||
<section id="type">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §2 · TYPE · V2.1 MIXED STRATEGY</span>
|
||
<h2>字体系统 · 中英协作</h2>
|
||
<p>V2.1 改为**中英双字体协作** —— <code class="mono" style="background:var(--background-lighter);padding:2px 8px;border-radius:4px;color:var(--ink)">Inter</code> 处理英文/数字,<code class="mono" style="background:var(--background-lighter);padding:2px 8px;border-radius:4px;color:var(--ink)">Alibaba PuHuiTi</code> 处理中文,装饰用 <code class="mono" style="background:var(--background-lighter);padding:2px 8px;border-radius:4px;color:var(--ink)">JetBrains Mono</code>。浏览器按字符级 fallthrough,Inter 不含 CJK 字形 → 中文自动跳到普惠体。**不需要 JS,中英自然分工。**</p>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>字体族原理 <span class="mono-num">// browser-level character fallthrough</span></h3>
|
||
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:14px;margin-bottom:24px">
|
||
<div style="padding:24px 26px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
|
||
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--ink-alpha-48);letter-spacing:.06em;margin-bottom:14px">// 01 · ENGLISH</div>
|
||
<div style="font-family:'Inter',sans-serif;font-size:24px;font-weight:500;letter-spacing:-.01em;color:var(--ink);margin-bottom:8px">Inter</div>
|
||
<div style="font-family:'Inter',sans-serif;font-size:13px;color:var(--ink-alpha-64);line-height:1.6">The quick brown fox jumps. 0123456789 — Vercel / Linear / Stripe 御用,屏幕 UI 优化,数字同宽。</div>
|
||
</div>
|
||
<div style="padding:24px 26px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
|
||
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--ink-alpha-48);letter-spacing:.06em;margin-bottom:14px">// 02 · 中文</div>
|
||
<div style="font-family:'Alibaba PuHuiTi','PingFang SC',sans-serif;font-size:24px;font-weight:500;letter-spacing:-.01em;color:var(--ink);margin-bottom:8px">阿里普惠体</div>
|
||
<div style="font-family:'Alibaba PuHuiTi','PingFang SC',sans-serif;font-size:13px;color:var(--ink-alpha-64);line-height:1.6">为中英混排专门设计的笔画粗细配比,与 Inter 视觉重量贴近,中文版面舒适匀质。</div>
|
||
</div>
|
||
<div style="padding:24px 26px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
|
||
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--ink-alpha-48);letter-spacing:.06em;margin-bottom:14px">// 03 · 装饰 MONO</div>
|
||
<div style="font-family:var(--font-mono);font-size:22px;font-weight:500;color:var(--ink);margin-bottom:8px">JetBrains</div>
|
||
<div style="font-family:var(--font-mono);font-size:12px;color:var(--ink-alpha-64);line-height:1.6;letter-spacing:.02em">[ 200 OK ] · // 05.14 · /v2 — 仅用于装饰标签,不参与正文。</div>
|
||
</div>
|
||
</div>
|
||
<div style="padding:22px 26px;background:var(--heat-8);border:1px solid var(--heat-20);border-radius:8px">
|
||
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--heat);letter-spacing:.06em;margin-bottom:10px">// 混排实测 · MIXED RENDERING</div>
|
||
<div style="font-size:18px;font-weight:500;color:var(--ink);line-height:1.5">本月营收 ¥327,400 较上月 +33%,共 5 个 AI 项目处于 "生成中" 状态</div>
|
||
<div style="font-family:var(--font-mono);font-size:11px;color:var(--ink-alpha-48);margin-top:10px;letter-spacing:.04em">↑ 这一行里:中文走 PuHuiTi · "¥" "327,400" "+33%" "5" "AI" 走 Inter · 字重视觉匀质,无错位</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>字号 / 字重 / 行高阶梯 <span class="mono-num">// 11 档</span></h3>
|
||
<div class="type-row">
|
||
<div class="meta-col"><strong>H1 / Hero</strong>36 / 500 / -0.024em / 1.2</div>
|
||
<div class="sample" style="font-size:36px;font-weight:500;letter-spacing:-.024em;line-height:1.2">早上好,大莱</div>
|
||
</div>
|
||
<div class="type-row">
|
||
<div class="meta-col"><strong>区块 H2</strong>28 / 500 / -0.02em / 1.25</div>
|
||
<div class="sample" style="font-size:28px;font-weight:500;letter-spacing:-.02em;line-height:1.25">设计系统总览</div>
|
||
</div>
|
||
<div class="type-row">
|
||
<div class="meta-col"><strong>KPI 数值</strong>32 / 500 / -0.02em / tabular-nums</div>
|
||
<div class="sample" style="font-size:32px;font-weight:500;letter-spacing:-.02em;font-variant-numeric:tabular-nums">¥327<small style="font-size:15px;color:var(--ink-alpha-48)">.40 K</small></div>
|
||
</div>
|
||
<div class="type-row">
|
||
<div class="meta-col"><strong>子区 H3</strong>16 / 500 / -0.01em / 1.4</div>
|
||
<div class="sample" style="font-size:16px;font-weight:500;letter-spacing:-.01em">最近项目</div>
|
||
</div>
|
||
<div class="type-row">
|
||
<div class="meta-col"><strong>卡片标题</strong>14 / 500 / normal / 1.4</div>
|
||
<div class="sample" style="font-size:14px;font-weight:500">夏季新款蕾丝连衣裙 · 蓝色 / M</div>
|
||
</div>
|
||
<div class="type-row">
|
||
<div class="meta-col"><strong>正文 body</strong>14 / 400 / normal / **1.65**</div>
|
||
<div class="sample" style="font-size:14px;line-height:1.65">商家可能没有现成的商品图,需要新增一种「AI 生成」模式 —— 商家上传一张随手拍的原图,AI 生成 4 张满意的头图,选 1 张。</div>
|
||
</div>
|
||
<div class="type-row">
|
||
<div class="meta-col"><strong>Label · 按钮 / Tab</strong>13 / 500 / normal</div>
|
||
<div class="sample" style="font-size:13px;font-weight:500">查看 Demo</div>
|
||
</div>
|
||
<div class="type-row">
|
||
<div class="meta-col"><strong>描述次级</strong>13 / 400 / --ink-alpha-64 / 1.8</div>
|
||
<div class="sample" style="font-size:13px;color:var(--ink-alpha-64);line-height:1.8">本月营收较上月增长 33%,5 个项目处于"生成中"状态,2 个需要重新调整模特模板</div>
|
||
</div>
|
||
<div class="type-row">
|
||
<div class="meta-col"><strong>Pill 文字</strong>11.5 / 500 / normal</div>
|
||
<div class="sample" style="font-size:11.5px;font-weight:500">生成中</div>
|
||
</div>
|
||
<div class="type-row">
|
||
<div class="meta-col"><strong>Inter Bold · 徽标</strong>11.5 / 700 / Inter only</div>
|
||
<div class="sample" style="font-family:var(--font-inter);font-size:11.5px;font-weight:700;color:var(--black-alpha-56);letter-spacing:.02em">Ctrl K · ESC · Enter · ⇧+Tab</div>
|
||
</div>
|
||
<div class="type-row">
|
||
<div class="meta-col"><strong>Mono 标签</strong>11 / 400 / 0.04em · JetBrains</div>
|
||
<div class="sample" style="font-family:var(--font-mono);font-size:11px;letter-spacing:.04em;color:var(--ink-alpha-48)">[ 200 OK ] [ .MP4 · 9:16 ] [ /v2 ]</div>
|
||
</div>
|
||
<div class="type-row">
|
||
<div class="meta-col"><strong>Mono 散点装饰</strong>8.5 / 400 / 0.04em</div>
|
||
<div class="sample" style="font-family:var(--font-mono);font-size:8.5px;letter-spacing:.04em;color:var(--ink-alpha-12)">· · + · +XX+ +XXXX· +X·</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>字重档位 <span class="mono-num">// 仅 400 / 500 / 600 / 700</span></h3>
|
||
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px">
|
||
<div style="padding:20px 22px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
|
||
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--ink-alpha-48);letter-spacing:.04em;margin-bottom:10px">// REGULAR · 400</div>
|
||
<div style="font-size:18px;font-weight:400">流·Studio · Aa Bb 123</div>
|
||
</div>
|
||
<div style="padding:20px 22px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
|
||
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--ink-alpha-48);letter-spacing:.04em;margin-bottom:10px">// MEDIUM · 500 ★ 默认强调</div>
|
||
<div style="font-size:18px;font-weight:500">流·Studio · Aa Bb 123</div>
|
||
</div>
|
||
<div style="padding:20px 22px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
|
||
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--ink-alpha-48);letter-spacing:.04em;margin-bottom:10px">// SEMIBOLD · 600</div>
|
||
<div style="font-size:18px;font-weight:600">流·Studio · Aa Bb 123</div>
|
||
</div>
|
||
<div style="padding:20px 22px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
|
||
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--ink-alpha-48);letter-spacing:.04em;margin-bottom:10px">// BOLD · 700 · 限徽标</div>
|
||
<div style="font-size:18px;font-weight:700">流·Studio · Aa Bb 123</div>
|
||
</div>
|
||
</div>
|
||
<p class="mono" style="margin-top:14px">// Bold 700 仅用于 Ctrl K 这种纯英文徽标场景,**正文严禁 700**(中英字重错位会暴露)</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §3 RADIUS -->
|
||
<!-- =========================================== -->
|
||
<section id="radius">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §3 · RADIUS</span>
|
||
<h2>圆角阶梯</h2>
|
||
<p>V2 核心变化:统一 <strong style="color:var(--ink)">8 px</strong> 作为默认主圆角。完全圆 999 px 仅用于 pill 和 dot。微元素降到 4–6 px。</p>
|
||
</div>
|
||
|
||
<div class="radius-row">
|
||
<div class="radius-box"><div class="box" style="border-radius:0"><span class="mono">x</span></div><div class="lbl">禁用 V1</div><div class="px">0 px</div></div>
|
||
<div class="radius-box"><div class="box" style="border-radius:2px"></div><div class="lbl">progress</div><div class="px">2 px</div></div>
|
||
<div class="radius-box"><div class="box" style="border-radius:4px"></div><div class="lbl">kbd / badge</div><div class="px">4 px</div></div>
|
||
<div class="radius-box"><div class="box" style="border-radius:6px"></div><div class="lbl">小色块</div><div class="px">6 px</div></div>
|
||
<div class="radius-box"><div class="box" style="border-radius:8px;border-color:var(--heat);background:var(--heat-8)"></div><div class="lbl" style="color:var(--heat);font-weight:500">主默认</div><div class="px" style="color:var(--heat)">8 px ★</div></div>
|
||
<div class="radius-box"><div class="box" style="border-radius:999px;width:160px;height:48px"><span class="mono">pill</span></div><div class="lbl">pill / dot</div><div class="px">999 px</div></div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §4 ICONS -->
|
||
<!-- =========================================== -->
|
||
<section id="icons">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §4 · ICONS</span>
|
||
<h2>Icon 系统</h2>
|
||
<p>统一 SVG line icon · stroke 1.5 · linecap round · 颜色通过 <code class="mono" style="background:var(--bg-soft);padding:1px 6px;border-radius:4px">currentColor</code> 继承。禁用 emoji / filled icon。</p>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>尺寸阶梯 <span class="mono-num">// 5 档</span></h3>
|
||
<div class="icon-row">
|
||
<div class="icon-cell">
|
||
<div class="ic" style="width:32px;height:32px"><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></div>
|
||
<div class="lbl">S · 14 px</div>
|
||
</div>
|
||
<div class="icon-cell">
|
||
<div class="ic" style="width:36px;height:36px"><svg width="16" height="16" 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></div>
|
||
<div class="lbl">M · 16 px ★</div>
|
||
</div>
|
||
<div class="icon-cell">
|
||
<div class="ic" style="width:40px;height:40px"><svg width="20" height="20" 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></div>
|
||
<div class="lbl">L · 20 px</div>
|
||
</div>
|
||
<div class="icon-cell">
|
||
<div class="ic" style="width:48px;height:48px"><svg width="24" height="24" 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></div>
|
||
<div class="lbl">XL · 24 px</div>
|
||
</div>
|
||
<div class="icon-cell">
|
||
<div class="ic" style="width:64px;height:64px"><svg width="36" height="36" 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></div>
|
||
<div class="lbl">Hero · 36 px</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>颜色场景 <span class="mono-num">// 通过 currentColor 继承</span></h3>
|
||
<div class="icon-color-row">
|
||
<div class="demo">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="color:var(--ink-alpha-56)"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
||
<span>默认 ink-56</span>
|
||
</div>
|
||
<div class="demo" style="background:var(--ink-alpha-4);color:var(--ink)">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
||
<span>hover · ink</span>
|
||
</div>
|
||
<div class="demo" style="color:var(--heat);background:var(--heat-12);border-color:var(--heat-20)">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
||
<span>active · heat</span>
|
||
</div>
|
||
<div class="demo primary">
|
||
<svg width="16" height="16" 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>在主 CTA 内</span>
|
||
</div>
|
||
<div class="demo disabled">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
||
<span>disabled</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>Icon Box <span class="mono-num">// 快捷入口/Modal 头部用</span></h3>
|
||
<div style="display:flex;gap:14px;align-items:center;flex-wrap:wrap">
|
||
<div class="icon-box"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><path d="m9 11 3 3L22 4"/></svg></div>
|
||
<div class="icon-box"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="m9 9 6 6m0-6-6 6"/></svg></div>
|
||
<div class="icon-box"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83"/></svg></div>
|
||
<span class="mono">32×32 · 8 px 圆角 · --heat-12 底 · 16 px line icon</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §5 BUTTONS -->
|
||
<!-- =========================================== -->
|
||
<section id="buttons">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §5 · BUTTONS</span>
|
||
<h2>按钮 · 3 类型 × 5 状态 × 3 尺寸</h2>
|
||
<p>所有按钮:<strong style="color:var(--ink)">高 32 / 圆角 8 / 字号 13 / 字重 500</strong>。默认按钮用 <code class="mono" style="background:var(--bg-soft);padding:1px 6px;border-radius:4px">::before inside-border</code>,hover 时边框淡出底色淡入,无布局抖动。</p>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>类型 1 · 默认 <span class="mono-num">// .btn</span></h3>
|
||
<div class="btn-row"><span class="state-label">// default</span><button class="btn">取消</button><button class="btn"><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="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>导出</button></div>
|
||
<div class="btn-row"><span class="state-label">// hover</span><button class="btn demo-hover">取消</button></div>
|
||
<div class="btn-row"><span class="state-label">// active</span><button class="btn demo-active">取消</button></div>
|
||
<div class="btn-row"><span class="state-label">// focused</span><button class="btn demo-focus">取消</button></div>
|
||
<div class="btn-row"><span class="state-label">// disabled</span><button class="btn" disabled>取消</button></div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>类型 2 · 主 CTA <span class="mono-num">// .btn-primary</span></h3>
|
||
<p class="lead">唯一允许阴影的按钮 —— 4 层橙色多重阴影,hover 时阴影向上抬起。</p>
|
||
<div class="btn-row"><span class="state-label">// default</span><button class="btn btn-primary">查看 Demo</button><button class="btn btn-primary">下一步<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 class="btn-row"><span class="state-label">// hover</span><button class="btn btn-primary demo-hover">查看 Demo</button></div>
|
||
<div class="btn-row"><span class="state-label">// active</span><button class="btn btn-primary demo-active">查看 Demo</button></div>
|
||
<div class="btn-row"><span class="state-label">// focused</span><button class="btn btn-primary demo-focus">查看 Demo</button></div>
|
||
<div class="btn-row"><span class="state-label">// disabled</span><button class="btn btn-primary" disabled>查看 Demo</button></div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>类型 3 · 无框 <span class="mono-num">// .btn-ghost</span></h3>
|
||
<div class="btn-row"><span class="state-label">// default</span><button class="btn btn-ghost">取消</button><button class="btn btn-ghost">了解更多 →</button></div>
|
||
<div class="btn-row"><span class="state-label">// hover</span><button class="btn btn-ghost demo-hover">取消</button></div>
|
||
<div class="btn-row"><span class="state-label">// active</span><button class="btn btn-ghost demo-active">取消</button></div>
|
||
<div class="btn-row"><span class="state-label">// disabled</span><button class="btn btn-ghost" disabled>取消</button></div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>尺寸 <span class="mono-num">// -sm / 默认 / -lg</span></h3>
|
||
<div class="btn-row">
|
||
<button class="btn btn-sm">Small · 28h</button>
|
||
<button class="btn">Default · 32h</button>
|
||
<button class="btn btn-lg">Large · 40h</button>
|
||
</div>
|
||
<div class="btn-row" style="margin-top:12px">
|
||
<button class="btn btn-primary btn-sm">Small</button>
|
||
<button class="btn btn-primary">Default</button>
|
||
<button class="btn btn-primary btn-lg">Large</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §6 PILLS -->
|
||
<!-- =========================================== -->
|
||
<section id="pills">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §6 · PILLS</span>
|
||
<h2>胶囊 · 严格 3 级分层</h2>
|
||
<p><strong style="color:var(--ink)">同级别尺寸必须完全一致。</strong>不允许混用。pill 永远是 <code class="mono" style="background:var(--bg-soft);padding:1px 6px;border-radius:4px">999 px</code>(完全圆),靠 dot 体现状态。</p>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>L1 · 大胶囊 <span class="mono-num">// h:28 / fs:13 / dot:8</span></h3>
|
||
<p class="lead">用于项目状态、列表行主标签。</p>
|
||
<div class="pill-row">
|
||
<span class="pill pill-l1 pill-info"><span class="dot"></span>生成中</span>
|
||
<span class="pill pill-l1 pill-ok"><span class="dot"></span>已完成</span>
|
||
<span class="pill pill-l1 pill-err"><span class="dot"></span>失败</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>L2 · 中胶囊 <span class="mono-num">// h:22 / fs:11.5 / dot:6 ★ 默认</span></h3>
|
||
<p class="lead">最常用尺寸。卡片内 / 表格内默认。</p>
|
||
<div class="pill-row">
|
||
<span class="pill pill-l2 pill-info"><span class="dot"></span>生成中</span>
|
||
<span class="pill pill-l2 pill-ok"><span class="dot"></span>200 OK</span>
|
||
<span class="pill pill-l2 pill-err"><span class="dot"></span>超时</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>L3 · 小胶囊 <span class="mono-num">// h:18 / fs:10.5 / dot:5</span></h3>
|
||
<p class="lead">KPI 角标 / 行内 Mono 标签场景。</p>
|
||
<div class="pill-row">
|
||
<span class="pill pill-l3 pill-info"><span class="dot"></span>NEW</span>
|
||
<span class="pill pill-l3 pill-ok"><span class="dot"></span>+33%</span>
|
||
<span class="pill pill-l3 pill-err"><span class="dot"></span>-1.2%</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>对比展示 <span class="mono-num">// 同色 3 级并列看大小差距</span></h3>
|
||
<div class="card" style="display:flex;gap:14px;align-items:center;flex-wrap:wrap">
|
||
<span class="pill pill-l1 pill-info"><span class="dot"></span>L1 · 生成中</span>
|
||
<span class="pill pill-l2 pill-info"><span class="dot"></span>L2 · 生成中</span>
|
||
<span class="pill pill-l3 pill-info"><span class="dot"></span>L3 · 生成中</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §7 INPUTS -->
|
||
<!-- =========================================== -->
|
||
<section id="inputs">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §7 · INPUTS</span>
|
||
<h2>输入框 · 5 状态</h2>
|
||
<p>同样用 inside-border。focused 时橙色 ring 2 px,error 时红色边框 + 红色软底。点击下方各字段可看到真实 focus 反馈。</p>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<div class="field-row"><span class="lbl">// default</span><div class="input-wrap"><input class="input" placeholder="搜索商品 / 项目..."/></div></div>
|
||
<div class="field-row"><span class="lbl">// hover</span><div class="input-wrap" style="--hover:1" onmouseenter="this.classList.add('is-hover-demo')" onmouseleave="this.classList.remove('is-hover-demo')"><input class="input" placeholder="hover 我看效果"/></div></div>
|
||
<div class="field-row"><span class="lbl">// focused</span><div class="input-wrap is-focus"><input class="input" value="已聚焦"/></div></div>
|
||
<div class="field-row"><span class="lbl">// error</span><div class="input-wrap is-error"><input class="input" value="invalid@example"/></div></div>
|
||
<div class="field-row"><span class="lbl">// disabled</span><div class="input-wrap is-disabled"><input class="input" placeholder="不可编辑" disabled/></div></div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>带图标 / 搜索 <span class="mono-num">// 含 Ctrl+K 提示</span></h3>
|
||
<div class="search-wrap input-wrap">
|
||
<svg class="ic-left" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
|
||
<input class="input" placeholder="搜索任意内容..."/>
|
||
<span class="k">Ctrl K</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §8 FORM CONTROLS -->
|
||
<!-- =========================================== -->
|
||
<section id="form-controls">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §8 · FORM CONTROLS</span>
|
||
<h2>表单控件</h2>
|
||
<p>Checkbox / Radio / Switch 全部可点击。disabled 状态也可演示。</p>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>Checkbox</h3>
|
||
<div class="ck-row">
|
||
<label class="ck"><input type="checkbox"/><span class="ck-box"></span>未选中</label>
|
||
<label class="ck"><input type="checkbox" checked/><span class="ck-box"></span>已选中</label>
|
||
<label class="ck is-indeterminate"><input type="checkbox"/><span class="ck-box"></span>半选中</label>
|
||
<label class="ck is-disabled"><input type="checkbox" disabled/><span class="ck-box"></span>Disabled</label>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>Radio</h3>
|
||
<div class="ck-row">
|
||
<label class="rd"><input type="radio" name="rdemo"/><span class="rd-box"></span>选项 A</label>
|
||
<label class="rd"><input type="radio" name="rdemo" checked/><span class="rd-box"></span>选项 B(已选)</label>
|
||
<label class="rd"><input type="radio" name="rdemo"/><span class="rd-box"></span>选项 C</label>
|
||
<label class="rd" style="opacity:.5;cursor:not-allowed"><input type="radio" disabled/><span class="rd-box"></span>Disabled</label>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>Switch</h3>
|
||
<div class="ck-row">
|
||
<label class="sw"><input type="checkbox"/><span class="sw-box"></span>关</label>
|
||
<label class="sw"><input type="checkbox" checked/><span class="sw-box"></span>开</label>
|
||
<label class="sw is-disabled"><input type="checkbox" disabled/><span class="sw-box"></span>Disabled</label>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §9 TABS -->
|
||
<!-- =========================================== -->
|
||
<section id="tabs">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §9 · TABS</span>
|
||
<h2>Tab · 双层结构</h2>
|
||
<p>主 Tab 在区块顶部,带橙色下划线指示;副 Tab 用于过滤,带灰度→彩色 icon 反馈。点击切换。</p>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>主 Tab</h3>
|
||
<div class="tabs" data-tabs>
|
||
<button class="tab is-active" data-tab="all">全部</button>
|
||
<button class="tab" data-tab="img">商品图</button>
|
||
<button class="tab" data-tab="vid">短视频</button>
|
||
<button class="tab" data-tab="ad">投放素材</button>
|
||
</div>
|
||
<div class="card">当前显示:<span data-tab-content style="color:var(--heat)">全部</span></div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>副 Tab · 灰度→彩色</h3>
|
||
<div class="subtabs" data-subtabs>
|
||
<button class="subtab is-active"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>Search</button>
|
||
<div class="subtab-divider"></div>
|
||
<button class="subtab"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg>Scrape</button>
|
||
<div class="subtab-divider"></div>
|
||
<button class="subtab"><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="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>Parse</button>
|
||
<div class="subtab-divider"></div>
|
||
<button class="subtab"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="3 6 9 3 15 6 21 3 21 18 15 21 9 18 3 21 3 6"/></svg>Map</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §10 CARDS / SHORTCUT -->
|
||
<!-- =========================================== -->
|
||
<section id="cards">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §10 · CARDS</span>
|
||
<h2>卡片 / 快捷入口</h2>
|
||
<p>所有卡片统一 8 px 圆角、1 px 边框、无阴影。快捷入口含 hover / active 状态。</p>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>快捷入口 <span class="mono-num">// hover 我</span></h3>
|
||
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px">
|
||
<a class="shortcut" href="#">
|
||
<div class="icon-box"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg></div>
|
||
<div class="meta"><div class="title">新建商品</div><div class="desc">// AI 生成 / 上传图</div></div>
|
||
</a>
|
||
<a class="shortcut" href="#">
|
||
<div class="icon-box"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="20" height="12" rx="2"/><path d="m10 9 5 3-5 3z" fill="currentColor"/></svg></div>
|
||
<div class="meta"><div class="title">短视频工坊</div><div class="desc">// 9:16 · MP4</div></div>
|
||
</a>
|
||
<a class="shortcut" href="#">
|
||
<div class="icon-box"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></div>
|
||
<div class="meta"><div class="title">投放话术库</div><div class="desc">// /v2 · 模板</div></div>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §11 KPI STATS -->
|
||
<!-- =========================================== -->
|
||
<section id="stats">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §11 · KPI</span>
|
||
<h2>统计行 · 4 格 stats</h2>
|
||
</div>
|
||
|
||
<div class="stats">
|
||
<div class="cell">
|
||
<div class="lbl-row"><span class="lbl">本月营收</span><span class="pill pill-l3 pill-ok"><span class="dot"></span>+33%</span></div>
|
||
<div class="num">¥327<small>.40 K</small></div>
|
||
<div class="delta"><span class="up">↑ 较上月 +33%</span></div>
|
||
</div>
|
||
<div class="cell">
|
||
<div class="lbl-row"><span class="lbl">活跃项目</span></div>
|
||
<div class="num">12</div>
|
||
<div class="delta">↑ 本月 +3</div>
|
||
</div>
|
||
<div class="cell">
|
||
<div class="lbl-row"><span class="lbl">生成中</span><span class="pill pill-l3 pill-info"><span class="dot"></span>RUNNING</span></div>
|
||
<div class="num">5</div>
|
||
<div class="prog"><span class="done"></span><span class="done"></span><span class="now"></span><span></span><span></span></div>
|
||
</div>
|
||
<div class="cell">
|
||
<div class="lbl-row"><span class="lbl">资产总数</span></div>
|
||
<div class="num">847</div>
|
||
<div class="delta">·MP4·JPG·PNG</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §12 LIST ROW -->
|
||
<!-- =========================================== -->
|
||
<section id="list">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §12 · LIST</span>
|
||
<h2>列表行</h2>
|
||
<p>hover 我看整行底色变化。</p>
|
||
</div>
|
||
|
||
<div class="list-card">
|
||
<div class="list-row">
|
||
<div class="thumb">9:16</div>
|
||
<div class="meta"><div class="ti">夏季新款蕾丝连衣裙</div><div class="sub">// 创建于 05.14 · 蓝色 / M</div></div>
|
||
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="now"></span><span></span></div>
|
||
<span class="pill pill-l2 pill-info"><span class="dot"></span>生成中</span>
|
||
<button class="btn btn-sm">查看</button>
|
||
</div>
|
||
<div class="list-row">
|
||
<div class="thumb">4:5</div>
|
||
<div class="meta"><div class="ti">秋季风衣 · 卡其色</div><div class="sub">// 创建于 05.12 · M / L</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 pill-l2 pill-ok"><span class="dot"></span>已完成</span>
|
||
<button class="btn btn-sm">导出</button>
|
||
</div>
|
||
<div class="list-row">
|
||
<div class="thumb">1:1</div>
|
||
<div class="meta"><div class="ti">运动 T 恤 · 黑白款</div><div class="sub">// 创建于 05.10 · 全色系</div></div>
|
||
<div class="prog"><span class="done"></span><span class="err"></span><span></span><span></span><span></span></div>
|
||
<span class="pill pill-l2 pill-err"><span class="dot"></span>生成失败</span>
|
||
<button class="btn btn-sm">重试</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §13 TIP / PROGRESS -->
|
||
<!-- =========================================== -->
|
||
<section id="tip">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §13 · TIP</span>
|
||
<h2>提示框 / 进度</h2>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<div class="tip" style="max-width:560px">
|
||
<div class="head">小提示</div>
|
||
<div class="body">使用 <span class="mono-code">Ctrl+K</span> 快速搜索任意项目、商品或资产。Tab 切换不同维度,Enter 直达。</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>进度条段位 <span class="mono-num">// 5 段 · 流水线专用</span></h3>
|
||
<div style="display:flex;gap:24px;flex-wrap:wrap">
|
||
<div><div class="prog"><span></span><span></span><span></span><span></span><span></span></div><div class="mono" style="margin-top:6px">未开始</div></div>
|
||
<div><div class="prog"><span class="done"></span><span class="done"></span><span class="now"></span><span></span><span></span></div><div class="mono" style="margin-top:6px">进行中(2/5)</div></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><div class="mono" style="margin-top:6px">已完成</div></div>
|
||
<div><div class="prog"><span class="done"></span><span class="err"></span><span></span><span></span><span></span></div><div class="mono" style="margin-top:6px">失败</div></div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §14 MODAL -->
|
||
<!-- =========================================== -->
|
||
<section id="modal">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §14 · MODAL</span>
|
||
<h2>弹窗 Modal</h2>
|
||
<p>点击下方按钮打开。ESC / 点击遮罩关闭。带 4 角 SVG 准星 + 8 px 圆角 + 半透明遮罩 + 弹性入场。</p>
|
||
</div>
|
||
|
||
<button class="btn btn-primary" id="open-modal">打开 Modal Demo</button>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §15 TOAST -->
|
||
<!-- =========================================== -->
|
||
<section id="toast">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §15 · TOAST</span>
|
||
<h2>Toast 通知</h2>
|
||
<p>右下角浮出。300ms 弹性入场,2400ms 自动消失。</p>
|
||
</div>
|
||
|
||
<div style="display:flex;gap:10px;flex-wrap:wrap">
|
||
<button class="btn" data-toast='{"ti":"项目已保存","sub":"// 200 OK · /projects/12"}'>触发默认 Toast</button>
|
||
<button class="btn btn-primary" data-toast='{"ti":"商品生成完成","sub":"// 4 张待审核 · 02:34"}'>主 CTA Toast</button>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §16 CONTAINER -->
|
||
<!-- =========================================== -->
|
||
<section id="container">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §16 · SIGNATURE</span>
|
||
<h2>主容器装订线</h2>
|
||
<p>整个工作区被左右两条 1 px 边线包夹,四角放圆弧内凹的 SVG 准星。这是流·Studio 视觉的"图纸"签名。Modal 内不必加。</p>
|
||
</div>
|
||
|
||
<div class="container-demo">
|
||
<svg class="corner tl" viewBox="0 0 22 21" fill="currentColor"><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"/></svg>
|
||
<svg class="corner tr" viewBox="0 0 22 21" fill="currentColor"><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"/></svg>
|
||
<svg class="corner bl" viewBox="0 0 22 21" fill="currentColor"><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"/></svg>
|
||
<svg class="corner br" viewBox="0 0 22 21" fill="currentColor"><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"/></svg>
|
||
<div class="inner">
|
||
这块容器左右贯穿两条 1 px 边线,四角带圆弧内凹的 SVG 准星<br>
|
||
<span class="mono">// container-demo · max-width: 720 · border-x only</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §17 MONO DECOR -->
|
||
<!-- =========================================== -->
|
||
<section id="mono-decor">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §17 · DECOR</span>
|
||
<h2>Mono 装饰元素 · 品牌签名</h2>
|
||
<p>方括号标签 / 双斜杠注释 / 中点连接 —— 这些是流·Studio 独有的"调试视图感",Firecrawl 没有,绝对保留。</p>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>方括号标签</h3>
|
||
<div class="mono-sample-row">
|
||
<span class="mono-tag-sample">[ 200 OK ]</span>
|
||
<span class="mono-tag-sample">[ /v2 ]</span>
|
||
<span class="mono-tag-sample">[ .MP4 · 9:16 ]</span>
|
||
<span class="mono-tag-sample heat">[ STUDIO ]</span>
|
||
<span class="mono-tag-sample">[ ALL · 12 ] →</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>注释样式时间戳</h3>
|
||
<div class="mono" style="font-size:13px">// 05.14 · 周五 · 14:32</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>命令路径</h3>
|
||
<div class="mono" style="font-size:13px;color:var(--ink-alpha-64)">/sidebar collapse · /toast dismiss · /modal open</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>ASCII 散点(背景装饰)</h3>
|
||
<div style="font-family:var(--font-mono);font-size:11px;color:var(--ink-alpha-12);line-height:1.4;letter-spacing:.04em;background:var(--card);border:1px solid var(--border-faint);border-radius:var(--r-md);padding:18px 22px">
|
||
· · +<br>
|
||
· +XX+<br>
|
||
+XXXX·<br>
|
||
+X·
|
||
</div>
|
||
</div>
|
||
|
||
<div class="subsection">
|
||
<h3>强调单词上色</h3>
|
||
<p style="font-size:13.5px;color:var(--ink-alpha-72);max-width:680px;line-height:1.7">
|
||
本月营收较上月增长 <b style="color:var(--ink)">+33%</b>,有 <b style="color:var(--ink)">5 个项目</b>处于"生成中"状态。其中 <b style="color:var(--ink)">2 个</b>需要重新调整模特模板。
|
||
</p>
|
||
<p class="mono" style="margin-top:8px">// 关键名词加深一档(不变橙),橙色只留给 CTA</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- =========================================== -->
|
||
<!-- §18 DON'T LIST -->
|
||
<!-- =========================================== -->
|
||
<section id="dont">
|
||
<div class="section-head">
|
||
<span class="mono-tag">// §18 · GUARDRAILS</span>
|
||
<h2>Don't List · 绝对禁止</h2>
|
||
<p>任何 mockup / 代码 review 时,对照此清单。每一条违反都判错。</p>
|
||
</div>
|
||
|
||
<div class="dodont-grid">
|
||
<div class="dodont do">
|
||
<span class="head">DO</span>
|
||
<div class="body">用 8 px 统一圆角 + 准星 + 装订线 + mono 装饰做"图纸感"</div>
|
||
</div>
|
||
<div class="dodont dont">
|
||
<span class="head">DON'T</span>
|
||
<div class="body">用 0 px 硬切角的卡片 —— V1 的做法,V2 起判错</div>
|
||
</div>
|
||
<div class="dodont do">
|
||
<span class="head">DO</span>
|
||
<div class="body">橙色 hover 用 <code class="mono" style="background:var(--card);padding:1px 5px;border-radius:3px;color:var(--heat)">--heat-90</code> 等 alpha 阶梯</div>
|
||
</div>
|
||
<div class="dodont dont">
|
||
<span class="head">DON'T</span>
|
||
<div class="body">hover 时切换到更深的橙 hex(如 #D04E1F)</div>
|
||
</div>
|
||
<div class="dodont do">
|
||
<span class="head">DO</span>
|
||
<div class="body">主 CTA 用多层橙色阴影(4 层)制造发光感</div>
|
||
</div>
|
||
<div class="dodont dont">
|
||
<span class="head">DON'T</span>
|
||
<div class="body">用灰色阴影 / 文字阴影 / 通用 box-shadow 装饰</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" style="margin-top:18px;padding:18px 22px">
|
||
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--ink)">渐变背景</strong> —— 只有 hero 区可考虑,首选纯色。绝禁多色渐变。</span></div>
|
||
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--ink)">玻璃拟态</strong> —— <code class="mono" style="background:var(--bg-soft);padding:1px 5px;border-radius:3px">backdrop-filter</code> 只用于 modal 遮罩。</span></div>
|
||
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--ink)">彩色 emoji</strong> —— 所有图标必须 SVG line(stroke 1.5)。</span></div>
|
||
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--ink)">多 accent 色</strong> —— 全场只有橙色一个 accent。</span></div>
|
||
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--ink)">大圆角容器</strong>(>12 px)—— 直接判错。</span></div>
|
||
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--ink)">鲜艳荧光状态色</strong> —— 避免霓虹绿、电光蓝、霓虹粉。</span></div>
|
||
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--ink)">居中对齐大段正文</strong> —— 全部左对齐。</span></div>
|
||
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--ink)">装饰当主角</strong> —— 场记板 / 丝绒 / 霓虹灯都不要。</span></div>
|
||
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--ink)">无意义微动效</strong> —— hover 旋转、缩放、彩虹流光,禁。</span></div>
|
||
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--ink)">同行混用直角+圆角</strong> —— 用户原话:"不要有些是直角,胶囊又是圆角"。</span></div>
|
||
</div>
|
||
</section>
|
||
|
||
</main>
|
||
</div>
|
||
|
||
<!-- ===== Modal HTML ===== -->
|
||
<div class="modal-mask" id="modal-mask">
|
||
<div class="modal" role="dialog">
|
||
<svg class="corner tl" viewBox="0 0 22 21" fill="currentColor"><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"/></svg>
|
||
<svg class="corner tr" viewBox="0 0 22 21" fill="currentColor"><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"/></svg>
|
||
<svg class="corner bl" viewBox="0 0 22 21" fill="currentColor"><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"/></svg>
|
||
<svg class="corner br" viewBox="0 0 22 21" fill="currentColor"><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"/></svg>
|
||
<div class="head">
|
||
<div class="ic-box"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 8v4M12 16h.01"/></svg></div>
|
||
<div>
|
||
<div class="ti">确认删除此商品?</div>
|
||
<div class="sub">// /products/dlt · IRREVERSIBLE</div>
|
||
</div>
|
||
</div>
|
||
<div class="body">
|
||
该操作不可撤销。商品「夏季新款蕾丝连衣裙」及其关联的 <b style="color:var(--ink)">4 张候选图</b>、<b style="color:var(--ink)">2 段短视频</b>将一并删除。
|
||
</div>
|
||
<div class="foot">
|
||
<button class="btn" data-close-modal>取消</button>
|
||
<button class="btn btn-primary">确认删除</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ===== Toast container ===== -->
|
||
<div class="toast-stack" id="toast-stack"></div>
|
||
|
||
<script>
|
||
// ---- Copy hex on click ----
|
||
document.querySelectorAll('[data-copy-grid] .swatch').forEach(sw => {
|
||
sw.addEventListener('click', () => {
|
||
const hex = sw.dataset.hex;
|
||
navigator.clipboard?.writeText(hex);
|
||
sw.classList.add('copied');
|
||
setTimeout(() => sw.classList.remove('copied'), 1200);
|
||
});
|
||
});
|
||
|
||
// ---- Input wrapper focus state ----
|
||
document.querySelectorAll('.input').forEach(inp => {
|
||
const wrap = inp.closest('.input-wrap');
|
||
if (!wrap || wrap.classList.contains('is-focus') || wrap.classList.contains('is-error') || wrap.classList.contains('is-disabled')) return;
|
||
inp.addEventListener('focus', () => wrap.classList.add('is-focus'));
|
||
inp.addEventListener('blur', () => wrap.classList.remove('is-focus'));
|
||
});
|
||
|
||
// ---- Checkbox indeterminate visual toggle on click ----
|
||
document.querySelectorAll('.ck.is-indeterminate input').forEach(cb => {
|
||
cb.addEventListener('change', e => {
|
||
e.target.closest('.ck').classList.remove('is-indeterminate');
|
||
});
|
||
});
|
||
|
||
// ---- Tabs ----
|
||
document.querySelectorAll('[data-tabs]').forEach(group => {
|
||
const out = document.querySelector('[data-tab-content]');
|
||
group.addEventListener('click', e => {
|
||
const btn = e.target.closest('.tab');
|
||
if (!btn) return;
|
||
group.querySelectorAll('.tab').forEach(b => b.classList.remove('is-active'));
|
||
btn.classList.add('is-active');
|
||
if (out) out.textContent = btn.textContent;
|
||
});
|
||
});
|
||
|
||
// ---- Subtabs ----
|
||
document.querySelectorAll('[data-subtabs]').forEach(group => {
|
||
group.addEventListener('click', e => {
|
||
const btn = e.target.closest('.subtab');
|
||
if (!btn) return;
|
||
group.querySelectorAll('.subtab').forEach(b => b.classList.remove('is-active'));
|
||
btn.classList.add('is-active');
|
||
});
|
||
});
|
||
|
||
// ---- Modal ----
|
||
const mask = document.getElementById('modal-mask');
|
||
document.getElementById('open-modal').addEventListener('click', () => mask.classList.add('is-open'));
|
||
mask.addEventListener('click', e => {
|
||
if (e.target === mask || e.target.matches('[data-close-modal]')) mask.classList.remove('is-open');
|
||
});
|
||
document.addEventListener('keydown', e => { if (e.key === 'Escape') mask.classList.remove('is-open') });
|
||
|
||
// ---- Toast ----
|
||
const stack = document.getElementById('toast-stack');
|
||
document.querySelectorAll('[data-toast]').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
const data = JSON.parse(btn.dataset.toast);
|
||
const t = document.createElement('div');
|
||
t.className = 'toast';
|
||
t.innerHTML = `
|
||
<div class="ic-box"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div>
|
||
<div><div class="ti">${data.ti}</div><div class="sub">${data.sub}</div></div>
|
||
`;
|
||
stack.appendChild(t);
|
||
setTimeout(() => { t.classList.add('is-leave'); setTimeout(() => t.remove(), 220) }, 2400);
|
||
});
|
||
});
|
||
|
||
// ---- Nav active on scroll ----
|
||
const navLinks = document.querySelectorAll('.nav-list a');
|
||
const sections = [...document.querySelectorAll('.main > section')];
|
||
function syncNav() {
|
||
const y = window.scrollY + 100;
|
||
let cur = sections[0]?.id;
|
||
sections.forEach(s => { if (s.offsetTop <= y) cur = s.id });
|
||
navLinks.forEach(a => a.classList.toggle('active', a.getAttribute('href') === '#' + cur));
|
||
}
|
||
window.addEventListener('scroll', syncNav, {passive:true});
|
||
syncNav();
|
||
</script>
|
||
</body>
|
||
</html>
|