design(prototype): 渲染新 IA 视觉稿(桌面+移动)— 含 bell 图标单源 + 通知/邀请预留
- icons.js 加 bell(codegen→pangolin_icons.dart,L1 同集 59) - 侧栏提 Account 为一级/顶栏通知铃铛/Account 重排(购买&订单&兑换 + 邀请好友) - Settings 归三组(连接/外观/关于)+ Web 链接降级;Contact 单源;兑换码仅码 - 通知收件箱 + 邀请好友 占位屏(细节各自 Spec ②③) 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:
@@ -9,6 +9,7 @@ class PangolinIcons {
|
||||
static const link = LucideIcons.link;
|
||||
static const ticket = LucideIcons.ticket;
|
||||
static const users = LucideIcons.users;
|
||||
static const bell = LucideIcons.bell;
|
||||
static const copy = LucideIcons.copy;
|
||||
static const refreshCw = LucideIcons.refreshCw;
|
||||
static const qrCode = LucideIcons.qrCode;
|
||||
|
||||
Vendored
+1
@@ -12,6 +12,7 @@
|
||||
'link': '<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>',
|
||||
'ticket': '<path d="M2 9a3 3 0 0 1 0 6v2a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-2a3 3 0 0 1 0-6V7a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2Z"/><path d="M13 5v2"/><path d="M13 17v2"/><path d="M13 11v2"/>',
|
||||
'users': '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
|
||||
'bell': '<path d="M10.268 21a2 2 0 0 0 3.464 0"/><path d="M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326"/>',
|
||||
'copy': '<rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>',
|
||||
'refresh-cw': '<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M3 21v-5h5"/>',
|
||||
'qr-code': '<rect width="5" height="5" x="3" y="3" rx="1"/><rect width="5" height="5" x="16" y="3" rx="1"/><rect width="5" height="5" x="3" y="16" rx="1"/><path d="M21 16h-3a2 2 0 0 0-2 2v3"/><path d="M21 21v.01"/><path d="M12 7v3a2 2 0 0 1-2 2H7"/><path d="M3 12h.01"/><path d="M12 3h.01"/><path d="M12 16v.01"/><path d="M16 12h1"/><path d="M21 12v.01"/><path d="M12 21v-1"/>',
|
||||
|
||||
@@ -320,6 +320,38 @@
|
||||
overflow:hidden; background:var(--surface); text-align:left; }
|
||||
.limit-logout{ align-self:center; margin-top:var(--space-4); border:none; background:transparent; cursor:pointer;
|
||||
font-family:var(--font-sans); font-size:13px; font-weight:600; color:var(--fg3); padding:6px 12px; }
|
||||
|
||||
/* ---- 顶栏通知铃铛 + 未读红点 ---- */
|
||||
.tb-bell{ position:relative; }
|
||||
.tb-bell .tb-dot{ position:absolute; top:6px; right:6px; width:7px; height:7px; border-radius:var(--radius-full);
|
||||
background:var(--danger); border:1.5px solid var(--bg); }
|
||||
|
||||
/* ---- 通知收件箱视图 ---- */
|
||||
.notif-view{ padding:var(--space-5) var(--space-6) var(--space-6); max-width:600px; }
|
||||
.notif-row{ display:flex; align-items:flex-start; gap:var(--space-3); padding:14px 16px; border-top:1px solid var(--border); }
|
||||
.notif-row:first-child{ border-top:none; }
|
||||
.notif-dot{ flex:none; width:8px; height:8px; margin-top:6px; border-radius:var(--radius-full); background:var(--danger); }
|
||||
.notif-row:not(.is-unread) .notif-dot{ background:transparent; border:1.5px solid var(--border-strong); }
|
||||
.notif-row:not(.is-unread) .notif-t{ color:var(--fg2); }
|
||||
.notif-body{ flex:1; min-width:0; }
|
||||
.notif-head{ display:flex; align-items:center; gap:var(--space-2); margin-bottom:4px; }
|
||||
.notif-time{ margin-left:auto; font-family:var(--font-mono); font-size:11px; color:var(--fg3); }
|
||||
.notif-t{ font-size:14px; font-weight:600; color:var(--fg1); }
|
||||
.notif-s{ font-size:12.5px; color:var(--fg3); margin-top:2px; line-height:var(--leading-normal); }
|
||||
|
||||
/* ---- 邀请好友视图 ---- */
|
||||
.invite-view{ padding:var(--space-5) var(--space-6) var(--space-6); max-width:600px; }
|
||||
.invite-code-card{ margin-bottom:var(--space-5); display:flex; flex-direction:column; gap:var(--space-3); }
|
||||
.inv-lead{ font-size:13px; color:var(--fg2); line-height:var(--leading-relaxed); }
|
||||
.inv-code-box, .inv-link-box{ display:flex; align-items:center; gap:var(--space-2);
|
||||
background:var(--bg-subtle); border-radius:var(--radius-md); padding:10px 12px; }
|
||||
.inv-code{ flex:1; font-family:var(--font-mono); font-size:18px; font-weight:700; color:var(--accent); letter-spacing:0.06em; }
|
||||
.inv-link{ flex:1; font-family:var(--font-mono); font-size:12.5px; color:var(--fg2);
|
||||
overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
||||
.inv-prog-row{ display:flex; align-items:center; justify-content:space-between; padding:8px 0; }
|
||||
.inv-prog-row + .inv-prog-row{ border-top:1px solid var(--border); }
|
||||
.inv-prog-k{ font-size:13px; color:var(--fg2); }
|
||||
.inv-prog-v{ font-family:var(--font-mono); font-size:15px; font-weight:700; color:var(--accent); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -357,6 +389,7 @@
|
||||
<button class="nav-item is-active" data-view="connect"><svg><use href="#i-power"/></svg><span data-i18n="nav.connect">连接</span></button>
|
||||
<button class="nav-item" data-view="nodes"><svg><use href="#i-globe"/></svg><span data-i18n="nav.nodes">节点</span></button>
|
||||
<button class="nav-item" data-view="stats"><svg><use href="#i-chart-no-axes-column"/></svg><span data-i18n="nav.stats">统计</span></button>
|
||||
<button class="nav-item" data-view="account"><svg><use href="#i-user"/></svg><span data-i18n="nav.account">账户</span></button>
|
||||
<button class="nav-item" data-view="settings"><svg><use href="#i-settings"/></svg><span data-i18n="nav.settings">设置</span></button>
|
||||
<button class="nav-item" data-view="contact"><svg><use href="#i-message-circle"/></svg><span data-i18n="nav.contact">联系</span></button>
|
||||
</nav>
|
||||
@@ -374,7 +407,7 @@
|
||||
|
||||
<!-- ===== 主区 ===== -->
|
||||
<div class="main">
|
||||
<div class="titlebar"><span class="tt" id="viewTitle">连接</span><div class="tb-right"><span class="st off" id="statusPill">○ 未连接</span><button class="tb-theme" id="tbTheme" aria-label="切换主题"><svg><use href="#i-moon" id="tbThemeIcon"/></svg></button></div></div>
|
||||
<div class="titlebar"><span class="tt" id="viewTitle">连接</span><div class="tb-right"><span class="st off" id="statusPill">○ 未连接</span><button class="tb-theme tb-bell" id="tbBell" data-view="notifications" aria-label="通知"><svg><use href="#i-bell"/></svg><span class="tb-dot"></span></button><button class="tb-theme" id="tbTheme" aria-label="切换主题"><svg><use href="#i-moon" id="tbThemeIcon"/></svg></button></div></div>
|
||||
<div class="content">
|
||||
|
||||
<!-- 更新顶部横条(演示开关切显隐) -->
|
||||
@@ -521,6 +554,33 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sec-label" data-i18n="acc.billing">购买 & 订单 & 兑换</div>
|
||||
<div class="card card-flush" style="margin-bottom:var(--space-5)">
|
||||
<button class="setting-row is-tap" id="accBuyRow" style="width:100%">
|
||||
<span class="icon-box"><svg><use href="#i-crown"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="acc.buy">购买套餐</div><div class="st-sub" data-i18n="acc.buySub">升级 PRO 会员</div></div>
|
||||
<span class="st-trail"><svg><use href="#i-chevron-right"/></svg></span>
|
||||
</button>
|
||||
<button class="setting-row is-tap" id="accOrdersRow" style="width:100%">
|
||||
<span class="icon-box"><svg><use href="#i-ticket"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="acc.orders">我的订单</div><div class="st-sub" data-i18n="acc.ordersSub">查看订单记录</div></div>
|
||||
<span class="st-trail"><svg><use href="#i-chevron-right"/></svg></span>
|
||||
</button>
|
||||
<button class="setting-row is-tap" id="accRedeemRow" style="width:100%">
|
||||
<span class="icon-box"><svg><use href="#i-gift"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="acc.redeem">兑换码</div><div class="st-sub" data-i18n="acc.redeemSub">输入激活码开通</div></div>
|
||||
<span class="st-trail"><svg><use href="#i-chevron-right"/></svg></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="card card-flush" style="margin-bottom:var(--space-5)">
|
||||
<button class="setting-row is-tap" id="accInviteRow" style="width:100%">
|
||||
<span class="icon-box"><svg><use href="#i-gift"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="acc.invite">邀请好友得会员</div><div class="st-sub" data-i18n="acc.inviteSub">好友注册 · 双方都得会员天数</div></div>
|
||||
<span class="st-trail"><svg><use href="#i-chevron-right"/></svg></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="sec-label" data-i18n="acc.info">账户信息</div>
|
||||
<div class="card card-flush" style="margin-bottom:var(--space-5)">
|
||||
<div class="setting-row">
|
||||
@@ -538,25 +598,6 @@
|
||||
<div class="sec-label"><span data-i18n="acc.devices">设备管理</span> · <span id="devHeaderCount">1 / 5</span></div>
|
||||
<div class="card card-flush" id="deviceList" style="margin-bottom:var(--space-5)"></div>
|
||||
|
||||
<div class="sec-label" data-i18n="acc.pref">偏好</div>
|
||||
<div class="card card-flush" style="margin-bottom:var(--space-5)">
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-globe"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="acc.lang">语言</div></div>
|
||||
<span class="st-trail"><span class="st-val" id="accLangVal">简体中文</span></span>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg id="accDarkIcon"><use href="#i-sun"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="acc.dark">深色外观</div><div class="st-sub js-dark-sub">跟随浅色</div></div>
|
||||
<span class="st-trail"><button class="toggle" data-toggle="dark"><i></i></button></span>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-shield"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="acc.protocol">协议</div></div>
|
||||
<span class="st-trail"><span class="st-val" style="font-family:var(--font-mono)">REALITY / Hysteria2</span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-flush">
|
||||
<button class="setting-row is-tap" id="logoutRow" style="width:100%">
|
||||
<span class="icon-box is-danger"><svg><use href="#i-log-out"/></svg></span>
|
||||
@@ -569,19 +610,8 @@
|
||||
<!-- 设置视图 -->
|
||||
<section class="view" data-view="settings">
|
||||
<div class="settings-view">
|
||||
<div class="card card-flush" style="margin-bottom:var(--space-4)">
|
||||
<div class="setting-row is-tap" id="redeemRow">
|
||||
<div class="st-body"><div class="st-title" data-i18n="set.redeem">兑换 & 购买</div><div class="st-sub" data-i18n="set.redeemSub">PRO 会员</div></div>
|
||||
<span class="st-trail"><svg><use href="#i-chevron-right"/></svg></span>
|
||||
</div>
|
||||
<div class="setting-row is-tap" id="ordersRow">
|
||||
<span class="icon-box"><svg><use href="#i-ticket"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="set.orders">我的订单</div><div class="st-sub" data-i18n="set.ordersSub">查看订单记录</div></div>
|
||||
<span class="st-trail"><svg><use href="#i-chevron-right"/></svg></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-flush" style="margin-bottom:var(--space-4)">
|
||||
<div class="sec-label" data-i18n="set.grpConn">连接</div>
|
||||
<div class="card card-flush" style="margin-bottom:var(--space-5)">
|
||||
<div class="setting-row">
|
||||
<div class="st-body"><div class="st-title" data-i18n="set.autostart">开机自启</div><div class="st-sub" data-i18n="set.autostartSub">系统启动时自动运行</div></div>
|
||||
<span class="st-trail"><button class="toggle is-on" data-toggle="autostart"><i></i></button></span>
|
||||
@@ -600,7 +630,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-flush">
|
||||
<div class="sec-label" data-i18n="set.grpAppear">外观</div>
|
||||
<div class="card card-flush" style="margin-bottom:var(--space-5)">
|
||||
<div class="setting-row">
|
||||
<div class="st-body"><div class="st-title" data-i18n="set.lang">语言</div></div>
|
||||
<span class="st-trail">
|
||||
@@ -621,14 +652,14 @@
|
||||
<div class="st-body"><div class="st-title" data-i18n="set.dark">深色外观</div><div class="st-sub js-dark-sub">跟随浅色</div></div>
|
||||
<span class="st-trail"><button class="toggle" data-toggle="dark"><i></i></button></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sec-label" data-i18n="set.grpAbout">关于</div>
|
||||
<div class="card card-flush">
|
||||
<div class="setting-row">
|
||||
<div class="st-body"><div class="st-title" data-i18n="set.protocol">协议</div></div>
|
||||
<span class="st-trail"><span class="st-val" style="font-family:var(--font-mono)">REALITY / Hysteria2</span></span>
|
||||
</div>
|
||||
<div class="setting-row is-tap">
|
||||
<div class="st-body"><div class="st-title" data-i18n="set.web">用户中心(网页)</div></div>
|
||||
<span class="st-trail"><svg><use href="#i-external-link"/></svg></span>
|
||||
</div>
|
||||
<div class="setting-row is-tap">
|
||||
<div class="st-body"><div class="st-title" data-i18n="set.update">检查更新</div></div>
|
||||
<span class="st-trail"><svg><use href="#i-chevron-right"/></svg></span>
|
||||
@@ -637,6 +668,10 @@
|
||||
<div class="st-body"><div class="st-title">Version</div></div>
|
||||
<span class="st-trail"><span class="st-val" style="font-family:var(--font-mono)">v2.4.0 (macOS)</span></span>
|
||||
</div>
|
||||
<div class="setting-row is-tap">
|
||||
<div class="st-body"><div class="st-title" style="color:var(--fg3)" data-i18n="set.web">网页版用户中心</div></div>
|
||||
<span class="st-trail"><svg><use href="#i-external-link"/></svg></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -806,6 +841,90 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 通知收件箱视图(占位 · Spec ③) -->
|
||||
<section class="view" data-view="notifications">
|
||||
<div class="notif-view">
|
||||
<button class="pv-back" id="ntBack"><svg><use href="#i-arrow-left"/></svg><span data-i18n="nt.back">返回</span></button>
|
||||
<div class="sec-label" data-i18n="nt.title">通知</div>
|
||||
<div class="card card-flush">
|
||||
<div class="notif-row is-unread">
|
||||
<span class="notif-dot"></span>
|
||||
<div class="notif-body">
|
||||
<div class="notif-head"><span class="pill pill-outline" data-i18n="nt.tImportant">重要</span><span class="notif-time">2h</span></div>
|
||||
<div class="notif-t" data-i18n="nt.n1t">服务条款与隐私政策更新</div>
|
||||
<div class="notif-s" data-i18n="nt.n1s">我们更新了服务条款,请查阅最新内容。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="notif-row is-unread">
|
||||
<span class="notif-dot"></span>
|
||||
<div class="notif-body">
|
||||
<div class="notif-head"><span class="pill pill-outline" data-i18n="nt.tFeature">功能</span><span class="notif-time">1d</span></div>
|
||||
<div class="notif-t" data-i18n="nt.n2t">新增日本 · 大阪加速线路</div>
|
||||
<div class="notif-s" data-i18n="nt.n2s">三条低延迟线路已上线,欢迎体验。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="notif-row">
|
||||
<span class="notif-dot"></span>
|
||||
<div class="notif-body">
|
||||
<div class="notif-head"><span class="pill pill-outline" data-i18n="nt.tNews">新闻</span><span class="notif-time">3d</span></div>
|
||||
<div class="notif-t" data-i18n="nt.n3t">邀请好友活动进行中</div>
|
||||
<div class="notif-s" data-i18n="nt.n3s">邀请好友注册,双方都可获得会员天数。</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 邀请好友视图(占位 · Spec ②) -->
|
||||
<section class="view" data-view="invite">
|
||||
<div class="invite-view">
|
||||
<button class="pv-back" id="invBack"><svg><use href="#i-arrow-left"/></svg><span data-i18n="inv.back">返回</span></button>
|
||||
<div class="sec-label" data-i18n="inv.title">邀请好友</div>
|
||||
<div class="card invite-code-card">
|
||||
<div class="inv-lead" data-i18n="inv.lead">分享你的邀请码或链接,好友注册后双方都得会员天数。</div>
|
||||
<div class="inv-code-box">
|
||||
<span class="inv-code">PANGO-7F3A</span>
|
||||
<button class="kv-copy js-inv-copy" data-copy="PANGO-7F3A"><svg><use href="#i-copy"/></svg></button>
|
||||
</div>
|
||||
<div class="inv-link-box">
|
||||
<span class="inv-link">https://pangolin.app/i/7F3A</span>
|
||||
<button class="kv-copy js-inv-copy" data-copy="https://pangolin.app/i/7F3A"><svg><use href="#i-copy"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sec-label" data-i18n="inv.rewardsHead">奖励说明 · 双方都得</div>
|
||||
<div class="card card-flush" style="margin-bottom:var(--space-5)">
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-user"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="inv.r1">好友注册</div><div class="st-sub" data-i18n="inv.r1s">双方各得会员天数</div></div>
|
||||
<span class="st-trail"><span class="pill pill-outline">+3d</span></span>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-crown"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="inv.r2">好友首次购买</div><div class="st-sub" data-i18n="inv.r2s">双方各得更多天数</div></div>
|
||||
<span class="st-trail"><span class="pill pill-outline">+30d</span></span>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-send"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="inv.r3">加入 TG 频道</div><div class="st-sub" data-i18n="inv.r3s">额外获得会员天数</div></div>
|
||||
<span class="st-trail"><span class="pill pill-outline">+7d</span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sec-label" data-i18n="inv.progHead">奖励进度</div>
|
||||
<div class="card">
|
||||
<div class="inv-prog-row">
|
||||
<span class="inv-prog-k" data-i18n="inv.invited">已邀请好友</span>
|
||||
<span class="inv-prog-v">3</span>
|
||||
</div>
|
||||
<div class="inv-prog-row">
|
||||
<span class="inv-prog-k" data-i18n="inv.earned">累计获得会员</span>
|
||||
<span class="inv-prog-v">+42d</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- toast -->
|
||||
<div class="pv-toast" id="pvToast"><svg><use href="#i-check"/></svg><span id="pvToastText"></span></div>
|
||||
|
||||
@@ -882,6 +1001,26 @@ var I18N = {
|
||||
'nav.contact':{zh:'联系',en:'Contact'}, 'nav.account':{zh:'账户',en:'Account'},
|
||||
'nav.purchase':{zh:'升级 PRO',en:'Upgrade PRO'},
|
||||
'nav.orders':{zh:'我的订单',en:'Orders'},
|
||||
'nav.account':{zh:'账户',en:'Account'},
|
||||
'nav.notifications':{zh:'通知',en:'Notifications'}, 'nav.invite':{zh:'邀请好友',en:'Invite friends'},
|
||||
'acc.billing':{zh:'购买 & 订单 & 兑换',en:'Buy · Orders · Redeem'},
|
||||
'acc.buy':{zh:'购买套餐',en:'Buy a plan'}, 'acc.buySub':{zh:'升级 PRO 会员',en:'Upgrade to PRO'},
|
||||
'acc.orders':{zh:'我的订单',en:'My orders'}, 'acc.ordersSub':{zh:'查看订单记录',en:'View order history'},
|
||||
'acc.redeem':{zh:'兑换码',en:'Redeem code'}, 'acc.redeemSub':{zh:'输入激活码开通',en:'Activate with a code'},
|
||||
'acc.invite':{zh:'邀请好友得会员',en:'Invite friends, earn membership'}, 'acc.inviteSub':{zh:'好友注册 · 双方都得会员天数',en:'Both sides earn membership days'},
|
||||
'nt.back':{zh:'返回',en:'Back'}, 'nt.title':{zh:'通知',en:'Notifications'},
|
||||
'nt.tImportant':{zh:'重要',en:'Important'}, 'nt.tFeature':{zh:'功能',en:'Feature'}, 'nt.tNews':{zh:'新闻',en:'News'},
|
||||
'nt.n1t':{zh:'服务条款与隐私政策更新',en:'Terms & privacy policy updated'}, 'nt.n1s':{zh:'我们更新了服务条款,请查阅最新内容。',en:'We have updated our terms — please review the latest version.'},
|
||||
'nt.n2t':{zh:'新增日本 · 大阪加速线路',en:'New Japan · Osaka lines added'}, 'nt.n2s':{zh:'三条低延迟线路已上线,欢迎体验。',en:'Three low-latency lines are now live.'},
|
||||
'nt.n3t':{zh:'邀请好友活动进行中',en:'Invite-a-friend event is live'}, 'nt.n3s':{zh:'邀请好友注册,双方都可获得会员天数。',en:'Invite friends to sign up — both sides earn membership days.'},
|
||||
'inv.back':{zh:'返回',en:'Back'}, 'inv.title':{zh:'邀请好友',en:'Invite friends'},
|
||||
'inv.lead':{zh:'分享你的邀请码或链接,好友注册后双方都得会员天数。',en:'Share your code or link — when a friend signs up, both of you earn membership days.'},
|
||||
'inv.rewardsHead':{zh:'奖励说明 · 双方都得',en:'Rewards · both sides earn'},
|
||||
'inv.r1':{zh:'好友注册',en:'Friend signs up'}, 'inv.r1s':{zh:'双方各得会员天数',en:'Both earn membership days'},
|
||||
'inv.r2':{zh:'好友首次购买',en:'Friend first purchase'}, 'inv.r2s':{zh:'双方各得更多天数',en:'Both earn more days'},
|
||||
'inv.r3':{zh:'加入 TG 频道',en:'Join the TG channel'}, 'inv.r3s':{zh:'额外获得会员天数',en:'Earn extra days'},
|
||||
'inv.progHead':{zh:'奖励进度',en:'Reward progress'},
|
||||
'inv.invited':{zh:'已邀请好友',en:'Friends invited'}, 'inv.earned':{zh:'累计获得会员',en:'Membership earned'},
|
||||
'set.orders':{zh:'我的订单',en:'My orders'}, 'set.ordersSub':{zh:'查看订单记录',en:'View order history'},
|
||||
'ord.back':{zh:'返回',en:'Back'}, 'ord.details':{zh:'明细',en:'Details'},
|
||||
'ord.kOrderNo':{zh:'订单号',en:'Order No.'}, 'ord.kPlan':{zh:'套餐',en:'Plan'}, 'ord.kAmount':{zh:'金额',en:'Amount'},
|
||||
@@ -933,7 +1072,8 @@ var I18N = {
|
||||
'set.smart':{zh:'智能分流',en:'Smart routing'}, 'set.smartSub':{zh:'海外应用走加速,国内直连',en:'Accelerate abroad, direct at home'},
|
||||
'set.kill':{zh:'断连保护 Kill Switch',en:'Kill Switch'}, 'set.killSub':{zh:'断线时阻断网络,防止数据泄露',en:'Block traffic if the link drops'},
|
||||
'set.lang':{zh:'语言',en:'Language'}, 'set.dark':{zh:'深色外观',en:'Dark appearance'},
|
||||
'set.protocol':{zh:'协议',en:'Protocol'}, 'set.web':{zh:'用户中心(网页)',en:'User Center (Web)'},
|
||||
'set.protocol':{zh:'协议',en:'Protocol'}, 'set.web':{zh:'网页版用户中心',en:'Web User Center'},
|
||||
'set.grpConn':{zh:'连接',en:'Connection'}, 'set.grpAppear':{zh:'外观',en:'Appearance'}, 'set.grpAbout':{zh:'关于',en:'About'},
|
||||
'set.update':{zh:'检查更新',en:'Check for updates'},
|
||||
'contact.intro':{zh:'遇到问题?通过以下任一渠道联系我们,通常数分钟内回复。',en:'Having trouble? Reach us on any channel below — usually a reply within minutes.'},
|
||||
'contact.email':{zh:'邮箱客服',en:'Email support'}, 'contact.web':{zh:'官网',en:'Website'},
|
||||
@@ -982,7 +1122,7 @@ var PLAN = {
|
||||
};
|
||||
|
||||
/* ========= 全局状态 ========= */
|
||||
var S = { theme:'light', lang:'en', langLabel:'English', persp:'free', conn:'off', view:'connect', secs:0, timerId:null, connId:null, upd:true, statsDev:'all' };
|
||||
var S = { theme:'light', lang:'en', langLabel:'English', persp:'free', conn:'off', view:'connect', secs:0, timerId:null, connId:null, upd:true, statsDev:'all', notifFrom:'connect' };
|
||||
|
||||
/* ========= 主题 ========= */
|
||||
function applyTheme(t){
|
||||
@@ -1171,7 +1311,7 @@ function syncSegs(){
|
||||
// langsel(6 语显示层)
|
||||
document.getElementById('langSelLabel').textContent = S.langLabel;
|
||||
document.querySelectorAll('#langSelMenu .menu-item').forEach(function(m){ m.classList.toggle('is-selected', m.dataset.langlabel===S.langLabel); });
|
||||
document.getElementById('accLangVal').textContent = S.langLabel;
|
||||
var _accLang=document.getElementById('accLangVal'); if(_accLang) _accLang.textContent = S.langLabel;
|
||||
}
|
||||
|
||||
/* ========= 连接状态机(仅 PRO 视角可用) ========= */
|
||||
@@ -1480,6 +1620,16 @@ function ordRelabel(){ renderOrderList(); if(ORD.screen==='detail'&&ORD.curId){
|
||||
var _ordersRow=document.getElementById('ordersRow'); if(_ordersRow) _ordersRow.addEventListener('click', function(){ openOrders('settings'); });
|
||||
var _odBack=document.getElementById('odBack'); if(_odBack) _odBack.addEventListener('click', function(){ if(ORD.screen==='detail'){ ordShow('list'); } else { setView(ORD.from); } });
|
||||
|
||||
/* ========= 账户新入口 / 通知铃铛 / 邀请(IA 重构) ========= */
|
||||
var _accBuy=document.getElementById('accBuyRow'); if(_accBuy) _accBuy.addEventListener('click', function(){ openPurchase('account'); });
|
||||
var _accOrders=document.getElementById('accOrdersRow'); if(_accOrders) _accOrders.addEventListener('click', function(){ openOrders('account'); });
|
||||
var _accRedeem=document.getElementById('accRedeemRow'); if(_accRedeem) _accRedeem.addEventListener('click', function(){ openPurchase('account'); });
|
||||
var _accInvite=document.getElementById('accInviteRow'); if(_accInvite) _accInvite.addEventListener('click', function(){ setView('invite'); });
|
||||
var _tbBell=document.getElementById('tbBell'); if(_tbBell) _tbBell.addEventListener('click', function(){ if(S.view!=='notifications'){ S.notifFrom=S.view; } setView('notifications'); });
|
||||
var _ntBack=document.getElementById('ntBack'); if(_ntBack) _ntBack.addEventListener('click', function(){ setView(S.notifFrom||'connect'); });
|
||||
var _invBack=document.getElementById('invBack'); if(_invBack) _invBack.addEventListener('click', function(){ setView('account'); });
|
||||
document.querySelectorAll('.js-inv-copy').forEach(function(b){ b.addEventListener('click', function(){ pvToast((S.lang==='zh'?'已复制:':'Copied: ')+b.dataset.copy); }); });
|
||||
|
||||
/* ========= 初始化 ========= */
|
||||
(function init(){
|
||||
var saved='light'; try{ saved=localStorage.getItem('pangolin-ds-theme')||'light'; }catch(e){}
|
||||
|
||||
@@ -302,6 +302,60 @@
|
||||
transition:opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out); z-index:60; }
|
||||
.ord-toast svg{ width:14px; height:14px; }
|
||||
.ord-toast.show{ opacity:1; transform:translate(-50%, 0); }
|
||||
|
||||
/* 顶栏通知铃铛 + 未读红点 */
|
||||
.bell-btn{ position:relative; border:none; background:transparent; cursor:pointer; color:var(--fg2);
|
||||
padding:var(--space-1); border-radius:var(--radius-sm); display:inline-flex; }
|
||||
.bell-btn:hover{ color:var(--accent); background:var(--accent-subtle); }
|
||||
.bell-btn svg{ width:20px; height:20px; }
|
||||
.bell-dot{ position:absolute; top:2px; right:2px; width:7px; height:7px; border-radius:var(--radius-full);
|
||||
background:var(--danger); border:1.5px solid var(--surface); }
|
||||
|
||||
/* 通用子屏覆盖层(设置 / 联系 / 通知 / 邀请 / 兑换;命名空间 .sub-*) */
|
||||
#subOverlay{ position:absolute; left:0; right:0; top:30px; bottom:0; z-index:45;
|
||||
background:var(--bg); display:none; flex-direction:column; }
|
||||
#subOverlay.is-open{ display:flex; }
|
||||
.sub-top{ height:48px; flex:none; display:flex; align-items:center; gap:var(--space-2);
|
||||
padding:0 var(--space-2); border-bottom:1px solid var(--border); background:var(--surface); }
|
||||
.sub-back{ width:38px; height:38px; display:flex; align-items:center; justify-content:center;
|
||||
border:none; background:transparent; color:var(--fg1); cursor:pointer; }
|
||||
.sub-back svg{ width:20px; height:20px; }
|
||||
.sub-ttl{ font-family:var(--font-sans); font-size:var(--text-h3); font-weight:700; color:var(--fg1); }
|
||||
.sub-body{ flex:1; position:relative; overflow:hidden; }
|
||||
.sub-screen{ position:absolute; inset:0; display:none; flex-direction:column; }
|
||||
.sub-screen.is-active{ display:flex; }
|
||||
.sub-scr{ flex:1; overflow:auto; padding:var(--space-5); }
|
||||
.sub-stack > *{ margin-bottom:var(--space-4); }
|
||||
.sub-stack > *:last-child{ margin-bottom:0; }
|
||||
.sub-note{ font-size:var(--text-caption); color:var(--fg3); line-height:var(--leading-relaxed); text-align:center; }
|
||||
|
||||
/* 通知收件箱 · 未读点 */
|
||||
.noti-dot{ width:8px; height:8px; border-radius:var(--radius-full); background:var(--danger); flex:none; display:block; }
|
||||
.noti-item.is-read .noti-dot{ background:var(--border-strong); }
|
||||
.noti-item.is-read .st-title{ color:var(--fg2); font-weight:600; }
|
||||
|
||||
/* 邀请好友 */
|
||||
.inv-hero{ text-align:center; display:flex; flex-direction:column; align-items:center; gap:var(--space-2); }
|
||||
.inv-ic{ width:56px; height:56px; border-radius:var(--radius-xl); color:var(--fg-on-accent);
|
||||
background:linear-gradient(135deg,var(--clay-500),var(--clay-800));
|
||||
display:flex; align-items:center; justify-content:center; box-shadow:var(--shadow-md); }
|
||||
.inv-ic svg{ width:28px; height:28px; }
|
||||
.inv-title{ font-family:var(--font-display); font-size:var(--text-h3); font-weight:700; color:var(--fg1); }
|
||||
.inv-sub{ font-size:var(--text-sm); color:var(--fg2); line-height:var(--leading-relaxed); }
|
||||
.inv-prog-row{ display:flex; align-items:baseline; justify-content:space-between; margin-bottom:var(--space-2); }
|
||||
.inv-prog-v{ font-family:var(--font-mono); font-size:var(--text-sm); color:var(--fg1); font-weight:600; }
|
||||
.inv-bar{ height:8px; border-radius:var(--radius-full); background:var(--bg-subtle); overflow:hidden; }
|
||||
.inv-bar > i{ display:block; height:100%; border-radius:var(--radius-full);
|
||||
background:linear-gradient(90deg,var(--clay-500),var(--clay-800)); }
|
||||
|
||||
/* 子屏 toast */
|
||||
.sub-toast{ position:absolute; left:50%; bottom:var(--space-6); transform:translate(-50%, 12px);
|
||||
background:var(--fg1); color:var(--bg); font-size:var(--text-caption); font-weight:600;
|
||||
padding:var(--space-2) var(--space-4); border-radius:var(--radius-full); box-shadow:var(--shadow-lg);
|
||||
display:flex; align-items:center; gap:var(--space-2); opacity:0; pointer-events:none;
|
||||
transition:opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out); z-index:60; }
|
||||
.sub-toast svg{ width:14px; height:14px; }
|
||||
.sub-toast.show{ opacity:1; transform:translate(-50%, 0); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -365,7 +419,7 @@
|
||||
<!-- App 顶栏 -->
|
||||
<div class="phone-top">
|
||||
<span class="ttl" id="scrTitle" data-i18n="navConnect">连接</span>
|
||||
<div class="rt"><span class="pill is-neutral" id="connPill" hidden><span class="dot"></span><span id="connPillTxt">免费版</span></span></div>
|
||||
<div class="rt"><span class="pill is-neutral" id="connPill" hidden><span class="dot"></span><span id="connPillTxt">免费版</span></span><button class="bell-btn" id="bellBtn" aria-label="通知"><svg><use href="#i-bell"/></svg><span class="bell-dot"></span></button></div>
|
||||
</div>
|
||||
|
||||
<!-- 更新顶部横条 -->
|
||||
@@ -478,7 +532,7 @@
|
||||
<div class="pbn-name" style="font-size:var(--text-body)">me@pangolin.app</div>
|
||||
<div style="margin-top:4px"><span class="quota-tag" data-i18n="planFree">免费版</span></div>
|
||||
</div>
|
||||
<button class="btn btn-primary"><span data-i18n="upgrade">续费 / 升级</span></button>
|
||||
<button class="btn btn-primary pbn-buy"><span data-i18n="upgrade">续费 / 升级</span></button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- PRO 横幅 -->
|
||||
@@ -489,10 +543,41 @@
|
||||
<div class="pbn-name" style="font-size:var(--text-body)">me@pangolin.app</div>
|
||||
<div class="pbn-meta" data-i18n="planProMeta">PRO 会员 · 有效期至 2027-07-11</div>
|
||||
</div>
|
||||
<button class="btn btn-primary" data-i18n="renew">续费 / 升级</button>
|
||||
<button class="btn btn-primary pbn-buy" data-i18n="renew">续费 / 升级</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 购买 & 订单 & 兑换 -->
|
||||
<div class="sec-label" data-i18n="secBilling">购买 · 订单 · 兑换</div>
|
||||
<div class="card card-flush">
|
||||
<div class="setting-row is-tap" id="rowBuy">
|
||||
<span class="icon-box"><svg><use href="#i-crown"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="rowBuyPlan">购买套餐</div></div>
|
||||
<div class="st-trail"><svg><use href="#i-chevron-right"/></svg></div>
|
||||
</div>
|
||||
<div class="setting-row is-tap" id="rowOrders">
|
||||
<span class="icon-box"><svg><use href="#i-ticket"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="navOrders">我的订单</div></div>
|
||||
<div class="st-trail"><svg><use href="#i-chevron-right"/></svg></div>
|
||||
</div>
|
||||
<div class="setting-row is-tap" id="rowRedeem">
|
||||
<span class="icon-box"><svg><use href="#i-key"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="navRedeemCode">兑换码</div></div>
|
||||
<div class="st-trail"><svg><use href="#i-chevron-right"/></svg></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 邀请好友 -->
|
||||
<div class="sec-label" data-i18n="secInvite">推广</div>
|
||||
<div class="card card-flush">
|
||||
<div class="setting-row is-tap" id="rowInvite">
|
||||
<span class="icon-box"><svg><use href="#i-gift"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="inviteEntry">邀请好友得会员</div><div class="st-sub" data-i18n="inviteEntrySub">双方各得订阅天数</div></div>
|
||||
<div class="st-trail"><svg><use href="#i-chevron-right"/></svg></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 账户信息 -->
|
||||
<div class="sec-label" data-i18n="secAccount">账户信息</div>
|
||||
<div class="card card-flush">
|
||||
<div class="setting-row">
|
||||
@@ -507,7 +592,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 设备 · 免费 1/1 -->
|
||||
<!-- 我的设备 · 免费 1/1 -->
|
||||
<div id="devFree">
|
||||
<div class="sec-label" data-i18n="devFreeLbl">我的设备 · 1 / 1 台</div>
|
||||
<div class="dl-list">
|
||||
@@ -521,7 +606,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 设备 · PRO 3/5 -->
|
||||
<!-- 我的设备 · PRO 3/5 -->
|
||||
<div id="devPro" hidden>
|
||||
<div class="sec-label" data-i18n="devProLbl">我的设备 · 3 / 5 台</div>
|
||||
<div class="dl-list">
|
||||
@@ -552,69 +637,19 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sec-label" data-i18n="secPref">偏好</div>
|
||||
<!-- 设置 / 联系(移动端无侧栏,入口收进 Account) -->
|
||||
<div class="sec-label" data-i18n="secGeneral">通用</div>
|
||||
<div class="card card-flush">
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-globe"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="prefLang">语言</div></div>
|
||||
<div class="st-trail">
|
||||
<div class="langsel" id="acctLang">
|
||||
<button class="langsel-trigger" id="acctLangTrigger" aria-expanded="false"><span id="acctLangLabel">简体中文</span><svg><use href="#i-chevron-down"/></svg></button>
|
||||
<div class="menu" id="acctLangMenu" hidden>
|
||||
<button class="menu-item is-selected" data-lang="zh" data-label="简体中文">简体中文</button>
|
||||
<button class="menu-item" data-lang="en" data-label="English">English</button>
|
||||
<button class="menu-item" data-lang="ja" data-label="日本語">日本語</button>
|
||||
<button class="menu-item" data-lang="ko" data-label="한국어">한국어</button>
|
||||
<button class="menu-item" data-lang="ru" data-label="Русский">Русский</button>
|
||||
<button class="menu-item" data-lang="es" data-label="Español">Español</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span class="icon-box" id="themeIconBox"><svg id="themeIcon"><use href="#i-sun"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="prefTheme">深色外观</div><div class="st-sub" id="themeSub" data-i18n="followLight">跟随浅色</div></div>
|
||||
<div class="st-trail"><button class="toggle" id="themeToggle"><i></i></button></div>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-shield"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="prefProtocol">协议</div></div>
|
||||
<div class="st-trail"><span class="st-val" style="font-family:var(--font-mono)">REALITY / Hysteria2</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sec-label" data-i18n="secMore">更多</div>
|
||||
<div class="card card-flush">
|
||||
<div class="setting-row is-tap">
|
||||
<span class="icon-box"><svg><use href="#i-monitor-smartphone"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="navDevices">设备管理</div></div>
|
||||
<div class="st-trail"><svg><use href="#i-chevron-right"/></svg></div>
|
||||
</div>
|
||||
<div class="setting-row is-tap">
|
||||
<div class="setting-row is-tap" id="rowSettings">
|
||||
<span class="icon-box"><svg><use href="#i-settings"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="navSettings">设置</div></div>
|
||||
<div class="st-trail"><svg><use href="#i-chevron-right"/></svg></div>
|
||||
</div>
|
||||
<div class="setting-row is-tap" id="rowRedeem">
|
||||
<span class="icon-box"><svg><use href="#i-shopping-bag"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="navRedeem">兑换 & 购买</div></div>
|
||||
<div class="st-trail"><svg><use href="#i-chevron-right"/></svg></div>
|
||||
</div>
|
||||
<div class="setting-row is-tap" id="rowOrders">
|
||||
<span class="icon-box"><svg><use href="#i-ticket"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="navOrders">我的订单</div></div>
|
||||
<div class="st-trail"><svg><use href="#i-chevron-right"/></svg></div>
|
||||
</div>
|
||||
<div class="setting-row is-tap">
|
||||
<div class="setting-row is-tap" id="rowContact">
|
||||
<span class="icon-box"><svg><use href="#i-message-circle"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="navContact">联系我们</div></div>
|
||||
<div class="st-trail"><svg><use href="#i-chevron-right"/></svg></div>
|
||||
</div>
|
||||
<div class="setting-row is-tap">
|
||||
<span class="icon-box"><svg><use href="#i-globe"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="navWebUC">网页用户中心</div></div>
|
||||
<div class="st-trail"><svg><use href="#i-external-link"/></svg></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-flush">
|
||||
@@ -785,6 +820,199 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- 通用子屏覆盖层(顶栏铃铛→通知;账户入口→设置 / 联系 / 邀请 / 兑换;命名空间 .sub-*) -->
|
||||
<div id="subOverlay">
|
||||
<div class="sub-top">
|
||||
<button class="sub-back" id="subBack" aria-label="返回"><svg><use href="#i-arrow-left"/></svg></button>
|
||||
<span class="sub-ttl" id="subTitle"></span>
|
||||
</div>
|
||||
<div class="sub-body">
|
||||
|
||||
<!-- 设置:连接 / 外观 / 关于(语言·主题在此,Account 顶层不放) -->
|
||||
<section class="sub-screen" data-sub="settings">
|
||||
<div class="sub-scr sub-stack">
|
||||
<div class="sec-label" data-i18n="setGrpConn">连接</div>
|
||||
<div class="card card-flush">
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-power"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="setLaunch">开机自启</div></div>
|
||||
<div class="st-trail"><button class="toggle js-toggle"><i></i></button></div>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-zap"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="setAutoConn">自动连接</div></div>
|
||||
<div class="st-trail"><button class="toggle js-toggle is-on"><i></i></button></div>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-compass"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="setSmartRoute">智能分流</div></div>
|
||||
<div class="st-trail"><button class="toggle js-toggle is-on"><i></i></button></div>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-shield"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="setKill">断网保护</div></div>
|
||||
<div class="st-trail"><button class="toggle js-toggle"><i></i></button></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sec-label" data-i18n="setGrpAppr">外观</div>
|
||||
<div class="card card-flush">
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-globe"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="prefLang">语言</div></div>
|
||||
<div class="st-trail">
|
||||
<div class="langsel" id="acctLang">
|
||||
<button class="langsel-trigger" id="acctLangTrigger" aria-expanded="false"><span id="acctLangLabel">简体中文</span><svg><use href="#i-chevron-down"/></svg></button>
|
||||
<div class="menu" id="acctLangMenu" hidden>
|
||||
<button class="menu-item is-selected" data-lang="zh" data-label="简体中文">简体中文</button>
|
||||
<button class="menu-item" data-lang="en" data-label="English">English</button>
|
||||
<button class="menu-item" data-lang="ja" data-label="日本語">日本語</button>
|
||||
<button class="menu-item" data-lang="ko" data-label="한국어">한국어</button>
|
||||
<button class="menu-item" data-lang="ru" data-label="Русский">Русский</button>
|
||||
<button class="menu-item" data-lang="es" data-label="Español">Español</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span class="icon-box" id="themeIconBox"><svg id="themeIcon"><use href="#i-sun"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="prefTheme">深色外观</div><div class="st-sub" id="themeSub" data-i18n="followLight">跟随浅色</div></div>
|
||||
<div class="st-trail"><button class="toggle" id="themeToggle"><i></i></button></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sec-label" data-i18n="setGrpAbout">关于</div>
|
||||
<div class="card card-flush">
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-shield"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="prefProtocol">协议</div></div>
|
||||
<div class="st-trail"><span class="st-val" style="font-family:var(--font-mono)">REALITY / Hysteria2</span></div>
|
||||
</div>
|
||||
<div class="setting-row is-tap">
|
||||
<span class="icon-box"><svg><use href="#i-download"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="setCheckUpdate">检查更新</div><div class="st-sub">v1.1.0</div></div>
|
||||
<div class="st-trail"><svg><use href="#i-chevron-right"/></svg></div>
|
||||
</div>
|
||||
<div class="setting-row is-tap">
|
||||
<span class="icon-box"><svg><use href="#i-globe"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="navWebUC">网页用户中心</div></div>
|
||||
<div class="st-trail"><svg><use href="#i-external-link"/></svg></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 联系我们:唯一渠道来源(无「去哪买」引流) -->
|
||||
<section class="sub-screen" data-sub="contact">
|
||||
<div class="sub-scr sub-stack">
|
||||
<div class="card card-flush">
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-send"/></svg></span>
|
||||
<div class="st-body"><div class="st-title">Telegram</div><div class="st-sub">@Pangolin_Support</div></div>
|
||||
<button class="kv-copy sub-copy" data-copy="@Pangolin_Support" aria-label="copy"><svg><use href="#i-copy"/></svg></button>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-mail"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="contactEmail">邮箱</div><div class="st-sub">support@pangolin.app</div></div>
|
||||
<button class="kv-copy sub-copy" data-copy="support@pangolin.app" aria-label="copy"><svg><use href="#i-copy"/></svg></button>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-globe"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="contactWeb">官网</div><div class="st-sub">pangolin.app</div></div>
|
||||
<button class="kv-copy sub-copy" data-copy="pangolin.app" aria-label="copy"><svg><use href="#i-copy"/></svg></button>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-clock"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="contactHours">服务时间</div><div class="st-sub" data-i18n="contactHoursVal">每日 9:00–24:00 (GMT+8)</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 通知收件箱(占位·mockup 级) -->
|
||||
<section class="sub-screen" data-sub="notifications">
|
||||
<div class="sub-scr sub-stack">
|
||||
<div class="card card-flush">
|
||||
<div class="setting-row noti-item">
|
||||
<span class="icon-box"><svg><use href="#i-zap"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="noti1">新增日本 · 大阪加速线路</div><div class="st-sub" data-i18n="noti1sub">功能 · 2 小时前</div></div>
|
||||
<div class="st-trail"><span class="noti-dot"></span></div>
|
||||
</div>
|
||||
<div class="setting-row noti-item">
|
||||
<span class="icon-box"><svg><use href="#i-shield"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="noti2">安全提示:请及时更新到 v1.1.0</div><div class="st-sub" data-i18n="noti2sub">重要 · 昨天</div></div>
|
||||
<div class="st-trail"><span class="noti-dot"></span></div>
|
||||
</div>
|
||||
<div class="setting-row noti-item is-read">
|
||||
<span class="icon-box"><svg><use href="#i-gift"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="noti3">邀请好友活动上线,双方得会员</div><div class="st-sub" data-i18n="noti3sub">新闻 · 3 天前</div></div>
|
||||
<div class="st-trail"><span class="noti-dot"></span></div>
|
||||
</div>
|
||||
<div class="setting-row noti-item is-read">
|
||||
<span class="icon-box"><svg><use href="#i-check-circle"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="noti4">欢迎使用穿山甲,体验期 7 天已开启</div><div class="st-sub" data-i18n="noti4sub">新闻 · 1 周前</div></div>
|
||||
<div class="st-trail"><span class="noti-dot"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="sub-note" data-i18n="notiFoot">仅显示最近通知(演示占位)</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 邀请好友(占位·mockup 级) -->
|
||||
<section class="sub-screen" data-sub="invite">
|
||||
<div class="sub-scr sub-stack">
|
||||
<div class="inv-hero">
|
||||
<span class="inv-ic"><svg><use href="#i-gift"/></svg></span>
|
||||
<div class="inv-title" data-i18n="inviteHeadline">邀请好友得会员</div>
|
||||
<div class="inv-sub" data-i18n="inviteLede">好友注册、首购、加入社区,双方都各得订阅天数。</div>
|
||||
</div>
|
||||
<div class="card card-flush">
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-key"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="inviteCode">邀请码</div><div class="st-sub" style="font-family:var(--font-mono)">PANGO-8F3A2K</div></div>
|
||||
<button class="kv-copy sub-copy" data-copy="PANGO-8F3A2K" aria-label="copy"><svg><use href="#i-copy"/></svg></button>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span class="icon-box"><svg><use href="#i-link"/></svg></span>
|
||||
<div class="st-body"><div class="st-title" data-i18n="inviteLink">邀请链接</div><div class="st-sub" style="font-family:var(--font-mono)">pangolin.app/i/8F3A2K</div></div>
|
||||
<button class="kv-copy sub-copy" data-copy="pangolin.app/i/8F3A2K" aria-label="copy"><svg><use href="#i-copy"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="pur-feat-h" data-i18n="inviteRewards">奖励规则</div>
|
||||
<div class="plan-feats" style="margin:0">
|
||||
<div class="plan-feat"><svg><use href="#i-check"/></svg><span data-i18n="inviteR1">好友注册 · 双方各得 3 天</span></div>
|
||||
<div class="plan-feat"><svg><use href="#i-check"/></svg><span data-i18n="inviteR2">好友首次购买 · 双方各得 30 天</span></div>
|
||||
<div class="plan-feat"><svg><use href="#i-check"/></svg><span data-i18n="inviteR3">加入 Telegram 社区 · 各得 2 天</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="inv-prog-row"><span class="st-title" data-i18n="inviteProgress">邀请进度</span><span class="inv-prog-v">2 · +6d</span></div>
|
||||
<div class="inv-bar"><i style="width:40%"></i></div>
|
||||
<p class="sub-note" style="text-align:left;margin-top:var(--space-2)" data-i18n="inviteProgressSub">已邀请 2 位好友,累计获得 6 天会员(演示占位)</p>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-block btn-lg sub-copy" data-copy="pangolin.app/i/8F3A2K"><svg><use href="#i-send"/></svg><span data-i18n="inviteShare">分享邀请链接</span></button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 兑换码(仅码,无「去哪买」) -->
|
||||
<section class="sub-screen" data-sub="redeem">
|
||||
<div class="sub-scr sub-stack">
|
||||
<div class="field">
|
||||
<label class="flabel" data-i18n="redeemLabel">兑换码</label>
|
||||
<div class="input-ic"><svg><use href="#i-key"/></svg>
|
||||
<input class="input" data-i18n="redeemPh" data-i18n-attr="placeholder" placeholder="输入兑换 / 激活码" readonly></div>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-block btn-lg" data-i18n="redeemBtn">立即兑换</button>
|
||||
<p class="sub-note" data-i18n="redeemHint">输入卡密即可激活对应时长,激活后立即生效。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- toast -->
|
||||
<div class="sub-toast" id="subToast"><svg><use href="#i-check"/></svg><span id="subToastText"></span></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -975,7 +1203,22 @@ const I18N = {
|
||||
demoReview:'评审演示', demoPaid:'▸ 模拟到账', demoFailed:'▸ 模拟失败',
|
||||
succTitle:'支付成功', succSubTpl:'PRO({name})有效期至 {date}', purDone:'完成',
|
||||
failTitle:'支付失败', failSub:'订单已超时,请重试', purRetry:'重新支付',
|
||||
toastCopied:'已复制:{v}', toastAlipay:'已拉起支付宝(演示)'
|
||||
toastCopied:'已复制:{v}', toastAlipay:'已拉起支付宝(演示)',
|
||||
secBilling:'购买 · 订单 · 兑换', rowBuyPlan:'购买套餐', navRedeemCode:'兑换码',
|
||||
secInvite:'推广', inviteEntry:'邀请好友得会员', inviteEntrySub:'双方各得订阅天数', secGeneral:'通用',
|
||||
setGrpConn:'连接', setLaunch:'开机自启', setAutoConn:'自动连接', setSmartRoute:'智能分流', setKill:'断网保护',
|
||||
setGrpAppr:'外观', setGrpAbout:'关于', setCheckUpdate:'检查更新',
|
||||
contactEmail:'邮箱', contactWeb:'官网', contactHours:'服务时间', contactHoursVal:'每日 9:00–24:00 (GMT+8)',
|
||||
navNotifications:'通知', notiFoot:'仅显示最近通知(演示占位)',
|
||||
noti1:'新增日本 · 大阪加速线路', noti1sub:'功能 · 2 小时前',
|
||||
noti2:'安全提示:请及时更新到 v1.1.0', noti2sub:'重要 · 昨天',
|
||||
noti3:'邀请好友活动上线,双方得会员', noti3sub:'新闻 · 3 天前',
|
||||
noti4:'欢迎使用穿山甲,体验期 7 天已开启', noti4sub:'新闻 · 1 周前',
|
||||
inviteTitle:'邀请好友', inviteHeadline:'邀请好友得会员', inviteLede:'好友注册、首购、加入社区,双方都各得订阅天数。',
|
||||
inviteCode:'邀请码', inviteLink:'邀请链接', inviteRewards:'奖励规则',
|
||||
inviteR1:'好友注册 · 双方各得 3 天', inviteR2:'好友首次购买 · 双方各得 30 天', inviteR3:'加入 Telegram 社区 · 各得 2 天',
|
||||
inviteProgress:'邀请进度', inviteProgressSub:'已邀请 2 位好友,累计获得 6 天会员(演示占位)', inviteShare:'分享邀请链接',
|
||||
redeemLabel:'兑换码', redeemPh:'输入兑换 / 激活码', redeemBtn:'立即兑换', redeemHint:'输入卡密即可激活对应时长,激活后立即生效。'
|
||||
},
|
||||
en:{
|
||||
brandName:'Pangolin', brandLatin:'',
|
||||
@@ -1029,7 +1272,22 @@ const I18N = {
|
||||
demoReview:'Demo', demoPaid:'▸ Simulate paid', demoFailed:'▸ Simulate failure',
|
||||
succTitle:'Payment successful', succSubTpl:'PRO ({name}) · valid until {date}', purDone:'Done',
|
||||
failTitle:'Payment failed', failSub:'Order timed out, please retry', purRetry:'Retry',
|
||||
toastCopied:'Copied: {v}', toastAlipay:'Opened Alipay (demo)'
|
||||
toastCopied:'Copied: {v}', toastAlipay:'Opened Alipay (demo)',
|
||||
secBilling:'Buy · Orders · Redeem', rowBuyPlan:'Buy a plan', navRedeemCode:'Redeem code',
|
||||
secInvite:'Referral', inviteEntry:'Invite friends, earn membership', inviteEntrySub:'Both sides earn plan days', secGeneral:'General',
|
||||
setGrpConn:'Connection', setLaunch:'Launch at startup', setAutoConn:'Auto-connect', setSmartRoute:'Smart routing', setKill:'Kill Switch',
|
||||
setGrpAppr:'Appearance', setGrpAbout:'About', setCheckUpdate:'Check for updates',
|
||||
contactEmail:'Email', contactWeb:'Website', contactHours:'Service hours', contactHoursVal:'Daily 9:00–24:00 (GMT+8)',
|
||||
navNotifications:'Notifications', notiFoot:'Recent notifications only (demo)',
|
||||
noti1:'New node: Japan · Osaka', noti1sub:'Feature · 2h ago',
|
||||
noti2:'Please update to v1.1.0', noti2sub:'Important · yesterday',
|
||||
noti3:'Referral program is live', noti3sub:'News · 3d ago',
|
||||
noti4:'Welcome — your 7-day trial is on', noti4sub:'News · 1w ago',
|
||||
inviteTitle:'Invite friends', inviteHeadline:'Invite friends, earn membership', inviteLede:'When friends sign up, buy, or join the community, both of you earn plan days.',
|
||||
inviteCode:'Invite code', inviteLink:'Invite link', inviteRewards:'How rewards work',
|
||||
inviteR1:'Friend signs up · +3 days each', inviteR2:'Friend first purchase · +30 days each', inviteR3:'Join Telegram · +2 days each',
|
||||
inviteProgress:'Your progress', inviteProgressSub:'Invited 2 friends · earned 6 days (demo)', inviteShare:'Share invite link',
|
||||
redeemLabel:'Redemption code', redeemPh:'Enter your code', redeemBtn:'Redeem now', redeemHint:'Enter a code to instantly activate plan time.'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1272,6 +1530,7 @@ function render(){
|
||||
renderAuth();
|
||||
purLangSync();
|
||||
ordLangSync();
|
||||
subLangSync();
|
||||
}
|
||||
|
||||
/* ---------- 连接状态机 ---------- */
|
||||
@@ -1461,8 +1720,9 @@ function purLangSync(){
|
||||
purRenderPrices(); purSuccessSub(); purOrderCard(); purCryptoExact();
|
||||
}
|
||||
|
||||
// 入口:账户页「兑换 & 购买」
|
||||
$('#rowRedeem').addEventListener('click', purOpen);
|
||||
// 入口:账户页「购买套餐」+ 会员横幅按钮 → 购买流程
|
||||
$('#rowBuy').addEventListener('click', purOpen);
|
||||
document.querySelectorAll('.pbn-buy').forEach(b=>b.addEventListener('click', purOpen));
|
||||
// 支付渠道 switch:切渠道 → 币种/方式随之定,套餐价刷新
|
||||
document.querySelectorAll('#purchaseOverlay .js-pur-chan').forEach(b=>b.addEventListener('click', ()=>{
|
||||
purOrder.chan=b.dataset.chan;
|
||||
@@ -1607,6 +1867,36 @@ $('#rowOrders').addEventListener('click', ordOpen);
|
||||
// 顶栏返回:详情→列表,列表→关闭回账户
|
||||
$('#ordBack').addEventListener('click', ()=>{ if(ordOverlay.dataset.screen==='detail') ordShow('list'); else ordClose(); });
|
||||
|
||||
/* ---------- 通用子屏(顶栏铃铛→通知;账户→设置 / 联系 / 邀请 / 兑换;命名空间 sub) ---------- */
|
||||
const subOverlay = $('#subOverlay');
|
||||
let subToastTimer=null;
|
||||
const SUB_TITLE = { settings:'navSettings', contact:'navContact', notifications:'navNotifications', invite:'inviteTitle', redeem:'navRedeemCode' };
|
||||
function subShow(name){
|
||||
document.querySelectorAll('#subOverlay .sub-screen').forEach(sc=>sc.classList.toggle('is-active', sc.dataset.sub===name));
|
||||
subOverlay.dataset.sub=name;
|
||||
const k=SUB_TITLE[name]; $('#subTitle').textContent = k ? D()[k] : '';
|
||||
document.querySelectorAll('#subOverlay .sub-scr').forEach(el=>el.scrollTop=0);
|
||||
}
|
||||
function subOpen(name){ subShow(name); subOverlay.classList.add('is-open'); }
|
||||
function subClose(){ subOverlay.classList.remove('is-open'); }
|
||||
function subToast(msg){ const t=$('#subToast'); $('#subToastText').textContent=msg; t.classList.add('show'); clearTimeout(subToastTimer); subToastTimer=setTimeout(()=>t.classList.remove('show'),1800); }
|
||||
/* 语言切换时同步子屏标题(由 render() 调用) */
|
||||
function subLangSync(){ if(subOverlay && subOverlay.classList.contains('is-open')) subShow(subOverlay.dataset.sub||'settings'); }
|
||||
|
||||
// 顶栏铃铛 → 通知收件箱
|
||||
$('#bellBtn').addEventListener('click', ()=>subOpen('notifications'));
|
||||
// 账户入口
|
||||
$('#rowSettings').addEventListener('click', ()=>subOpen('settings'));
|
||||
$('#rowContact').addEventListener('click', ()=>subOpen('contact'));
|
||||
$('#rowInvite').addEventListener('click', ()=>subOpen('invite'));
|
||||
$('#rowRedeem').addEventListener('click', ()=>subOpen('redeem'));
|
||||
// 返回 → 关闭回上一屏
|
||||
$('#subBack').addEventListener('click', subClose);
|
||||
// 复制反馈
|
||||
document.querySelectorAll('#subOverlay .sub-copy').forEach(b=>b.addEventListener('click', ()=>subToast(D().toastCopied.replace('{v}', b.dataset.copy))));
|
||||
// 演示开关(设置·连接组)
|
||||
document.querySelectorAll('#subOverlay .js-toggle').forEach(t=>t.addEventListener('click', ()=>t.classList.toggle('is-on')));
|
||||
|
||||
/* ---------- 启动 ---------- */
|
||||
applyTheme(localStorage.getItem('pangolin-ds-theme') || 'light');
|
||||
syncAcctLang();
|
||||
|
||||
Reference in New Issue
Block a user