Skip to content

feat: 新增 Light/Dark 雙主題切換功能#3

Open
innochic wants to merge 3 commits intodeancourse:masterfrom
innochic:feature/theme-toggle
Open

feat: 新增 Light/Dark 雙主題切換功能#3
innochic wants to merge 3 commits intodeancourse:masterfrom
innochic:feature/theme-toggle

Conversation

@innochic
Copy link

🎯 為什麼要這樣做

網站原先只支援固定深色主題,為提升使用者體驗,需新增淺色主題並允許使用者手動切換。同時要求系統能記憶使用者偏好,並在不同主題之間提供平滑的視覺過渡效果。

⚠️ 修改的內容

CSS 主題 Token 系統

  • 修改方向:重構全域樣式變數架構,以支援雙主題
  • 內容
    • 將原本 :root 的顏色 token 拆分為 [data-theme="dark"][data-theme="light"] 兩套獨立色彩系統
    • 深色主題保留原有高對比深藍色系,淺色主題採用白底藍紫色系調色盤
    • Navbar 背景色抽離為主題專屬 token,使其隨主題自動切換
    • 陰影強度依主題調整(深色較重、淺色較輕)
    • 所有主題相關過渡均設為 300ms smooth,符合設計規格

useTheme Hook

  • 修改方向:新增 React 自定義 Hook,集中管理主題狀態邏輯
  • 內容
    • 讀取初始主題時依優先順序判斷:localStorage 儲存值 → OS prefers-color-scheme → 預設深色
    • 每次主題切換時同步更新 <html data-theme="..."> 屬性與 localStorage,確保刷新後仍保留偏好
    • 提供 theme 狀態值與 toggleTheme 切換函式供元件使用

ThemeToggle 元件

  • 修改方向:新增主題切換按鈕 UI 元件
  • 內容
    • 設計為滑軌切換開關(Toggle Switch),深色模式顯示🌙,淺色模式顯示☀️
    • 滑鈕採用 cubic-bezier(0.34, 1.56, 0.64, 1) 彈跳動畫,增加操作的趣味回饋感
    • 深色模式下滑鈕呈靛紫漸層,淺色模式下呈琥珀黃漸層
    • 具備完整無障礙屬性(aria-labelaria-pressedfocus-visible 輪廓)
391c5a9d-ab53-441a-bb8c-fd4a9872678e

Navbar 與 App 整合

  • 修改方向:將主題切換按鈕整合至導覽列,並於頂層元件注入主題狀態
  • 內容
    • 在頂層元件引入 useTheme Hook,取得 themetoggleTheme
    • themetoggleTheme 以 props 傳遞至 Navbar
    • Navbar 右側(CTA 按鈕旁)置入 ThemeToggle 元件
    • Navbar 背景改用主題 token,切換主題時背景隨之平滑過渡

🧪 測試步驟

測試案例 1:主題切換基本功能

  1. 開啟網站,預設應呈現深色主題
  2. 點擊 Navbar 右側的主題切換按鈕(🌙 圖示)
  3. 預期結果:整個頁面平滑過渡至淺色主題,按鈕圖示切換為 ☀️,滑鈕滑至右側

測試案例 2:主題偏好持久化

  1. 切換至淺色主題後,重新整理頁面(F5)
  2. 預期結果:頁面刷新後仍保持淺色主題,不會閃回深色

測試案例 3:跟隨系統偏好

  1. 清除 localStorage 中的 sp-theme
  2. 將 OS 顯示設定切換至「淺色模式」後重新整理頁面
  3. 預期結果:網站初始主題自動跟隨 OS 設定顯示淺色主題

測試案例 4:ThemeToggle 動畫與無障礙

  1. 滑鼠懸停於切換按鈕上,確認出現 hover 高亮效果與 glow 漸層
  2. 以鍵盤 Tab 鍵聚焦至切換按鈕,確認出現 focus-visible 輪廓
  3. 使用 Tab + Enter 切換主題
  4. 預期結果:鍵盤可獨立操作切換,aria-label 與 aria-pressed 正確反映當前狀態

測試案例 5:Navbar 主題過渡

  1. 在淺色與深色主題之間來回切換
  2. 觀察 Navbar 背景顏色變化
  3. 預期結果:Navbar 背景在 300ms 內平滑過渡(深色為深藍半透明,淺色為白色半透明)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant