ad845328fb
design/prototype/index.html:设计系统组件登记簿(照 jiu 骨架,light/dark 双主题)。 顶栏主题切换(持久化 localStorage)+ 左侧 dnav scrollspy 导航 + 分区: ① 色板(clay/sand 色阶 + 语义 token,data-swatches 声明式随主题刷新) ② 字号梯度(display-xl→caption,中英分行不并排) ③ 圆角/间距/阴影比例尺 ④ 公用组件(atoms.css 每个 class 一张展示卡,全变体全态含 disabled) ⑤ 图标库(icons.js 全 57 图标网格) 链 tokens.css + atoms.css + icons.js(相对路径,自包含)。 验证:每个 atom 类均登记、57 图标全展示、主题切换正常、文案脱敏无红线词。 评审:node design/prototype/serve.mjs → http://localhost:5180/ Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
408 lines
28 KiB
HTML
408 lines
28 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>穿山甲 Pangolin · 设计系统</title>
|
||
<link rel="stylesheet" href="tokens.css">
|
||
<link rel="stylesheet" href="atoms.css">
|
||
<script src="icons.js"></script>
|
||
<style>
|
||
/* ── 登记页自身骨架(chrome)— 尽量走 token,登记页外壳可适度宽松 ── */
|
||
body{ margin:0; background:var(--bg); color:var(--fg1); font-family:var(--font-sans);
|
||
-webkit-font-smoothing:antialiased; transition:background-color var(--dur-base) var(--ease-out); overflow-x:hidden; }
|
||
|
||
.ic{ width:22px; height:22px; color:currentColor; }
|
||
|
||
/* 顶栏 */
|
||
.ds-top{ position:sticky; top:0; z-index:50; height:60px; background:var(--surface);
|
||
border-bottom:1px solid var(--border); display:flex; align-items:center; gap:14px;
|
||
padding:0 var(--space-6); box-shadow:var(--shadow-sm); }
|
||
.ds-brand{ display:flex; align-items:center; gap:var(--space-3); font-family:var(--font-display);
|
||
font-weight:700; color:var(--fg1); font-size:var(--text-body); }
|
||
.ds-brand .mk{ width:30px; height:30px; border-radius:var(--radius-md);
|
||
background:linear-gradient(135deg,var(--clay-500),var(--clay-800));
|
||
color:#fff; display:flex; align-items:center; justify-content:center; }
|
||
.ds-brand .mk svg{ width:17px; height:17px; }
|
||
.ds-tag{ font-size:var(--text-caption); color:var(--fg3); padding-left:var(--space-3);
|
||
border-left:1px solid var(--border); font-weight:500; }
|
||
.theme-toggle{ margin-left:auto; display:inline-flex; align-items:center; gap:var(--space-2);
|
||
background:var(--bg-subtle); border:1px solid var(--border); color:var(--fg2);
|
||
border-radius:var(--radius-full); padding:var(--space-2) var(--space-4);
|
||
font-family:var(--font-sans); font-weight:600; font-size:var(--text-caption);
|
||
cursor:pointer; transition:border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out); }
|
||
.theme-toggle:hover{ border-color:var(--border-strong); color:var(--fg1); }
|
||
.theme-toggle svg{ width:15px; height:15px; }
|
||
|
||
/* 三栏文档布局 */
|
||
.doc{ display:flex; align-items:flex-start; max-width:1360px; margin:0 auto; }
|
||
.doc-nav{ width:238px; flex:none; position:sticky; top:60px; height:calc(100vh - 60px);
|
||
overflow:auto; border-right:1px solid var(--border); padding:var(--space-5) var(--space-4); }
|
||
.dgroup{ font-size:var(--text-caption); font-weight:700; color:var(--fg3); letter-spacing:var(--tracking-caps);
|
||
text-transform:uppercase; padding:var(--space-4) var(--space-2) var(--space-2); }
|
||
.dnav{ display:block; padding:var(--space-2) var(--space-3); border-radius:var(--radius-md);
|
||
font-size:var(--text-sm); color:var(--fg2); text-decoration:none; cursor:pointer;
|
||
transition:background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out); }
|
||
.dnav:hover{ background:var(--bg-subtle); color:var(--fg1); }
|
||
.dnav.on{ background:var(--accent-subtle); color:var(--accent); font-weight:600; }
|
||
|
||
.doc-main{ flex:1; min-width:0; padding:var(--space-8) var(--space-10) var(--space-16); max-width:1080px; }
|
||
.section{ margin-bottom:var(--space-12); scroll-margin-top:76px; }
|
||
.section > h2{ margin:0 0 var(--space-1); font-family:var(--font-display); font-size:var(--text-h1);
|
||
font-weight:700; letter-spacing:var(--tracking-tight); color:var(--fg1); }
|
||
.section > .desc{ margin:0 0 var(--space-5); font-size:var(--text-sm); color:var(--fg2); line-height:var(--leading-normal); }
|
||
.section > .desc code{ font-family:var(--font-mono); font-size:0.85em; color:var(--accent);
|
||
background:var(--accent-subtle); padding:1px 6px; border-radius:var(--radius-sm); }
|
||
|
||
/* 展示卡(页面 chrome,非 atoms.card 以免混淆语义) */
|
||
.pcard{ background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-lg);
|
||
margin-bottom:var(--space-4); overflow:hidden; }
|
||
.pcard-h{ display:flex; align-items:baseline; gap:var(--space-3); padding:var(--space-3) var(--space-5);
|
||
border-bottom:1px solid var(--border); }
|
||
.pcard-h h3{ margin:0; font-family:var(--font-sans); font-size:var(--text-h3); font-weight:600; color:var(--fg1); }
|
||
.pcard-h .tk{ font-size:var(--text-caption); color:var(--fg3); font-family:var(--font-mono); }
|
||
.pcard-b{ padding:var(--space-5); display:flex; flex-wrap:wrap; gap:var(--space-4); align-items:center; }
|
||
.pcard-b.col{ display:block; }
|
||
.cap{ width:100%; font-size:var(--text-caption); color:var(--fg3); font-family:var(--font-mono);
|
||
margin:var(--space-4) 0 var(--space-2); }
|
||
.cap:first-child{ margin-top:0; }
|
||
|
||
/* 色板 */
|
||
.sw-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:var(--space-3); width:100%; }
|
||
.sw{ border:1px solid var(--border); border-radius:var(--radius-md); overflow:hidden; background:var(--surface); }
|
||
.sw .band{ display:block; width:100%; height:56px; box-shadow:inset 0 0 0 1px rgba(45,30,20,.08); }
|
||
.sw .m{ padding:var(--space-2) var(--space-3); }
|
||
.sw .m .n{ font-size:var(--text-caption); color:var(--fg1); font-weight:600; }
|
||
.sw .m .v{ font-size:11px; color:var(--fg3); font-family:var(--font-mono); }
|
||
|
||
/* 字号梯度 */
|
||
.type-row{ display:flex; align-items:baseline; gap:var(--space-5); padding:var(--space-3) 0;
|
||
border-bottom:1px solid var(--border); width:100%; }
|
||
.type-row:last-child{ border-bottom:none; }
|
||
.type-row .tk{ width:170px; font-size:var(--text-caption); color:var(--fg3);
|
||
font-family:var(--font-mono); flex:none; }
|
||
.type-row .spec{ display:flex; flex-direction:column; gap:2px; min-width:0; }
|
||
|
||
/* 圆角 / 间距 / 阴影 比例尺 */
|
||
.scale{ display:flex; flex-wrap:wrap; gap:var(--space-5); align-items:flex-end; width:100%; }
|
||
.scale .box{ display:flex; flex-direction:column; align-items:center; gap:var(--space-2);
|
||
font-size:var(--text-caption); color:var(--fg2); font-family:var(--font-mono); }
|
||
.scale .rq{ width:60px; height:60px; background:var(--accent-subtle); border:1.5px solid var(--accent); }
|
||
.scale .sq{ height:38px; background:var(--accent); border-radius:2px; }
|
||
.scale .sh{ width:72px; height:52px; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-md); }
|
||
|
||
/* 图标库网格 */
|
||
.icon-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(108px,1fr)); gap:var(--space-2); width:100%; }
|
||
.icell{ display:flex; flex-direction:column; align-items:center; gap:var(--space-2);
|
||
padding:var(--space-4) var(--space-2); border:1px solid var(--border);
|
||
border-radius:var(--radius-md); background:var(--surface); color:var(--fg1); }
|
||
.icell .ic{ width:24px; height:24px; }
|
||
.icell span{ font-size:11px; color:var(--fg2); font-family:var(--font-mono); text-align:center; word-break:break-all; line-height:1.3; }
|
||
.count-pill{ font-family:var(--font-sans); }
|
||
|
||
@media (max-width:840px){
|
||
.doc-nav{ display:none; }
|
||
.doc-main{ padding:var(--space-6) var(--space-5) var(--space-12); }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="ds-top">
|
||
<div class="ds-brand"><span class="mk"><svg class="ic"><use href="#i-shield-check"/></svg></span>穿山甲 Pangolin</div>
|
||
<span class="ds-tag">设计系统登记簿 · Prototype</span>
|
||
<button class="theme-toggle" id="themeBtn" aria-label="切换主题">
|
||
<svg class="ic"><use href="#i-sun" id="themeIcon"/></svg><span id="themeLabel">浅色</span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="doc">
|
||
<nav class="doc-nav" id="docNav">
|
||
<div class="dgroup">色彩 Colors</div>
|
||
<a class="dnav" data-s="c-clay">clay 黏土铜色阶</a>
|
||
<a class="dnav" data-s="c-sand">sand 沙米中性阶</a>
|
||
<a class="dnav" data-s="c-hue">语义色相</a>
|
||
<a class="dnav" data-s="c-sem">语义 token</a>
|
||
<div class="dgroup">字体 Type</div>
|
||
<a class="dnav" data-s="type">字号梯度</a>
|
||
<div class="dgroup">尺度 Scale</div>
|
||
<a class="dnav" data-s="radius">圆角</a>
|
||
<a class="dnav" data-s="space">间距</a>
|
||
<a class="dnav" data-s="shadow">阴影</a>
|
||
<div class="dgroup">组件 Atoms</div>
|
||
<a class="dnav" data-s="a-btn">按钮 .btn</a>
|
||
<a class="dnav" data-s="a-card">卡片 .card</a>
|
||
<a class="dnav" data-s="a-input">输入 .input</a>
|
||
<a class="dnav" data-s="a-pill">胶囊 .pill / .badge</a>
|
||
<a class="dnav" data-s="a-lang">语言下拉 .langsel</a>
|
||
<div class="dgroup">图标 Icons</div>
|
||
<a class="dnav" data-s="icons">Lucide 图标库</a>
|
||
</nav>
|
||
|
||
<main class="doc-main">
|
||
<!-- ══════════ 色彩 ══════════ -->
|
||
<section class="section" id="c-clay">
|
||
<h2>clay · 黏土铜色阶</h2>
|
||
<p class="desc">品牌主色阶(穿山甲鳞甲的暖大地色)。<code>--clay-500</code> 为品牌主色,浅色主题 accent 取 500、深色取 400。</p>
|
||
<div class="pcard"><div class="pcard-b"><div class="sw-grid" data-swatches="--clay-50,--clay-100,--clay-200,--clay-300,--clay-400,--clay-500,--clay-600,--clay-700,--clay-800,--clay-900"></div></div></div>
|
||
</section>
|
||
|
||
<section class="section" id="c-sand">
|
||
<h2>sand · 沙米中性阶</h2>
|
||
<p class="desc">暖中性色阶。浅色画布 <code>--sand-50</code>,深色画布暖 espresso <code>--sand-950</code>(非纯黑)。</p>
|
||
<div class="pcard"><div class="pcard-b"><div class="sw-grid" data-swatches="--sand-50,--sand-100,--sand-200,--sand-300,--sand-400,--sand-500,--sand-600,--sand-700,--sand-800,--sand-900,--sand-950"></div></div></div>
|
||
</section>
|
||
|
||
<section class="section" id="c-hue">
|
||
<h2>语义色相</h2>
|
||
<p class="desc">地色调校过的三组状态色相:绿=连接/安全,琥珀=连接中/提示,红=断开/错误。</p>
|
||
<div class="pcard"><div class="pcard-b"><div class="sw-grid" data-swatches="--green-400,--green-500,--green-600,--amber-400,--amber-500,--amber-600,--red-400,--red-500,--red-600"></div></div></div>
|
||
</section>
|
||
|
||
<section class="section" id="c-sem">
|
||
<h2>语义 token</h2>
|
||
<p class="desc">界面只引用这一层(浅/深自动切换)。切右上主题看色值实时变化。</p>
|
||
<div class="pcard"><div class="pcard-h"><h3>背景 / 表面</h3><span class="tk">--bg · --surface · --overlay</span></div><div class="pcard-b"><div class="sw-grid" data-swatches="--bg,--bg-subtle,--surface,--surface-2,--overlay"></div></div></div>
|
||
<div class="pcard"><div class="pcard-h"><h3>前景 / 文本</h3><span class="tk">--fg1/2/3 · --fg-on-accent</span></div><div class="pcard-b"><div class="sw-grid" data-swatches="--fg1,--fg2,--fg3,--fg-on-accent"></div></div></div>
|
||
<div class="pcard"><div class="pcard-h"><h3>品牌 accent</h3><span class="tk">--accent(+hover/press/subtle/border)</span></div><div class="pcard-b"><div class="sw-grid" data-swatches="--accent,--accent-hover,--accent-press,--accent-subtle,--accent-border"></div></div></div>
|
||
<div class="pcard"><div class="pcard-h"><h3>描边 / 光环</h3><span class="tk">--border · --border-strong · --ring</span></div><div class="pcard-b"><div class="sw-grid" data-swatches="--border,--border-strong,--ring"></div></div></div>
|
||
<div class="pcard"><div class="pcard-h"><h3>状态语义</h3><span class="tk">success / warning / danger (+ -subtle)</span></div><div class="pcard-b"><div class="sw-grid" data-swatches="--success,--success-subtle,--warning,--warning-subtle,--danger,--danger-subtle"></div></div></div>
|
||
</section>
|
||
|
||
<!-- ══════════ 字号 ══════════ -->
|
||
<section class="section" id="type">
|
||
<h2>字号梯度</h2>
|
||
<p class="desc">Display 用 Sora,正文/UI 用 Manrope,中文伴随 Noto Sans SC,数据用 JetBrains Mono。示例单语显示(中英分行,非并排同句)。</p>
|
||
<div class="pcard"><div class="pcard-b col">
|
||
<div class="type-row"><span class="tk">--text-display-xl 48</span><span class="spec"><span class="t-display-xl">极速畅连</span><span class="t-display-xl">Fast & Stable</span></span></div>
|
||
<div class="type-row"><span class="tk">--text-display 36</span><span class="spec"><span class="t-display">网络加速</span><span class="t-display">Network Boost</span></span></div>
|
||
<div class="type-row"><span class="tk">--text-h1 30</span><span class="spec"><span class="t-h1">一键连接</span><span class="t-h1">One-tap Connect</span></span></div>
|
||
<div class="type-row"><span class="tk">--text-h2 24</span><span class="spec"><span class="t-h2">智能选线</span><span class="t-h2">Smart Routing</span></span></div>
|
||
<div class="type-row"><span class="tk">--text-h3 20</span><span class="spec"><span class="t-h3">隐私保护</span><span class="t-h3">Privacy First</span></span></div>
|
||
<div class="type-row"><span class="tk">--text-body-lg 18</span><span class="spec"><span class="t-body-lg">稳定加速线路,即开即用。</span><span class="t-body-lg">Stable links, ready instantly.</span></span></div>
|
||
<div class="type-row"><span class="tk">--text-body 16</span><span class="spec"><span class="t-body">正文与界面主力字号,兼顾中英排版。</span><span class="t-body">Body copy for UI and long-form reading.</span></span></div>
|
||
<div class="type-row"><span class="tk">--text-sm 14</span><span class="spec"><span class="t-sm">次要说明与表单标签。</span><span class="t-sm">Secondary hints and form labels.</span></span></div>
|
||
<div class="type-row"><span class="tk">--text-caption 12</span><span class="spec"><span class="t-caption">辅助注释与胶囊文字。</span><span class="t-caption">Captions and pill text.</span></span></div>
|
||
<div class="type-row"><span class="tk">.t-overline</span><span class="spec"><span class="t-overline">连接状态</span><span class="t-overline">Connection Status</span></span></div>
|
||
<div class="type-row"><span class="tk">.t-mono 数据</span><span class="spec"><span class="t-mono">103.119.13.48 · 42 ms · 1.28 GB</span></span></div>
|
||
</div></div>
|
||
</section>
|
||
|
||
<!-- ══════════ 尺度 ══════════ -->
|
||
<section class="section" id="radius">
|
||
<h2>圆角 Radius</h2>
|
||
<p class="desc">偏大圆角传递亲和。按钮全胶囊 <code>--radius-full</code>,卡片 lg–xl,输入 md。</p>
|
||
<div class="pcard"><div class="pcard-b"><div class="scale">
|
||
<div class="box"><div class="rq" style="border-radius:var(--radius-sm)"></div>sm · 6</div>
|
||
<div class="box"><div class="rq" style="border-radius:var(--radius-md)"></div>md · 10</div>
|
||
<div class="box"><div class="rq" style="border-radius:var(--radius-lg)"></div>lg · 14</div>
|
||
<div class="box"><div class="rq" style="border-radius:var(--radius-xl)"></div>xl · 20</div>
|
||
<div class="box"><div class="rq" style="border-radius:var(--radius-2xl)"></div>2xl · 28</div>
|
||
<div class="box"><div class="rq" style="border-radius:var(--radius-full)"></div>full · 999</div>
|
||
</div></div></div>
|
||
</section>
|
||
|
||
<section class="section" id="space">
|
||
<h2>间距 Spacing</h2>
|
||
<p class="desc">4px 基准网格。</p>
|
||
<div class="pcard"><div class="pcard-b"><div class="scale">
|
||
<div class="box"><div class="sq" style="width:var(--space-1)"></div>1 · 4</div>
|
||
<div class="box"><div class="sq" style="width:var(--space-2)"></div>2 · 8</div>
|
||
<div class="box"><div class="sq" style="width:var(--space-3)"></div>3 · 12</div>
|
||
<div class="box"><div class="sq" style="width:var(--space-4)"></div>4 · 16</div>
|
||
<div class="box"><div class="sq" style="width:var(--space-5)"></div>5 · 20</div>
|
||
<div class="box"><div class="sq" style="width:var(--space-6)"></div>6 · 24</div>
|
||
<div class="box"><div class="sq" style="width:var(--space-8)"></div>8 · 32</div>
|
||
<div class="box"><div class="sq" style="width:var(--space-10)"></div>10 · 40</div>
|
||
<div class="box"><div class="sq" style="width:var(--space-12)"></div>12 · 48</div>
|
||
<div class="box"><div class="sq" style="width:var(--space-16)"></div>16 · 64</div>
|
||
</div></div></div>
|
||
</section>
|
||
|
||
<section class="section" id="shadow">
|
||
<h2>阴影 Shadow</h2>
|
||
<p class="desc">柔和暖调(<code>rgba(45,30,20,…)</code>),绝不用冷灰阴影。</p>
|
||
<div class="pcard"><div class="pcard-b"><div class="scale">
|
||
<div class="box"><div class="sh" style="box-shadow:var(--shadow-sm)"></div>sm</div>
|
||
<div class="box"><div class="sh" style="box-shadow:var(--shadow-md)"></div>md</div>
|
||
<div class="box"><div class="sh" style="box-shadow:var(--shadow-lg)"></div>lg</div>
|
||
<div class="box"><div class="sh" style="box-shadow:var(--shadow-xl)"></div>xl</div>
|
||
<div class="box"><div class="sh" style="box-shadow:var(--shadow-focus)"></div>focus</div>
|
||
</div></div></div>
|
||
</section>
|
||
|
||
<!-- ══════════ 组件 ══════════ -->
|
||
<section class="section" id="a-btn">
|
||
<h2>按钮 · .btn</h2>
|
||
<p class="desc">全胶囊圆角 · hover 主色加深 · press 缩放 .97 · focus clay 光环。变体 <code>.btn-primary/-ghost/-subtle/-danger</code>,尺寸 <code>.btn-lg/-icon/-block</code>。</p>
|
||
|
||
<div class="pcard"><div class="pcard-h"><h3>变体</h3><span class="tk">.btn + .btn-primary/-ghost/-subtle/-danger</span></div><div class="pcard-b">
|
||
<button class="btn btn-primary"><svg class="ic"><use href="#i-power"/></svg>点击连接</button>
|
||
<button class="btn btn-ghost"><svg class="ic"><use href="#i-refresh-cw"/></svg>刷新延迟</button>
|
||
<button class="btn btn-subtle"><svg class="ic"><use href="#i-settings"/></svg>偏好设置</button>
|
||
<button class="btn btn-danger"><svg class="ic"><use href="#i-power"/></svg>断开连接</button>
|
||
</div></div>
|
||
|
||
<div class="pcard"><div class="pcard-h"><h3>尺寸 / 形态</h3><span class="tk">.btn-lg · .btn-icon · .btn-block</span></div><div class="pcard-b">
|
||
<button class="btn btn-primary btn-lg"><svg class="ic"><use href="#i-zap"/></svg>智能选择</button>
|
||
<button class="btn btn-primary btn-icon" aria-label="更多"><svg class="ic"><use href="#i-more-vertical"/></svg></button>
|
||
<button class="btn btn-subtle btn-icon" aria-label="搜索"><svg class="ic"><use href="#i-search"/></svg></button>
|
||
<div style="width:100%"><button class="btn btn-primary btn-block"><svg class="ic"><use href="#i-download"/></svg>立即下载</button></div>
|
||
</div></div>
|
||
|
||
<div class="pcard"><div class="pcard-h"><h3>禁用态</h3><span class="tk">:disabled · .is-disabled</span></div><div class="pcard-b">
|
||
<button class="btn btn-primary" disabled>已连接</button>
|
||
<button class="btn btn-subtle is-disabled">不可用</button>
|
||
<button class="btn btn-danger" disabled>断开连接</button>
|
||
</div></div>
|
||
</section>
|
||
|
||
<section class="section" id="a-card">
|
||
<h2>卡片 · .card</h2>
|
||
<p class="desc">surface 底 + border + radius-xl + shadow-sm。<code>.card-flush</code> 用于列表容器(内容自带 padding)。</p>
|
||
<div class="pcard"><div class="pcard-b">
|
||
<div class="card" style="max-width:280px">
|
||
<div class="t-overline" style="color:var(--fg3)">当前节点</div>
|
||
<div class="t-h3" style="margin:var(--space-2) 0 var(--space-1)">香港 · HK 加速线路</div>
|
||
<div class="t-sm" style="color:var(--fg2)">稳定 · 无日志 · 隐私保护</div>
|
||
</div>
|
||
<div class="card card-flush" style="max-width:280px; width:100%">
|
||
<div style="padding:var(--space-4) var(--space-5); border-bottom:1px solid var(--border)" class="t-sm">HK · 香港</div>
|
||
<div style="padding:var(--space-4) var(--space-5); border-bottom:1px solid var(--border)" class="t-sm">JP · 东京</div>
|
||
<div style="padding:var(--space-4) var(--space-5)" class="t-sm">SG · 新加坡</div>
|
||
</div>
|
||
</div></div>
|
||
</section>
|
||
|
||
<section class="section" id="a-input">
|
||
<h2>输入 · .input / .field / .flabel</h2>
|
||
<p class="desc">强描边 + radius-md + focus clay 光环。状态 <code>.is-focused</code> / <code>.is-error</code> / <code>:disabled</code>。</p>
|
||
<div class="pcard"><div class="pcard-b" style="align-items:flex-start">
|
||
<label class="field" style="width:220px"><span class="flabel">邮箱</span><input class="input" placeholder="me@pangolin.app"></label>
|
||
<label class="field" style="width:220px"><span class="flabel">焦点态</span><input class="input is-focused" value="已聚焦"></label>
|
||
<label class="field" style="width:220px"><span class="flabel">错误态</span><input class="input is-error" value="激活码无效"></label>
|
||
<label class="field" style="width:220px"><span class="flabel">禁用态</span><input class="input" value="不可编辑" disabled></label>
|
||
</div></div>
|
||
</section>
|
||
|
||
<section class="section" id="a-pill">
|
||
<h2>胶囊 · .pill / .badge</h2>
|
||
<p class="desc">状态用「色点 + 文字胶囊」,非 emoji。状态修饰 <code>.is-success/-warning/-danger/-neutral</code>,变体 <code>.pill-accent</code> / <code>.pill-outline</code>。<code>.badge</code> 为 <code>.pill</code> 语义别名。</p>
|
||
<div class="pcard"><div class="pcard-h"><h3>状态修饰</h3><span class="tk">.pill.is-*(含 .dot)</span></div><div class="pcard-b">
|
||
<span class="pill is-success"><span class="dot"></span>已连接</span>
|
||
<span class="pill is-warning"><span class="dot"></span>连接中</span>
|
||
<span class="pill is-danger"><span class="dot"></span>已断开</span>
|
||
<span class="pill is-neutral"><span class="dot"></span>未连接</span>
|
||
<span class="pill"><span class="dot"></span>默认</span>
|
||
</div></div>
|
||
<div class="pcard"><div class="pcard-h"><h3>变体 / 别名</h3><span class="tk">.pill-accent · .pill-outline · .badge</span></div><div class="pcard-b">
|
||
<span class="pill pill-accent">PRO 会员</span>
|
||
<span class="pill pill-outline">流媒体</span>
|
||
<span class="pill pill-outline">P2P</span>
|
||
<span class="badge is-success"><span class="dot"></span>badge 别名</span>
|
||
</div></div>
|
||
</section>
|
||
|
||
<section class="section" id="a-lang">
|
||
<h2>语言下拉 · .langsel</h2>
|
||
<p class="desc">不依赖原生 <code><select></code>:触发药丸 <code>.langsel-trigger</code> + 自控绝对定位菜单 <code>.menu</code> / <code>.menu-item</code>(选中态 <code>.is-selected</code>)。点触发按钮可实际展开/收起。</p>
|
||
<div class="pcard"><div class="pcard-b" style="min-height:180px; align-items:flex-start">
|
||
<div class="langsel" id="langselDemo">
|
||
<button class="langsel-trigger" id="langTrigger" aria-expanded="true" aria-haspopup="true">
|
||
简体中文 <svg class="ic"><use href="#i-chevron-down"/></svg>
|
||
</button>
|
||
<div class="menu" id="langMenu">
|
||
<button class="menu-item is-selected" aria-selected="true">简体中文</button>
|
||
<button class="menu-item">English</button>
|
||
<button class="menu-item">繁體中文</button>
|
||
</div>
|
||
</div>
|
||
<span class="t-caption" style="color:var(--fg3)">↖ 默认展开演示,可点击触发按钮收起 / 展开</span>
|
||
</div></div>
|
||
</section>
|
||
|
||
<!-- ══════════ 图标 ══════════ -->
|
||
<section class="section" id="icons">
|
||
<h2>Lucide 图标库 <span class="pill pill-outline count-pill" id="iconCount">—</span></h2>
|
||
<p class="desc">细线条 · 2px stroke · 圆角端点。sprite 单源 <code>icons.js</code>,用法 <code><svg class="ic"><use href="#i-<name>"/></svg></code>。</p>
|
||
<div class="pcard"><div class="pcard-b"><div class="icon-grid" id="iconGrid"></div></div></div>
|
||
</section>
|
||
</main>
|
||
</div>
|
||
|
||
<script>
|
||
/* ── 主题切换(light / dark),持久化 localStorage ── */
|
||
function applyTheme(t){
|
||
if(t==='dark'){ document.documentElement.dataset.theme='dark'; }
|
||
else { delete document.documentElement.dataset.theme; }
|
||
document.getElementById('themeIcon').setAttribute('href', t==='dark' ? '#i-moon' : '#i-sun');
|
||
document.getElementById('themeLabel').textContent = t==='dark' ? '深色' : '浅色';
|
||
localStorage.setItem('pangolin-ds-theme', t);
|
||
renderSwatches();
|
||
}
|
||
document.getElementById('themeBtn').onclick = () => {
|
||
const cur = document.documentElement.dataset.theme==='dark' ? 'dark' : 'light';
|
||
applyTheme(cur==='dark' ? 'light' : 'dark');
|
||
};
|
||
|
||
/* ── 色板:读实际 CSS 变量(换主题刷新色值文本) ── */
|
||
function renderSwatches(){
|
||
const cs = getComputedStyle(document.documentElement);
|
||
document.querySelectorAll('[data-swatches]').forEach(grid=>{
|
||
grid.innerHTML = grid.dataset.swatches.split(',').map(tok=>{
|
||
const v = cs.getPropertyValue(tok).trim();
|
||
return `<div class="sw"><div class="band" style="background:var(${tok})"></div>`+
|
||
`<div class="m"><div class="n">${tok.replace('--','')}</div><div class="v">${v||'—'}</div></div></div>`;
|
||
}).join('');
|
||
});
|
||
}
|
||
|
||
/* ── 图标库:遍历 sprite 全量渲染 ── */
|
||
function renderIcons(){
|
||
const map = window.PANGOLIN_ICONS || {};
|
||
const names = Object.keys(map);
|
||
document.getElementById('iconCount').textContent = names.length + ' 个';
|
||
document.getElementById('iconGrid').innerHTML = names.map(n=>
|
||
`<div class="icell"><svg class="ic"><use href="#i-${n}"/></svg><span>${n}</span></div>`
|
||
).join('');
|
||
}
|
||
|
||
/* ── 语言下拉演示:点触发展开 / 收起 ── */
|
||
(function(){
|
||
const trigger = document.getElementById('langTrigger');
|
||
const sel = document.getElementById('langselDemo');
|
||
const menu = document.getElementById('langMenu');
|
||
sel.classList.add('is-open');
|
||
trigger.onclick = (e)=>{
|
||
e.stopPropagation();
|
||
const open = trigger.getAttribute('aria-expanded')==='true';
|
||
trigger.setAttribute('aria-expanded', String(!open));
|
||
sel.classList.toggle('is-open', !open);
|
||
menu.style.display = open ? 'none' : 'flex';
|
||
};
|
||
menu.querySelectorAll('.menu-item').forEach(mi=>{
|
||
mi.onclick = ()=>{
|
||
menu.querySelectorAll('.menu-item').forEach(x=>{ x.classList.remove('is-selected'); x.removeAttribute('aria-selected'); });
|
||
mi.classList.add('is-selected'); mi.setAttribute('aria-selected','true');
|
||
trigger.childNodes[0].nodeValue = mi.textContent + ' ';
|
||
};
|
||
});
|
||
})();
|
||
|
||
/* ── 导航 scrollspy ── */
|
||
const navLinks=[...document.querySelectorAll('.dnav')];
|
||
navLinks.forEach(a=>a.onclick=(e)=>{ e.preventDefault(); const el=document.getElementById(a.dataset.s); if(el) el.scrollIntoView({behavior:'smooth',block:'start'}); });
|
||
const obs=new IntersectionObserver(es=>{ es.forEach(en=>{ if(en.isIntersecting){ const id=en.target.id; navLinks.forEach(a=>a.classList.toggle('on',a.dataset.s===id)); } }); },{rootMargin:'-70px 0px -75% 0px'});
|
||
document.querySelectorAll('.section').forEach(s=>obs.observe(s));
|
||
|
||
/* ── init(sprite 注入可能在 DOMContentLoaded,稍等确保 PANGOLIN_ICONS 就绪) ── */
|
||
function boot(){
|
||
applyTheme(localStorage.getItem('pangolin-ds-theme') || 'light');
|
||
renderIcons();
|
||
}
|
||
if(document.readyState!=='loading') boot(); else document.addEventListener('DOMContentLoaded', boot);
|
||
</script>
|
||
</body>
|
||
</html>
|
||
</content>
|
||
</invoke>
|