feat(design): 支付渠道 switch 原型 + segswitch 原子 + 图标/语言同源闸
- .segswitch 段控原子入 atoms.css + 登记 index.html - purchase/ui-mobile/ui-desktop 三屏:购买页支付渠道 switch(USDT→crypto 默认 / 人民币→alipay),套餐价随渠道分币种显示,删两步弹层 + nezha - 订单列表/详情集成进移动+桌面主框架 - icons.js 58 图标 sprite 单源 + gen_flutter_icons codegen + check-l1-sync 同源闸(图标同集 + l10n 完整) - pay-v2 开发决策日志 docs/pay-v2-dev-log.md Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
This commit is contained in:
+521
-9
@@ -37,10 +37,33 @@
|
||||
/* 三栏文档布局 */
|
||||
.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);
|
||||
overflow-y:auto; overscroll-behavior:contain; border-right:1px solid var(--border);
|
||||
padding:var(--space-5) var(--space-4) calc(var(--space-16) * 2);
|
||||
transition:width var(--dur-base) var(--ease-out); }
|
||||
/* 收起态(宽度由 JS 置 0,此处收内边距/边框) */
|
||||
.doc.nav-collapsed .doc-nav{ padding-left:0; padding-right:0; border-right:none; overflow:hidden; }
|
||||
.doc.nav-collapsed .nav-resize{ display:none; }
|
||||
/* 拖拽把手(改侧栏宽度) */
|
||||
.nav-resize{ flex:none; align-self:stretch; position:sticky; top:60px; height:calc(100vh - 60px);
|
||||
width:9px; margin-left:-5px; cursor:col-resize; z-index:40; background:transparent; }
|
||||
.nav-resize::after{ content:""; position:absolute; left:4px; top:0; bottom:0; width:2px; border-radius:var(--radius-full);
|
||||
background:transparent; transition:background-color var(--dur-fast) var(--ease-out); }
|
||||
.nav-resize:hover::after, .nav-resize.dragging::after{ background:var(--accent); }
|
||||
body.nav-dragging{ cursor:col-resize; user-select:none; }
|
||||
/* 顶栏收起按钮 */
|
||||
.nav-toggle{ display:inline-flex; align-items:center; justify-content:center; width:34px; height:34px; flex:none;
|
||||
border:1px solid var(--border); border-radius:var(--radius-md); background:var(--bg-subtle);
|
||||
color:var(--fg2); cursor:pointer; transition:color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out); }
|
||||
.nav-toggle:hover{ color:var(--fg1); border-color:var(--border-strong); }
|
||||
.nav-toggle svg{ width:18px; height:18px; }
|
||||
|
||||
/* L1 分组头 —— 分隔线 + 提亮加粗,与二级明显区分 */
|
||||
.dgroup{ font-size:var(--text-caption); font-weight:700; color:var(--fg2); letter-spacing:var(--tracking-caps);
|
||||
text-transform:uppercase; padding:var(--space-2) var(--space-2);
|
||||
margin-top:var(--space-5); border-top:1px solid var(--border); }
|
||||
.doc-nav .dgroup:first-child{ margin-top:var(--space-1); border-top:none; }
|
||||
/* L2 条目 —— 缩进内嵌于分组下 */
|
||||
.dnav{ display:block; padding:var(--space-2) var(--space-3) var(--space-2) var(--space-5); 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); }
|
||||
@@ -102,13 +125,36 @@
|
||||
|
||||
@media (max-width:840px){
|
||||
.doc-nav{ display:none; }
|
||||
.nav-resize{ display:none; }
|
||||
.nav-toggle{ display:none; }
|
||||
.doc-main{ padding:var(--space-6) var(--space-5) var(--space-12); }
|
||||
}
|
||||
|
||||
/* ── 品牌 / 字体 specimen 展示用(登记页 chrome,非 atoms;全走 token) ── */
|
||||
.brand-appicon{ display:flex; align-items:flex-end; gap:var(--space-8); flex-wrap:wrap; }
|
||||
.brand-appicon .unit{ display:flex; flex-direction:column; align-items:center; gap:var(--space-2); }
|
||||
.brand-appicon .unit .n{ font-family:var(--font-mono); font-size:11px; color:var(--fg3); }
|
||||
.brand-appicon img{ display:block; box-shadow:var(--shadow-md); border-radius:22%; }
|
||||
.lockup{ display:flex; align-items:center; gap:var(--space-3); }
|
||||
.lockup img{ display:block; }
|
||||
.lockup .tw{ display:flex; flex-direction:column; line-height:1; }
|
||||
.lockup .cn{ font-family:var(--font-display); font-weight:700; font-size:22px; letter-spacing:var(--tracking-snug); color:var(--fg1); }
|
||||
.lockup .en{ font-family:var(--font-display); font-weight:600; font-size:10px; letter-spacing:0.22em; color:var(--accent); margin-top:4px; }
|
||||
.lockup-panel{ flex:1; min-width:220px; display:flex; flex-direction:column; align-items:center; gap:var(--space-3);
|
||||
padding:var(--space-8); border-radius:var(--radius-lg); border:1px solid var(--border); }
|
||||
.lockup-panel .plab{ font-family:var(--font-mono); font-size:10px; color:var(--fg3); }
|
||||
.spec-mono-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:var(--space-5); width:100%; }
|
||||
.spec-mono-grid .k{ font-family:var(--font-mono); font-size:11px; color:var(--fg3); margin-bottom:4px; }
|
||||
.spec-mono-grid .v{ font-family:var(--font-mono); font-size:22px; font-weight:500; letter-spacing:var(--tracking-snug);
|
||||
color:var(--fg1); font-feature-settings:'tnum' 1; }
|
||||
.spec-mono-grid .v .u{ font-size:12px; color:var(--accent); font-weight:400; }
|
||||
@media (max-width:560px){ .spec-mono-grid{ grid-template-columns:repeat(2,1fr); } }
|
||||
</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>
|
||||
<button class="nav-toggle" id="navToggle" aria-label="收起 / 展开侧栏" title="收起 / 展开侧栏"><svg class="ic"><use href="#i-menu"/></svg></button>
|
||||
<div class="ds-brand"><span class="mk"><img src="../assets/app-icon.svg" alt="穿山甲" style="width:100%;height:100%;object-fit:contain;border-radius:inherit"></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>
|
||||
@@ -117,12 +163,24 @@
|
||||
|
||||
<div class="doc">
|
||||
<nav class="doc-nav" id="docNav">
|
||||
<div class="dgroup">UI Kit · 交互原型</div>
|
||||
<a class="dnav" href="screens/ui-mobile.html" style="color:var(--accent);font-weight:600">↗ 移动版 App</a>
|
||||
<a class="dnav" href="screens/ui-desktop.html" style="color:var(--accent);font-weight:600">↗ 桌面版</a>
|
||||
<a class="dnav" href="screens/site.html" style="color:var(--accent);font-weight:600">↗ 官网 Site</a>
|
||||
<div class="dgroup">品牌 Brand</div>
|
||||
<a class="dnav" data-s="b-appicon">App 图标家族</a>
|
||||
<a class="dnav" data-s="b-logo">Logo 锁版</a>
|
||||
<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>
|
||||
<a class="dnav" data-s="c-dark">暗色主题表面</a>
|
||||
<div class="dgroup">字体 Type</div>
|
||||
<a class="dnav" data-s="t-body">正文字体 Manrope</a>
|
||||
<a class="dnav" data-s="t-cjk">中文字体 Noto Sans SC</a>
|
||||
<a class="dnav" data-s="t-display">Display 字体 Sora</a>
|
||||
<a class="dnav" data-s="t-mono">等宽数据字体 JetBrains Mono</a>
|
||||
<a class="dnav" data-s="type">字号梯度</a>
|
||||
<div class="dgroup">尺度 Scale</div>
|
||||
<a class="dnav" data-s="radius">圆角</a>
|
||||
@@ -134,11 +192,57 @@
|
||||
<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>
|
||||
<a class="dnav" data-s="a-connect">核心连接按钮 .connect-btn</a>
|
||||
<a class="dnav" data-s="a-server">服务器列表行 .server-row</a>
|
||||
<a class="dnav" data-s="a-badge">状态徽章 .pill 场景</a>
|
||||
<div class="dgroup">组件 · 线上对齐</div>
|
||||
<a class="dnav" data-s="a-formctl">复合输入 · 开关 · 图标框</a>
|
||||
<a class="dnav" data-s="a-quota">额度卡 · 指标卡</a>
|
||||
<a class="dnav" data-s="a-rows">设备行 · 设置行</a>
|
||||
<a class="dnav" data-s="a-planbn">套餐横幅 · 会员卡</a>
|
||||
<a class="dnav" data-s="a-appchrome">更新条 · Tab · 侧栏项</a>
|
||||
<div class="dgroup">购买 Purchase</div>
|
||||
<a class="dnav" data-s="a-plan">套餐卡 .plan-card</a>
|
||||
<a class="dnav" data-s="a-paym">支付方式 .pay-method</a>
|
||||
<a class="dnav" data-s="a-kv">明细行 .kv-row</a>
|
||||
<a class="dnav" data-s="a-result">结果态 .result</a>
|
||||
<div class="dgroup">图标 Icons</div>
|
||||
<a class="dnav" data-s="icons">Lucide 图标库</a>
|
||||
</nav>
|
||||
|
||||
<div class="nav-resize" id="navResize" title="拖动调整侧栏宽度"></div>
|
||||
|
||||
<main class="doc-main">
|
||||
<!-- ══════════ 品牌 Brand ══════════ -->
|
||||
<section class="section" id="b-appicon">
|
||||
<h2>App 图标家族</h2>
|
||||
<p class="desc">母题=行走穿山甲(实心鳞甲剪影,朝右)置于 clay 渐变圆角方。矢量单源 <code>design/assets/app-icon.svg</code>,多尺寸直接引用同一文件(零漂移,非内联副本)。</p>
|
||||
<div class="pcard"><div class="pcard-h"><h3>多尺寸</h3><span class="tk">104 · 64 · 40 · 28</span></div><div class="pcard-b"><div class="brand-appicon">
|
||||
<div class="unit"><img src="../assets/app-icon.svg" width="104" height="104" alt="穿山甲 app 图标 104"><span class="n">104 · 主图标</span></div>
|
||||
<div class="unit"><img src="../assets/app-icon.svg" width="64" height="64" alt="app 图标 64"><span class="n">64</span></div>
|
||||
<div class="unit"><img src="../assets/app-icon.svg" width="40" height="40" alt="app 图标 40"><span class="n">40</span></div>
|
||||
<div class="unit"><img src="../assets/app-icon.svg" width="28" height="28" alt="app 图标 28"><span class="n">28</span></div>
|
||||
</div></div></div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="b-logo">
|
||||
<h2>Logo 锁版</h2>
|
||||
<p class="desc">图标 mark + 字标水平锁版。浅色背景用主锁版 <code>logo-mark.svg</code>,深色背景用反白锁版 <code>logo-mark-white.svg</code>;整体横版字标 <code>logo-wordmark.svg</code>。矢量单源 <code>design/assets/</code>。</p>
|
||||
<div class="pcard"><div class="pcard-h"><h3>主锁版 / 反白锁版</h3><span class="tk">logo-mark.svg · logo-mark-white.svg</span></div><div class="pcard-b" style="align-items:stretch">
|
||||
<div class="lockup-panel" style="background:var(--sand-50)">
|
||||
<div class="lockup"><img src="../assets/logo-mark.svg" width="46" height="46" alt="穿山甲 mark"><div class="tw"><span class="cn">穿山甲</span><span class="en">PANGOLIN</span></div></div>
|
||||
<span class="plab">主锁版 · 浅色背景</span>
|
||||
</div>
|
||||
<div class="lockup-panel" data-theme="dark" style="background:var(--sand-950)">
|
||||
<div class="lockup"><img src="../assets/logo-mark-white.svg" width="46" height="46" alt="穿山甲 mark 反白"><div class="tw"><span class="cn">穿山甲</span><span class="en">PANGOLIN</span></div></div>
|
||||
<span class="plab">反白锁版 · 深色背景</span>
|
||||
</div>
|
||||
</div></div>
|
||||
<div class="pcard"><div class="pcard-h"><h3>横版字标</h3><span class="tk">logo-wordmark.svg · 240×56</span></div><div class="pcard-b" style="background:var(--sand-50)">
|
||||
<img src="../assets/logo-wordmark.svg" width="240" height="56" alt="穿山甲 Pangolin 字标">
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<!-- ══════════ 色彩 ══════════ -->
|
||||
<section class="section" id="c-clay">
|
||||
<h2>clay · 黏土铜色阶</h2>
|
||||
@@ -168,6 +272,62 @@
|
||||
<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="c-dark">
|
||||
<h2>暗色主题表面</h2>
|
||||
<p class="desc">暗色画布=暖 espresso <code>--sand-950</code>(非纯黑)。表面层级 <code>--bg</code>(应用画布)→ <code>--surface</code>(卡片/面板)→ <code>--surface-2</code>(嵌套层),逐级提亮保持暖调。此卡固定演示暗色,不随右上主题切换。</p>
|
||||
<div class="pcard"><div class="pcard-h"><h3>表面层级(固定暗色演示)</h3><span class="tk">--bg · --surface · --surface-2</span></div>
|
||||
<div class="pcard-b" data-theme="dark" style="background:var(--sand-950); gap:var(--space-3)">
|
||||
<div class="card" style="flex:1; min-width:150px; background:var(--bg)"><div class="t-h3" style="color:var(--fg1); font-size:15px">bg</div><div class="t-caption" style="color:var(--fg2); margin-top:4px">应用画布</div><div class="t-mono" style="color:var(--fg3); font-size:11px; margin-top:2px">#14110E</div></div>
|
||||
<div class="card" style="flex:1; min-width:150px; background:var(--surface)"><div class="t-h3" style="color:var(--fg1); font-size:15px">surface</div><div class="t-caption" style="color:var(--fg2); margin-top:4px">卡片 / 面板</div><div class="t-mono" style="color:var(--fg3); font-size:11px; margin-top:2px">#221E19</div></div>
|
||||
<div class="card" style="flex:1; min-width:150px; background:var(--surface-2)"><div class="t-h3" style="color:var(--fg1); font-size:15px">surface-2</div><div class="t-caption" style="color:var(--fg2); margin-top:4px">嵌套层</div><div class="t-mono" style="color:var(--fg3); font-size:11px; margin-top:2px">#2A251F</div><span class="pill pill-accent" style="margin-top:var(--space-3)">Accent</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ══════════ 字体 specimen ══════════ -->
|
||||
<section class="section" id="t-body">
|
||||
<h2>正文字体 · Manrope</h2>
|
||||
<p class="desc">界面与正文主力(<code>--font-sans</code>,权重 400–700)。人文几何,中英混排稳定。示例中英分行、单句不并排。</p>
|
||||
<div class="pcard"><div class="pcard-h"><h3>Body · Manrope</h3><span class="tk">--font-sans · 400 / 500 / 600 / 700</span></div><div class="pcard-b col">
|
||||
<p class="t-h3" style="margin:0 0 var(--space-2)">一键连接,极速畅连</p>
|
||||
<p class="t-body-lg" style="margin:0 0 var(--space-2); color:var(--fg2)">轻盈、亲和、即开即用的网络加速。</p>
|
||||
<p class="t-body" style="margin:0 0 var(--space-2)">Body 16px — 全球 80+ 加速线路,智能选择最快节点,稳定不掉线。</p>
|
||||
<p class="t-sm" style="margin:0; color:var(--fg2)">Small 14px — 适用于次要说明、列表副标题与表单提示文字。</p>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="t-cjk">
|
||||
<h2>中文字体 · Noto Sans SC</h2>
|
||||
<p class="desc">中文专用伴随字体(<code>--font-cjk</code>,权重 400 / 500 / 700)。与 Manrope / Sora 同框时保证中文字形与字重一致。</p>
|
||||
<div class="pcard"><div class="pcard-h"><h3>CJK · Noto Sans SC</h3><span class="tk">--font-cjk · 400 / 500 / 700</span></div><div class="pcard-b col" style="font-family:var(--font-cjk)">
|
||||
<p style="margin:0; font-size:34px; font-weight:700; letter-spacing:var(--tracking-snug)">穿山甲 · 守护每一次连接</p>
|
||||
<p style="margin:var(--space-3) 0 0; font-size:18px; font-weight:500; color:var(--fg2)">无需配置,打开即用。智能分流,海外应用秒开。</p>
|
||||
<p style="margin:var(--space-2) 0 0; font-size:14px; color:var(--fg3)">隐私保护 · 我们不记录你的浏览数据 · 端到端加密</p>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="t-display">
|
||||
<h2>Display 字体 · Sora</h2>
|
||||
<p class="desc">标题、营销大字、Logo 字标(<code>--font-display</code>,权重 600 / 700)。几何友好,字距收紧 <code>-0.02em</code>。</p>
|
||||
<div class="pcard"><div class="pcard-h"><h3>Display · Sora</h3><span class="tk">--font-display · 600 / 700</span></div><div class="pcard-b col">
|
||||
<p class="t-display-xl" style="margin:0 0 var(--space-3); line-height:1.05">极速畅连 Smooth</p>
|
||||
<p class="t-display" style="margin:0; line-height:1.05; color:var(--accent)">极速 · 稳定 · 省心</p>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="t-mono">
|
||||
<h2>等宽数据字体 · JetBrains Mono</h2>
|
||||
<p class="desc">IP / 速率 / 时长 / 密钥等数据读数(<code>--font-mono</code>,开 tabular nums 等宽对齐,数字不跳动)。</p>
|
||||
<div class="pcard"><div class="pcard-h"><h3>Mono · JetBrains Mono</h3><span class="tk">--font-mono · tnum</span></div><div class="pcard-b"><div class="spec-mono-grid">
|
||||
<div><div class="k">DOWNLOAD</div><div class="v">86.4<span class="u"> Mb/s</span></div></div>
|
||||
<div><div class="k">PING</div><div class="v">24<span class="u"> ms</span></div></div>
|
||||
<div><div class="k">UPTIME</div><div class="v">02:14:08</div></div>
|
||||
<div><div class="k">EXIT IP</div><div class="v" style="font-size:16px">103.27.18.204</div></div>
|
||||
<div><div class="k">PROTOCOL</div><div class="v" style="font-size:16px">REALITY</div></div>
|
||||
<div><div class="k">DATA</div><div class="v">1.82<span class="u"> GB</span></div></div>
|
||||
</div></div></div>
|
||||
</section>
|
||||
|
||||
<!-- ══════════ 字号 ══════════ -->
|
||||
<section class="section" id="type">
|
||||
<h2>字号梯度</h2>
|
||||
@@ -305,21 +465,331 @@
|
||||
<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="pcard" style="overflow:visible"><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">
|
||||
<div class="menu" id="langMenu" style="left:0; right:auto">
|
||||
<button class="menu-item is-selected" aria-selected="true">简体中文</button>
|
||||
<button class="menu-item">English</button>
|
||||
<button class="menu-item">繁體中文</button>
|
||||
<button class="menu-item">日本語</button>
|
||||
<button class="menu-item">한국어</button>
|
||||
<button class="menu-item">Русский</button>
|
||||
<button class="menu-item">Español</button>
|
||||
</div>
|
||||
</div>
|
||||
<span class="t-caption" style="color:var(--fg3)">↖ 默认展开演示,可点击触发按钮收起 / 展开</span>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<!-- ══════════ 核心连接按钮 ══════════ -->
|
||||
<section class="section" id="a-connect">
|
||||
<h2>核心连接按钮 · .connect-btn</h2>
|
||||
<p class="desc">产品<strong>招牌组件</strong>:圆形一键连接键,三态 <code>.is-off</code> / <code>.is-connecting</code> / <code>.is-on</code>。背景在渐变↔纯色间切换仅过渡 <code>box-shadow</code>/<code>background-color</code>(<strong>禁</strong> <code>transition:all</code>,否则背景计算失效)。轨道环用内联 <code><svg></code>,圆内为图标 + 标签 / 计时。镜像 <code>client/lib/widgets/connect_button.dart</code>。</p>
|
||||
<div class="pcard"><div class="pcard-b" style="justify-content:center; gap:var(--space-10); padding:var(--space-8) var(--space-5)">
|
||||
|
||||
<div style="display:flex; flex-direction:column; align-items:center; gap:var(--space-3)">
|
||||
<button class="connect-btn is-off">
|
||||
<svg class="cb-ring" viewBox="0 0 140 140"><circle class="cb-track" cx="70" cy="70" r="64"/></svg>
|
||||
<svg class="cb-icon"><use href="#i-power"/></svg>
|
||||
<span class="cb-label">点击连接</span>
|
||||
<span class="cb-sub">TAP TO CONNECT</span>
|
||||
</button>
|
||||
<span class="t-caption" style="color:var(--fg3)">未连接 Off</span>
|
||||
</div>
|
||||
|
||||
<div style="display:flex; flex-direction:column; align-items:center; gap:var(--space-3)">
|
||||
<button class="connect-btn is-connecting">
|
||||
<svg class="cb-ring cb-spin" viewBox="0 0 140 140">
|
||||
<circle class="cb-arc-track" cx="70" cy="70" r="64"/>
|
||||
<circle class="cb-arc" cx="70" cy="70" r="64"/>
|
||||
</svg>
|
||||
<svg class="cb-icon cb-spin"><use href="#i-loader-circle"/></svg>
|
||||
<span class="cb-label">连接中</span>
|
||||
<span class="cb-sub">CONNECTING…</span>
|
||||
</button>
|
||||
<span class="t-caption" style="color:var(--fg3)">建立隧道 Connecting</span>
|
||||
</div>
|
||||
|
||||
<div style="display:flex; flex-direction:column; align-items:center; gap:var(--space-3)">
|
||||
<button class="connect-btn is-on">
|
||||
<svg class="cb-ring" viewBox="0 0 140 140"><circle class="cb-ring-full" cx="70" cy="70" r="64"/></svg>
|
||||
<svg class="cb-icon"><use href="#i-shield-check"/></svg>
|
||||
<span class="cb-timer">02:14:08</span>
|
||||
<span class="cb-sub">已加密 · SECURE</span>
|
||||
</button>
|
||||
<span class="t-caption" style="color:var(--fg3)">已连接 Connected</span>
|
||||
</div>
|
||||
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<!-- ══════════ 服务器列表行 ══════════ -->
|
||||
<section class="section" id="a-server">
|
||||
<h2>服务器列表行 · .server-row</h2>
|
||||
<p class="desc">节点列表一行:<strong>国家码块</strong>(2 字母,绝不用 emoji 国旗)+ 名称/子名 + 属性胶囊(<code>.pill-outline</code>)+ 延迟(<code>--font-mono</code>·按值变色)+ 信号条 + 选中/推荐/不可用态。镜像 <code>client/lib/widgets/server_tile.dart</code>。放进 <code>.card.card-flush</code> 列表容器。</p>
|
||||
|
||||
<div class="pcard"><div class="pcard-h"><h3>列表行</h3><span class="tk">.server-row · .is-selected · .is-down</span></div><div class="pcard-b col">
|
||||
<div class="card card-flush" style="max-width:460px; width:100%">
|
||||
<div class="server-row is-selected">
|
||||
<div class="sr-cc">HK</div>
|
||||
<div class="sr-body">
|
||||
<div class="sr-title">香港 · 加速线路</div>
|
||||
<div class="sr-tags"><span class="pill pill-outline">流媒体</span></div>
|
||||
</div>
|
||||
<span class="sr-latency is-good">18ms</span>
|
||||
<span class="sr-check"><svg class="ic"><use href="#i-check"/></svg></span>
|
||||
</div>
|
||||
<div class="server-row">
|
||||
<div class="sr-cc">JP</div>
|
||||
<div class="sr-body">
|
||||
<div class="sr-title">日本 东京</div>
|
||||
<div class="sr-sub">Tokyo</div>
|
||||
</div>
|
||||
<span class="sr-latency is-good">32ms</span>
|
||||
<span class="sr-signal"><i></i><i></i><i></i></span>
|
||||
</div>
|
||||
<div class="server-row">
|
||||
<div class="sr-cc">SG</div>
|
||||
<div class="sr-body">
|
||||
<div class="sr-title">新加坡</div>
|
||||
<div class="sr-tags"><span class="pill pill-outline">P2P</span></div>
|
||||
</div>
|
||||
<span class="sr-latency is-warn">54ms</span>
|
||||
<span class="sr-signal"><i></i><i></i><i class="is-off"></i></span>
|
||||
</div>
|
||||
<div class="server-row is-down">
|
||||
<div class="sr-cc">US</div>
|
||||
<div class="sr-body">
|
||||
<div class="sr-title">美国 洛杉矶</div>
|
||||
<div class="sr-sub">Los Angeles</div>
|
||||
</div>
|
||||
<span class="sr-unavail">不可用</span>
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
<div class="pcard"><div class="pcard-h"><h3>智能选择推荐行</h3><span class="tk">.server-row.is-smart · zap + 推荐胶囊</span></div><div class="pcard-b col">
|
||||
<div class="card card-flush" style="max-width:460px; width:100%">
|
||||
<div class="server-row is-smart">
|
||||
<div class="sr-smart-ic"><svg class="ic"><use href="#i-zap"/></svg></div>
|
||||
<div class="sr-body">
|
||||
<div class="sr-title">智能选择</div>
|
||||
<div class="sr-sub">根据当前网络环境,自动选择最优节点</div>
|
||||
</div>
|
||||
<span class="pill pill-outline">推荐</span>
|
||||
<span class="sr-check"><svg class="ic"><use href="#i-check"/></svg></span>
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<!-- ══════════ 状态徽章 ══════════ -->
|
||||
<section class="section" id="a-badge">
|
||||
<h2>状态徽章 · .pill 场景</h2>
|
||||
<p class="desc">徽章复用胶囊原子 <code>.pill</code>(见「胶囊 .pill / .badge」),此处按业务场景分组:<strong>连接态</strong>(色点 + 文字,非 emoji · 铁律 #7)· <strong>套餐</strong> · <strong>节点属性</strong>。镜像 <code>client/lib/widgets/status_pill.dart</code>。</p>
|
||||
|
||||
<div class="pcard"><div class="pcard-h"><h3>连接态</h3><span class="tk">.pill.is-success/-warning/-danger/-neutral</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>
|
||||
</div></div>
|
||||
|
||||
<div class="pcard"><div class="pcard-h"><h3>套餐</h3><span class="tk">.pill-accent · .pill.is-neutral</span></div><div class="pcard-b">
|
||||
<span class="pill pill-accent">PRO 会员</span>
|
||||
<span class="pill is-neutral">免费版</span>
|
||||
</div></div>
|
||||
|
||||
<div class="pcard"><div class="pcard-h"><h3>节点属性</h3><span class="tk">.pill-outline · .pill.is-neutral(数据)</span></div><div class="pcard-b">
|
||||
<span class="pill pill-outline">流媒体优化</span>
|
||||
<span class="pill pill-outline">P2P</span>
|
||||
<span class="pill is-neutral">延迟 24ms</span>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<!-- ══════════ 组件 · 线上对齐 ══════════ -->
|
||||
<section class="section" id="a-formctl">
|
||||
<h2>复合输入 · 开关 · 图标框 · Toast</h2>
|
||||
<p class="desc">对齐线上 <code>pangolin_field.dart</code> / <code>dtoggle</code> / <code>pangolin_toast.dart</code>。<code>.field-box</code> 复合输入(前置图标 + 裸 input + 后置槽),<code>.toggle</code> 开关,<code>.segswitch</code> 二选一段控开关(支付渠道/币种),<code>.icon-box</code> 图标框,<code>.status-dot</code> 状态点,<code>.toast</code> 轻提示。</p>
|
||||
<div class="pcard"><div class="pcard-b" style="align-items:flex-start; gap:var(--space-4)">
|
||||
<label class="field-box" style="width:240px"><svg class="fb-lead"><use href="#i-search"/></svg><input class="fb-input" placeholder="搜索国家或城市"></label>
|
||||
<label class="field-box" style="width:240px"><svg class="fb-lead"><use href="#i-lock"/></svg><input class="fb-input" type="password" value="123456"><button class="fb-trailing" style="border:none;background:none;cursor:pointer"><svg style="width:16px;height:16px"><use href="#i-eye"/></svg></button></label>
|
||||
<label class="field-box is-plain" style="width:240px"><svg class="fb-lead"><use href="#i-search"/></svg><input class="fb-input" placeholder="无边框搜索变体"></label>
|
||||
</div></div>
|
||||
<div class="pcard"><div class="pcard-b">
|
||||
<span class="toggle is-on"><i></i></span>
|
||||
<span class="toggle"><i></i></span>
|
||||
<span class="icon-box"><svg><use href="#i-smartphone"/></svg></span>
|
||||
<span class="icon-box is-danger"><svg><use href="#i-trash-2"/></svg></span>
|
||||
<span style="display:inline-flex;align-items:center;gap:8px"><span class="status-dot is-online"></span>在线</span>
|
||||
<span style="display:inline-flex;align-items:center;gap:8px"><span class="status-dot is-offline"></span>离线</span>
|
||||
<span class="toast"><svg><use href="#i-check-circle"/></svg>已复制</span>
|
||||
</div></div>
|
||||
<div class="pcard"><div class="pcard-b" style="flex-direction:column; align-items:stretch; gap:var(--space-3); max-width:320px">
|
||||
<div class="segswitch">
|
||||
<button class="segswitch-opt is-active"><svg><use href="#i-globe"/></svg>USDT</button>
|
||||
<button class="segswitch-opt"><svg><use href="#i-credit-card"/></svg>人民币</button>
|
||||
</div>
|
||||
<div class="segswitch">
|
||||
<button class="segswitch-opt">USDT · 加密货币</button>
|
||||
<button class="segswitch-opt is-active">人民币 · 支付宝</button>
|
||||
</div>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="a-quota">
|
||||
<h2>额度卡 · 指标卡</h2>
|
||||
<p class="desc">对齐线上 <code>quota_card.dart</code>(免费版今日额度:倒计时收缩条 + 「免费版」短标签 + 三档阈值;<strong>无绿色「已解锁」态</strong>,线上以倒计时收缩条表达)与统计 <code>.metric</code> 指标瓦片。</p>
|
||||
<div class="pcard"><div class="pcard-b" style="align-items:flex-start; gap:var(--space-4)">
|
||||
<div class="quota-card" style="width:280px">
|
||||
<div class="quota-head"><svg><use href="#i-clock"/></svg><span class="quota-label">今日剩余</span><span class="quota-val">10 分钟</span><span class="quota-tag">免费版</span></div>
|
||||
<div class="quota-bar"><i style="width:100%"></i></div>
|
||||
</div>
|
||||
<div class="quota-card" style="width:280px">
|
||||
<div class="quota-head"><svg><use href="#i-clock"/></svg><span class="quota-label">剩余</span><span class="quota-val">02:18</span><span class="quota-tag">免费版</span></div>
|
||||
<div class="quota-bar is-low"><i style="width:23%"></i></div>
|
||||
</div>
|
||||
<div class="quota-card is-exhausted" style="width:280px">
|
||||
<div class="quota-head"><svg><use href="#i-clock"/></svg><span class="quota-label">今日已用完</span><span class="quota-tag">免费版</span></div>
|
||||
<div class="quota-bar is-exhausted"><i style="width:100%"></i></div>
|
||||
</div>
|
||||
</div></div>
|
||||
<div class="pcard"><div class="pcard-b" style="gap:var(--space-3)">
|
||||
<div class="metric" style="width:150px"><span class="m-ic"><svg><use href="#i-arrow-down"/></svg></span><div class="m-val">12.4G</div><div class="m-label">本周流量</div></div>
|
||||
<div class="metric" style="width:150px"><span class="m-ic"><svg><use href="#i-clock"/></svg></span><div class="m-val">6.2h</div><div class="m-label">在线时长</div></div>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="a-rows">
|
||||
<h2>设备行 · 设置行</h2>
|
||||
<p class="desc">对齐线上 <code>DevicesScreen</code> / <code>settings_page.dart</code>。<code>.device-row</code>(图标框 + 名 + 最后在线 + 本机/移除/⋯)与 <code>.setting-row</code>(图标框 + 标题 + 副标 + trailing:chevron / 开关 / 值)。</p>
|
||||
<div class="pcard"><div class="pcard-h"><h3>设备管理</h3><span class="tk">.device-row</span></div><div class="pcard-b col">
|
||||
<div class="card card-flush" style="max-width:460px">
|
||||
<div class="device-row"><span class="icon-box"><svg><use href="#i-smartphone"/></svg></span><div class="dv-body"><div class="dv-name">iPhone 15</div><div class="dv-sub"><span class="status-dot is-online"></span>当前设备 · 刚刚在线</div></div><span class="dv-trail"><span class="pill is-success"><span class="dot"></span>本机</span></span></div>
|
||||
<div class="device-row"><span class="icon-box"><svg><use href="#i-laptop"/></svg></span><div class="dv-body"><div class="dv-name">MacBook Pro</div><div class="dv-sub"><span class="status-dot is-offline"></span>最后在线 2 小时前</div></div><span class="dv-trail"><button class="btn btn-icon btn-subtle" aria-label="更多"><svg class="ic" style="width:16px;height:16px"><use href="#i-more-vertical"/></svg></button></span></div>
|
||||
</div>
|
||||
</div></div>
|
||||
<div class="pcard"><div class="pcard-h"><h3>设置</h3><span class="tk">.setting-row</span></div><div class="pcard-b col">
|
||||
<div class="card card-flush" style="max-width:460px">
|
||||
<div class="setting-row"><span class="icon-box"><svg><use href="#i-zap"/></svg></span><div class="st-body"><div class="st-title">智能分流</div><div class="st-sub">海外应用走加速,国内直连</div></div><span class="st-trail"><span class="toggle is-on"><i></i></span></span></div>
|
||||
<div class="setting-row"><span class="icon-box"><svg><use href="#i-globe"/></svg></span><div class="st-body"><div class="st-title">语言</div></div><span class="st-trail"><span class="st-val">简体中文</span></span></div>
|
||||
<div class="setting-row is-tap"><span class="icon-box"><svg><use href="#i-shield"/></svg></span><div class="st-body"><div class="st-title">协议</div></div><span class="st-trail"><span class="st-val">REALITY</span><svg><use href="#i-chevron-right"/></svg></span></div>
|
||||
</div>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="a-planbn">
|
||||
<h2>套餐横幅 · 侧栏会员卡</h2>
|
||||
<p class="desc">对齐线上 <code>_PlanBanner</code>(账户页)与 <code>plan_badge_card.dart</code>(桌面侧栏底部)。免费=surface 卡;<code>.is-pro</code>=clay 渐变。</p>
|
||||
<div class="pcard"><div class="pcard-b" style="align-items:stretch; gap:var(--space-4)">
|
||||
<div class="plan-banner" style="width:300px">
|
||||
<div class="pbn-row"><span class="pbn-badge"><svg><use href="#i-gift"/></svg></span><div style="flex:1"><div class="pbn-name">免费版</div><div class="pbn-meta">注册享 7 天免费试用</div></div><button class="btn btn-primary"><svg><use href="#i-crown"/></svg>升级</button></div>
|
||||
</div>
|
||||
<div class="plan-banner is-pro" style="width:300px">
|
||||
<div class="pbn-row"><span class="pbn-badge"><svg><use href="#i-crown"/></svg></span><div style="flex:1"><div class="pbn-name">PRO 会员</div><div class="pbn-meta">有效期至 2027-07-11</div></div><button class="btn btn-primary">续费</button></div>
|
||||
</div>
|
||||
</div></div>
|
||||
<div class="pcard"><div class="pcard-h"><h3>侧栏会员卡</h3><span class="tk">.plan-badge</span></div><div class="pcard-b">
|
||||
<div class="plan-badge is-active" style="width:200px"><span class="plb-crown"><svg><use href="#i-crown"/></svg></span><div class="plb-body"><span class="plb-name">PRO 会员</span><span class="plb-sub">至 2027-07-11</span></div><svg class="plb-chev"><use href="#i-chevron-right"/></svg></div>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="a-appchrome">
|
||||
<h2>更新条 · 底部 Tab · 侧栏项</h2>
|
||||
<p class="desc">app-chrome 组件。<code>.update-banner</code>(jiu 式更新顶部横条,对齐 <code>UpdateBanner</code>)、<code>.tabbar</code>/<code>.tab</code>(移动底部 4-Tab,对齐 <code>bottom_tab_bar.dart</code>)、<code>.nav-item</code>(桌面/iPad 侧栏项,对齐 <code>nav_sidebar.dart</code>)。</p>
|
||||
<div class="pcard"><div class="pcard-b col" style="padding:0">
|
||||
<div class="update-banner"><svg class="ub-ic"><use href="#i-zap"/></svg><span class="ub-title">发现新版本 v1.1.0,建议更新</span><button class="ub-cta">立即更新</button><button class="ub-close"><svg><use href="#i-x"/></svg></button></div>
|
||||
</div></div>
|
||||
<div class="pcard"><div class="pcard-b col" style="padding:0">
|
||||
<div class="tabbar">
|
||||
<button class="tab is-active"><svg><use href="#i-power"/></svg>连接</button>
|
||||
<button class="tab"><svg><use href="#i-globe"/></svg>节点</button>
|
||||
<button class="tab"><svg><use href="#i-chart-no-axes-column"/></svg>统计</button>
|
||||
<button class="tab"><svg><use href="#i-user"/></svg>我的</button>
|
||||
</div>
|
||||
</div></div>
|
||||
<div class="pcard"><div class="pcard-b col">
|
||||
<div style="max-width:220px; display:flex; flex-direction:column; gap:var(--space-1)">
|
||||
<div class="nav-item is-active"><svg><use href="#i-power"/></svg>连接</div>
|
||||
<div class="nav-item"><svg><use href="#i-globe"/></svg>节点</div>
|
||||
<div class="nav-item"><svg><use href="#i-chart-no-axes-column"/></svg>统计</div>
|
||||
<div class="nav-item"><svg><use href="#i-settings"/></svg>设置</div>
|
||||
<div class="nav-item"><svg><use href="#i-message-circle"/></svg>联系</div>
|
||||
</div>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<!-- ══════════ 购买 Purchase ══════════ -->
|
||||
<section class="section" id="a-plan">
|
||||
<h2>套餐卡 · .plan-card</h2>
|
||||
<p class="desc">购买套餐档位卡。常规档 surface 底;<code>.is-featured</code> 走 clay 渐变高亮(年付/最优惠),内含反色 CTA,顶部可挂 <code>.plan-pop</code>「最受欢迎」浮标。镜像 <code>client/lib/widgets/plan_card.dart</code>。金额仅展示,扣款以 pay 服务为准。</p>
|
||||
<div class="pcard"><div class="pcard-b" style="align-items:stretch; gap:var(--space-4)">
|
||||
<div class="plan-card" style="width:230px">
|
||||
<div class="plan-name">按月</div>
|
||||
<div class="plan-price-row"><span class="plan-price">¥29.99</span><span class="plan-per">/ 月</span></div>
|
||||
<div class="plan-feats">
|
||||
<div class="plan-feat"><svg><use href="#i-check"/></svg>不限时长 · 不限流量</div>
|
||||
<div class="plan-feat"><svg><use href="#i-check"/></svg>80+ 全球加速线路</div>
|
||||
<div class="plan-feat"><svg><use href="#i-check"/></svg>5 台设备同时在线</div>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-block">立即购买</button>
|
||||
</div>
|
||||
<div class="plan-card is-featured" style="width:230px">
|
||||
<span class="plan-pop">最受欢迎</span>
|
||||
<div class="plan-name">按年</div>
|
||||
<div class="plan-price-row"><span class="plan-price">¥199.99</span><span class="plan-per">/ 年 · ¥16.7/月</span></div>
|
||||
<div class="plan-feats">
|
||||
<div class="plan-feat"><svg><use href="#i-check"/></svg>不限时长 · 不限流量</div>
|
||||
<div class="plan-feat"><svg><use href="#i-check"/></svg>80+ 全球加速线路</div>
|
||||
<div class="plan-feat"><svg><use href="#i-check"/></svg>5 台设备同时在线</div>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-block">立即购买</button>
|
||||
</div>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="a-paym">
|
||||
<h2>支付方式 · .pay-method</h2>
|
||||
<p class="desc">底部弹层选择支付渠道,一行 = leading 图标 + 标题 + trailing chevron。资金外流(拉起支付宝 / 展示加密地址),<strong>App 内无卡号录入表单</strong>(设计铁律 #10)。生产渠道:哪吒聚合(支付宝)+ 加密货币 USDT。</p>
|
||||
<div class="pcard"><div class="pcard-b col">
|
||||
<div class="card card-flush" style="max-width:360px; padding:var(--space-2)">
|
||||
<button class="pay-method"><svg class="pm-ic"><use href="#i-credit-card"/></svg><span class="pm-title">支付宝</span><svg class="pm-chev"><use href="#i-chevron-right"/></svg></button>
|
||||
<button class="pay-method"><svg class="pm-ic"><use href="#i-globe"/></svg><span class="pm-title">加密货币 · USDT (TRC20)</span><svg class="pm-chev"><use href="#i-chevron-right"/></svg></button>
|
||||
</div>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="a-kv">
|
||||
<h2>明细行 · .kv-row</h2>
|
||||
<p class="desc">可复制键值行,用于加密支付态展示「网络 / 收款地址 / 精确金额」。值用等宽字(<code>--font-mono</code> + tabular nums),右侧复制按钮。</p>
|
||||
<div class="pcard"><div class="pcard-b col">
|
||||
<div class="card" style="max-width:420px">
|
||||
<div class="kv-row"><span class="kv-label">网络</span><span class="kv-val">USDT · TRC20</span><button class="kv-copy"><svg><use href="#i-copy"/></svg></button></div>
|
||||
<div class="kv-row"><span class="kv-label">收款地址</span><span class="kv-val">TB1e7q1333iuLMLc2iQaoaqeuDF2U7cxan</span><button class="kv-copy"><svg><use href="#i-copy"/></svg></button></div>
|
||||
<div class="kv-row"><span class="kv-label">精确金额</span><span class="kv-val">4.990001</span><button class="kv-copy"><svg><use href="#i-copy"/></svg></button></div>
|
||||
</div>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="a-result">
|
||||
<h2>结果态 · .result</h2>
|
||||
<p class="desc">支付终态:居中大图标 + 标题 + 说明。成功用 <code>--success</code>,失败加 <code>.is-fail</code> 走 <code>--danger</code>。</p>
|
||||
<div class="pcard"><div class="pcard-b" style="gap:var(--space-6)">
|
||||
<div class="result" style="width:280px">
|
||||
<div class="result-icon"><svg><use href="#i-check-circle"/></svg></div>
|
||||
<div class="result-title">支付成功</div>
|
||||
<div class="result-sub">有效期至 2027-07-11</div>
|
||||
</div>
|
||||
<div class="result is-fail" style="width:280px">
|
||||
<div class="result-icon"><svg><use href="#i-alert-triangle"/></svg></div>
|
||||
<div class="result-title">支付失败</div>
|
||||
<div class="result-sub">订单已超时,请重试</div>
|
||||
</div>
|
||||
</div></div>
|
||||
</section>
|
||||
|
||||
<!-- ══════════ 图标 ══════════ -->
|
||||
<section class="section" id="icons">
|
||||
<h2>Lucide 图标库 <span class="pill pill-outline count-pill" id="iconCount">—</span></h2>
|
||||
@@ -390,10 +860,52 @@ function renderIcons(){
|
||||
|
||||
/* ── 导航 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'}); });
|
||||
navLinks.forEach(a=>a.onclick=(e)=>{ if(!a.dataset.s) return; /* 外链(如屏预览)正常跳转 */ 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));
|
||||
|
||||
/* ── 侧栏:收起 + 拖拽改宽(持久化 localStorage) ── */
|
||||
(function(){
|
||||
const doc = document.querySelector('.doc');
|
||||
const nav = document.querySelector('.doc-nav');
|
||||
const handle = document.getElementById('navResize');
|
||||
const toggle = document.getElementById('navToggle');
|
||||
if(!doc || !nav || !handle || !toggle) return;
|
||||
const MIN = 180, MAX = 460, DEF = 238;
|
||||
let curW = parseInt(localStorage.getItem('pangolin-ds-navw') || '', 10);
|
||||
if (!(curW >= MIN && curW <= MAX)) curW = DEF;
|
||||
let collapsed = localStorage.getItem('pangolin-ds-navcollapsed') === '1';
|
||||
function apply(){
|
||||
if (collapsed) { doc.classList.add('nav-collapsed'); nav.style.width = '0px'; }
|
||||
else { doc.classList.remove('nav-collapsed'); nav.style.width = curW + 'px'; }
|
||||
}
|
||||
apply();
|
||||
// 收起 / 展开
|
||||
toggle.onclick = () => {
|
||||
collapsed = !collapsed;
|
||||
localStorage.setItem('pangolin-ds-navcollapsed', collapsed ? '1' : '0');
|
||||
apply();
|
||||
};
|
||||
// 拖拽改宽(纯 JS 内联宽度,避免自定义 CSS 变量触发闸误报)
|
||||
let dragging = false;
|
||||
handle.addEventListener('mousedown', (e) => {
|
||||
if (collapsed) return;
|
||||
dragging = true; handle.classList.add('dragging'); document.body.classList.add('nav-dragging');
|
||||
e.preventDefault();
|
||||
});
|
||||
window.addEventListener('mousemove', (e) => {
|
||||
if (!dragging) return;
|
||||
const rect = nav.getBoundingClientRect();
|
||||
curW = Math.max(MIN, Math.min(MAX, e.clientX - rect.left));
|
||||
nav.style.width = curW + 'px';
|
||||
});
|
||||
window.addEventListener('mouseup', () => {
|
||||
if (!dragging) return;
|
||||
dragging = false; handle.classList.remove('dragging'); document.body.classList.remove('nav-dragging');
|
||||
localStorage.setItem('pangolin-ds-navw', curW);
|
||||
});
|
||||
})();
|
||||
|
||||
/* ── init(sprite 注入可能在 DOMContentLoaded,稍等确保 PANGOLIN_ICONS 就绪) ── */
|
||||
function boot(){
|
||||
applyTheme(localStorage.getItem('pangolin-ds-theme') || 'light');
|
||||
|
||||
Reference in New Issue
Block a user