fix(portal): 瀏覽器實測抓到的兩個前端缺陷——連結被路由吃掉、.hide 從來沒有在藏東西

兩個都是「HTTP 200 看不出來、真的開瀏覽器才會現形」的(規則五點五③)。

① `#/reset?token=…` 被路由正規化吃掉
   route() 的第一行是「raw 不在 VIEWS 就換成 HOME」,而 reset 不是站內的 view
   ⇒ 使用者點信裡的連結,網址被改寫成 `#/search`、修改密碼畫面根本沒出現,
     **而且 token 一起被丟掉**——連結一次有效,等於這條連結就這樣廢了。
   改:route() 開頭先看有沒有 reset token,有就走 showReset 並 return。
   (boot() 那條只顧得到「整頁重新載入」;hash 變動這條路以前沒人守。)

② `.hide` 一直只有三條有 scope 的規則(#tabbar .tab / #sidenav .nav / .modebtn)
   沒有通用的 `.hide { display:none }` ⇒ 任何其他元素掛上 class="hide" **完全沒被藏起來**,
   看起來有藏、其實沒藏。實測畫面:登入頁還沒按「忘記密碼」就已經露出 email 欄與「寄出連結」;
   連結模式下「現有密碼」那一格也照樣顯示(D62 的「差別只有一格」當場破功)。
   補通用規則,帶 !important 以蓋過 inline display(#forgot-box 有)。
   既有三種用法意圖一致(都是要藏),行為不變。

stage 瀏覽器實測(youlin,playwright):忘記密碼 → 取連結 → 點進去 →
不輸入現有密碼設新密碼 → 自動回登入頁 → 用新密碼登入成功 → 進站 →
設定頁同一份表單(現有密碼那一格回來)改密碼 → **沒有被踢出去、可以繼續操作**。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8vF2zS2XpaZjzkC75Fjss
This commit is contained in:
Claude
2026-08-10 13:51:41 +00:00
parent 8d49d883c0
commit 9a29eb5af6
+12
View File
@@ -122,6 +122,12 @@
.modebtn { flex: none; padding: 9px 18px; font-size: 14.5px; border-radius: 999px; cursor: pointer; border: 1px solid rgba(var(--ink-rgb),.18); background: none; color: rgba(var(--ink-rgb),.6); }
.modebtn.on { border-color: rgba(var(--amber-rgb),.6); background: rgba(var(--amber-rgb),.14); color: var(--amber); font-weight: 600; }
.modebtn.hide { display: none; }
/* 🔴 2026-08-10 實測撞到:`.hide` 一直**只有上面那三條有 scope 的規則**#tabbar .tab / #sidenav .nav / .modebtn),
所以任何其他元素掛上 class="hide" 都**完全沒有被藏起來**——看起來有藏、其實沒藏。
D62 的「忘記密碼」欄位與「現有密碼」欄位就是這樣在瀏覽器上原形畢露的。
補一條通用規則;帶 !important 是因為要蓋過 inline 的 display#forgot-box 就有)。
既有那三種用法的意圖與本規則一致(都是「藏起來」),加這條不改變它們的行為。 */
.hide { display: none !important; }
.kgrid { display: grid; grid-template-columns: 1fr; gap: 12px; padding-bottom: 8px; }
@media (min-width: 700px) { .kgrid { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } }
.kcard { padding: 18px; border-radius: 13px; background: rgba(var(--ink-rgb),.045); border: 1px solid rgba(var(--ink-rgb),.1); cursor: pointer; display: flex; flex-direction: column; gap: 9px; }
@@ -780,6 +786,12 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return {
}
var LOADERS = { card: loadCard, map: loadMap, workflows: loadWorkflows, admin: loadAdmin, settings: loadSettings };
function route() {
// 🔴 D62`#/reset?token=…` **不是站內的一個 view**,是「還沒登入的人拿著連結進來」。
// 少了這一段,下面那行正規化會把不認得的 `reset` 換成 HOME ⇒ **連 token 一起丟掉**
// 使用者點信裡的連結會落在搜尋頁、而且再也回不去(連結一次有效,已經耗掉了)。
// 實測(2026-08-10 stage,瀏覽器):網址被改寫成 `#/search`、修改密碼畫面根本沒出現。
var rt = resetTokenFromUrl();
if (rt) { showReset(rt); return; }
var r = currentRoute();
if (r.raw && r.raw !== r.view) { location.hash = '#/' + r.view; return; }
if (r.view === 'card' && r.arg) S.cardId = decodeURIComponent(r.arg);