diff --git a/client/lib/widgets/pangolin_icons.dart b/client/lib/widgets/pangolin_icons.dart index 5fcd8ba..331847f 100644 --- a/client/lib/widgets/pangolin_icons.dart +++ b/client/lib/widgets/pangolin_icons.dart @@ -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; diff --git a/design/prototype/icons.js b/design/prototype/icons.js index b2faa60..4327c39 100644 --- a/design/prototype/icons.js +++ b/design/prototype/icons.js @@ -12,6 +12,7 @@ 'link': '', 'ticket': '', 'users': '', + 'bell': '', 'copy': '', 'refresh-cw': '', 'qr-code': '', diff --git a/design/prototype/screens/ui-desktop.html b/design/prototype/screens/ui-desktop.html index 7c138fe..dc168ab 100644 --- a/design/prototype/screens/ui-desktop.html +++ b/design/prototype/screens/ui-desktop.html @@ -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); } @@ -357,6 +389,7 @@ + @@ -374,7 +407,7 @@
-
连接
○ 未连接
+
连接
○ 未连接
@@ -521,6 +554,33 @@
+
购买 & 订单 & 兑换
+
+ + + +
+ +
+ +
+
账户信息
@@ -538,25 +598,6 @@
设备管理 · 1 / 5
-
偏好
-
-
- -
语言
- 简体中文 -
-
- -
深色外观
跟随浅色
- -
-
- -
协议
- REALITY / Hysteria2 -
-
-
@@ -600,7 +630,8 @@
-
+
外观
+
语言
@@ -621,14 +652,14 @@
深色外观
跟随浅色
+
+ +
关于
+
协议
REALITY / Hysteria2
-
-
用户中心(网页)
- -
检查更新
@@ -637,6 +668,10 @@
Version
v2.4.0 (macOS)
+
+
网页版用户中心
+ +
@@ -806,6 +841,90 @@
+ +
+
+ +
通知
+
+
+ +
+
重要2h
+
服务条款与隐私政策更新
+
我们更新了服务条款,请查阅最新内容。
+
+
+
+ +
+
功能1d
+
新增日本 · 大阪加速线路
+
三条低延迟线路已上线,欢迎体验。
+
+
+
+ +
+
新闻3d
+
邀请好友活动进行中
+
邀请好友注册,双方都可获得会员天数。
+
+
+
+
+
+ + +
+
+ +
邀请好友
+
+
分享你的邀请码或链接,好友注册后双方都得会员天数。
+
+ PANGO-7F3A + +
+ +
+ +
奖励说明 · 双方都得
+
+
+ +
好友注册
双方各得会员天数
+ +3d +
+
+ +
好友首次购买
双方各得更多天数
+ +30d +
+
+ +
加入 TG 频道
额外获得会员天数
+ +7d +
+
+ +
奖励进度
+
+
+ 已邀请好友 + 3 +
+
+ 累计获得会员 + +42d +
+
+
+
+
@@ -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){} diff --git a/design/prototype/screens/ui-mobile.html b/design/prototype/screens/ui-mobile.html index c5789c5..a242a93 100644 --- a/design/prototype/screens/ui-mobile.html +++ b/design/prototype/screens/ui-mobile.html @@ -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); } @@ -365,7 +419,7 @@
连接 -
+
@@ -478,7 +532,7 @@
me@pangolin.app
免费版
- + @@ -489,10 +543,41 @@
me@pangolin.app
PRO 会员 · 有效期至 2027-07-11
- + + +
购买 · 订单 · 兑换
+
+
+ +
购买套餐
+
+
+
+ +
我的订单
+
+
+
+ +
兑换码
+
+
+
+ + +
推广
+
+
+ +
邀请好友得会员
双方各得订阅天数
+
+
+
+ +
账户信息
@@ -507,7 +592,7 @@
- +
我的设备 · 1 / 1 台
@@ -521,7 +606,7 @@
- + -
偏好
+ +
通用
-
- -
语言
-
-
- - -
-
-
-
- -
深色外观
跟随浅色
-
-
-
- -
协议
-
REALITY / Hysteria2
-
-
- -
更多
-
-
- -
设备管理
-
-
-
+
设置
-
- -
兑换 & 购买
-
-
-
- -
我的订单
-
-
-
+
联系我们
-
- -
网页用户中心
-
-
@@ -785,6 +820,199 @@
+ +
+
+ + +
+
+ + +
+
+
连接
+
+
+ +
开机自启
+
+
+
+ +
自动连接
+
+
+
+ +
智能分流
+
+
+
+ +
断网保护
+
+
+
+ +
外观
+
+
+ +
语言
+
+
+ + +
+
+
+
+ +
深色外观
跟随浅色
+
+
+
+ +
关于
+
+
+ +
协议
+
REALITY / Hysteria2
+
+
+ +
检查更新
v1.1.0
+
+
+
+ +
网页用户中心
+
+
+
+
+
+ + +
+
+
+
+ +
Telegram
@Pangolin_Support
+ +
+
+ +
邮箱
support@pangolin.app
+ +
+
+ +
官网
pangolin.app
+ +
+
+ +
服务时间
每日 9:00–24:00 (GMT+8)
+
+
+
+
+ + +
+
+
+
+ +
新增日本 · 大阪加速线路
功能 · 2 小时前
+
+
+
+ +
安全提示:请及时更新到 v1.1.0
重要 · 昨天
+
+
+
+ +
邀请好友活动上线,双方得会员
新闻 · 3 天前
+
+
+
+ +
欢迎使用穿山甲,体验期 7 天已开启
新闻 · 1 周前
+
+
+
+

仅显示最近通知(演示占位)

+
+
+ + +
+
+
+ +
邀请好友得会员
+
好友注册、首购、加入社区,双方都各得订阅天数。
+
+
+
+ +
邀请码
PANGO-8F3A2K
+ +
+
+ +
邀请链接
pangolin.app/i/8F3A2K
+ +
+
+
+
奖励规则
+
+
好友注册 · 双方各得 3 天
+
好友首次购买 · 双方各得 30 天
+
加入 Telegram 社区 · 各得 2 天
+
+
+
+
邀请进度2 · +6d
+
+

已邀请 2 位好友,累计获得 6 天会员(演示占位)

+
+ +
+
+ + +
+
+
+ +
+
+
+ +

输入卡密即可激活对应时长,激活后立即生效。

+
+
+ + +
+ +
+
@@ -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();