feat: establish enterprise-grade UI design master plan and clean up legacy assets
## Major Changes - ✨ Add comprehensive Enterprise Design Master Plan v4.0 - 🏗️ Establish 12-week execution roadmap for 95+ UI screens - 🎨 Define enterprise-grade quality standards and design system - 📋 Map all designs to function specifications with explicit references - 🧹 Archive legacy prototype files to maintain clean repository structure ## Key Features - Complete UI/UX guidelines enhancement plan - Mobile-first design system with Web optimization - WCAG 2.1 AA compliance framework - Cross-platform design consistency standards - Quality assurance and usability testing protocols ## Architecture - Based on v3.0 shared module architecture - 100% function specification compliance - Modular design system approach - Comprehensive documentation strategy This establishes the foundation for creating world-class UI designs that meet Fortune 500 enterprise standards while ensuring perfect alignment with Drama Ling's functional requirements. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
|
|
@ -0,0 +1,389 @@
|
|||
# 🚀 Drama Ling 企業級UI設計總體計劃
|
||||
|
||||
**建立日期**: 2025-01-15
|
||||
**計劃版本**: v4.0 - 企業級重構
|
||||
**架構基礎**: 共用模組架構 v3.0
|
||||
**設計標準**: 企業級UI/UX規範
|
||||
**執行目標**: 95+ UI畫面完整重設計
|
||||
|
||||
## 📋 計劃概述
|
||||
|
||||
### 🎯 核心目標
|
||||
基於 Drama Ling v3.0 共用模組架構,創建企業級標準的完整UI設計系統,確保:
|
||||
- **100%符合功能規格**: 嚴格按照 `/docs/02_design/function-specs/` 規格執行
|
||||
- **統一設計語言**: 完全遵循 `/docs/02_design/ui-ux/ui-ux-guidelines.md` 規範
|
||||
- **企業級品質**: 達到Fortune 500企業內部系統標準
|
||||
- **零設計債務**: 徹底重構,消除所有設計不一致問題
|
||||
|
||||
### 🏗️ 設計架構原則
|
||||
1. **規格優先**: 所有設計必須100%符合功能規格文件
|
||||
2. **模組化設計**: 基於v3.0共用模組架構的設計組件系統
|
||||
3. **一致性保證**: 跨平台設計語言統一
|
||||
4. **可擴展性**: 支援未來功能快速擴展的設計框架
|
||||
5. **無障礙標準**: 符合WCAG 2.1 AA級無障礙要求
|
||||
|
||||
## 🔍 階段一:設計規範完善與標準化 (第1-2週)
|
||||
|
||||
### 1.1 UI/UX規範補全與更新 ⭐ **CRITICAL**
|
||||
|
||||
**目標**: 建立企業級完整設計規範系統
|
||||
|
||||
**工作內容**:
|
||||
- [ ] **色彩系統完善**
|
||||
- 引用文件: `/docs/02_design/ui-ux/ui-ux-guidelines.md` (第35-103行)
|
||||
- 補全遺失的色彩定義:狀態色彩、反饋色彩、學習進度色彩
|
||||
- 建立暗色/亮色主題完整色彩對照表
|
||||
- 定義色彩使用場景和層次規範
|
||||
|
||||
- [ ] **字體系統標準化**
|
||||
- 引用文件: `/docs/02_design/ui-ux/ui-ux-guidelines.md` (第105-136行)
|
||||
- 補全遺失字體規格:多語言字體、特殊用途字體
|
||||
- 建立響應式字體大小系統 (mobile/tablet/desktop)
|
||||
- 定義字體層次和使用場景指南
|
||||
|
||||
- [ ] **間距與佈局系統**
|
||||
- 引用文件: `/docs/02_design/ui-ux/ui-ux-guidelines.md` (第139-163行)
|
||||
- 建立8px grid系統標準
|
||||
- 定義響應式佈局斷點和規則
|
||||
- 創建元件間距和頁面佈局標準模板
|
||||
|
||||
- [ ] **組件設計規範**
|
||||
- 引用文件: `/docs/02_design/ui-ux/ui-ux-guidelines.md` (第188-200行)
|
||||
- 補全缺失的組件規範:表單元件、遊戲化元件、學習專用元件
|
||||
- 建立組件狀態系統 (default/hover/active/disabled/loading)
|
||||
- 定義組件變體和使用場景
|
||||
|
||||
**輸出物**:
|
||||
- `ui-ux-guidelines.md` 完整更新版本 (企業級標準)
|
||||
- `design-system-components.md` 完整組件庫文檔
|
||||
- `responsive-design-standards.md` 響應式設計標準
|
||||
- `accessibility-guidelines.md` 無障礙設計指南
|
||||
|
||||
### 1.2 企業級設計系統建立
|
||||
|
||||
**目標**: 創建可重用的設計系統和組件庫
|
||||
|
||||
**工作內容**:
|
||||
- [ ] **原子設計系統**: Atoms → Molecules → Organisms → Templates → Pages
|
||||
- [ ] **Design Tokens**: 設計變數化管理系統
|
||||
- [ ] **組件庫標準化**: 可重用UI組件集合
|
||||
- [ ] **圖標系統**: 學習情境專用圖標設計
|
||||
- [ ] **動畫設計語言**: 統一的動畫效果和互動反饋
|
||||
|
||||
**輸出物**:
|
||||
- `design-system-tokens.css` - 完整設計變數系統
|
||||
- `component-library.html` - 互動式組件展示
|
||||
- `animation-guidelines.md` - 動畫設計標準
|
||||
- `icon-system.svg` - 完整圖標庫
|
||||
|
||||
## 📱 階段二:Mobile端企業級重設計 (第3-6週)
|
||||
|
||||
### 2.1 核心學習功能頁面群組 (第3-4週)
|
||||
|
||||
#### 2.1.1 情境對話系統 🎯 (優先級: P0)
|
||||
|
||||
**規格參考**:
|
||||
- 主規格: `/docs/02_design/function-specs/mobile/01_situational-dialogue-mobile.md`
|
||||
- 共用模組: `/docs/02_design/function-specs/common/ai-algorithm-specs.md`
|
||||
- 共用模組: `/docs/02_design/function-specs/common/speaking-evaluation-specs.md`
|
||||
- 共用模組: `/docs/02_design/function-specs/common/pragmatic-analysis-specs.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] **UI_Dialogue_Practice_Main** - 情境對話練習主界面
|
||||
- 設計要求: 語音輸入界面 (參考: ai-algorithm-specs.md 語音處理)
|
||||
- 設計要求: 即時AI反饋顯示 (參考: ai-algorithm-specs.md AI評估系統)
|
||||
- 設計要求: 劇情任務和詞彙任務雙重可視化
|
||||
- 設計要求: 300秒限時挑戰計時器
|
||||
- UI規範: 語音優先設計、即時語法反饋 (ui-ux-guidelines.md 第27-28行)
|
||||
|
||||
- [ ] **UI_Dialogue_Character_Selection** - 角色選擇頁面
|
||||
- 設計要求: 角色卡片設計,突出角色特色和學習情境
|
||||
- 設計要求: 角色能力和適合程度顯示
|
||||
|
||||
- [ ] **UI_Dialogue_Scene_Setting** - 場景設定頁面
|
||||
- 設計要求: 沉浸式場景展示
|
||||
- UI規範: 沉浸式學習環境設計 (ui-ux-guidelines.md 第9行)
|
||||
|
||||
- [ ] **UI_AI_Assistance_Panel** - AI輔助功能面板
|
||||
- 設計要求: 回覆提示道具使用界面
|
||||
- 設計要求: 語法即時檢測顯示
|
||||
- UI規範: 智慧輔助、漸進引導 (ui-ux-guidelines.md 第21-22行)
|
||||
|
||||
- [ ] **UI_Dialogue_Results** - 對話練習結果頁面
|
||||
- 設計要求: 口說評分五維雷達圖 (參考: speaking-evaluation-specs.md)
|
||||
- 設計要求: 語用分析六維評估 (參考: pragmatic-analysis-specs.md)
|
||||
- UI規範: 即時成就反饋 (ui-ux-guidelines.md 第25行)
|
||||
|
||||
#### 2.1.2 詞彙學習系統 📝 (優先級: P0)
|
||||
|
||||
**規格參考**:
|
||||
- 主規格: `/docs/02_design/function-specs/mobile/02_vocabulary-learning-mobile.md`
|
||||
- 共用模組: `/docs/02_design/function-specs/common/progressive-stage-system.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] **UI_Vocab_Learning_Enhanced** - 多媒體詞彙學習主界面
|
||||
- 設計要求: 詞彙展示 (音標、定義、例句)
|
||||
- 設計要求: 雙語音頻系統 (標準速度/慢速)
|
||||
- 設計要求: 智慧詞彙標註 (Source + Example)
|
||||
- 設計要求: 視覺輔助學習 (例句配圖)
|
||||
- UI規範: 詞彙學習流程 (ui-ux-guidelines.md 第29行)
|
||||
|
||||
- [ ] **UI_Vocab_Choice_Practice** - 詞彙選擇練習頁面
|
||||
- 設計要求: 選擇題界面,支援多選和單選模式
|
||||
- 設計要求: 即時正確性反饋
|
||||
|
||||
- [ ] **UI_Vocab_Fluency_Results** - 流暢度練習綜合結果
|
||||
- 設計要求: 學習成效可視化展示
|
||||
- 設計要求: 進度追蹤和建議系統
|
||||
|
||||
- [ ] **UI_Vocab_Review_System** - 間隔複習系統界面
|
||||
- 設計要求: 複習提醒和排程界面
|
||||
- UI規範: 間隔複習提醒 (ui-ux-guidelines.md 第31行)
|
||||
|
||||
#### 2.1.3 學習地圖系統 🗺️ (優先級: P0)
|
||||
|
||||
**規格參考**:
|
||||
- 主規格: `/docs/02_design/function-specs/mobile/03_learning-map-mobile.md`
|
||||
- 共用模組: `/docs/02_design/function-specs/common/progressive-stage-system.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] **UI_Level_Map** - 學習地圖主畫面 (線性闖關版)
|
||||
- 設計要求: 13階段×20劇本的地圖視覺化
|
||||
- 設計要求: 四關進度指示器 (詞彙學習→詞彙熟悉→口說練習→情境對話)
|
||||
- 設計要求: 關卡狀態管理 (🔒鎖定/⏳可進行/🔄進行中/✅已完成)
|
||||
- 引用規格: progressive-stage-system.md 完整關卡系統
|
||||
|
||||
- [ ] **UI_Current_Level_Info** - 當前可進行關卡資訊面板
|
||||
- 設計要求: 關卡詳細資訊展示
|
||||
- 設計要求: 開始學習入口和準備指南
|
||||
|
||||
- [ ] **UI_Level_Progress_Detail** - 關卡進度詳情頁面
|
||||
- 設計要求: 詳細進度追蹤和統計
|
||||
- 設計要求: 個人表現分析
|
||||
|
||||
- [ ] **UI_Stage_Overview** - 階段總覽和劇本選擇
|
||||
- 設計要求: 階段性學習目標展示
|
||||
- 設計要求: 劇本選擇和預覽功能
|
||||
|
||||
- [ ] **UI_Level_Locked_Modal** - 關卡鎖定提示彈窗
|
||||
- 設計要求: 解鎖條件清晰提示
|
||||
- 設計要求: 引導用戶完成前置任務
|
||||
|
||||
### 2.2 商業功能頁面群組 (第4-5週)
|
||||
|
||||
#### 2.2.1 道具商店系統 🛒 (優先級: P1)
|
||||
|
||||
**規格參考**:
|
||||
- 主規格: `/docs/02_design/function-specs/mobile/04_item-shop-mobile.md`
|
||||
- 共用模組: `/docs/02_design/function-specs/common/business-rules.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] **UI_Shop_Categories** - 道具商店分類主頁面
|
||||
- 設計要求: 鑽石購買區 (5個價格套餐)
|
||||
- 設計要求: 學習輔助道具區 (回覆提示、補命、加時)
|
||||
- 設計要求: 限時挑戰道具區 (時間暫停、時間加成)
|
||||
- 引用規格: business-rules.md 命條系統和經濟系統
|
||||
|
||||
- [ ] **UI_Diamond_Purchase** - 鑽石購買頁面
|
||||
- 設計要求: 價格套餐展示和優惠信息
|
||||
- 設計要求: 支付流程整合
|
||||
|
||||
- [ ] **UI_Item_Details** - 單一道具詳情頁面
|
||||
- 設計要求: 道具功能詳細說明
|
||||
- 設計要求: 使用場景和效果展示
|
||||
|
||||
- [ ] **UI_Shop_Item_Confirm** - 道具購買確認彈窗
|
||||
- 設計要求: 購買資訊確認和風險提示
|
||||
- UI規範: 高風險按鈕文字標注 (ui-ux-guidelines.md 第194行)
|
||||
|
||||
- [ ] **UI_Cost_Confirm_Popup** - 成本確認彈窗 (口說練習特別關卡)
|
||||
- 設計要求: 特殊關卡成本說明
|
||||
- 設計要求: 用戶決策支援資訊
|
||||
|
||||
#### 2.2.2 用戶認證系統 🔐 (優先級: P1)
|
||||
|
||||
**規格參考**:
|
||||
- 主規格: `/docs/02_design/function-specs/mobile/05_user-authentication-mobile.md`
|
||||
- 共用模組: `/docs/02_design/function-specs/common/business-rules.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] **UI_Login_Main** - 主要登入頁面
|
||||
- 設計要求: 多平台登入選項 (Google, Facebook, Apple)
|
||||
- 設計要求: 記住登入和安全驗證
|
||||
- 設計要求: 錯誤處理和安全提示
|
||||
|
||||
- [ ] **UI_SignUp_Main** - 用戶註冊頁面
|
||||
- 設計要求: 分步驟註冊流程
|
||||
- 設計要求: 即時驗證和錯誤提示
|
||||
- 設計要求: 學習目標和程度設定
|
||||
|
||||
- [ ] **UI_PasswordReset_Form** - 密碼重置表單
|
||||
- 設計要求: 多步驟驗證流程
|
||||
- 設計要求: 安全性說明和引導
|
||||
|
||||
- [ ] **UI_PasswordReset_Popup** - 密碼重置確認彈窗
|
||||
- 設計要求: 重置成功確認和後續指引
|
||||
|
||||
- [ ] **UI_Account_List** - 帳戶列表管理頁面
|
||||
- 設計要求: 多帳戶管理和切換
|
||||
- 設計要求: 帳戶安全狀態顯示
|
||||
|
||||
- [ ] **UI_Account_Option** - 帳戶選項設定頁面
|
||||
- 設計要求: 帳戶設定和隱私控制
|
||||
- 設計要求: 帳戶關聯和解綁功能
|
||||
|
||||
### 2.3 支援功能頁面群組 (第5-6週)
|
||||
|
||||
#### 2.3.1 系統介面和狀態頁面 📊 (優先級: P2)
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] **UI_Insufficient_Resources** - 資源不足提示頁面
|
||||
- 設計要求: 清晰的資源不足說明
|
||||
- 設計要求: 獲取資源的引導路徑
|
||||
|
||||
- [ ] **UI_LifePoints_Display** - 生命點數顯示組件
|
||||
- 設計要求: 直觀的生命值視覺化
|
||||
- UI規範: 命條生命系統 (ui-ux-guidelines.md 第30行)
|
||||
|
||||
- [ ] **UI_Subscription_Success** - 訂閱成功頁面
|
||||
- 設計要求: 訂閱確認和權益說明
|
||||
- 設計要求: 後續使用指引
|
||||
|
||||
- [ ] **UI_TimeWarp_Cards** - 時光卷使用介面
|
||||
- 設計要求: 時光卷功能說明和使用確認
|
||||
- 設計要求: 使用後效果展示
|
||||
|
||||
- [ ] **UI_LevelResult_SuccessResult** - 關卡成功結果頁面
|
||||
- 設計要求: 成就慶祝動畫和統計展示
|
||||
- UI規範: 即時成就反饋 (ui-ux-guidelines.md 第25行)
|
||||
|
||||
## 💻 階段三:Web端企業級重設計 (第7-9週)
|
||||
|
||||
### 3.1 Web端專屬功能設計 (第7-8週)
|
||||
|
||||
**規格參考**: `/docs/02_design/function-specs/web/` 全部Web端規格
|
||||
|
||||
**設計重點**:
|
||||
- [ ] **桌面優化界面**: 大螢幕佈局和多視窗支援
|
||||
- [ ] **鍵盤導航**: 完整的鍵盤操作支援
|
||||
- [ ] **批量操作**: 企業級批量管理功能
|
||||
- [ ] **高級分析**: 詳細的學習分析和報告功能
|
||||
|
||||
**需設計的主要頁面**:
|
||||
- [ ] **詞彙學習Web版**: 桌面優化的詞彙學習界面
|
||||
- [ ] **情境對話Web版**: 大螢幕對話練習界面
|
||||
- [ ] **學習地圖Web版**: 多層級地圖導航界面
|
||||
- [ ] **道具商店Web版**: 企業級商店管理界面
|
||||
- [ ] **用戶認證Web版**: SSO和企業登入支援
|
||||
|
||||
### 3.2 響應式設計和跨平台整合 (第8-9週)
|
||||
|
||||
**工作內容**:
|
||||
- [ ] **響應式佈局**: Mobile → Tablet → Desktop 完整適配
|
||||
- [ ] **跨瀏覽器相容性**: Chrome, Firefox, Safari, Edge 完整支援
|
||||
- [ ] **效能優化**: 載入時間和互動回應最佳化
|
||||
- [ ] **PWA功能**: 漸進式Web應用功能整合
|
||||
|
||||
## 🔧 階段四:設計系統完善和品質保證 (第10-12週)
|
||||
|
||||
### 4.1 設計系統文檔化和工具化 (第10-11週)
|
||||
|
||||
**工作內容**:
|
||||
- [ ] **設計規範手冊**: 完整的設計規範使用指南
|
||||
- [ ] **組件使用指南**: 每個組件的使用場景和最佳實踐
|
||||
- [ ] **設計審查清單**: 品質控制清單和審查標準
|
||||
- [ ] **維護指南**: 設計系統維護和更新流程
|
||||
|
||||
### 4.2 品質保證和使用性測試 (第11-12週)
|
||||
|
||||
**工作內容**:
|
||||
- [ ] **設計一致性審查**: 跨平台設計一致性檢查
|
||||
- [ ] **無障礙性測試**: WCAG 2.1 AA級合規驗證
|
||||
- [ ] **使用性測試**: 用戶測試和回饋收集
|
||||
- [ ] **效能評估**: 設計對系統效能的影響評估
|
||||
|
||||
## 📊 成功標準和驗收條件
|
||||
|
||||
### 🎯 品質標準
|
||||
1. **功能規格符合度**: 100%符合所有功能規格要求
|
||||
2. **設計一致性**: 跨平台設計語言100%統一
|
||||
3. **無障礙標準**: WCAG 2.1 AA級100%合規
|
||||
4. **效能標準**: 頁面載入時間<3秒,互動回應時間<200ms
|
||||
5. **瀏覽器支援**: 主流瀏覽器100%相容
|
||||
|
||||
### 📋 驗收清單
|
||||
- [ ] 所有UI畫面符合對應功能規格文件要求
|
||||
- [ ] 所有設計符合UI/UX規範標準
|
||||
- [ ] 跨平台視覺一致性通過審查
|
||||
- [ ] 無障礙功能測試全部通過
|
||||
- [ ] 使用性測試滿意度≥90%
|
||||
|
||||
## 📁 交付物清單
|
||||
|
||||
### 🎨 設計文檔
|
||||
- [ ] `ui-ux-guidelines.md` - 完善的UI/UX設計規範
|
||||
- [ ] `design-system-documentation.md` - 設計系統完整文檔
|
||||
- [ ] `component-library-guide.md` - 組件庫使用指南
|
||||
- [ ] `responsive-design-standards.md` - 響應式設計標準
|
||||
|
||||
### 💻 設計資產
|
||||
- [ ] `design-system.css` - 完整CSS設計系統
|
||||
- [ ] 95+ HTML原型頁面 (Mobile + Web)
|
||||
- [ ] 完整SVG圖標庫
|
||||
- [ ] 設計系統展示網站
|
||||
|
||||
### 📋 支援文檔
|
||||
- [ ] `design-review-checklist.md` - 設計審查清單
|
||||
- [ ] `accessibility-compliance-report.md` - 無障礙合規報告
|
||||
- [ ] `usability-test-results.md` - 使用性測試報告
|
||||
- [ ] `maintenance-guidelines.md` - 維護指南
|
||||
|
||||
## 🚨 風險管控和品質保證
|
||||
|
||||
### ⚠️ 關鍵風險點
|
||||
1. **規格理解偏差**: 設計不符合功能規格要求
|
||||
- **控制措施**: 每個設計階段都進行規格文件交叉檢查
|
||||
- **責任人**: 設計師必須深度閱讀相關規格文件
|
||||
|
||||
2. **設計一致性風險**: 跨頁面設計語言不統一
|
||||
- **控制措施**: 建立設計審查機制,每週進行一致性檢查
|
||||
- **工具支援**: 建立設計系統檢查清單
|
||||
|
||||
3. **無障礙合規風險**: 無障礙功能不完整
|
||||
- **控制措施**: 每個組件設計完成都進行無障礙測試
|
||||
- **標準遵循**: 嚴格遵循WCAG 2.1 AA級標準
|
||||
|
||||
### 🔍 品質控制機制
|
||||
1. **階段性審查**: 每個階段結束進行全面審查
|
||||
2. **同行評議**: 設計師之間相互審查和回饋
|
||||
3. **用戶測試**: 關鍵頁面進行真實用戶測試
|
||||
4. **技術可行性評估**: 設計與開發團隊聯合評估
|
||||
|
||||
## 📞 執行支援和溝通機制
|
||||
|
||||
### 🤝 團隊協作
|
||||
- **設計團隊**: 負責設計執行和品質控制
|
||||
- **產品團隊**: 提供功能需求解釋和使用者回饋
|
||||
- **開發團隊**: 提供技術可行性建議和實現支援
|
||||
- **測試團隊**: 提供品質測試和驗收支援
|
||||
|
||||
### 📋 進度追蹤
|
||||
- **每週進度會議**: 檢討進度和解決阻礙
|
||||
- **里程碑審查**: 階段性成果展示和評估
|
||||
- **問題升級機制**: 重大問題快速上報和解決
|
||||
- **文檔同步更新**: 確保所有團隊資訊同步
|
||||
|
||||
---
|
||||
|
||||
**📝 重要聲明**:
|
||||
本計劃基於Drama Ling v3.0共用模組架構制定,確保所有設計完全符合功能規格要求,達到企業級應用標準。所有設計師在執行前必須深入理解相關功能規格文件和UI/UX規範,確保設計品質和一致性。
|
||||
|
||||
**🎯 最終目標**:
|
||||
創建Drama Ling史上最高品質的UI設計系統,為用戶提供世界級的沉浸式英語學習體驗。
|
||||
|
||||
---
|
||||
|
||||
**最後更新**: 2025-01-15
|
||||
**計劃版本**: v4.0 - 企業級重構
|
||||
**執行週期**: 12週
|
||||
**預期成果**: 95+ 企業級UI畫面
|
||||
|
|
@ -21,15 +21,15 @@ docs/
|
|||
### 🚀 `/00_starter` - 專案基礎
|
||||
**用途**: 包含專案初始化和AI輔助開發所使用的基礎模板和提示詞。
|
||||
|
||||
| 檔案名稱 | 用途 |
|
||||
|------|---------|
|
||||
| `CLAUDE_TEMPLATE.md` | Claude AI 互動模板和專案設置 |
|
||||
| `READ.md` | 使用入門模板的說明指引 |
|
||||
| `business_function_design_prompt.md` | 生成業務功能設計的 AI 提示詞 |
|
||||
| `generate_requirements_prompt.md` | 創建專案需求的 AI 提示詞 |
|
||||
| `generate_system_structure_prompt.md` | 系統架構生成的 AI 提示詞 |
|
||||
| `system_detail_prompt.md` | 詳細系統規格的 AI 提示詞 |
|
||||
| `system_structured_schema.json` | 結構化系統設計輸出的 JSON 架構 |
|
||||
| 檔案名稱 | 用途 |
|
||||
| ------------------------------------- | ------------------------------ |
|
||||
| `CLAUDE_TEMPLATE.md` | Claude AI 互動模板和專案設置 |
|
||||
| `READ.md` | 使用入門模板的說明指引 |
|
||||
| `business_function_design_prompt.md` | 生成業務功能設計的 AI 提示詞 |
|
||||
| `generate_requirements_prompt.md` | 創建專案需求的 AI 提示詞 |
|
||||
| `generate_system_structure_prompt.md` | 系統架構生成的 AI 提示詞 |
|
||||
| `system_detail_prompt.md` | 詳細系統規格的 AI 提示詞 |
|
||||
| `system_structured_schema.json` | 結構化系統設計輸出的 JSON 架構 |
|
||||
|
||||
**使用時機**: 這些檔案主要在專案初始化時使用,以及與 AI 助手協作生成文檔和程式碼結構時使用。
|
||||
|
||||
|
|
@ -38,13 +38,13 @@ docs/
|
|||
### 📋 `/01_requirement` - 需求文檔
|
||||
**用途**: 包含核心專案需求、規格說明和系統設計文檔。**專注於知識管理和規格定義**。
|
||||
|
||||
| 檔案名稱 | 用途 |
|
||||
|------|---------|
|
||||
| `founding_pitch.md` | 初始專案提案和商業案例 |
|
||||
| `requirements.md` | **產品功能需求總覽** - 詳細的產品規格和功能概述 |
|
||||
| `user-stories.md` | **用戶故事和使用場景** - 用戶需求和互動情境 |
|
||||
| `business-rules.md` | **業務邏輯和規則定義** - 核心商業規則和流程 |
|
||||
| `acceptance-criteria.md` | **驗收標準和測試條件** - 功能驗收和品質標準 |
|
||||
| 檔案名稱 | 用途 |
|
||||
| ------------------------------ | ----------------------------------------------------------------- |
|
||||
| `founding_pitch.md` | 初始專案提案和商業案例 |
|
||||
| `requirements.md` | **產品功能需求總覽** - 詳細的產品規格和功能概述 |
|
||||
| `user-stories.md` | **用戶故事和使用場景** - 用戶需求和互動情境 |
|
||||
| `business-rules.md` | **業務邏輯和規則定義** - 核心商業規則和流程 |
|
||||
| `acceptance-criteria.md` | **驗收標準和測試條件** - 功能驗收和品質標準 |
|
||||
| `system_structure_design.json` | **結構化系統設計** - 從需求生成,包含模組、功能和UI視圖的JSON格式 |
|
||||
|
||||
**關鍵文檔**: `requirements.md` 是產品應該做什麼以及如何運作的唯一真實來源。
|
||||
|
|
@ -54,20 +54,20 @@ docs/
|
|||
### 🎨 `/02_design` - 設計規格 (更新 2025-09-09)
|
||||
**用途**: 涵蓋使用者體驗、視覺設計和互動模式的文檔。**專注於知識管理和規格定義**。
|
||||
|
||||
| 檔案名稱 | 用途 |
|
||||
|------|---------|
|
||||
| `ui-specifications.md` | **UI設計規範和標準** - 視覺設計標準和介面規範 |
|
||||
| `ux-guidelines.md` | **用戶體驗設計指南** - 互動模式和使用者流程 |
|
||||
| `component-library.md` | **UI組件庫文檔** - 可重用組件和設計系統 |
|
||||
| `design-tokens.md` | **設計令牌和主題系統** - 顏色、字體、間距等設計變量 |
|
||||
| `ai-algorithm-specs.md` | AI 分析演算法和語言處理規格 |
|
||||
| `business-logic-rules.md` | 核心商業規則和邏輯流程定義 |
|
||||
| `content-management-specs.md` | 內容創建、策劃和管理工作流程 |
|
||||
| `gamification-mechanics.md` | 遊戲元素、成就和獎勵系統設計 |
|
||||
| `ui-ux-guidelines.md` | 視覺設計標準、組件庫和使用者介面指南 |
|
||||
| `function-specs/` | 平台別功能規格(mobile/web/common)|
|
||||
| `html-prototypes/` | HTML原型和頁面範例 |
|
||||
| `views/` | UI視圖設計檔案 |
|
||||
| 檔案名稱 | 用途 |
|
||||
| ---------------------------- | --------------------------------------------------- |
|
||||
| `prototype-design-plan.md` | **原型設計製作計劃** - 雛形畫面開發的完整規劃 |
|
||||
| `function-specs/` | **平台別功能規格** - mobile/web/common功能詳細規格 |
|
||||
| `prototypes/` | **HTML原型系統** - 可互動的功能演示界面 |
|
||||
| `ui-ux/` | **UI/UX設計系統** - 視覺規範、組件庫、樣式指南 |
|
||||
| `views/` | **UI視圖設計檔案** - 介面設計的視覺化參考 |
|
||||
|
||||
**實際子目錄結構**:
|
||||
- `function-specs/common/` - 跨平台共用規格(API、資料模型、業務規則等)
|
||||
- `function-specs/mobile/` - 行動端專用功能規格
|
||||
- `function-specs/web/` - 網頁端專用功能規格
|
||||
- `ui-ux/ui-ux-guidelines.md` - 統一的UI/UX設計規範
|
||||
- `ui-ux/dramaling-ui.css` - Drama Ling設計系統樣式表
|
||||
|
||||
**目標讀者**: 設計師、前端開發人員和產品經理。
|
||||
|
||||
|
|
@ -76,14 +76,14 @@ docs/
|
|||
### 👨💻 `/03_development` - 開發文檔 (更新 2025-09-09)
|
||||
**用途**: 為開發人員提供編碼標準、工作流程和專案路線圖的指南。**專注於知識管理和規格定義**。
|
||||
|
||||
| 檔案名稱 | 用途 |
|
||||
|------|---------|
|
||||
| `coding-standards.md` | **程式碼規範** - Flutter/Dart 和 .NET/C# 的程式碼風格指南、命名慣例和最佳實踐 |
|
||||
| `architecture-overview.md` | **系統架構概述** - 整體系統架構和設計決策說明 |
|
||||
| `deployment-guide.md` | **部署流程文檔** - 部署步驟、環境配置和發布流程 |
|
||||
| `troubleshooting.md` | **常見問題排除** - 開發過程中常見問題的解決方案 |
|
||||
| `development-workflow.md` | Git 工作流程、分支策略、程式碼審查流程和開發生命週期 |
|
||||
| `project-roadmap.md` | **開發時程表** - 階段、里程碑和功能交付時程 |
|
||||
| 檔案名稱 | 用途 |
|
||||
| -------------------------- | ----------------------------------------------------------------------------- |
|
||||
| `coding-standards.md` | **程式碼規範** - Flutter/Dart 和 .NET/C# 的程式碼風格指南、命名慣例和最佳實踐 |
|
||||
| `architecture-overview.md` | **系統架構概述** - 整體系統架構和設計決策說明 |
|
||||
| `deployment-guide.md` | **部署流程文檔** - 部署步驟、環境配置和發布流程 |
|
||||
| `troubleshooting.md` | **常見問題排除** - 開發過程中常見問題的解決方案 |
|
||||
| `development-workflow.md` | Git 工作流程、分支策略、程式碼審查流程和開發生命週期 |
|
||||
| `project-roadmap.md` | **開發時程表** - 階段、里程碑和功能交付時程 |
|
||||
|
||||
**目標讀者**: 所有參與專案的開發人員。
|
||||
|
||||
|
|
@ -92,19 +92,19 @@ docs/
|
|||
### ⚙️ `/04_technical` - 技術規格 (更新 2025-09-09)
|
||||
**用途**: 技術實作細節、系統架構和整合規格說明。**專注於知識管理和規格定義**。
|
||||
|
||||
| 子目錄/檔案 | 用途 |
|
||||
|------|---------|
|
||||
| `api-specifications.md` | **API接口文檔** - 完整API規格、端點定義和資料格式 |
|
||||
| `database-schema.md` | **資料庫設計文檔** - 資料表結構、關聯和索引設計 |
|
||||
| `security-requirements.md` | **安全性需求** - 安全標準、認證機制和資料保護 |
|
||||
| `performance-standards.md` | **效能標準定義** - 效能指標、基準測試和優化準則 |
|
||||
| `01_architecture/` | 系統架構設計和決策文檔 |
|
||||
| `02_api/` | **REST API 文檔** - 完整API規格、端點文檔、Swagger UI |
|
||||
| `03_frontend/` | 前端技術規格和實作指南 |
|
||||
| `04_mobile/` | 移動端開發技術規格 |
|
||||
| `05_deployment/` | 部署流程和環境配置 |
|
||||
| `06_development/` | **開發過程管理** - 問題追蹤、環境設定和開發工具配置 |
|
||||
| `07_planning/` | 技術規劃和決策記錄 |
|
||||
| 子目錄/檔案 | 用途 |
|
||||
| -------------------------- | ----------------------------------------------------- |
|
||||
| `api-specifications.md` | **API接口文檔** - 完整API規格、端點定義和資料格式 |
|
||||
| `database-schema.md` | **資料庫設計文檔** - 資料表結構、關聯和索引設計 |
|
||||
| `security-requirements.md` | **安全性需求** - 安全標準、認證機制和資料保護 |
|
||||
| `performance-standards.md` | **效能標準定義** - 效能指標、基準測試和優化準則 |
|
||||
| `01_architecture/` | 系統架構設計和決策文檔 |
|
||||
| `02_api/` | **REST API 文檔** - 完整API規格、端點文檔、Swagger UI |
|
||||
| `03_frontend/` | 前端技術規格和實作指南 |
|
||||
| `04_mobile/` | 移動端開發技術規格 |
|
||||
| `05_deployment/` | 部署流程和環境配置 |
|
||||
| `06_development/` | **開發過程管理** - 問題追蹤、環境設定和開發工具配置 |
|
||||
| `07_planning/` | 技術規劃和決策記錄 |
|
||||
|
||||
**關鍵文檔**: `02_api/` 目錄中的API文檔作為前端和後端團隊之間的契約。
|
||||
|
||||
|
|
@ -135,15 +135,15 @@ docs/
|
|||
|
||||
### ✅ 正確的內容分層
|
||||
|
||||
| 內容類型 | 正確位置 |
|
||||
|---------|----------|
|
||||
| 產品規格和需求 | `docs/01_requirement/` |
|
||||
| 設計標準和指南 | `docs/02_design/` |
|
||||
| 技術架構和 API 規格 | `docs/04_technical/` |
|
||||
| 編碼規範和流程 | `docs/03_development/` |
|
||||
| 具體任務和待辦事項 | `TASKS.md` |
|
||||
| 專案執行計畫 | `projects/[專案名].md` |
|
||||
| 進度追蹤和狀態更新 | 專案管理工具 |
|
||||
| 內容類型 | 正確位置 |
|
||||
| ------------------- | ---------------------- |
|
||||
| 產品規格和需求 | `docs/01_requirement/` |
|
||||
| 設計標準和指南 | `docs/02_design/` |
|
||||
| 技術架構和 API 規格 | `docs/04_technical/` |
|
||||
| 編碼規範和流程 | `docs/03_development/` |
|
||||
| 具體任務和待辦事項 | `TASKS.md` |
|
||||
| 專案執行計畫 | `projects/[專案名].md` |
|
||||
| 進度追蹤和狀態更新 | 專案管理工具 |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -176,7 +176,7 @@ docs/
|
|||
- 主要文檔: `/02_design/ui-ux-guidelines.md`, `/02_design/gamification-mechanics.md`
|
||||
- 內容策略: `/02_design/content-management-specs.md`
|
||||
- 功能規格: `/02_design/function-specs/`
|
||||
- 原型參考: `/02_design/html-prototypes/`
|
||||
- 原型參考: `/02_design/prototypes/`
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -198,16 +198,16 @@ docs/
|
|||
|
||||
## 🔍 快速參考
|
||||
|
||||
| 尋找... | 前往... |
|
||||
|----------------|----------|
|
||||
| 要建構什麼功能 | `/01_requirement/requirements.md` |
|
||||
| API 端點和資料格式 | `/04_technical/02_api/` |
|
||||
| 系統架構 | `/04_technical/01_architecture/` |
|
||||
| UI 設計標準 | `/02_design/ui-ux-guidelines.md` |
|
||||
| 如何貢獻程式碼 | `/03_development/development-workflow.md` |
|
||||
| 開發時程表 | `/03_development/project-roadmap.md` |
|
||||
| 功能規格 | `/02_design/function-specs/` |
|
||||
| 部署流程 | `/04_technical/05_deployment/` |
|
||||
| 尋找... | 前往... |
|
||||
| ------------------ | ----------------------------------------- |
|
||||
| 要建構什麼功能 | `/01_requirement/requirements.md` |
|
||||
| API 端點和資料格式 | `/04_technical/02_api/` |
|
||||
| 系統架構 | `/04_technical/01_architecture/` |
|
||||
| UI 設計標準 | `/02_design/ui-ux-guidelines.md` |
|
||||
| 如何貢獻程式碼 | `/03_development/development-workflow.md` |
|
||||
| 開發時程表 | `/03_development/project-roadmap.md` |
|
||||
| 功能規格 | `/02_design/function-specs/` |
|
||||
| 部署流程 | `/04_technical/05_deployment/` |
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
|
|
@ -18,19 +18,18 @@
|
|||
- 訂閱用戶: 30個
|
||||
- 進階用戶: 50個
|
||||
- **恢復機制**:
|
||||
- 免費用戶: 每5小時自動恢復1個命條
|
||||
- 訂閱用戶: 每小時自動恢復3個命條
|
||||
- 進階用戶: 每小時自動恢復5個命條
|
||||
- **命條消耗**: 1、2、3關啟動時消耗命條(第2+關不消耗)
|
||||
|
||||
### 消耗場景 (四關闖關系統)
|
||||
| 場景 | 命條消耗 | 說明 |
|
||||
| -------------- | -------- | ---------------------------- |
|
||||
| 第1關:詞彙學習 | 1個 | 啟動關卡時消耗,學習過程免費 |
|
||||
| 第2關:詞彙熟悉 | 1個 | 啟動關卡時消耗,無論答對答錯 |
|
||||
| 場景 | 命條消耗 | 說明 |
|
||||
| ------------------------ | -------- | ----------------------------- |
|
||||
| 第1關:詞彙學習 | 1個 | 啟動關卡時消耗,學習過程免費 |
|
||||
| 第2關:詞彙熟悉 | 1個 | 啟動關卡時消耗,無論答對答錯 |
|
||||
| 第2+關:口說練習特別關卡 | 0個 | 付費關卡(5鑽石),不消耗命條 |
|
||||
| 第3關:情境對話 | 1個 | 啟動關卡時消耗,無論成功失敗 |
|
||||
| 對話有辱罵情形 | 3個 | 額外扣除懲罰 |
|
||||
| 第3關:情境對話 | 1個 | 啟動關卡時消耗,無論成功失敗 |
|
||||
| 對話有辱罵情形 | 3個 | 額外扣除懲罰 |
|
||||
|
||||
### 獲得命條方式
|
||||
- **自動恢復**: 依用戶等級不同恢復速度(見上方基本規則)
|
||||
|
|
@ -286,12 +285,12 @@
|
|||
- **學習階層**: 第x階段 > 第x劇本 > 第x關卡
|
||||
|
||||
#### 關卡類型與規則
|
||||
| 關卡類型 | 收費模式 | 命條消耗 | 星級獲得 | 解鎖條件 | 通關條件 |
|
||||
|---------|---------|----------|----------|----------|----------|
|
||||
| 詞彙學習 | 免費 | 啟動扣1條 | 自動3星 | 無 | 全部答對 |
|
||||
| 詞彙熟悉 | 免費 | 啟動扣1條 | 自動3星 | 完成第1關 | 全部答對 |
|
||||
| 口說練習特別關卡 | 5鑽石 | 不扣命條 | 1-3星 | 完成第2關 | 平均70分+ |
|
||||
| 情境對話 | 免費 | 啟動扣1條 | 1-3星 | 完成第2+關或跳過 | 雙重通關條件 |
|
||||
| 關卡類型 | 收費模式 | 命條消耗 | 星級獲得 | 解鎖條件 | 通關條件 |
|
||||
| ---------------- | -------- | --------- | -------- | ---------------- | ------------ |
|
||||
| 詞彙學習 | 免費 | 啟動扣1條 | 自動3星 | 無 | 全部答對 |
|
||||
| 詞彙熟悉 | 免費 | 啟動扣1條 | 自動3星 | 完成第1關 | 全部答對 |
|
||||
| 口說練習特別關卡 | 5鑽石 | 不扣命條 | 1-3星 | 完成第2關 | 平均70分+ |
|
||||
| 情境對話 | 免費 | 啟動扣1條 | 1-3星 | 完成第2+關或跳過 | 雙重通關條件 |
|
||||
|
||||
### 舊版關卡結構系統
|
||||
#### BR-LEARN-01: 階段化學習架構
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
詞彙
|
||||
- Vocab: optimal
|
||||
- Level: B2
|
||||
- Definition:
|
||||
The best or most effective possible in a particular situation.
|
||||
- Original Sentence:
|
||||
For the optimal coding experience, enable the recommended settings
|
||||
- Example Sentence:
|
||||
The optimal time to plant these seeds is in early spring.
|
||||
- Example Image url:
|
||||
- 例句音檔
|
||||
- 詞彙正常速度音檔
|
||||
- 詞彙慢速速度音檔
|
||||
|
||||
劇本
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
**建立日期**: 2025-09-08
|
||||
**最後更新**: 2025-09-12
|
||||
**負責團隊**: 產品/設計/開發
|
||||
**原型參考**: `/prototypes/screens/phase2/05-vocabulary-learning-enhanced.html`
|
||||
**原型參考**: `/docs/02_design/prototypes/screens/phase2/05-vocabulary-learning-enhanced.html`
|
||||
|
||||
### 主要功能
|
||||
- **沉浸式詞彙展示**: 詞彙、音標、定義、多媒體整合展示
|
||||
|
|
@ -346,7 +346,7 @@
|
|||
|
||||
## 📚 參考資源
|
||||
|
||||
- **原型畫面**: `/prototypes/screens/phase2/05-vocabulary-learning-enhanced.html`
|
||||
- **原型畫面**: `/docs/02_design/prototypes/screens/phase2/05-vocabulary-learning-enhanced.html`
|
||||
- **線性闖關系統**: `docs/02_design/function-specs/common/progressive-stage-system.md`
|
||||
- **UI/UX設計規範**: `docs/02_design/ui-ux/ui-ux-guidelines.md` - 按鈕文字標注原則
|
||||
- **命條系統規則**: `docs/02_design/function-specs/common/business-rules.md`
|
||||
|
|
|
|||
|
|
@ -1,279 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-TW">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Drama Ling - 登入</title>
|
||||
<link rel="stylesheet" href="../../../docs/02_design/ui-ux/dramaling-ui.css">
|
||||
<style>
|
||||
/* UI_Login_Screen - 用戶登入界面 */
|
||||
.login-container {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, var(--primary-teal) 0%, var(--secondary-purple) 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--space-6);
|
||||
}
|
||||
|
||||
.app-logo {
|
||||
margin-bottom: var(--space-12);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.app-logo h1 {
|
||||
font-size: var(--text-4xl);
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--space-2);
|
||||
font-weight: bold;
|
||||
text-shadow: 0 2px 4px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.app-logo p {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--text-secondary);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.login-card {
|
||||
background: var(--card-background);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-8);
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
box-shadow: var(--shadow-xl);
|
||||
border: 3px solid rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: var(--text-base);
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--space-2);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: var(--space-4);
|
||||
border: 2px solid var(--divider);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--background-secondary);
|
||||
color: var(--text-primary);
|
||||
font-size: var(--text-base);
|
||||
transition: border-color var(--duration-normal);
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-teal);
|
||||
box-shadow: 0 0 0 3px rgba(0, 229, 204, 0.2);
|
||||
}
|
||||
|
||||
.btn-login {
|
||||
width: 100%;
|
||||
padding: var(--space-4);
|
||||
background: var(--primary-teal);
|
||||
color: var(--background-dark);
|
||||
border: 3px solid var(--primary-teal-dark);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-lg);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
margin-bottom: var(--space-4);
|
||||
box-shadow: 0 4px 0 var(--primary-teal-dark);
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-login:hover {
|
||||
background: var(--primary-teal-light);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 5px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.btn-login:active {
|
||||
transform: translateY(2px);
|
||||
box-shadow: 0 2px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.divider {
|
||||
text-align: center;
|
||||
margin: var(--space-6) 0;
|
||||
position: relative;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.divider::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 1px;
|
||||
background: var(--divider);
|
||||
}
|
||||
|
||||
.divider span {
|
||||
background: var(--card-background);
|
||||
padding: 0 var(--space-4);
|
||||
}
|
||||
|
||||
.btn-google {
|
||||
width: 100%;
|
||||
padding: var(--space-4);
|
||||
background: var(--text-primary);
|
||||
color: var(--background-dark);
|
||||
border: 3px solid #e0e0e0;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-3);
|
||||
margin-bottom: var(--space-6);
|
||||
box-shadow: 0 4px 0 #d0d0d0;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-google:hover {
|
||||
background: #f5f5f5;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 5px 0 #d0d0d0;
|
||||
}
|
||||
|
||||
.btn-google:active {
|
||||
transform: translateY(2px);
|
||||
box-shadow: 0 2px 0 #d0d0d0;
|
||||
}
|
||||
|
||||
.google-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.signup-link {
|
||||
text-align: center;
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.signup-link a {
|
||||
color: var(--primary-teal);
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.signup-link a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.login-container {
|
||||
padding: var(--space-4);
|
||||
}
|
||||
|
||||
.login-card {
|
||||
padding: var(--space-6);
|
||||
}
|
||||
|
||||
.app-logo h1 {
|
||||
font-size: var(--text-3xl);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-container">
|
||||
<!-- UI_App_Logo - 應用程式標識 -->
|
||||
<div class="app-logo">
|
||||
<h1>Drama Ling</h1>
|
||||
<p>用英語演出你的故事</p>
|
||||
</div>
|
||||
|
||||
<!-- UI_Login_Form - 登入表單 -->
|
||||
<div class="login-card">
|
||||
<form id="loginForm">
|
||||
<div class="form-group">
|
||||
<label for="email" class="form-label">電子信箱</label>
|
||||
<input type="email" id="email" class="form-input" placeholder="輸入您的電子信箱" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password" class="form-label">密碼</label>
|
||||
<input type="password" id="password" class="form-input" placeholder="輸入您的密碼" required>
|
||||
</div>
|
||||
|
||||
<!-- UI_Login_Button - 登入按鈕 -->
|
||||
<button type="submit" class="btn-login">
|
||||
登入
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<!-- UI_Divider - 分隔線 -->
|
||||
<div class="divider">
|
||||
<span>或者</span>
|
||||
</div>
|
||||
|
||||
<!-- UI_Google_Login_Button - Google登入按鈕 -->
|
||||
<button class="btn-google" id="googleLogin">
|
||||
<svg class="google-icon" viewBox="0 0 24 24">
|
||||
<path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
|
||||
<path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
|
||||
<path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
|
||||
<path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
|
||||
</svg>
|
||||
使用 Google 登入
|
||||
</button>
|
||||
|
||||
<!-- UI_Signup_Link - 註冊連結 -->
|
||||
<div class="signup-link">
|
||||
還沒有帳號?<a href="02-signup.html">立即註冊</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 登入表單處理
|
||||
document.getElementById('loginForm').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const email = document.getElementById('email').value;
|
||||
const password = document.getElementById('password').value;
|
||||
|
||||
// 模擬登入處理
|
||||
if (email && password) {
|
||||
// 顯示載入狀態
|
||||
const loginBtn = document.querySelector('.btn-login');
|
||||
loginBtn.textContent = '登入中...';
|
||||
loginBtn.disabled = true;
|
||||
|
||||
// 模擬API請求延遲
|
||||
setTimeout(() => {
|
||||
// 成功登入後跳轉到儀表板
|
||||
window.location.href = '03-onboarding.html';
|
||||
}, 1500);
|
||||
}
|
||||
});
|
||||
|
||||
// Google登入處理
|
||||
document.getElementById('googleLogin').addEventListener('click', function() {
|
||||
// 模擬Google OAuth流程
|
||||
this.textContent = '連接中...';
|
||||
this.disabled = true;
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.href = '03-onboarding.html';
|
||||
}, 2000);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,491 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-TW">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Drama Ling - 註冊</title>
|
||||
<link rel="stylesheet" href="../../../docs/02_design/ui-ux/dramaling-ui.css">
|
||||
<style>
|
||||
/* UI_Signup_Screen - 用戶註冊界面 */
|
||||
.signup-container {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, var(--secondary-purple) 0%, var(--accent-violet) 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--space-6);
|
||||
}
|
||||
|
||||
.app-logo {
|
||||
margin-bottom: var(--space-8);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.app-logo h1 {
|
||||
font-size: var(--text-4xl);
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--space-2);
|
||||
font-weight: bold;
|
||||
text-shadow: 0 2px 4px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.app-logo p {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--text-secondary);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.signup-card {
|
||||
background: var(--card-background);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-8);
|
||||
width: 100%;
|
||||
max-width: 450px;
|
||||
box-shadow: var(--shadow-xl);
|
||||
border: 3px solid rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: var(--space-5);
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: var(--text-base);
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--space-2);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: var(--space-4);
|
||||
border: 2px solid var(--divider);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--background-secondary);
|
||||
color: var(--text-primary);
|
||||
font-size: var(--text-base);
|
||||
transition: border-color var(--duration-normal);
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent-violet);
|
||||
box-shadow: 0 0 0 3px rgba(155, 89, 182, 0.2);
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: flex;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.form-row .form-group {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* UI_Age_Selection - 年齡選擇 */
|
||||
.age-selection {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-3);
|
||||
margin-top: var(--space-2);
|
||||
}
|
||||
|
||||
.age-option {
|
||||
padding: var(--space-3);
|
||||
background: var(--background-secondary);
|
||||
border: 2px solid var(--divider);
|
||||
border-radius: var(--radius-md);
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.age-option:hover {
|
||||
border-color: var(--accent-violet);
|
||||
background: var(--background-primary);
|
||||
}
|
||||
|
||||
.age-option.selected {
|
||||
background: var(--accent-violet);
|
||||
border-color: var(--accent-violet-dark);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* UI_Terms_Checkbox - 服務條款勾選 */
|
||||
.terms-group {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: var(--space-3);
|
||||
margin-bottom: var(--space-6);
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.custom-checkbox {
|
||||
position: relative;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.custom-checkbox input {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.checkmark {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
background: var(--background-secondary);
|
||||
border: 2px solid var(--divider);
|
||||
border-radius: var(--radius-sm);
|
||||
transition: all var(--duration-normal);
|
||||
}
|
||||
|
||||
.custom-checkbox input:checked + .checkmark {
|
||||
background: var(--accent-violet);
|
||||
border-color: var(--accent-violet-dark);
|
||||
}
|
||||
|
||||
.checkmark::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: none;
|
||||
left: 5px;
|
||||
top: 2px;
|
||||
width: 6px;
|
||||
height: 10px;
|
||||
border: solid white;
|
||||
border-width: 0 2px 2px 0;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.custom-checkbox input:checked + .checkmark::after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.terms-text a {
|
||||
color: var(--primary-teal);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.terms-text a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.btn-signup {
|
||||
width: 100%;
|
||||
padding: var(--space-4);
|
||||
background: var(--accent-violet);
|
||||
color: var(--text-primary);
|
||||
border: 3px solid var(--accent-violet-dark);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-lg);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
margin-bottom: var(--space-4);
|
||||
box-shadow: 0 4px 0 var(--accent-violet-dark);
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-signup:hover {
|
||||
background: var(--accent-violet-light);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 5px 0 var(--accent-violet-dark);
|
||||
}
|
||||
|
||||
.btn-signup:active {
|
||||
transform: translateY(2px);
|
||||
box-shadow: 0 2px 0 var(--accent-violet-dark);
|
||||
}
|
||||
|
||||
.btn-signup:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: 0 4px 0 var(--accent-violet-dark);
|
||||
}
|
||||
|
||||
.divider {
|
||||
text-align: center;
|
||||
margin: var(--space-6) 0;
|
||||
position: relative;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.divider::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 1px;
|
||||
background: var(--divider);
|
||||
}
|
||||
|
||||
.divider span {
|
||||
background: var(--card-background);
|
||||
padding: 0 var(--space-4);
|
||||
}
|
||||
|
||||
.btn-google {
|
||||
width: 100%;
|
||||
padding: var(--space-4);
|
||||
background: var(--text-primary);
|
||||
color: var(--background-dark);
|
||||
border: 3px solid #e0e0e0;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-3);
|
||||
margin-bottom: var(--space-6);
|
||||
box-shadow: 0 4px 0 #d0d0d0;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-google:hover {
|
||||
background: #f5f5f5;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 5px 0 #d0d0d0;
|
||||
}
|
||||
|
||||
.btn-google:active {
|
||||
transform: translateY(2px);
|
||||
box-shadow: 0 2px 0 #d0d0d0;
|
||||
}
|
||||
|
||||
.google-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.login-link {
|
||||
text-align: center;
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.login-link a {
|
||||
color: var(--primary-teal);
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.login-link a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.signup-container {
|
||||
padding: var(--space-4);
|
||||
}
|
||||
|
||||
.signup-card {
|
||||
padding: var(--space-6);
|
||||
}
|
||||
|
||||
.app-logo h1 {
|
||||
font-size: var(--text-3xl);
|
||||
}
|
||||
|
||||
.form-row {
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.age-selection {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="signup-container">
|
||||
<!-- UI_App_Logo - 應用程式標識 -->
|
||||
<div class="app-logo">
|
||||
<h1>Drama Ling</h1>
|
||||
<p>開始你的英語學習之旅</p>
|
||||
</div>
|
||||
|
||||
<!-- UI_Signup_Form - 註冊表單 -->
|
||||
<div class="signup-card">
|
||||
<form id="signupForm">
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="firstName" class="form-label">名字</label>
|
||||
<input type="text" id="firstName" class="form-input" placeholder="輸入您的名字" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="lastName" class="form-label">姓氏</label>
|
||||
<input type="text" id="lastName" class="form-input" placeholder="輸入您的姓氏" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email" class="form-label">電子信箱</label>
|
||||
<input type="email" id="email" class="form-input" placeholder="輸入您的電子信箱" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password" class="form-label">密碼</label>
|
||||
<input type="password" id="password" class="form-input" placeholder="至少8個字符" required minlength="8">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="confirmPassword" class="form-label">確認密碼</label>
|
||||
<input type="password" id="confirmPassword" class="form-input" placeholder="再次輸入密碼" required>
|
||||
</div>
|
||||
|
||||
<!-- UI_Age_Selection - 年齡選擇 -->
|
||||
<div class="form-group">
|
||||
<label class="form-label">年齡範圍</label>
|
||||
<div class="age-selection">
|
||||
<div class="age-option" data-age="13-17">13-17歲</div>
|
||||
<div class="age-option" data-age="18-24">18-24歲</div>
|
||||
<div class="age-option" data-age="25-34">25-34歲</div>
|
||||
<div class="age-option" data-age="35-44">35-44歲</div>
|
||||
<div class="age-option" data-age="45-54">45-54歲</div>
|
||||
<div class="age-option" data-age="55+">55歲以上</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UI_Terms_Checkbox - 服務條款勾選 -->
|
||||
<div class="terms-group">
|
||||
<label class="custom-checkbox">
|
||||
<input type="checkbox" id="agreeTerms" required>
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<div class="terms-text">
|
||||
我同意 <a href="#" target="_blank">服務條款</a> 和 <a href="#" target="_blank">隱私政策</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UI_Signup_Button - 註冊按鈕 -->
|
||||
<button type="submit" class="btn-signup" id="signupBtn">
|
||||
創建帳戶
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<!-- UI_Divider - 分隔線 -->
|
||||
<div class="divider">
|
||||
<span>或者</span>
|
||||
</div>
|
||||
|
||||
<!-- UI_Google_Signup_Button - Google註冊按鈕 -->
|
||||
<button class="btn-google" id="googleSignup">
|
||||
<svg class="google-icon" viewBox="0 0 24 24">
|
||||
<path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
|
||||
<path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
|
||||
<path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
|
||||
<path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
|
||||
</svg>
|
||||
使用 Google 註冊
|
||||
</button>
|
||||
|
||||
<!-- UI_Login_Link - 登入連結 -->
|
||||
<div class="login-link">
|
||||
已經有帳號?<a href="01-login.html">立即登入</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 年齡選擇處理
|
||||
const ageOptions = document.querySelectorAll('.age-option');
|
||||
let selectedAge = null;
|
||||
|
||||
ageOptions.forEach(option => {
|
||||
option.addEventListener('click', function() {
|
||||
// 移除其他選項的選中狀態
|
||||
ageOptions.forEach(opt => opt.classList.remove('selected'));
|
||||
|
||||
// 設置當前選項為選中狀態
|
||||
this.classList.add('selected');
|
||||
selectedAge = this.dataset.age;
|
||||
});
|
||||
});
|
||||
|
||||
// 註冊表單處理
|
||||
document.getElementById('signupForm').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const firstName = document.getElementById('firstName').value;
|
||||
const lastName = document.getElementById('lastName').value;
|
||||
const email = document.getElementById('email').value;
|
||||
const password = document.getElementById('password').value;
|
||||
const confirmPassword = document.getElementById('confirmPassword').value;
|
||||
const agreeTerms = document.getElementById('agreeTerms').checked;
|
||||
|
||||
// 驗證密碼匹配
|
||||
if (password !== confirmPassword) {
|
||||
alert('密碼不匹配,請重新輸入');
|
||||
return;
|
||||
}
|
||||
|
||||
// 驗證年齡選擇
|
||||
if (!selectedAge) {
|
||||
alert('請選擇您的年齡範圍');
|
||||
return;
|
||||
}
|
||||
|
||||
// 驗證服務條款
|
||||
if (!agreeTerms) {
|
||||
alert('請同意服務條款和隱私政策');
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstName && lastName && email && password) {
|
||||
// 顯示載入狀態
|
||||
const signupBtn = document.getElementById('signupBtn');
|
||||
signupBtn.textContent = '創建中...';
|
||||
signupBtn.disabled = true;
|
||||
|
||||
// 模擬API請求延遲
|
||||
setTimeout(() => {
|
||||
// 成功註冊後跳轉到引導流程
|
||||
window.location.href = '03-onboarding.html';
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
|
||||
// Google註冊處理
|
||||
document.getElementById('googleSignup').addEventListener('click', function() {
|
||||
// 模擬Google OAuth流程
|
||||
this.textContent = '連接中...';
|
||||
this.disabled = true;
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.href = '03-onboarding.html';
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
// 密碼確認即時驗證
|
||||
document.getElementById('confirmPassword').addEventListener('input', function() {
|
||||
const password = document.getElementById('password').value;
|
||||
const confirmPassword = this.value;
|
||||
|
||||
if (confirmPassword && password !== confirmPassword) {
|
||||
this.style.borderColor = 'var(--error-red)';
|
||||
} else {
|
||||
this.style.borderColor = 'var(--divider)';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,562 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-TW">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Drama Ling - 新手引導</title>
|
||||
<link rel="stylesheet" href="../../../docs/02_design/ui-ux/dramaling-ui.css">
|
||||
<style>
|
||||
/* UI_Onboarding_Screen - 新手引導界面 */
|
||||
.onboarding-container {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(45deg, var(--primary-teal) 0%, var(--secondary-purple) 50%, var(--accent-violet) 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.onboarding-container::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: radial-gradient(circle at 30% 20%, rgba(255,255,255,0.1) 0%, transparent 50%),
|
||||
radial-gradient(circle at 70% 80%, rgba(255,255,255,0.05) 0%, transparent 50%);
|
||||
}
|
||||
|
||||
.onboarding-header {
|
||||
padding: var(--space-6) var(--space-6) 0;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.welcome-title {
|
||||
font-size: var(--text-3xl);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
margin-bottom: var(--space-2);
|
||||
text-shadow: 0 2px 4px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.welcome-subtitle {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--text-secondary);
|
||||
opacity: 0.9;
|
||||
margin-bottom: var(--space-8);
|
||||
}
|
||||
|
||||
.onboarding-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 0 var(--space-6);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* UI_Onboarding_Steps - 引導步驟 */
|
||||
.onboarding-steps {
|
||||
background: var(--card-background);
|
||||
border-radius: var(--radius-xl);
|
||||
padding: var(--space-8);
|
||||
margin-bottom: var(--space-8);
|
||||
box-shadow: var(--shadow-xl);
|
||||
border: 3px solid rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
.step-indicators {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: var(--space-8);
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.step-dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: var(--divider);
|
||||
transition: all var(--duration-normal);
|
||||
}
|
||||
|
||||
.step-dot.active {
|
||||
background: var(--primary-teal);
|
||||
transform: scale(1.2);
|
||||
box-shadow: 0 0 10px rgba(0, 229, 204, 0.5);
|
||||
}
|
||||
|
||||
.step-dot.completed {
|
||||
background: var(--success-green);
|
||||
}
|
||||
|
||||
.step-content {
|
||||
text-align: center;
|
||||
min-height: 300px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.step-icon {
|
||||
font-size: 80px;
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.step-title {
|
||||
font-size: var(--text-2xl);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.step-description {
|
||||
font-size: var(--text-base);
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.6;
|
||||
max-width: 400px;
|
||||
margin: 0 auto var(--space-6);
|
||||
}
|
||||
|
||||
/* UI_Learning_Goals_Selection - 學習目標選擇 */
|
||||
.goals-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: var(--space-4);
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.goal-option {
|
||||
padding: var(--space-5);
|
||||
background: var(--background-secondary);
|
||||
border: 2px solid var(--divider);
|
||||
border-radius: var(--radius-lg);
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
}
|
||||
|
||||
.goal-option:hover {
|
||||
border-color: var(--primary-teal);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.goal-option.selected {
|
||||
background: var(--primary-teal);
|
||||
border-color: var(--primary-teal-dark);
|
||||
color: var(--background-dark);
|
||||
font-weight: bold;
|
||||
box-shadow: 0 4px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.goal-icon {
|
||||
font-size: 40px;
|
||||
margin-bottom: var(--space-2);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.goal-title {
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* UI_English_Level_Assessment - 英語程度評估 */
|
||||
.level-options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.level-option {
|
||||
padding: var(--space-4);
|
||||
background: var(--background-secondary);
|
||||
border: 2px solid var(--divider);
|
||||
border-radius: var(--radius-lg);
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.level-option:hover {
|
||||
border-color: var(--secondary-purple);
|
||||
background: var(--background-primary);
|
||||
}
|
||||
|
||||
.level-option.selected {
|
||||
background: var(--secondary-purple);
|
||||
border-color: var(--secondary-purple-dark);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
box-shadow: 0 4px 0 var(--secondary-purple-dark);
|
||||
}
|
||||
|
||||
.level-badge {
|
||||
background: var(--divider);
|
||||
color: var(--text-primary);
|
||||
padding: var(--space-2) var(--space-3);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: bold;
|
||||
min-width: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.level-option.selected .level-badge {
|
||||
background: var(--secondary-purple-dark);
|
||||
}
|
||||
|
||||
.level-details {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.level-title {
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
margin-bottom: var(--space-1);
|
||||
}
|
||||
|
||||
.level-desc {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.level-option.selected .level-desc {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* 導航按鈕 */
|
||||
.onboarding-navigation {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: var(--space-6);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.btn-skip {
|
||||
background: transparent;
|
||||
color: var(--text-secondary);
|
||||
border: none;
|
||||
font-size: var(--text-base);
|
||||
cursor: pointer;
|
||||
padding: var(--space-3) var(--space-4);
|
||||
border-radius: var(--radius-md);
|
||||
transition: all var(--duration-normal);
|
||||
}
|
||||
|
||||
.btn-skip:hover {
|
||||
color: var(--text-primary);
|
||||
background: rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
.btn-next {
|
||||
padding: var(--space-4) var(--space-8);
|
||||
background: var(--primary-teal);
|
||||
color: var(--background-dark);
|
||||
border: 3px solid var(--primary-teal-dark);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-base);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
box-shadow: 0 4px 0 var(--primary-teal-dark);
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-next:hover {
|
||||
background: var(--primary-teal-light);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 5px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.btn-next:active {
|
||||
transform: translateY(2px);
|
||||
box-shadow: 0 2px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.btn-next:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: 0 4px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.onboarding-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.onboarding-header, .onboarding-content, .onboarding-navigation {
|
||||
padding-left: var(--space-4);
|
||||
padding-right: var(--space-4);
|
||||
}
|
||||
|
||||
.onboarding-steps {
|
||||
padding: var(--space-6);
|
||||
}
|
||||
|
||||
.welcome-title {
|
||||
font-size: var(--text-2xl);
|
||||
}
|
||||
|
||||
.goals-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.step-icon {
|
||||
font-size: 60px;
|
||||
}
|
||||
|
||||
.onboarding-navigation {
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.btn-next {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="onboarding-container">
|
||||
<!-- UI_Welcome_Header - 歡迎標題 -->
|
||||
<div class="onboarding-header">
|
||||
<h1 class="welcome-title">歡迎來到 Drama Ling!</h1>
|
||||
<p class="welcome-subtitle">讓我們了解您的學習需求</p>
|
||||
</div>
|
||||
|
||||
<div class="onboarding-content">
|
||||
<div class="onboarding-steps">
|
||||
<!-- UI_Step_Indicators - 步驟指示器 -->
|
||||
<div class="step-indicators">
|
||||
<div class="step-dot active" data-step="1"></div>
|
||||
<div class="step-dot" data-step="2"></div>
|
||||
<div class="step-dot" data-step="3"></div>
|
||||
</div>
|
||||
|
||||
<!-- 步驟1:歡迎介紹 -->
|
||||
<div class="step-content" id="step1">
|
||||
<div class="step-icon">🎭</div>
|
||||
<h2 class="step-title">用英語演出你的故事</h2>
|
||||
<p class="step-description">
|
||||
Drama Ling 結合情境對話和AI智能分析,讓您在真實場景中練習英語,提升溝通能力。我們將根據您的學習目標和程度,為您量身打造個人化的學習路徑。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 步驟2:學習目標選擇 -->
|
||||
<div class="step-content" id="step2" style="display: none;">
|
||||
<div class="step-icon">🎯</div>
|
||||
<h2 class="step-title">您的學習目標是什麼?</h2>
|
||||
<p class="step-description">選擇最符合您需求的學習目標(可選擇多個)</p>
|
||||
|
||||
<!-- UI_Learning_Goals_Selection - 學習目標選擇 -->
|
||||
<div class="goals-grid">
|
||||
<div class="goal-option" data-goal="daily">
|
||||
<span class="goal-icon">💬</span>
|
||||
<div class="goal-title">日常對話</div>
|
||||
</div>
|
||||
<div class="goal-option" data-goal="business">
|
||||
<span class="goal-icon">💼</span>
|
||||
<div class="goal-title">商務英語</div>
|
||||
</div>
|
||||
<div class="goal-option" data-goal="travel">
|
||||
<span class="goal-icon">✈️</span>
|
||||
<div class="goal-title">旅遊英語</div>
|
||||
</div>
|
||||
<div class="goal-option" data-goal="exam">
|
||||
<span class="goal-icon">📚</span>
|
||||
<div class="goal-title">考試準備</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 步驟3:英語程度評估 -->
|
||||
<div class="step-content" id="step3" style="display: none;">
|
||||
<div class="step-icon">📊</div>
|
||||
<h2 class="step-title">您的英語程度如何?</h2>
|
||||
<p class="step-description">選擇最符合您目前程度的選項</p>
|
||||
|
||||
<!-- UI_English_Level_Assessment - 英語程度評估 -->
|
||||
<div class="level-options">
|
||||
<div class="level-option" data-level="beginner">
|
||||
<div class="level-badge">A1-A2</div>
|
||||
<div class="level-details">
|
||||
<div class="level-title">初學者</div>
|
||||
<div class="level-desc">基礎詞彙和簡單句型</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="level-option" data-level="intermediate">
|
||||
<div class="level-badge">B1-B2</div>
|
||||
<div class="level-details">
|
||||
<div class="level-title">中級</div>
|
||||
<div class="level-desc">能進行日常對話,但需要更多練習</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="level-option" data-level="advanced">
|
||||
<div class="level-badge">C1-C2</div>
|
||||
<div class="level-details">
|
||||
<div class="level-title">高級</div>
|
||||
<div class="level-desc">流利對話,想要精進表達能力</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UI_Navigation_Buttons - 導航按鈕 -->
|
||||
<div class="onboarding-navigation">
|
||||
<button class="btn-skip" id="skipBtn">跳過</button>
|
||||
<button class="btn-next" id="nextBtn">下一步</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let currentStep = 1;
|
||||
const totalSteps = 3;
|
||||
let selectedGoals = [];
|
||||
let selectedLevel = null;
|
||||
|
||||
// 更新步驟指示器
|
||||
function updateStepIndicators() {
|
||||
const dots = document.querySelectorAll('.step-dot');
|
||||
dots.forEach((dot, index) => {
|
||||
const stepNumber = index + 1;
|
||||
dot.classList.remove('active', 'completed');
|
||||
|
||||
if (stepNumber < currentStep) {
|
||||
dot.classList.add('completed');
|
||||
} else if (stepNumber === currentStep) {
|
||||
dot.classList.add('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 顯示當前步驟
|
||||
function showStep(stepNumber) {
|
||||
// 隱藏所有步驟內容
|
||||
document.querySelectorAll('.step-content').forEach(step => {
|
||||
step.style.display = 'none';
|
||||
});
|
||||
|
||||
// 顯示當前步驟
|
||||
document.getElementById(`step${stepNumber}`).style.display = 'block';
|
||||
|
||||
// 更新步驟指示器
|
||||
updateStepIndicators();
|
||||
|
||||
// 更新按鈕狀態
|
||||
updateButtonState();
|
||||
}
|
||||
|
||||
// 更新按鈕狀態
|
||||
function updateButtonState() {
|
||||
const nextBtn = document.getElementById('nextBtn');
|
||||
const skipBtn = document.getElementById('skipBtn');
|
||||
|
||||
// 檢查當前步驟是否已完成
|
||||
let canProceed = true;
|
||||
|
||||
if (currentStep === 2 && selectedGoals.length === 0) {
|
||||
canProceed = false;
|
||||
}
|
||||
|
||||
if (currentStep === 3 && !selectedLevel) {
|
||||
canProceed = false;
|
||||
}
|
||||
|
||||
nextBtn.disabled = !canProceed;
|
||||
|
||||
// 更新按鈕文字
|
||||
if (currentStep === totalSteps) {
|
||||
nextBtn.textContent = '開始學習';
|
||||
skipBtn.style.display = 'none';
|
||||
} else {
|
||||
nextBtn.textContent = '下一步';
|
||||
skipBtn.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
// 學習目標選擇處理
|
||||
document.querySelectorAll('.goal-option').forEach(option => {
|
||||
option.addEventListener('click', function() {
|
||||
const goal = this.dataset.goal;
|
||||
|
||||
if (this.classList.contains('selected')) {
|
||||
// 取消選擇
|
||||
this.classList.remove('selected');
|
||||
selectedGoals = selectedGoals.filter(g => g !== goal);
|
||||
} else {
|
||||
// 選擇
|
||||
this.classList.add('selected');
|
||||
selectedGoals.push(goal);
|
||||
}
|
||||
|
||||
updateButtonState();
|
||||
});
|
||||
});
|
||||
|
||||
// 英語程度選擇處理
|
||||
document.querySelectorAll('.level-option').forEach(option => {
|
||||
option.addEventListener('click', function() {
|
||||
// 移除其他選項的選中狀態
|
||||
document.querySelectorAll('.level-option').forEach(opt => {
|
||||
opt.classList.remove('selected');
|
||||
});
|
||||
|
||||
// 設置當前選項為選中狀態
|
||||
this.classList.add('selected');
|
||||
selectedLevel = this.dataset.level;
|
||||
|
||||
updateButtonState();
|
||||
});
|
||||
});
|
||||
|
||||
// 下一步按鈕處理
|
||||
document.getElementById('nextBtn').addEventListener('click', function() {
|
||||
if (currentStep < totalSteps) {
|
||||
currentStep++;
|
||||
showStep(currentStep);
|
||||
} else {
|
||||
// 完成引導,跳轉到學習路徑選擇
|
||||
completeOnboarding();
|
||||
}
|
||||
});
|
||||
|
||||
// 跳過按鈕處理
|
||||
document.getElementById('skipBtn').addEventListener('click', function() {
|
||||
completeOnboarding();
|
||||
});
|
||||
|
||||
// 完成引導流程
|
||||
function completeOnboarding() {
|
||||
// 儲存用戶選擇
|
||||
const userData = {
|
||||
goals: selectedGoals,
|
||||
level: selectedLevel,
|
||||
completedOnboarding: true
|
||||
};
|
||||
|
||||
localStorage.setItem('dramatLingUserData', JSON.stringify(userData));
|
||||
|
||||
// 跳轉到學習路徑選擇
|
||||
window.location.href = '04-learning-path-selection.html';
|
||||
}
|
||||
|
||||
// 初始化
|
||||
showStep(currentStep);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,571 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-TW">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Drama Ling - 選擇學習路徑</title>
|
||||
<link rel="stylesheet" href="../../../docs/02_design/ui-ux/dramaling-ui.css">
|
||||
<style>
|
||||
/* UI_Learning_Path_Selection - 學習路徑選擇 */
|
||||
.path-selection-container {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, var(--background-primary) 0%, var(--background-secondary) 100%);
|
||||
padding: var(--space-6);
|
||||
}
|
||||
|
||||
.header-section {
|
||||
text-align: center;
|
||||
margin-bottom: var(--space-8);
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: var(--text-3xl);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--text-secondary);
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.paths-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||
gap: var(--space-8);
|
||||
max-width: 1200px;
|
||||
margin: 0 auto var(--space-8);
|
||||
}
|
||||
|
||||
/* UI_Learning_Path_Card - 學習路徑卡片 */
|
||||
.path-card {
|
||||
background: var(--card-background);
|
||||
border-radius: var(--radius-xl);
|
||||
padding: var(--space-8);
|
||||
border: 3px solid var(--divider);
|
||||
transition: all var(--duration-normal);
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.path-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
background: var(--divider);
|
||||
transition: all var(--duration-normal);
|
||||
}
|
||||
|
||||
.path-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: var(--shadow-xl);
|
||||
border-color: var(--primary-teal);
|
||||
}
|
||||
|
||||
.path-card:hover::before {
|
||||
background: var(--primary-teal);
|
||||
}
|
||||
|
||||
.path-card.selected {
|
||||
border-color: var(--primary-teal);
|
||||
background: linear-gradient(135deg, var(--card-background) 0%, rgba(0, 229, 204, 0.05) 100%);
|
||||
transform: translateY(-4px);
|
||||
box-shadow: var(--shadow-xl), 0 0 0 2px var(--primary-teal);
|
||||
}
|
||||
|
||||
.path-card.selected::before {
|
||||
background: var(--primary-teal);
|
||||
}
|
||||
|
||||
.path-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
margin: 0 auto var(--space-6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 40px;
|
||||
background: var(--background-secondary);
|
||||
border: 3px solid var(--divider);
|
||||
}
|
||||
|
||||
.path-card.selected .path-icon {
|
||||
background: var(--primary-teal);
|
||||
border-color: var(--primary-teal-dark);
|
||||
color: var(--background-dark);
|
||||
}
|
||||
|
||||
.path-title {
|
||||
font-size: var(--text-xl);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.path-description {
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.6;
|
||||
margin-bottom: var(--space-6);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* UI_Learning_Features - 學習特色 */
|
||||
.path-features {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 0 var(--space-6);
|
||||
}
|
||||
|
||||
.path-features li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: var(--space-3);
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.path-features li::before {
|
||||
content: '✓';
|
||||
color: var(--success-green);
|
||||
font-weight: bold;
|
||||
margin-right: var(--space-3);
|
||||
width: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.path-card.selected .path-features li::before {
|
||||
color: var(--primary-teal);
|
||||
}
|
||||
|
||||
/* UI_Difficulty_Badge - 難度標識 */
|
||||
.difficulty-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: var(--space-2) var(--space-4);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.difficulty-beginner {
|
||||
background: var(--success-green);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.difficulty-intermediate {
|
||||
background: var(--warning-yellow);
|
||||
color: var(--background-dark);
|
||||
}
|
||||
|
||||
.difficulty-advanced {
|
||||
background: var(--error-red);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.stars {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.star {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: var(--star-active);
|
||||
clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
|
||||
}
|
||||
|
||||
.star.inactive {
|
||||
background: var(--star-inactive);
|
||||
}
|
||||
|
||||
/* UI_Time_Estimate - 時間估計 */
|
||||
.time-estimate {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-2);
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-tertiary);
|
||||
padding: var(--space-3);
|
||||
background: var(--background-secondary);
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.path-card.selected .time-estimate {
|
||||
background: rgba(0, 229, 204, 0.1);
|
||||
color: var(--primary-teal);
|
||||
}
|
||||
|
||||
/* 開始學習按鈕 */
|
||||
.start-learning-section {
|
||||
text-align: center;
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.btn-start-learning {
|
||||
padding: var(--space-5) var(--space-12);
|
||||
background: var(--primary-teal);
|
||||
color: var(--background-dark);
|
||||
border: 3px solid var(--primary-teal-dark);
|
||||
border-radius: var(--radius-lg);
|
||||
font-size: var(--text-xl);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
box-shadow: 0 6px 0 var(--primary-teal-dark);
|
||||
transform: translateY(0);
|
||||
width: 100%;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.btn-start-learning:hover {
|
||||
background: var(--primary-teal-light);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.btn-start-learning:active {
|
||||
transform: translateY(3px);
|
||||
box-shadow: 0 3px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.btn-start-learning:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: 0 6px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.selection-hint {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-tertiary);
|
||||
margin-top: var(--space-3);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.paths-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-6);
|
||||
}
|
||||
|
||||
.path-selection-container {
|
||||
padding: var(--space-4);
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: var(--text-2xl);
|
||||
}
|
||||
|
||||
.path-card {
|
||||
padding: var(--space-6);
|
||||
}
|
||||
|
||||
.btn-start-learning {
|
||||
padding: var(--space-4) var(--space-8);
|
||||
font-size: var(--text-lg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="path-selection-container">
|
||||
<!-- UI_Page_Header - 頁面標題 -->
|
||||
<div class="header-section">
|
||||
<h1 class="page-title">選擇您的學習路徑</h1>
|
||||
<p class="page-subtitle">
|
||||
根據您的英語程度和學習目標,我們為您推薦了以下學習路徑。每個路徑都經過精心設計,幫助您循序漸進地提升英語能力。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- UI_Learning_Paths_Grid - 學習路徑網格 -->
|
||||
<div class="paths-grid">
|
||||
<!-- 日常對話路徑 -->
|
||||
<div class="path-card" data-path="daily-conversation">
|
||||
<div class="path-icon">💬</div>
|
||||
<h2 class="path-title">日常對話精通</h2>
|
||||
|
||||
<div class="difficulty-badge difficulty-beginner">
|
||||
<div class="stars">
|
||||
<div class="star"></div>
|
||||
<div class="star"></div>
|
||||
<div class="star inactive"></div>
|
||||
<div class="star inactive"></div>
|
||||
<div class="star inactive"></div>
|
||||
</div>
|
||||
<span>適合初學者</span>
|
||||
</div>
|
||||
|
||||
<p class="path-description">
|
||||
從基礎問候開始,逐步掌握購物、用餐、問路等日常情境對話,建立英語溝通的信心基礎。
|
||||
</p>
|
||||
|
||||
<ul class="path-features">
|
||||
<li>13個階段循序學習</li>
|
||||
<li>20+真實場景劇本</li>
|
||||
<li>AI即時發音糾正</li>
|
||||
<li>詞彙量從300增至1500</li>
|
||||
<li>三維對話能力評估</li>
|
||||
</ul>
|
||||
|
||||
<div class="time-estimate">
|
||||
<span>⏱️</span>
|
||||
<span>預估完成時間:8-12週</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 商務英語路徑 -->
|
||||
<div class="path-card" data-path="business-english">
|
||||
<div class="path-icon">💼</div>
|
||||
<h2 class="path-title">商務英語專精</h2>
|
||||
|
||||
<div class="difficulty-badge difficulty-intermediate">
|
||||
<div class="stars">
|
||||
<div class="star"></div>
|
||||
<div class="star"></div>
|
||||
<div class="star"></div>
|
||||
<div class="star"></div>
|
||||
<div class="star inactive"></div>
|
||||
</div>
|
||||
<span>中高級</span>
|
||||
</div>
|
||||
|
||||
<p class="path-description">
|
||||
專為職場人士設計,涵蓋會議討論、簡報演示、商務談判等專業場景,提升職場競爭力。
|
||||
</p>
|
||||
|
||||
<ul class="path-features">
|
||||
<li>職場核心情境訓練</li>
|
||||
<li>商務詞彙2000+</li>
|
||||
<li>簡報技巧專項練習</li>
|
||||
<li>談判對話深度分析</li>
|
||||
<li>專業表達能力評估</li>
|
||||
</ul>
|
||||
|
||||
<div class="time-estimate">
|
||||
<span>⏱️</span>
|
||||
<span>預估完成時間:12-16週</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 旅遊英語路徑 -->
|
||||
<div class="path-card" data-path="travel-english">
|
||||
<div class="path-icon">✈️</div>
|
||||
<h2 class="path-title">旅遊英語達人</h2>
|
||||
|
||||
<div class="difficulty-badge difficulty-beginner">
|
||||
<div class="stars">
|
||||
<div class="star"></div>
|
||||
<div class="star"></div>
|
||||
<div class="star"></div>
|
||||
<div class="star inactive"></div>
|
||||
<div class="star inactive"></div>
|
||||
</div>
|
||||
<span>初中級</span>
|
||||
</div>
|
||||
|
||||
<p class="path-description">
|
||||
為愛好旅遊的您量身打造,掌握機場、飯店、餐廳、景點等旅遊必備對話技能。
|
||||
</p>
|
||||
|
||||
<ul class="path-features">
|
||||
<li>旅遊場景全覆蓋</li>
|
||||
<li>緊急狀況應對訓練</li>
|
||||
<li>文化交流對話練習</li>
|
||||
<li>實用短語快速記憶</li>
|
||||
<li>口音適應性訓練</li>
|
||||
</ul>
|
||||
|
||||
<div class="time-estimate">
|
||||
<span>⏱️</span>
|
||||
<span>預估完成時間:6-10週</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 考試準備路徑 -->
|
||||
<div class="path-card" data-path="exam-prep">
|
||||
<div class="path-icon">📚</div>
|
||||
<h2 class="path-title">考試準備強化</h2>
|
||||
|
||||
<div class="difficulty-badge difficulty-advanced">
|
||||
<div class="stars">
|
||||
<div class="star"></div>
|
||||
<div class="star"></div>
|
||||
<div class="star"></div>
|
||||
<div class="star"></div>
|
||||
<div class="star"></div>
|
||||
</div>
|
||||
<span>高級</span>
|
||||
</div>
|
||||
|
||||
<p class="path-description">
|
||||
針對TOEIC、IELTS、TOEFL等英語檢定考試,重點強化口說測驗的應答技巧和流暢度。
|
||||
</p>
|
||||
|
||||
<ul class="path-features">
|
||||
<li>考試題型專項練習</li>
|
||||
<li>高頻詞彙密集訓練</li>
|
||||
<li>答題策略深度解析</li>
|
||||
<li>時間管理技巧培養</li>
|
||||
<li>模擬考試實戰演練</li>
|
||||
</ul>
|
||||
|
||||
<div class="time-estimate">
|
||||
<span>⏱️</span>
|
||||
<span>預估完成時間:10-14週</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UI_Start_Learning_Button - 開始學習按鈕 -->
|
||||
<div class="start-learning-section">
|
||||
<button class="btn-start-learning" id="startLearningBtn" disabled>
|
||||
開始我的學習之旅
|
||||
</button>
|
||||
<p class="selection-hint">請先選擇一個學習路徑</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let selectedPath = null;
|
||||
|
||||
// 學習路徑選擇處理
|
||||
document.querySelectorAll('.path-card').forEach(card => {
|
||||
card.addEventListener('click', function() {
|
||||
// 移除其他卡片的選中狀態
|
||||
document.querySelectorAll('.path-card').forEach(c => {
|
||||
c.classList.remove('selected');
|
||||
});
|
||||
|
||||
// 設置當前卡片為選中狀態
|
||||
this.classList.add('selected');
|
||||
selectedPath = this.dataset.path;
|
||||
|
||||
// 更新按鈕狀態
|
||||
updateStartButton();
|
||||
});
|
||||
});
|
||||
|
||||
// 更新開始學習按鈕狀態
|
||||
function updateStartButton() {
|
||||
const startBtn = document.getElementById('startLearningBtn');
|
||||
const hint = document.querySelector('.selection-hint');
|
||||
|
||||
if (selectedPath) {
|
||||
startBtn.disabled = false;
|
||||
hint.textContent = `已選擇:${getPathDisplayName(selectedPath)}`;
|
||||
hint.style.color = 'var(--primary-teal)';
|
||||
} else {
|
||||
startBtn.disabled = true;
|
||||
hint.textContent = '請先選擇一個學習路徑';
|
||||
hint.style.color = 'var(--text-tertiary)';
|
||||
}
|
||||
}
|
||||
|
||||
// 獲取路徑顯示名稱
|
||||
function getPathDisplayName(pathId) {
|
||||
const names = {
|
||||
'daily-conversation': '日常對話精通',
|
||||
'business-english': '商務英語專精',
|
||||
'travel-english': '旅遊英語達人',
|
||||
'exam-prep': '考試準備強化'
|
||||
};
|
||||
return names[pathId] || pathId;
|
||||
}
|
||||
|
||||
// 開始學習按鈕處理
|
||||
document.getElementById('startLearningBtn').addEventListener('click', function() {
|
||||
if (!selectedPath) return;
|
||||
|
||||
// 顯示載入狀態
|
||||
this.textContent = '準備中...';
|
||||
this.disabled = true;
|
||||
|
||||
// 儲存用戶選擇的學習路徑
|
||||
const existingData = JSON.parse(localStorage.getItem('dramatLingUserData') || '{}');
|
||||
const userData = {
|
||||
...existingData,
|
||||
selectedPath: selectedPath,
|
||||
startDate: new Date().toISOString(),
|
||||
currentStage: 1,
|
||||
unlockedStages: [1],
|
||||
completedStages: [],
|
||||
totalProgress: 0
|
||||
};
|
||||
|
||||
localStorage.setItem('dramatLingUserData', JSON.stringify(userData));
|
||||
|
||||
// 模擬準備過程
|
||||
setTimeout(() => {
|
||||
// 跳轉到四關學習系統主畫面
|
||||
window.location.href = '05-four-stage-learning.html';
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
// 初始化 - 檢查是否有推薦路徑
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const userData = JSON.parse(localStorage.getItem('dramatLingUserData') || '{}');
|
||||
|
||||
// 根據用戶的學習目標和程度推薦路徑
|
||||
if (userData.goals && userData.level) {
|
||||
let recommendedPath = null;
|
||||
|
||||
if (userData.goals.includes('business')) {
|
||||
recommendedPath = 'business-english';
|
||||
} else if (userData.goals.includes('travel')) {
|
||||
recommendedPath = 'travel-english';
|
||||
} else if (userData.goals.includes('exam')) {
|
||||
recommendedPath = 'exam-prep';
|
||||
} else if (userData.goals.includes('daily')) {
|
||||
recommendedPath = 'daily-conversation';
|
||||
} else {
|
||||
// 根據程度推薦
|
||||
if (userData.level === 'beginner') {
|
||||
recommendedPath = 'daily-conversation';
|
||||
} else if (userData.level === 'intermediate') {
|
||||
recommendedPath = 'travel-english';
|
||||
} else if (userData.level === 'advanced') {
|
||||
recommendedPath = 'business-english';
|
||||
}
|
||||
}
|
||||
|
||||
// 高亮推薦路徑
|
||||
if (recommendedPath) {
|
||||
const recommendedCard = document.querySelector(`[data-path="${recommendedPath}"]`);
|
||||
if (recommendedCard) {
|
||||
const recommendedBadge = document.createElement('div');
|
||||
recommendedBadge.style.cssText = `
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: -10px;
|
||||
background: var(--warning-yellow);
|
||||
color: var(--background-dark);
|
||||
padding: var(--space-2) var(--space-3);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: bold;
|
||||
transform: rotate(15deg);
|
||||
box-shadow: var(--shadow-md);
|
||||
`;
|
||||
recommendedBadge.textContent = '推薦';
|
||||
recommendedCard.appendChild(recommendedBadge);
|
||||
recommendedCard.style.position = 'relative';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,971 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-TW">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Drama Ling - 四關學習系統</title>
|
||||
<link rel="stylesheet" href="../../../docs/02_design/ui-ux/dramaling-ui.css">
|
||||
<style>
|
||||
/* UI_Four_Stage_Learning_Main - 四關學習主畫面 */
|
||||
.learning-main-container {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, var(--background-primary) 0%, var(--background-secondary) 100%);
|
||||
}
|
||||
|
||||
/* UI_Top_Status_Bar - 頂部狀態列 */
|
||||
.top-status-bar {
|
||||
background: var(--card-background);
|
||||
padding: var(--space-4) var(--space-6);
|
||||
border-bottom: 2px solid var(--divider);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background: var(--primary-teal);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--background-dark);
|
||||
font-weight: bold;
|
||||
font-size: var(--text-lg);
|
||||
}
|
||||
|
||||
.user-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: var(--text-base);
|
||||
color: var(--text-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.user-level {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* UI_Life_Points_Display - 生命點數顯示 */
|
||||
.status-indicators {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-6);
|
||||
}
|
||||
|
||||
.life-points {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.hearts {
|
||||
display: flex;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
.heart {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background: var(--error-red);
|
||||
clip-path: path('M12,21.35l-1.45-1.32C5.4,15.36,2,12.28,2,8.5 C2,5.42,4.42,3,7.5,3c1.74,0,3.41,0.81,4.5,2.09C13.09,3.81,14.76,3,16.5,3 C19.58,3,22,5.42,22,8.5c0,3.78-3.4,6.86-8.55,11.54L12,21.35z');
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.heart.empty {
|
||||
background: var(--divider);
|
||||
}
|
||||
|
||||
.heart.infinite {
|
||||
background: var(--gold);
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { transform: scale(1); }
|
||||
50% { transform: scale(1.1); }
|
||||
}
|
||||
|
||||
.diamonds {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
color: var(--diamond);
|
||||
}
|
||||
|
||||
.diamond-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: var(--diamond);
|
||||
clip-path: polygon(50% 0%, 0% 50%, 50% 100%, 100% 50%);
|
||||
}
|
||||
|
||||
.diamond-count {
|
||||
font-weight: bold;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* UI_Current_Stage_Header - 當前階段標題 */
|
||||
.stage-header {
|
||||
padding: var(--space-8) var(--space-6) var(--space-6);
|
||||
text-align: center;
|
||||
background: linear-gradient(135deg, rgba(0, 229, 204, 0.1) 0%, rgba(142, 68, 173, 0.1) 100%);
|
||||
}
|
||||
|
||||
.stage-title {
|
||||
font-size: var(--text-3xl);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.stage-subtitle {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
/* UI_Progress_Overview - 進度總覽 */
|
||||
.progress-overview {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: var(--space-8);
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.progress-item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.progress-value {
|
||||
font-size: var(--text-2xl);
|
||||
font-weight: bold;
|
||||
color: var(--primary-teal);
|
||||
margin-bottom: var(--space-1);
|
||||
}
|
||||
|
||||
.progress-label {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
/* UI_Script_Selection_Grid - 劇本選擇網格 */
|
||||
.scripts-section {
|
||||
padding: 0 var(--space-6) var(--space-8);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: var(--text-xl);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
margin-bottom: var(--space-6);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scripts-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: var(--space-6);
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* UI_Script_Card - 劇本卡片 */
|
||||
.script-card {
|
||||
background: var(--card-background);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
border: 3px solid var(--divider);
|
||||
transition: all var(--duration-normal);
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.script-card.available {
|
||||
border-color: var(--primary-teal);
|
||||
background: linear-gradient(135deg, var(--card-background) 0%, rgba(0, 229, 204, 0.05) 100%);
|
||||
}
|
||||
|
||||
.script-card.available:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-lg);
|
||||
border-color: var(--primary-teal-light);
|
||||
}
|
||||
|
||||
.script-card.locked {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.script-card.completed {
|
||||
border-color: var(--success-green);
|
||||
background: linear-gradient(135deg, var(--card-background) 0%, rgba(39, 174, 96, 0.05) 100%);
|
||||
}
|
||||
|
||||
.script-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
background: var(--divider);
|
||||
}
|
||||
|
||||
.script-card.available::before {
|
||||
background: var(--primary-teal);
|
||||
}
|
||||
|
||||
.script-card.completed::before {
|
||||
background: var(--success-green);
|
||||
}
|
||||
|
||||
.script-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.script-title {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
margin-bottom: var(--space-1);
|
||||
}
|
||||
|
||||
.script-scenario {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* UI_Script_Status_Badge - 劇本狀態標識 */
|
||||
.status-badge {
|
||||
padding: var(--space-2) var(--space-3);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.status-available {
|
||||
background: var(--primary-teal);
|
||||
color: var(--background-dark);
|
||||
}
|
||||
|
||||
.status-locked {
|
||||
background: var(--divider);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background: var(--success-green);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* UI_Four_Stage_Progress - 四關進度顯示 */
|
||||
.stages-progress {
|
||||
margin: var(--space-4) 0;
|
||||
}
|
||||
|
||||
.stages-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
|
||||
.stage-step {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: var(--space-2) var(--space-3);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-sm);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.stage-step.completed {
|
||||
background: var(--success-green);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.stage-step.current {
|
||||
background: var(--primary-teal);
|
||||
color: var(--background-dark);
|
||||
font-weight: bold;
|
||||
animation: glow 2s infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes glow {
|
||||
from { box-shadow: 0 0 5px rgba(0, 229, 204, 0.5); }
|
||||
to { box-shadow: 0 0 10px rgba(0, 229, 204, 0.8); }
|
||||
}
|
||||
|
||||
.stage-step.locked {
|
||||
background: var(--background-secondary);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.stage-step.bonus {
|
||||
background: var(--gold);
|
||||
color: var(--background-dark);
|
||||
border: 2px solid var(--warning-yellow);
|
||||
}
|
||||
|
||||
.stage-connector {
|
||||
flex: 1;
|
||||
height: 2px;
|
||||
background: var(--divider);
|
||||
margin: 0 var(--space-2);
|
||||
}
|
||||
|
||||
.stage-connector.completed {
|
||||
background: var(--success-green);
|
||||
}
|
||||
|
||||
.stage-connector.current {
|
||||
background: linear-gradient(90deg, var(--success-green) 0%, var(--primary-teal) 100%);
|
||||
}
|
||||
|
||||
/* UI_Stars_Rating - 星級評價 */
|
||||
.script-rating {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: var(--space-4);
|
||||
}
|
||||
|
||||
.stars-display {
|
||||
display: flex;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
.star-rating {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: var(--star-active);
|
||||
clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
|
||||
}
|
||||
|
||||
.star-rating.empty {
|
||||
background: var(--star-inactive);
|
||||
}
|
||||
|
||||
.script-card.locked .star-rating {
|
||||
background: var(--divider);
|
||||
}
|
||||
|
||||
.play-button {
|
||||
padding: var(--space-2) var(--space-4);
|
||||
background: var(--primary-teal);
|
||||
color: var(--background-dark);
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
}
|
||||
|
||||
.play-button:hover {
|
||||
background: var(--primary-teal-light);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.script-card.locked .play-button {
|
||||
background: var(--divider);
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.script-card.completed .play-button {
|
||||
background: var(--success-green);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.top-status-bar {
|
||||
padding: var(--space-3) var(--space-4);
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.status-indicators {
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.stage-header {
|
||||
padding: var(--space-6) var(--space-4) var(--space-4);
|
||||
}
|
||||
|
||||
.stage-title {
|
||||
font-size: var(--text-2xl);
|
||||
}
|
||||
|
||||
.progress-overview {
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.scripts-section {
|
||||
padding: 0 var(--space-4) var(--space-6);
|
||||
}
|
||||
|
||||
.scripts-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.stages-row {
|
||||
flex-direction: column;
|
||||
gap: var(--space-2);
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.stage-connector {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="learning-main-container">
|
||||
<!-- UI_Top_Status_Bar - 頂部狀態列 -->
|
||||
<div class="top-status-bar">
|
||||
<div class="user-info">
|
||||
<div class="user-avatar" id="userAvatar">J</div>
|
||||
<div class="user-details">
|
||||
<div class="user-name" id="userName">John Doe</div>
|
||||
<div class="user-level" id="userLevel">初學者 - 階段1</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="status-indicators">
|
||||
<!-- UI_Life_Points_Display - 生命點數顯示 -->
|
||||
<div class="life-points">
|
||||
<div class="hearts" id="heartsContainer">
|
||||
<div class="heart"></div>
|
||||
<div class="heart"></div>
|
||||
<div class="heart"></div>
|
||||
<div class="heart"></div>
|
||||
<div class="heart empty"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="diamonds">
|
||||
<div class="diamond-icon"></div>
|
||||
<span class="diamond-count" id="diamondCount">150</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UI_Current_Stage_Header - 當前階段標題 -->
|
||||
<div class="stage-header">
|
||||
<h1 class="stage-title">階段1:基礎對話入門</h1>
|
||||
<p class="stage-subtitle">掌握日常生活中最常用的基礎對話技巧</p>
|
||||
|
||||
<!-- UI_Progress_Overview - 進度總覽 -->
|
||||
<div class="progress-overview">
|
||||
<div class="progress-item">
|
||||
<div class="progress-value" id="completedScripts">3</div>
|
||||
<div class="progress-label">已完成劇本</div>
|
||||
</div>
|
||||
<div class="progress-item">
|
||||
<div class="progress-value" id="totalStars">9</div>
|
||||
<div class="progress-label">獲得星數</div>
|
||||
</div>
|
||||
<div class="progress-item">
|
||||
<div class="progress-value" id="totalWords">45</div>
|
||||
<div class="progress-label">學會詞彙</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UI_Script_Selection_Grid - 劇本選擇網格 -->
|
||||
<div class="scripts-section">
|
||||
<h2 class="section-title">選擇劇本開始學習</h2>
|
||||
|
||||
<div class="scripts-grid">
|
||||
<!-- 劇本1:問候與自我介紹 -->
|
||||
<div class="script-card completed" data-script="greeting">
|
||||
<div class="script-header">
|
||||
<div>
|
||||
<div class="script-title">問候與自我介紹</div>
|
||||
<div class="script-scenario">咖啡廳初次見面</div>
|
||||
</div>
|
||||
<div class="status-badge status-completed">已完成</div>
|
||||
</div>
|
||||
|
||||
<!-- UI_Four_Stage_Progress - 四關進度顯示 -->
|
||||
<div class="stages-progress">
|
||||
<div class="stages-row">
|
||||
<div class="stage-step completed">
|
||||
<span>✓</span>
|
||||
<span>詞彙學習</span>
|
||||
</div>
|
||||
<div class="stage-connector completed"></div>
|
||||
|
||||
<div class="stage-step completed">
|
||||
<span>✓</span>
|
||||
<span>詞彙熟悉</span>
|
||||
</div>
|
||||
<div class="stage-connector completed"></div>
|
||||
|
||||
<div class="stage-step completed bonus">
|
||||
<span>💎</span>
|
||||
<span>口說練習</span>
|
||||
</div>
|
||||
<div class="stage-connector completed"></div>
|
||||
|
||||
<div class="stage-step completed">
|
||||
<span>✓</span>
|
||||
<span>情境對話</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="script-rating">
|
||||
<div class="stars-display">
|
||||
<div class="star-rating"></div>
|
||||
<div class="star-rating"></div>
|
||||
<div class="star-rating"></div>
|
||||
</div>
|
||||
<button class="play-button">重新練習</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 劇本2:購物與詢價 -->
|
||||
<div class="script-card completed" data-script="shopping">
|
||||
<div class="script-header">
|
||||
<div>
|
||||
<div class="script-title">購物與詢價</div>
|
||||
<div class="script-scenario">服飾店購買衣物</div>
|
||||
</div>
|
||||
<div class="status-badge status-completed">已完成</div>
|
||||
</div>
|
||||
|
||||
<div class="stages-progress">
|
||||
<div class="stages-row">
|
||||
<div class="stage-step completed">
|
||||
<span>✓</span>
|
||||
<span>詞彙學習</span>
|
||||
</div>
|
||||
<div class="stage-connector completed"></div>
|
||||
|
||||
<div class="stage-step completed">
|
||||
<span>✓</span>
|
||||
<span>詞彙熟悉</span>
|
||||
</div>
|
||||
<div class="stage-connector"></div>
|
||||
|
||||
<div class="stage-step locked bonus">
|
||||
<span>🔒</span>
|
||||
<span>口說練習</span>
|
||||
</div>
|
||||
<div class="stage-connector completed"></div>
|
||||
|
||||
<div class="stage-step completed">
|
||||
<span>✓</span>
|
||||
<span>情境對話</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="script-rating">
|
||||
<div class="stars-display">
|
||||
<div class="star-rating"></div>
|
||||
<div class="star-rating"></div>
|
||||
<div class="star-rating empty"></div>
|
||||
</div>
|
||||
<button class="play-button">重新練習</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 劇本3:餐廳點餐 -->
|
||||
<div class="script-card completed" data-script="restaurant">
|
||||
<div class="script-header">
|
||||
<div>
|
||||
<div class="script-title">餐廳點餐</div>
|
||||
<div class="script-scenario">西餐廳用餐體驗</div>
|
||||
</div>
|
||||
<div class="status-badge status-completed">已完成</div>
|
||||
</div>
|
||||
|
||||
<div class="stages-progress">
|
||||
<div class="stages-row">
|
||||
<div class="stage-step completed">
|
||||
<span>✓</span>
|
||||
<span>詞彙學習</span>
|
||||
</div>
|
||||
<div class="stage-connector completed"></div>
|
||||
|
||||
<div class="stage-step completed">
|
||||
<span>✓</span>
|
||||
<span>詞彙熟悉</span>
|
||||
</div>
|
||||
<div class="stage-connector completed"></div>
|
||||
|
||||
<div class="stage-step completed bonus">
|
||||
<span>💎</span>
|
||||
<span>口說練習</span>
|
||||
</div>
|
||||
<div class="stage-connector completed"></div>
|
||||
|
||||
<div class="stage-step completed">
|
||||
<span>✓</span>
|
||||
<span>情境對話</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="script-rating">
|
||||
<div class="stars-display">
|
||||
<div class="star-rating"></div>
|
||||
<div class="star-rating"></div>
|
||||
<div class="star-rating"></div>
|
||||
</div>
|
||||
<button class="play-button">重新練習</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 劇本4:問路指南 - 當前可玩 -->
|
||||
<div class="script-card available" data-script="directions">
|
||||
<div class="script-header">
|
||||
<div>
|
||||
<div class="script-title">問路指南</div>
|
||||
<div class="script-scenario">街頭問路與指路</div>
|
||||
</div>
|
||||
<div class="status-badge status-available">可開始</div>
|
||||
</div>
|
||||
|
||||
<div class="stages-progress">
|
||||
<div class="stages-row">
|
||||
<div class="stage-step current">
|
||||
<span>1</span>
|
||||
<span>詞彙學習</span>
|
||||
</div>
|
||||
<div class="stage-connector"></div>
|
||||
|
||||
<div class="stage-step locked">
|
||||
<span>🔒</span>
|
||||
<span>詞彙熟悉</span>
|
||||
</div>
|
||||
<div class="stage-connector"></div>
|
||||
|
||||
<div class="stage-step locked bonus">
|
||||
<span>💎</span>
|
||||
<span>口說練習</span>
|
||||
</div>
|
||||
<div class="stage-connector"></div>
|
||||
|
||||
<div class="stage-step locked">
|
||||
<span>🔒</span>
|
||||
<span>情境對話</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="script-rating">
|
||||
<div class="stars-display">
|
||||
<div class="star-rating empty"></div>
|
||||
<div class="star-rating empty"></div>
|
||||
<div class="star-rating empty"></div>
|
||||
</div>
|
||||
<button class="play-button">開始學習</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 劇本5:天氣聊天 - 鎖定 -->
|
||||
<div class="script-card locked" data-script="weather">
|
||||
<div class="script-header">
|
||||
<div>
|
||||
<div class="script-title">天氣聊天</div>
|
||||
<div class="script-scenario">日常天氣話題</div>
|
||||
</div>
|
||||
<div class="status-badge status-locked">🔒 鎖定</div>
|
||||
</div>
|
||||
|
||||
<div class="stages-progress">
|
||||
<div class="stages-row">
|
||||
<div class="stage-step locked">
|
||||
<span>🔒</span>
|
||||
<span>詞彙學習</span>
|
||||
</div>
|
||||
<div class="stage-connector"></div>
|
||||
|
||||
<div class="stage-step locked">
|
||||
<span>🔒</span>
|
||||
<span>詞彙熟悉</span>
|
||||
</div>
|
||||
<div class="stage-connector"></div>
|
||||
|
||||
<div class="stage-step locked bonus">
|
||||
<span>💎</span>
|
||||
<span>口說練習</span>
|
||||
</div>
|
||||
<div class="stage-connector"></div>
|
||||
|
||||
<div class="stage-step locked">
|
||||
<span>🔒</span>
|
||||
<span>情境對話</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="script-rating">
|
||||
<div class="stars-display">
|
||||
<div class="star-rating"></div>
|
||||
<div class="star-rating"></div>
|
||||
<div class="star-rating"></div>
|
||||
</div>
|
||||
<button class="play-button">需完成前面劇本</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 劇本6:醫院看診 - 鎖定 -->
|
||||
<div class="script-card locked" data-script="hospital">
|
||||
<div class="script-header">
|
||||
<div>
|
||||
<div class="script-title">醫院看診</div>
|
||||
<div class="script-scenario">醫院掛號就診</div>
|
||||
</div>
|
||||
<div class="status-badge status-locked">🔒 鎖定</div>
|
||||
</div>
|
||||
|
||||
<div class="stages-progress">
|
||||
<div class="stages-row">
|
||||
<div class="stage-step locked">
|
||||
<span>🔒</span>
|
||||
<span>詞彙學習</span>
|
||||
</div>
|
||||
<div class="stage-connector"></div>
|
||||
|
||||
<div class="stage-step locked">
|
||||
<span>🔒</span>
|
||||
<span>詞彙熟悉</span>
|
||||
</div>
|
||||
<div class="stage-connector"></div>
|
||||
|
||||
<div class="stage-step locked bonus">
|
||||
<span>💎</span>
|
||||
<span>口說練習</span>
|
||||
</div>
|
||||
<div class="stage-connector"></div>
|
||||
|
||||
<div class="stage-step locked">
|
||||
<span>🔒</span>
|
||||
<span>情境對話</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="script-rating">
|
||||
<div class="stars-display">
|
||||
<div class="star-rating"></div>
|
||||
<div class="star-rating"></div>
|
||||
<div class="star-rating"></div>
|
||||
</div>
|
||||
<button class="play-button">需完成前面劇本</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 初始化用戶數據
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadUserData();
|
||||
updateUserInterface();
|
||||
});
|
||||
|
||||
// 載入用戶數據
|
||||
function loadUserData() {
|
||||
const userData = JSON.parse(localStorage.getItem('dramatLingUserData') || '{}');
|
||||
|
||||
// 模擬用戶數據
|
||||
const defaultData = {
|
||||
name: 'John Doe',
|
||||
level: 'beginner',
|
||||
currentStage: 1,
|
||||
lifePoints: 4,
|
||||
maxLifePoints: 5,
|
||||
diamonds: 150,
|
||||
completedScripts: 3,
|
||||
totalStars: 9,
|
||||
totalWords: 45,
|
||||
userTier: 'free' // free, premium, unlimited
|
||||
};
|
||||
|
||||
// 合併數據
|
||||
window.userData = { ...defaultData, ...userData };
|
||||
}
|
||||
|
||||
// 更新用戶界面
|
||||
function updateUserInterface() {
|
||||
const data = window.userData;
|
||||
|
||||
// 更新用戶信息
|
||||
document.getElementById('userName').textContent = data.name;
|
||||
document.getElementById('userLevel').textContent = `${getLevelDisplayName(data.level)} - 階段${data.currentStage}`;
|
||||
document.getElementById('userAvatar').textContent = data.name.charAt(0).toUpperCase();
|
||||
|
||||
// 更新生命點數
|
||||
updateLifePoints(data.lifePoints, data.maxLifePoints, data.userTier);
|
||||
|
||||
// 更新鑽石數量
|
||||
document.getElementById('diamondCount').textContent = data.diamonds;
|
||||
|
||||
// 更新進度統計
|
||||
document.getElementById('completedScripts').textContent = data.completedScripts;
|
||||
document.getElementById('totalStars').textContent = data.totalStars;
|
||||
document.getElementById('totalWords').textContent = data.totalWords;
|
||||
}
|
||||
|
||||
// 更新生命點數顯示
|
||||
function updateLifePoints(current, max, userTier) {
|
||||
const heartsContainer = document.getElementById('heartsContainer');
|
||||
heartsContainer.innerHTML = '';
|
||||
|
||||
if (userTier === 'unlimited') {
|
||||
// 無限生命
|
||||
const infiniteHeart = document.createElement('div');
|
||||
infiniteHeart.className = 'heart infinite';
|
||||
infiniteHeart.title = '無限生命';
|
||||
heartsContainer.appendChild(infiniteHeart);
|
||||
|
||||
const infiniteText = document.createElement('span');
|
||||
infiniteText.textContent = '∞';
|
||||
infiniteText.style.cssText = 'color: var(--gold); font-weight: bold; margin-left: var(--space-2);';
|
||||
heartsContainer.appendChild(infiniteText);
|
||||
} else {
|
||||
// 一般生命點數
|
||||
for (let i = 0; i < max; i++) {
|
||||
const heart = document.createElement('div');
|
||||
heart.className = i < current ? 'heart' : 'heart empty';
|
||||
heartsContainer.appendChild(heart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 獲取等級顯示名稱
|
||||
function getLevelDisplayName(level) {
|
||||
const levelNames = {
|
||||
'beginner': '初學者',
|
||||
'intermediate': '中級',
|
||||
'advanced': '高級'
|
||||
};
|
||||
return levelNames[level] || level;
|
||||
}
|
||||
|
||||
// 劇本卡片點擊處理
|
||||
document.querySelectorAll('.script-card').forEach(card => {
|
||||
card.addEventListener('click', function() {
|
||||
const scriptId = this.dataset.script;
|
||||
const isLocked = this.classList.contains('locked');
|
||||
const isCompleted = this.classList.contains('completed');
|
||||
const isAvailable = this.classList.contains('available');
|
||||
|
||||
if (isLocked) {
|
||||
// 顯示解鎖提示
|
||||
showLockedMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAvailable) {
|
||||
// 進入學習模式
|
||||
startScript(scriptId);
|
||||
} else if (isCompleted) {
|
||||
// 重新練習或查看詳情
|
||||
reviewScript(scriptId);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 開始劇本學習
|
||||
function startScript(scriptId) {
|
||||
// 儲存當前劇本ID
|
||||
localStorage.setItem('currentScript', scriptId);
|
||||
|
||||
// 根據劇本進度決定進入哪個關卡
|
||||
// 這裡模擬進入第1關(詞彙學習)
|
||||
window.location.href = `../phase2/vocabulary-learning.html?script=${scriptId}`;
|
||||
}
|
||||
|
||||
// 重新練習劇本
|
||||
function reviewScript(scriptId) {
|
||||
// 顯示劇本選項彈窗
|
||||
showScriptOptionsModal(scriptId);
|
||||
}
|
||||
|
||||
// 顯示鎖定訊息
|
||||
function showLockedMessage() {
|
||||
// 簡單的提示訊息
|
||||
alert('請先完成前面的劇本才能解鎖此內容!');
|
||||
}
|
||||
|
||||
// 顯示劇本選項彈窗
|
||||
function showScriptOptionsModal(scriptId) {
|
||||
// 簡化處理,直接重新開始
|
||||
if (confirm('要重新練習這個劇本嗎?')) {
|
||||
startScript(scriptId);
|
||||
}
|
||||
}
|
||||
|
||||
// 模擬學習進度更新
|
||||
function simulateProgress() {
|
||||
// 這個函數會在實際學習過程中被調用
|
||||
const data = window.userData;
|
||||
data.totalWords += 5; // 學會新詞彙
|
||||
data.totalStars += 1; // 獲得星級
|
||||
|
||||
if (Math.random() > 0.7) {
|
||||
data.completedScripts += 1; // 完成劇本
|
||||
}
|
||||
|
||||
// 儲存數據
|
||||
localStorage.setItem('dramatLingUserData', JSON.stringify(data));
|
||||
|
||||
// 更新界面
|
||||
updateUserInterface();
|
||||
}
|
||||
|
||||
// 生命點數消耗處理
|
||||
function consumeLifePoint() {
|
||||
const data = window.userData;
|
||||
|
||||
if (data.userTier === 'unlimited') {
|
||||
return true; // 無限生命不消耗
|
||||
}
|
||||
|
||||
if (data.lifePoints > 0) {
|
||||
data.lifePoints--;
|
||||
localStorage.setItem('dramatLingUserData', JSON.stringify(data));
|
||||
updateUserInterface();
|
||||
return true;
|
||||
} else {
|
||||
// 生命點數不足,顯示補充選項
|
||||
showLifePointsModal();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 顯示生命點數補充彈窗
|
||||
function showLifePointsModal() {
|
||||
alert('生命點數不足!請等待恢復或購買無限生命。');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,454 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-TW">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Drama Ling - 第1階段核心流程原型展示</title>
|
||||
<link rel="stylesheet" href="../../../docs/02_design/ui-ux/dramaling-ui.css">
|
||||
<style>
|
||||
/* Prototype Index Showcase Styles */
|
||||
.showcase-container {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, var(--background-primary) 0%, var(--background-secondary) 100%);
|
||||
padding: var(--space-8) var(--space-6);
|
||||
}
|
||||
|
||||
.showcase-header {
|
||||
text-align: center;
|
||||
margin-bottom: var(--space-12);
|
||||
}
|
||||
|
||||
.showcase-title {
|
||||
font-size: var(--text-4xl);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
margin-bottom: var(--space-4);
|
||||
background: linear-gradient(135deg, var(--primary-teal) 0%, var(--secondary-purple) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.showcase-subtitle {
|
||||
font-size: var(--text-xl);
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--space-6);
|
||||
max-width: 800px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.showcase-description {
|
||||
font-size: var(--text-base);
|
||||
color: var(--text-tertiary);
|
||||
max-width: 1000px;
|
||||
margin: 0 auto var(--space-8);
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.screens-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
||||
gap: var(--space-8);
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.screen-card {
|
||||
background: var(--card-background);
|
||||
border-radius: var(--radius-xl);
|
||||
padding: var(--space-8);
|
||||
border: 3px solid var(--divider);
|
||||
transition: all var(--duration-normal);
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.screen-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
background: linear-gradient(90deg, var(--primary-teal) 0%, var(--secondary-purple) 100%);
|
||||
transform: translateX(-100%);
|
||||
transition: transform var(--duration-normal);
|
||||
}
|
||||
|
||||
.screen-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: var(--shadow-xl);
|
||||
border-color: var(--primary-teal);
|
||||
}
|
||||
|
||||
.screen-card:hover::before {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.screen-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
margin: 0 auto var(--space-6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 40px;
|
||||
background: linear-gradient(135deg, var(--primary-teal) 0%, var(--secondary-purple) 100%);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.screen-title {
|
||||
font-size: var(--text-xl);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.screen-description {
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.6;
|
||||
margin-bottom: var(--space-6);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.screen-features {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 0 var(--space-6);
|
||||
}
|
||||
|
||||
.screen-features li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: var(--space-3);
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.screen-features li::before {
|
||||
content: '✓';
|
||||
color: var(--primary-teal);
|
||||
font-weight: bold;
|
||||
margin-right: var(--space-3);
|
||||
width: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.screen-status {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: var(--space-2) var(--space-4);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
margin-bottom: var(--space-4);
|
||||
background: var(--success-green);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.btn-view-screen {
|
||||
width: 100%;
|
||||
padding: var(--space-4) var(--space-6);
|
||||
background: var(--primary-teal);
|
||||
color: var(--background-dark);
|
||||
border: 3px solid var(--primary-teal-dark);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-base);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
box-shadow: 0 4px 0 var(--primary-teal-dark);
|
||||
transform: translateY(0);
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.btn-view-screen:hover {
|
||||
background: var(--primary-teal-light);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 5px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.btn-view-screen:active {
|
||||
transform: translateY(2px);
|
||||
box-shadow: 0 2px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.flow-navigation {
|
||||
text-align: center;
|
||||
margin-top: var(--space-12);
|
||||
padding: var(--space-8);
|
||||
background: var(--card-background);
|
||||
border-radius: var(--radius-lg);
|
||||
border: 2px solid var(--divider);
|
||||
}
|
||||
|
||||
.flow-title {
|
||||
font-size: var(--text-2xl);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.flow-description {
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--space-6);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.flow-steps {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.flow-step {
|
||||
padding: var(--space-3) var(--space-4);
|
||||
background: var(--background-secondary);
|
||||
border: 2px solid var(--divider);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-secondary);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.flow-arrow {
|
||||
color: var(--primary-teal);
|
||||
font-size: var(--text-lg);
|
||||
}
|
||||
|
||||
.btn-start-flow {
|
||||
padding: var(--space-5) var(--space-12);
|
||||
background: var(--secondary-purple);
|
||||
color: var(--text-primary);
|
||||
border: 3px solid var(--secondary-purple-dark);
|
||||
border-radius: var(--radius-lg);
|
||||
font-size: var(--text-lg);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
box-shadow: 0 6px 0 var(--secondary-purple-dark);
|
||||
transform: translateY(0);
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.btn-start-flow:hover {
|
||||
background: var(--secondary-purple-light);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 0 var(--secondary-purple-dark);
|
||||
}
|
||||
|
||||
.btn-start-flow:active {
|
||||
transform: translateY(3px);
|
||||
box-shadow: 0 3px 0 var(--secondary-purple-dark);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.showcase-container {
|
||||
padding: var(--space-6) var(--space-4);
|
||||
}
|
||||
|
||||
.showcase-title {
|
||||
font-size: var(--text-3xl);
|
||||
}
|
||||
|
||||
.showcase-subtitle {
|
||||
font-size: var(--text-lg);
|
||||
}
|
||||
|
||||
.screens-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-6);
|
||||
}
|
||||
|
||||
.screen-card {
|
||||
padding: var(--space-6);
|
||||
}
|
||||
|
||||
.flow-steps {
|
||||
flex-direction: column;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.flow-arrow {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="showcase-container">
|
||||
<!-- Showcase Header -->
|
||||
<div class="showcase-header">
|
||||
<h1 class="showcase-title">Drama Ling 原型展示</h1>
|
||||
<h2 class="showcase-subtitle">第1階段:核心學習流程畫面</h2>
|
||||
<p class="showcase-description">
|
||||
本展示包含 Drama Ling 核心學習流程的完整用戶體驗,從用戶註冊到四關學習系統的主要界面。
|
||||
每個畫面都基於完整的 UI/UX 設計系統,整合了 102 個 UI 元件,並實現了 Duolingo 風格的遊戲化學習體驗。
|
||||
所有畫面均採用響應式設計,支援桌面和行動裝置。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Screens Grid -->
|
||||
<div class="screens-grid">
|
||||
<!-- Login Screen -->
|
||||
<div class="screen-card">
|
||||
<div class="screen-icon">🔐</div>
|
||||
<h3 class="screen-title">用戶登入</h3>
|
||||
<div class="screen-status">
|
||||
<span>✅</span>
|
||||
<span>已完成</span>
|
||||
</div>
|
||||
<p class="screen-description">
|
||||
完整的用戶認證界面,支援電子郵件登入和 Google OAuth,包含表單驗證和載入狀態處理。
|
||||
</p>
|
||||
<ul class="screen-features">
|
||||
<li>UI_Login_Screen - 用戶登入界面</li>
|
||||
<li>UI_Login_Form - 登入表單</li>
|
||||
<li>UI_Google_Login_Button - Google登入</li>
|
||||
<li>響應式設計與動畫效果</li>
|
||||
<li>表單驗證與錯誤處理</li>
|
||||
</ul>
|
||||
<a href="01-login.html" class="btn-view-screen">查看登入畫面</a>
|
||||
</div>
|
||||
|
||||
<!-- Signup Screen -->
|
||||
<div class="screen-card">
|
||||
<div class="screen-icon">📝</div>
|
||||
<h3 class="screen-title">用戶註冊</h3>
|
||||
<div class="screen-status">
|
||||
<span>✅</span>
|
||||
<span>已完成</span>
|
||||
</div>
|
||||
<p class="screen-description">
|
||||
詳細的註冊流程,包含個人資料填寫、年齡選擇、服務條款確認等完整用戶資料收集。
|
||||
</p>
|
||||
<ul class="screen-features">
|
||||
<li>UI_Signup_Form - 註冊表單</li>
|
||||
<li>UI_Age_Selection - 年齡範圍選擇</li>
|
||||
<li>UI_Terms_Checkbox - 服務條款勾選</li>
|
||||
<li>密碼強度驗證</li>
|
||||
<li>即時表單驗證</li>
|
||||
</ul>
|
||||
<a href="02-signup.html" class="btn-view-screen">查看註冊畫面</a>
|
||||
</div>
|
||||
|
||||
<!-- Onboarding Screen -->
|
||||
<div class="screen-card">
|
||||
<div class="screen-icon">🎯</div>
|
||||
<h3 class="screen-title">新手引導</h3>
|
||||
<div class="screen-status">
|
||||
<span>✅</span>
|
||||
<span>已完成</span>
|
||||
</div>
|
||||
<p class="screen-description">
|
||||
三步驟引導流程,收集用戶學習目標和英語程度,為後續學習路徑推薦提供數據基礎。
|
||||
</p>
|
||||
<ul class="screen-features">
|
||||
<li>UI_Onboarding_Steps - 三步驟引導</li>
|
||||
<li>UI_Learning_Goals_Selection - 學習目標選擇</li>
|
||||
<li>UI_English_Level_Assessment - 程度評估</li>
|
||||
<li>步驟指示器與進度追蹤</li>
|
||||
<li>數據收集與儲存</li>
|
||||
</ul>
|
||||
<a href="03-onboarding.html" class="btn-view-screen">查看引導畫面</a>
|
||||
</div>
|
||||
|
||||
<!-- Learning Path Selection -->
|
||||
<div class="screen-card">
|
||||
<div class="screen-icon">🛤️</div>
|
||||
<h3 class="screen-title">學習路徑選擇</h3>
|
||||
<div class="screen-status">
|
||||
<span>✅</span>
|
||||
<span>已完成</span>
|
||||
</div>
|
||||
<p class="screen-description">
|
||||
四種專業學習路徑選擇,包含日常對話、商務英語、旅遊英語、考試準備等不同學習方向。
|
||||
</p>
|
||||
<ul class="screen-features">
|
||||
<li>UI_Learning_Path_Card - 學習路徑卡片</li>
|
||||
<li>UI_Difficulty_Badge - 難度等級標識</li>
|
||||
<li>UI_Time_Estimate - 完成時間預估</li>
|
||||
<li>智能推薦系統</li>
|
||||
<li>路徑特色說明</li>
|
||||
</ul>
|
||||
<a href="04-learning-path-selection.html" class="btn-view-screen">查看路徑選擇</a>
|
||||
</div>
|
||||
|
||||
<!-- Four Stage Learning System -->
|
||||
<div class="screen-card">
|
||||
<div class="screen-icon">🎮</div>
|
||||
<h3 class="screen-title">四關學習系統</h3>
|
||||
<div class="screen-status">
|
||||
<span>✅</span>
|
||||
<span>已完成</span>
|
||||
</div>
|
||||
<p class="screen-description">
|
||||
Drama Ling 的核心學習界面,展示13個階段的線性闖關系統,每個劇本包含4個循序漸進的學習關卡。
|
||||
</p>
|
||||
<ul class="screen-features">
|
||||
<li>UI_Four_Stage_Learning_Main - 主學習界面</li>
|
||||
<li>UI_Life_Points_Display - 生命點數系統</li>
|
||||
<li>UI_Script_Card - 劇本卡片設計</li>
|
||||
<li>UI_Four_Stage_Progress - 四關進度顯示</li>
|
||||
<li>UI_Stars_Rating - 星級評價系統</li>
|
||||
</ul>
|
||||
<a href="05-four-stage-learning.html" class="btn-view-screen">查看學習系統</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Flow Navigation -->
|
||||
<div class="flow-navigation">
|
||||
<h3 class="flow-title">完整用戶流程體驗</h3>
|
||||
<p class="flow-description">
|
||||
體驗從註冊到開始學習的完整流程,所有畫面間的導航和數據傳遞都已實現
|
||||
</p>
|
||||
|
||||
<div class="flow-steps">
|
||||
<div class="flow-step">用戶登入</div>
|
||||
<div class="flow-arrow">→</div>
|
||||
<div class="flow-step">新手引導</div>
|
||||
<div class="flow-arrow">→</div>
|
||||
<div class="flow-step">路徑選擇</div>
|
||||
<div class="flow-arrow">→</div>
|
||||
<div class="flow-step">開始學習</div>
|
||||
</div>
|
||||
|
||||
<a href="01-login.html" class="btn-start-flow">開始完整流程體驗</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 統計功能
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('Drama Ling Phase 1 Prototypes Loaded');
|
||||
console.log('包含畫面數量:', document.querySelectorAll('.screen-card').length);
|
||||
console.log('設計基於:docs/02_design/prototype-design-plan.md');
|
||||
console.log('UI 系統:docs/02_design/ui-ux/dramaling-ui.css');
|
||||
console.log('元件參考:docs/02_design/function-specs/common/system_structure_design.json');
|
||||
});
|
||||
|
||||
// 卡片hover效果增強
|
||||
document.querySelectorAll('.screen-card').forEach(card => {
|
||||
card.addEventListener('mouseenter', function() {
|
||||
this.style.transform = 'translateY(-8px) scale(1.02)';
|
||||
});
|
||||
|
||||
card.addEventListener('mouseleave', function() {
|
||||
this.style.transform = 'translateY(-4px) scale(1)';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,935 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-TW">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Drama Ling - 道具商店</title>
|
||||
<link rel="stylesheet" href="../../../docs/02_design/ui-ux/dramaling-ui.css">
|
||||
<style>
|
||||
/* UI_Shop_Main - 道具商店主頁面 */
|
||||
.shop-container {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, var(--background-primary) 0%, var(--background-secondary) 100%);
|
||||
}
|
||||
|
||||
/* UI_Shop_Header - 商店頂部區域 */
|
||||
.shop-header {
|
||||
background: var(--card-background);
|
||||
padding: var(--space-6);
|
||||
border-bottom: 2px solid var(--divider);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.shop-title-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.shop-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, var(--gold) 0%, var(--warning-yellow) 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 30px;
|
||||
border: 3px solid var(--warning-yellow);
|
||||
}
|
||||
|
||||
.shop-title {
|
||||
font-size: var(--text-3xl);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
margin-bottom: var(--space-1);
|
||||
}
|
||||
|
||||
.shop-subtitle {
|
||||
font-size: var(--text-base);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* UI_Diamond_Balance_Display - 鑽石餘額顯示 */
|
||||
.balance-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-6);
|
||||
}
|
||||
|
||||
.balance-display {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
padding: var(--space-4) var(--space-6);
|
||||
background: var(--background-secondary);
|
||||
border-radius: var(--radius-lg);
|
||||
border: 2px solid var(--divider);
|
||||
}
|
||||
|
||||
.diamond-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
background: var(--diamond);
|
||||
clip-path: polygon(50% 0%, 0% 50%, 50% 100%, 100% 50%);
|
||||
animation: sparkle 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes sparkle {
|
||||
0%, 100% { transform: scale(1) rotate(0deg); }
|
||||
50% { transform: scale(1.1) rotate(45deg); }
|
||||
}
|
||||
|
||||
.balance-amount {
|
||||
font-size: var(--text-xl);
|
||||
font-weight: bold;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.btn-buy-diamonds {
|
||||
padding: var(--space-3) var(--space-6);
|
||||
background: var(--primary-teal);
|
||||
color: var(--background-dark);
|
||||
border: 3px solid var(--primary-teal-dark);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-base);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
box-shadow: 0 4px 0 var(--primary-teal-dark);
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-buy-diamonds:hover {
|
||||
background: var(--primary-teal-light);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 5px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.btn-buy-diamonds:active {
|
||||
transform: translateY(2px);
|
||||
box-shadow: 0 2px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
/* UI_Shop_Categories - 商店分類選項 */
|
||||
.shop-nav {
|
||||
background: var(--card-background);
|
||||
padding: 0 var(--space-6);
|
||||
border-bottom: 1px solid var(--divider);
|
||||
}
|
||||
|
||||
.category-tabs {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.category-tab {
|
||||
padding: var(--space-4) var(--space-6);
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
border-bottom: 3px solid transparent;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.category-tab:hover {
|
||||
color: var(--text-primary);
|
||||
background: var(--background-secondary);
|
||||
}
|
||||
|
||||
.category-tab.active {
|
||||
color: var(--primary-teal);
|
||||
border-bottom-color: var(--primary-teal);
|
||||
background: var(--background-secondary);
|
||||
}
|
||||
|
||||
.category-tab .badge {
|
||||
position: absolute;
|
||||
top: var(--space-2);
|
||||
right: var(--space-2);
|
||||
background: var(--error-red);
|
||||
color: var(--text-primary);
|
||||
font-size: var(--text-xs);
|
||||
padding: 2px 6px;
|
||||
border-radius: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Shop Content Area */
|
||||
.shop-content {
|
||||
padding: var(--space-8) var(--space-6);
|
||||
}
|
||||
|
||||
.category-section {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.category-section.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: var(--text-xl);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
margin-bottom: var(--space-2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.section-description {
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--space-8);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* UI_Item_Grid - 道具網格佈局 */
|
||||
.items-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: var(--space-6);
|
||||
margin-bottom: var(--space-8);
|
||||
}
|
||||
|
||||
/* UI_Shop_Item_Card - 道具卡片 */
|
||||
.item-card {
|
||||
background: var(--card-background);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
border: 2px solid var(--divider);
|
||||
transition: all var(--duration-normal);
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.item-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
background: var(--divider);
|
||||
transition: all var(--duration-normal);
|
||||
}
|
||||
|
||||
.item-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: var(--shadow-lg);
|
||||
border-color: var(--primary-teal);
|
||||
}
|
||||
|
||||
.item-card:hover::before {
|
||||
background: var(--primary-teal);
|
||||
}
|
||||
|
||||
.item-card.popular {
|
||||
border-color: var(--warning-yellow);
|
||||
background: linear-gradient(135deg, var(--card-background) 0%, rgba(243, 156, 18, 0.05) 100%);
|
||||
}
|
||||
|
||||
.item-card.popular::before {
|
||||
background: var(--warning-yellow);
|
||||
}
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.item-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 24px;
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
|
||||
.item-helper { background: var(--info-cyan); }
|
||||
.item-life { background: var(--error-red); }
|
||||
.item-time { background: var(--warning-yellow); }
|
||||
.item-premium { background: var(--secondary-purple); }
|
||||
|
||||
/* UI_Popular_Badge - 熱門標籤 */
|
||||
.popular-badge {
|
||||
background: var(--warning-yellow);
|
||||
color: var(--background-dark);
|
||||
padding: var(--space-1) var(--space-3);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
top: var(--space-3);
|
||||
right: var(--space-3);
|
||||
transform: rotate(15deg);
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.item-description {
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--text-sm);
|
||||
line-height: 1.5;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
/* UI_Item_Price_Display - 價格顯示 */
|
||||
.item-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.price-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.price-amount {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
font-weight: bold;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.price-diamond {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: var(--diamond);
|
||||
clip-path: polygon(50% 0%, 0% 50%, 50% 100%, 100% 50%);
|
||||
}
|
||||
|
||||
.original-price {
|
||||
text-decoration: line-through;
|
||||
color: var(--text-tertiary);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.discount-badge {
|
||||
background: var(--error-red);
|
||||
color: var(--text-primary);
|
||||
padding: 2px 6px;
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* UI_Buy_Button - 購買按鈕 */
|
||||
.btn-buy-item {
|
||||
padding: var(--space-3) var(--space-5);
|
||||
background: var(--primary-teal);
|
||||
color: var(--background-dark);
|
||||
border: 2px solid var(--primary-teal-dark);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
box-shadow: 0 3px 0 var(--primary-teal-dark);
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-buy-item:hover {
|
||||
background: var(--primary-teal-light);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.btn-buy-item:active {
|
||||
transform: translateY(1px);
|
||||
box-shadow: 0 2px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.btn-buy-item:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: 0 3px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
/* UI_Diamond_Purchase_Section - 鑽石購買專區 */
|
||||
.diamond-packages {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.diamond-package {
|
||||
background: var(--card-background);
|
||||
border: 2px solid var(--divider);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
text-align: center;
|
||||
transition: all var(--duration-normal);
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.diamond-package:hover {
|
||||
transform: scale(1.02);
|
||||
border-color: var(--diamond);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
.diamond-package.recommended {
|
||||
border-color: var(--warning-yellow);
|
||||
background: linear-gradient(135deg, var(--card-background) 0%, rgba(243, 156, 18, 0.1) 100%);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.diamond-package.recommended::before {
|
||||
content: '最超值';
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: var(--warning-yellow);
|
||||
color: var(--background-dark);
|
||||
padding: var(--space-1) var(--space-3);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.package-amount {
|
||||
font-size: var(--text-2xl);
|
||||
font-weight: bold;
|
||||
color: var(--diamond);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.package-price {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: bold;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.package-bonus {
|
||||
color: var(--success-green);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.shop-header {
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
padding: var(--space-4);
|
||||
}
|
||||
|
||||
.balance-section {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.shop-content {
|
||||
padding: var(--space-6) var(--space-4);
|
||||
}
|
||||
|
||||
.category-tabs {
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.category-tab {
|
||||
padding: var(--space-3) var(--space-4);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.items-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.diamond-packages {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: var(--space-3);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="shop-container">
|
||||
<!-- UI_Shop_Header - 商店頂部區域 -->
|
||||
<div class="shop-header">
|
||||
<div class="shop-title-section">
|
||||
<div class="shop-icon">🛒</div>
|
||||
<div>
|
||||
<h1 class="shop-title">道具商店</h1>
|
||||
<p class="shop-subtitle">提升學習效率,解鎖更多可能</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UI_Diamond_Balance_Display - 鑽石餘額顯示 -->
|
||||
<div class="balance-section">
|
||||
<div class="balance-display">
|
||||
<div class="diamond-icon"></div>
|
||||
<span class="balance-amount" id="diamondBalance">1,250</span>
|
||||
</div>
|
||||
<button class="btn-buy-diamonds" id="buyDiamondsBtn">購買鑽石</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UI_Shop_Categories - 商店分類選項 -->
|
||||
<div class="shop-nav">
|
||||
<div class="category-tabs">
|
||||
<button class="category-tab active" data-category="learning">
|
||||
學習輔助
|
||||
<span class="badge">HOT</span>
|
||||
</button>
|
||||
<button class="category-tab" data-category="life">
|
||||
生命補充
|
||||
</button>
|
||||
<button class="category-tab" data-category="challenge">
|
||||
挑戰道具
|
||||
</button>
|
||||
<button class="category-tab" data-category="premium">
|
||||
會員專區
|
||||
</button>
|
||||
<button class="category-tab" data-category="diamonds">
|
||||
鑽石購買
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="shop-content">
|
||||
<!-- 學習輔助道具 -->
|
||||
<div class="category-section active" id="learning">
|
||||
<h2 class="section-title">
|
||||
<span>📚</span>
|
||||
學習輔助道具
|
||||
</h2>
|
||||
<p class="section-description">
|
||||
提升學習效果,讓英語學習更輕鬆有趣。這些道具能在四關闖關過程中提供即時幫助。
|
||||
</p>
|
||||
|
||||
<div class="items-grid">
|
||||
<!-- 回覆提示道具 -->
|
||||
<div class="item-card popular">
|
||||
<div class="popular-badge">熱門</div>
|
||||
<div class="item-icon item-helper">💡</div>
|
||||
<h3 class="item-title">智能回覆提示</h3>
|
||||
<p class="item-description">
|
||||
在情境對話中獲得AI智能回覆建議,幫助您選擇最恰當的回應。每次使用提供3個優質回覆選項。
|
||||
</p>
|
||||
<div class="item-footer">
|
||||
<div class="price-section">
|
||||
<div class="price-amount">
|
||||
<div class="price-diamond"></div>
|
||||
<span>50</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-buy-item">購買</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 翻譯輔助 -->
|
||||
<div class="item-card">
|
||||
<div class="item-icon item-helper">🌐</div>
|
||||
<h3 class="item-title">即時翻譯輔助</h3>
|
||||
<p class="item-description">
|
||||
遇到不熟悉的詞彙或句子時,一鍵查看中文翻譯和詳細解釋。包含文化背景說明。
|
||||
</p>
|
||||
<div class="item-footer">
|
||||
<div class="price-section">
|
||||
<div class="price-amount">
|
||||
<div class="price-diamond"></div>
|
||||
<span>30</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-buy-item">購買</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 語法檢查 -->
|
||||
<div class="item-card">
|
||||
<div class="item-icon item-helper">✏️</div>
|
||||
<h3 class="item-title">語法檢查器</h3>
|
||||
<p class="item-description">
|
||||
AI語法檢查工具,即時分析您的句子結構,提供語法改善建議和正確用法示例。
|
||||
</p>
|
||||
<div class="item-footer">
|
||||
<div class="price-section">
|
||||
<div class="price-amount">
|
||||
<div class="price-diamond"></div>
|
||||
<span>40</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-buy-item">購買</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 發音練習加強 -->
|
||||
<div class="item-card">
|
||||
<div class="item-icon item-helper">🎤</div>
|
||||
<h3 class="item-title">發音練習加強</h3>
|
||||
<p class="item-description">
|
||||
額外的發音練習機會,包含音標指導和發音技巧提示。AI評分系統提供詳細改善建議。
|
||||
</p>
|
||||
<div class="item-footer">
|
||||
<div class="price-section">
|
||||
<div class="price-amount">
|
||||
<div class="price-diamond"></div>
|
||||
<span>60</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-buy-item">購買</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 生命補充道具 -->
|
||||
<div class="category-section" id="life">
|
||||
<h2 class="section-title">
|
||||
<span>❤️</span>
|
||||
生命補充道具
|
||||
</h2>
|
||||
<p class="section-description">
|
||||
快速恢復生命點數,持續您的學習進度。不同套餐適合不同學習強度的需求。
|
||||
</p>
|
||||
|
||||
<div class="items-grid">
|
||||
<!-- 單次補命 -->
|
||||
<div class="item-card">
|
||||
<div class="item-icon item-life">💖</div>
|
||||
<h3 class="item-title">立即補命</h3>
|
||||
<p class="item-description">
|
||||
立即恢復1個生命點數,繼續您的學習之旅。適合偶爾使用的學習者。
|
||||
</p>
|
||||
<div class="item-footer">
|
||||
<div class="price-section">
|
||||
<div class="price-amount">
|
||||
<div class="price-diamond"></div>
|
||||
<span>20</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-buy-item">購買</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 完全恢復 -->
|
||||
<div class="item-card popular">
|
||||
<div class="popular-badge">推薦</div>
|
||||
<div class="item-icon item-life">💕</div>
|
||||
<h3 class="item-title">完全恢復</h3>
|
||||
<p class="item-description">
|
||||
將生命點數恢復至滿格狀態,適合密集學習時使用。比單次購買更划算。
|
||||
</p>
|
||||
<div class="item-footer">
|
||||
<div class="price-section">
|
||||
<div class="price-amount">
|
||||
<div class="price-diamond"></div>
|
||||
<span>80</span>
|
||||
</div>
|
||||
<span class="original-price">100💎</span>
|
||||
<span class="discount-badge">-20%</span>
|
||||
</div>
|
||||
<button class="btn-buy-item">購買</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 生命守護 -->
|
||||
<div class="item-card">
|
||||
<div class="item-icon item-life">🛡️</div>
|
||||
<h3 class="item-title">生命守護</h3>
|
||||
<p class="item-description">
|
||||
24小時內失敗不消耗生命點數,安心挑戰困難關卡。適合想要突破瓶頸的學習者。
|
||||
</p>
|
||||
<div class="item-footer">
|
||||
<div class="price-section">
|
||||
<div class="price-amount">
|
||||
<div class="price-diamond"></div>
|
||||
<span>150</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-buy-item">購買</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 挑戰道具 -->
|
||||
<div class="category-section" id="challenge">
|
||||
<h2 class="section-title">
|
||||
<span>⚡</span>
|
||||
挑戰道具
|
||||
</h2>
|
||||
<p class="section-description">
|
||||
在限時挑戰和競技模式中獲得優勢,提升排行榜名次和獎勵獲得。
|
||||
</p>
|
||||
|
||||
<div class="items-grid">
|
||||
<!-- 時間暫停 -->
|
||||
<div class="item-card">
|
||||
<div class="item-icon item-time">⏸️</div>
|
||||
<h3 class="item-title">時間暫停</h3>
|
||||
<p class="item-description">
|
||||
在300秒限時挑戰中暫停計時5秒,爭取更多思考時間。每次挑戰可使用1次。
|
||||
</p>
|
||||
<div class="item-footer">
|
||||
<div class="price-section">
|
||||
<div class="price-amount">
|
||||
<div class="price-diamond"></div>
|
||||
<span>35</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-buy-item">購買</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 額外時間 -->
|
||||
<div class="item-card">
|
||||
<div class="item-icon item-time">⏰</div>
|
||||
<h3 class="item-title">時間加成</h3>
|
||||
<p class="item-description">
|
||||
為限時挑戰增加30秒額外時間,完成更多題目獲得更高分數。
|
||||
</p>
|
||||
<div class="item-footer">
|
||||
<div class="price-section">
|
||||
<div class="price-amount">
|
||||
<div class="price-diamond"></div>
|
||||
<span>45</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-buy-item">購買</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 雙倍經驗 -->
|
||||
<div class="item-card popular">
|
||||
<div class="popular-badge">熱門</div>
|
||||
<div class="item-icon item-time">✨</div>
|
||||
<h3 class="item-title">經驗雙倍</h3>
|
||||
<p class="item-description">
|
||||
接下來的3次學習獲得雙倍經驗值,快速提升等級和解鎖新內容。
|
||||
</p>
|
||||
<div class="item-footer">
|
||||
<div class="price-section">
|
||||
<div class="price-amount">
|
||||
<div class="price-diamond"></div>
|
||||
<span>70</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-buy-item">購買</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 會員專區 -->
|
||||
<div class="category-section" id="premium">
|
||||
<h2 class="section-title">
|
||||
<span>👑</span>
|
||||
會員專區
|
||||
</h2>
|
||||
<p class="section-description">
|
||||
專為付費會員準備的超值道具包,享受更優惠的價格和獨家內容。
|
||||
</p>
|
||||
|
||||
<div class="items-grid">
|
||||
<!-- 會員專享包 -->
|
||||
<div class="item-card">
|
||||
<div class="item-icon item-premium">🎁</div>
|
||||
<h3 class="item-title">會員專享包</h3>
|
||||
<p class="item-description">
|
||||
包含5次智能回覆提示、3次完全恢復、2次時間暫停。只有會員才能享受的超值組合。
|
||||
</p>
|
||||
<div class="item-footer">
|
||||
<div class="price-section">
|
||||
<div class="price-amount">
|
||||
<div class="price-diamond"></div>
|
||||
<span>200</span>
|
||||
</div>
|
||||
<span class="original-price">350💎</span>
|
||||
<span class="discount-badge">-43%</span>
|
||||
</div>
|
||||
<button class="btn-buy-item">購買</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- VIP學習加速器 -->
|
||||
<div class="item-card">
|
||||
<div class="item-icon item-premium">🚀</div>
|
||||
<h3 class="item-title">VIP學習加速器</h3>
|
||||
<p class="item-description">
|
||||
7天內所有學習獲得3倍經驗值,生命恢復速度加倍,專屬徽章顯示。
|
||||
</p>
|
||||
<div class="item-footer">
|
||||
<div class="price-section">
|
||||
<div class="price-amount">
|
||||
<div class="price-diamond"></div>
|
||||
<span>500</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-buy-item">購買</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UI_Diamond_Purchase_Section - 鑽石購買專區 -->
|
||||
<div class="category-section" id="diamonds">
|
||||
<h2 class="section-title">
|
||||
<span>💎</span>
|
||||
鑽石購買專區
|
||||
</h2>
|
||||
<p class="section-description">
|
||||
選擇最適合您的鑽石套餐,享受更豐富的學習體驗。首次購買享有新手優惠。
|
||||
</p>
|
||||
|
||||
<div class="diamond-packages">
|
||||
<!-- 新手包 -->
|
||||
<div class="diamond-package">
|
||||
<div class="package-amount">💎 500</div>
|
||||
<div class="package-price">NT$ 30</div>
|
||||
<div class="package-bonus">首次購買專享</div>
|
||||
<button class="btn-buy-item">立即購買</button>
|
||||
</div>
|
||||
|
||||
<!-- 基礎包 -->
|
||||
<div class="diamond-package">
|
||||
<div class="package-amount">💎 1,200</div>
|
||||
<div class="package-price">NT$ 60</div>
|
||||
<div class="package-bonus">贈送200鑽石</div>
|
||||
<button class="btn-buy-item">立即購買</button>
|
||||
</div>
|
||||
|
||||
<!-- 價值包 - 推薦 -->
|
||||
<div class="diamond-package recommended">
|
||||
<div class="package-amount">💎 2,500</div>
|
||||
<div class="package-price">NT$ 99</div>
|
||||
<div class="package-bonus">贈送500鑽石</div>
|
||||
<button class="btn-buy-item">立即購買</button>
|
||||
</div>
|
||||
|
||||
<!-- 豪華包 -->
|
||||
<div class="diamond-package">
|
||||
<div class="package-amount">💎 5,000</div>
|
||||
<div class="package-price">NT$ 190</div>
|
||||
<div class="package-bonus">贈送1000鑽石</div>
|
||||
<button class="btn-buy-item">立即購買</button>
|
||||
</div>
|
||||
|
||||
<!-- 至尊包 -->
|
||||
<div class="diamond-package">
|
||||
<div class="package-amount">💎 12,000</div>
|
||||
<div class="package-price">NT$ 390</div>
|
||||
<div class="package-bonus">贈送3000鑽石</div>
|
||||
<button class="btn-buy-item">立即購買</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 分類切換功能
|
||||
document.querySelectorAll('.category-tab').forEach(tab => {
|
||||
tab.addEventListener('click', function() {
|
||||
// 移除所有active狀態
|
||||
document.querySelectorAll('.category-tab').forEach(t => t.classList.remove('active'));
|
||||
document.querySelectorAll('.category-section').forEach(s => s.classList.remove('active'));
|
||||
|
||||
// 設置當前active狀態
|
||||
this.classList.add('active');
|
||||
const category = this.dataset.category;
|
||||
document.getElementById(category).classList.add('active');
|
||||
});
|
||||
});
|
||||
|
||||
// 購買道具功能
|
||||
document.querySelectorAll('.btn-buy-item').forEach(button => {
|
||||
button.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
|
||||
const itemCard = this.closest('.item-card') || this.closest('.diamond-package');
|
||||
const itemName = itemCard.querySelector('.item-title')?.textContent ||
|
||||
itemCard.querySelector('.package-amount')?.textContent || '道具';
|
||||
const price = itemCard.querySelector('.price-amount span')?.textContent ||
|
||||
itemCard.querySelector('.package-price')?.textContent || '未知價格';
|
||||
|
||||
if (confirm(`確定要購買 ${itemName} 嗎?\n價格:${price.includes('NT$') ? price : price + '💎'}`)) {
|
||||
// 模擬購買過程
|
||||
this.textContent = '購買中...';
|
||||
this.disabled = true;
|
||||
|
||||
setTimeout(() => {
|
||||
// 更新鑽石餘額(如果是鑽石道具)
|
||||
if (!price.includes('NT$')) {
|
||||
const currentBalance = parseInt(document.getElementById('diamondBalance').textContent);
|
||||
const itemPrice = parseInt(price);
|
||||
|
||||
if (currentBalance >= itemPrice) {
|
||||
document.getElementById('diamondBalance').textContent = currentBalance - itemPrice;
|
||||
alert(`成功購買 ${itemName}!\n剩餘鑽石:${currentBalance - itemPrice}`);
|
||||
} else {
|
||||
alert('鑽石不足,請先購買鑽石!');
|
||||
// 自動切換到鑽石購買頁面
|
||||
document.querySelector('[data-category="diamonds"]').click();
|
||||
}
|
||||
} else {
|
||||
// 模擬金錢購買流程
|
||||
window.location.href = '../phase2/02-payment-flow.html';
|
||||
return;
|
||||
}
|
||||
|
||||
this.textContent = '購買';
|
||||
this.disabled = false;
|
||||
}, 1500);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 購買鑽石按鈕
|
||||
document.getElementById('buyDiamondsBtn').addEventListener('click', function() {
|
||||
document.querySelector('[data-category="diamonds"]').click();
|
||||
});
|
||||
|
||||
// 道具卡片hover效果
|
||||
document.querySelectorAll('.item-card, .diamond-package').forEach(card => {
|
||||
card.addEventListener('click', function() {
|
||||
// 顯示詳細信息(可擴展)
|
||||
const title = this.querySelector('.item-title')?.textContent ||
|
||||
this.querySelector('.package-amount')?.textContent;
|
||||
const description = this.querySelector('.item-description')?.textContent ||
|
||||
this.querySelector('.package-bonus')?.textContent;
|
||||
|
||||
console.log(`查看道具詳情:${title}`);
|
||||
// 這裡可以添加詳細信息彈窗
|
||||
});
|
||||
});
|
||||
|
||||
// 初始化用戶數據
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// 模擬從localStorage讀取用戶數據
|
||||
const userData = JSON.parse(localStorage.getItem('dramatLingUserData') || '{}');
|
||||
const defaultDiamonds = 1250;
|
||||
|
||||
document.getElementById('diamondBalance').textContent = userData.diamonds || defaultDiamonds;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,864 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-TW">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Drama Ling - 付費流程</title>
|
||||
<link rel="stylesheet" href="../../../docs/02_design/ui-ux/dramaling-ui.css">
|
||||
<style>
|
||||
/* UI_Payment_Flow - 付費流程主容器 */
|
||||
.payment-container {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, var(--background-primary) 0%, var(--background-secondary) 100%);
|
||||
padding: var(--space-6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.payment-wrapper {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
background: var(--card-background);
|
||||
border-radius: var(--radius-xl);
|
||||
padding: var(--space-8);
|
||||
border: 3px solid var(--divider);
|
||||
box-shadow: var(--shadow-xl);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.payment-wrapper::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
background: linear-gradient(90deg, var(--primary-teal) 0%, var(--secondary-purple) 100%);
|
||||
}
|
||||
|
||||
/* UI_Payment_Header - 付費標題區域 */
|
||||
.payment-header {
|
||||
text-align: center;
|
||||
margin-bottom: var(--space-8);
|
||||
}
|
||||
|
||||
.payment-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, var(--gold) 0%, var(--warning-yellow) 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 40px;
|
||||
margin: 0 auto var(--space-4);
|
||||
border: 3px solid var(--warning-yellow);
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { transform: scale(1); }
|
||||
50% { transform: scale(1.05); box-shadow: 0 0 20px rgba(243, 156, 18, 0.5); }
|
||||
}
|
||||
|
||||
.payment-title {
|
||||
font-size: var(--text-3xl);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.payment-subtitle {
|
||||
font-size: var(--text-base);
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* UI_Payment_Progress - 付費進度指示器 */
|
||||
.payment-progress {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: var(--space-8);
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.progress-step {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.step-circle {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
background: var(--background-secondary);
|
||||
border: 2px solid var(--divider);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: var(--text-sm);
|
||||
font-weight: bold;
|
||||
color: var(--text-tertiary);
|
||||
transition: all var(--duration-normal);
|
||||
}
|
||||
|
||||
.step-circle.active {
|
||||
background: var(--primary-teal);
|
||||
border-color: var(--primary-teal-dark);
|
||||
color: var(--background-dark);
|
||||
}
|
||||
|
||||
.step-circle.completed {
|
||||
background: var(--success-green);
|
||||
border-color: var(--success-green);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.step-connector {
|
||||
width: 40px;
|
||||
height: 2px;
|
||||
background: var(--divider);
|
||||
transition: all var(--duration-normal);
|
||||
}
|
||||
|
||||
.step-connector.active {
|
||||
background: var(--primary-teal);
|
||||
}
|
||||
|
||||
/* Payment Step Sections */
|
||||
.payment-step {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.payment-step.active {
|
||||
display: block;
|
||||
animation: fadeIn 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(20px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* UI_Package_Selection - 套餐選擇 */
|
||||
.package-selection {
|
||||
margin-bottom: var(--space-8);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: var(--text-xl);
|
||||
color: var(--text-primary);
|
||||
font-weight: bold;
|
||||
margin-bottom: var(--space-4);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.packages-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: var(--space-4);
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.package-option {
|
||||
background: var(--background-secondary);
|
||||
border: 2px solid var(--divider);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-4);
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.package-option:hover {
|
||||
transform: translateY(-2px);
|
||||
border-color: var(--primary-teal);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.package-option.selected {
|
||||
background: var(--primary-teal);
|
||||
border-color: var(--primary-teal-dark);
|
||||
color: var(--background-dark);
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 4px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.package-option.recommended {
|
||||
border-color: var(--warning-yellow);
|
||||
background: linear-gradient(135deg, var(--background-secondary) 0%, rgba(243, 156, 18, 0.1) 100%);
|
||||
}
|
||||
|
||||
.package-option.recommended::before {
|
||||
content: '最划算';
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: var(--warning-yellow);
|
||||
color: var(--background-dark);
|
||||
padding: 2px 8px;
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.package-diamonds {
|
||||
font-size: var(--text-xl);
|
||||
font-weight: bold;
|
||||
color: var(--diamond);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.package-option.selected .package-diamonds {
|
||||
color: var(--background-dark);
|
||||
}
|
||||
|
||||
.package-price {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: bold;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.package-option.selected .package-price {
|
||||
color: var(--background-dark);
|
||||
}
|
||||
|
||||
.package-bonus {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--success-green);
|
||||
}
|
||||
|
||||
.package-option.selected .package-bonus {
|
||||
color: var(--background-dark);
|
||||
}
|
||||
|
||||
/* UI_Payment_Methods - 支付方式選擇 */
|
||||
.payment-methods {
|
||||
margin-bottom: var(--space-8);
|
||||
}
|
||||
|
||||
.methods-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.payment-method {
|
||||
background: var(--background-secondary);
|
||||
border: 2px solid var(--divider);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-4);
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.payment-method:hover {
|
||||
border-color: var(--primary-teal);
|
||||
background: var(--background-primary);
|
||||
}
|
||||
|
||||
.payment-method.selected {
|
||||
background: var(--primary-teal);
|
||||
border-color: var(--primary-teal-dark);
|
||||
color: var(--background-dark);
|
||||
box-shadow: 0 4px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.method-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--text-primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.payment-method.selected .method-icon {
|
||||
background: var(--background-dark);
|
||||
color: var(--primary-teal);
|
||||
}
|
||||
|
||||
.method-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.method-name {
|
||||
font-size: var(--text-base);
|
||||
font-weight: bold;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--space-1);
|
||||
}
|
||||
|
||||
.payment-method.selected .method-name {
|
||||
color: var(--background-dark);
|
||||
}
|
||||
|
||||
.method-description {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.payment-method.selected .method-description {
|
||||
color: var(--background-dark);
|
||||
}
|
||||
|
||||
/* UI_Purchase_Confirmation - 購買確認 */
|
||||
.purchase-summary {
|
||||
background: var(--background-secondary);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
border: 2px solid var(--divider);
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.summary-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
|
||||
.summary-row:last-child {
|
||||
margin-bottom: 0;
|
||||
padding-top: var(--space-3);
|
||||
border-top: 1px solid var(--divider);
|
||||
font-weight: bold;
|
||||
font-size: var(--text-lg);
|
||||
}
|
||||
|
||||
.summary-label {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.summary-value {
|
||||
color: var(--text-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.total-label {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.total-value {
|
||||
color: var(--primary-teal);
|
||||
}
|
||||
|
||||
/* UI_Loading_Animation - 載入動畫 */
|
||||
.payment-loading {
|
||||
text-align: center;
|
||||
padding: var(--space-8) 0;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 4px solid var(--divider);
|
||||
border-top: 4px solid var(--primary-teal);
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto var(--space-4);
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: var(--text-lg);
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.loading-details {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
/* UI_Success_Confirmation - 成功確認 */
|
||||
.payment-success {
|
||||
text-align: center;
|
||||
padding: var(--space-8) 0;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: 50%;
|
||||
background: var(--success-green);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 60px;
|
||||
margin: 0 auto var(--space-6);
|
||||
animation: successPulse 0.6s ease-out;
|
||||
}
|
||||
|
||||
@keyframes successPulse {
|
||||
0% { transform: scale(0) rotate(0deg); }
|
||||
50% { transform: scale(1.2) rotate(180deg); }
|
||||
100% { transform: scale(1) rotate(360deg); }
|
||||
}
|
||||
|
||||
.success-title {
|
||||
font-size: var(--text-2xl);
|
||||
color: var(--success-green);
|
||||
font-weight: bold;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.success-message {
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.6;
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.success-details {
|
||||
background: var(--background-secondary);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-4);
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
/* Navigation Buttons */
|
||||
.payment-navigation {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
padding: var(--space-4) var(--space-6);
|
||||
background: var(--background-secondary);
|
||||
color: var(--text-primary);
|
||||
border: 2px solid var(--divider);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: var(--background-primary);
|
||||
border-color: var(--primary-teal);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
padding: var(--space-4) var(--space-8);
|
||||
background: var(--primary-teal);
|
||||
color: var(--background-dark);
|
||||
border: 3px solid var(--primary-teal-dark);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-base);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-normal);
|
||||
box-shadow: 0 4px 0 var(--primary-teal-dark);
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--primary-teal-light);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 5px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.btn-primary:active {
|
||||
transform: translateY(2px);
|
||||
box-shadow: 0 2px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
.btn-primary:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: 0 4px 0 var(--primary-teal-dark);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.payment-container {
|
||||
padding: var(--space-4);
|
||||
}
|
||||
|
||||
.payment-wrapper {
|
||||
padding: var(--space-6);
|
||||
}
|
||||
|
||||
.payment-progress {
|
||||
flex-direction: column;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
.step-connector {
|
||||
width: 2px;
|
||||
height: 20px;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.packages-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.methods-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.payment-navigation {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="payment-container">
|
||||
<div class="payment-wrapper">
|
||||
<!-- UI_Payment_Header - 付費標題區域 -->
|
||||
<div class="payment-header">
|
||||
<div class="payment-icon">💰</div>
|
||||
<h1 class="payment-title">購買鑽石</h1>
|
||||
<p class="payment-subtitle">選擇最適合您的套餐,立即開始豐富的學習體驗</p>
|
||||
</div>
|
||||
|
||||
<!-- UI_Payment_Progress - 付費進度指示器 -->
|
||||
<div class="payment-progress">
|
||||
<div class="progress-step">
|
||||
<div class="step-circle active" id="step1">1</div>
|
||||
<div class="step-connector active"></div>
|
||||
</div>
|
||||
<div class="progress-step">
|
||||
<div class="step-circle" id="step2">2</div>
|
||||
<div class="step-connector"></div>
|
||||
</div>
|
||||
<div class="progress-step">
|
||||
<div class="step-circle" id="step3">3</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 1: Package Selection -->
|
||||
<div class="payment-step active" id="packageStep">
|
||||
<!-- UI_Package_Selection - 套餐選擇 -->
|
||||
<div class="package-selection">
|
||||
<h2 class="section-title">
|
||||
<span>💎</span>
|
||||
選擇鑽石套餐
|
||||
</h2>
|
||||
|
||||
<div class="packages-grid">
|
||||
<div class="package-option" data-package="starter">
|
||||
<div class="package-diamonds">💎 500</div>
|
||||
<div class="package-price">NT$ 30</div>
|
||||
<div class="package-bonus">新手專享</div>
|
||||
</div>
|
||||
|
||||
<div class="package-option" data-package="basic">
|
||||
<div class="package-diamonds">💎 1,200</div>
|
||||
<div class="package-price">NT$ 60</div>
|
||||
<div class="package-bonus">+200贈送</div>
|
||||
</div>
|
||||
|
||||
<div class="package-option recommended" data-package="value">
|
||||
<div class="package-diamonds">💎 2,500</div>
|
||||
<div class="package-price">NT$ 99</div>
|
||||
<div class="package-bonus">+500贈送</div>
|
||||
</div>
|
||||
|
||||
<div class="package-option" data-package="premium">
|
||||
<div class="package-diamonds">💎 5,000</div>
|
||||
<div class="package-price">NT$ 190</div>
|
||||
<div class="package-bonus">+1000贈送</div>
|
||||
</div>
|
||||
|
||||
<div class="package-option" data-package="ultimate">
|
||||
<div class="package-diamonds">💎 12,000</div>
|
||||
<div class="package-price">NT$ 390</div>
|
||||
<div class="package-bonus">+3000贈送</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="payment-navigation">
|
||||
<button class="btn-secondary" onclick="goBack()">返回商店</button>
|
||||
<button class="btn-primary" id="nextToPayment" disabled>下一步</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: Payment Method Selection -->
|
||||
<div class="payment-step" id="paymentStep">
|
||||
<!-- UI_Payment_Methods - 支付方式選擇 -->
|
||||
<div class="payment-methods">
|
||||
<h2 class="section-title">
|
||||
<span>💳</span>
|
||||
選擇支付方式
|
||||
</h2>
|
||||
|
||||
<div class="methods-grid">
|
||||
<div class="payment-method" data-method="applepay">
|
||||
<div class="method-icon">🍎</div>
|
||||
<div class="method-info">
|
||||
<div class="method-name">Apple Pay</div>
|
||||
<div class="method-description">安全快速的一鍵支付</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="payment-method" data-method="googlepay">
|
||||
<div class="method-icon">📱</div>
|
||||
<div class="method-info">
|
||||
<div class="method-name">Google Pay</div>
|
||||
<div class="method-description">Google 官方支付服務</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="payment-method" data-method="creditcard">
|
||||
<div class="method-icon">💳</div>
|
||||
<div class="method-info">
|
||||
<div class="method-name">信用卡</div>
|
||||
<div class="method-description">Visa / MasterCard</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="payment-method" data-method="paypal">
|
||||
<div class="method-icon">🔵</div>
|
||||
<div class="method-info">
|
||||
<div class="method-name">PayPal</div>
|
||||
<div class="method-description">國際通用支付平台</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UI_Purchase_Confirmation - 購買確認 -->
|
||||
<div class="purchase-summary">
|
||||
<div class="summary-row">
|
||||
<span class="summary-label">套餐內容:</span>
|
||||
<span class="summary-value" id="summaryPackage">請選擇套餐</span>
|
||||
</div>
|
||||
<div class="summary-row">
|
||||
<span class="summary-label">基礎鑽石:</span>
|
||||
<span class="summary-value" id="summaryDiamonds">0</span>
|
||||
</div>
|
||||
<div class="summary-row">
|
||||
<span class="summary-label">贈送鑽石:</span>
|
||||
<span class="summary-value" id="summaryBonus">0</span>
|
||||
</div>
|
||||
<div class="summary-row">
|
||||
<span class="total-label">總計:</span>
|
||||
<span class="total-value" id="summaryTotal">NT$ 0</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="payment-navigation">
|
||||
<button class="btn-secondary" id="backToPackage">上一步</button>
|
||||
<button class="btn-primary" id="confirmPayment" disabled>確認付款</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3: Processing -->
|
||||
<div class="payment-step" id="processingStep">
|
||||
<!-- UI_Loading_Animation - 載入動畫 -->
|
||||
<div class="payment-loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<div class="loading-text">正在處理您的付款...</div>
|
||||
<div class="loading-details">請勿關閉此頁面,我們正在與支付服務商確認您的交易</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Success Step -->
|
||||
<div class="payment-step" id="successStep">
|
||||
<!-- UI_Success_Confirmation - 成功確認 -->
|
||||
<div class="payment-success">
|
||||
<div class="success-icon">✅</div>
|
||||
<h2 class="success-title">付款成功!</h2>
|
||||
<p class="success-message">
|
||||
恭喜您!鑽石已經成功充值到您的帳戶中。現在您可以盡情享受 Drama Ling 的完整學習體驗了!
|
||||
</p>
|
||||
|
||||
<div class="success-details">
|
||||
<div class="summary-row">
|
||||
<span class="summary-label">購買項目:</span>
|
||||
<span class="summary-value" id="successPackage">-</span>
|
||||
</div>
|
||||
<div class="summary-row">
|
||||
<span class="summary-label">獲得鑽石:</span>
|
||||
<span class="summary-value" id="successDiamonds">-</span>
|
||||
</div>
|
||||
<div class="summary-row">
|
||||
<span class="summary-label">交易時間:</span>
|
||||
<span class="summary-value" id="successTime">-</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="payment-navigation">
|
||||
<button class="btn-secondary" onclick="goToShop()">返回商店</button>
|
||||
<button class="btn-primary" onclick="goToLearning()">開始學習</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let currentStep = 1;
|
||||
let selectedPackage = null;
|
||||
let selectedPaymentMethod = null;
|
||||
|
||||
const packageData = {
|
||||
starter: { diamonds: 500, price: 30, bonus: 0, name: '新手包' },
|
||||
basic: { diamonds: 1000, price: 60, bonus: 200, name: '基礎包' },
|
||||
value: { diamonds: 2000, price: 99, bonus: 500, name: '價值包' },
|
||||
premium: { diamonds: 4000, price: 190, bonus: 1000, name: '豪華包' },
|
||||
ultimate: { diamonds: 9000, price: 390, bonus: 3000, name: '至尊包' }
|
||||
};
|
||||
|
||||
// 套餐選擇處理
|
||||
document.querySelectorAll('.package-option').forEach(option => {
|
||||
option.addEventListener('click', function() {
|
||||
document.querySelectorAll('.package-option').forEach(opt => opt.classList.remove('selected'));
|
||||
this.classList.add('selected');
|
||||
selectedPackage = this.dataset.package;
|
||||
|
||||
document.getElementById('nextToPayment').disabled = false;
|
||||
updateSummary();
|
||||
});
|
||||
});
|
||||
|
||||
// 支付方式選擇處理
|
||||
document.querySelectorAll('.payment-method').forEach(method => {
|
||||
method.addEventListener('click', function() {
|
||||
document.querySelectorAll('.payment-method').forEach(met => met.classList.remove('selected'));
|
||||
this.classList.add('selected');
|
||||
selectedPaymentMethod = this.dataset.method;
|
||||
|
||||
document.getElementById('confirmPayment').disabled = false;
|
||||
});
|
||||
});
|
||||
|
||||
// 更新購買摘要
|
||||
function updateSummary() {
|
||||
if (!selectedPackage) return;
|
||||
|
||||
const package = packageData[selectedPackage];
|
||||
document.getElementById('summaryPackage').textContent = package.name;
|
||||
document.getElementById('summaryDiamonds').textContent = `💎 ${package.diamonds}`;
|
||||
document.getElementById('summaryBonus').textContent = package.bonus > 0 ? `💎 ${package.bonus}` : '無';
|
||||
document.getElementById('summaryTotal').textContent = `NT$ ${package.price}`;
|
||||
}
|
||||
|
||||
// 步驟導航
|
||||
function goToStep(step) {
|
||||
// 隱藏所有步驟
|
||||
document.querySelectorAll('.payment-step').forEach(s => s.classList.remove('active'));
|
||||
|
||||
// 更新進度指示器
|
||||
document.querySelectorAll('.step-circle').forEach((circle, index) => {
|
||||
circle.classList.remove('active', 'completed');
|
||||
if (index + 1 < step) {
|
||||
circle.classList.add('completed');
|
||||
circle.textContent = '✓';
|
||||
} else if (index + 1 === step) {
|
||||
circle.classList.add('active');
|
||||
circle.textContent = index + 1;
|
||||
} else {
|
||||
circle.textContent = index + 1;
|
||||
}
|
||||
});
|
||||
|
||||
// 更新連接器
|
||||
document.querySelectorAll('.step-connector').forEach((connector, index) => {
|
||||
connector.classList.remove('active');
|
||||
if (index + 1 < step) {
|
||||
connector.classList.add('active');
|
||||
}
|
||||
});
|
||||
|
||||
// 顯示目標步驟
|
||||
const steps = ['packageStep', 'paymentStep', 'processingStep', 'successStep'];
|
||||
document.getElementById(steps[step - 1]).classList.add('active');
|
||||
|
||||
currentStep = step;
|
||||
}
|
||||
|
||||
// 按鈕事件處理
|
||||
document.getElementById('nextToPayment').addEventListener('click', function() {
|
||||
if (selectedPackage) {
|
||||
goToStep(2);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('backToPackage').addEventListener('click', function() {
|
||||
goToStep(1);
|
||||
});
|
||||
|
||||
document.getElementById('confirmPayment').addEventListener('click', function() {
|
||||
if (selectedPackage && selectedPaymentMethod) {
|
||||
goToStep(3);
|
||||
|
||||
// 模擬支付處理
|
||||
setTimeout(() => {
|
||||
processPaymentSuccess();
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
|
||||
// 處理支付成功
|
||||
function processPaymentSuccess() {
|
||||
const package = packageData[selectedPackage];
|
||||
const totalDiamonds = package.diamonds + package.bonus;
|
||||
|
||||
// 更新成功頁面信息
|
||||
document.getElementById('successPackage').textContent = package.name;
|
||||
document.getElementById('successDiamonds').textContent = `💎 ${totalDiamonds}`;
|
||||
document.getElementById('successTime').textContent = new Date().toLocaleString('zh-TW');
|
||||
|
||||
// 更新本地存儲的鑽石數量
|
||||
const userData = JSON.parse(localStorage.getItem('dramatLingUserData') || '{}');
|
||||
const currentDiamonds = userData.diamonds || 1250;
|
||||
userData.diamonds = currentDiamonds + totalDiamonds;
|
||||
localStorage.setItem('dramatLingUserData', JSON.stringify(userData));
|
||||
|
||||
goToStep(4);
|
||||
}
|
||||
|
||||
// 導航函數
|
||||
function goBack() {
|
||||
window.location.href = '01-item-shop.html';
|
||||
}
|
||||
|
||||
function goToShop() {
|
||||
window.location.href = '01-item-shop.html';
|
||||
}
|
||||
|
||||
function goToLearning() {
|
||||
window.location.href = '../phase1/05-four-stage-learning.html';
|
||||
}
|
||||
|
||||
// 初始化
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// 檢查URL參數是否有預選套餐
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const preselectedPackage = urlParams.get('package');
|
||||
|
||||
if (preselectedPackage && packageData[preselectedPackage]) {
|
||||
const packageElement = document.querySelector(`[data-package="${preselectedPackage}"]`);
|
||||
if (packageElement) {
|
||||
packageElement.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
# Common Function Specs 文件分析報告
|
||||
|
||||
## 📋 執行摘要
|
||||
|
||||
**分析日期**: 2025-09-12
|
||||
**分析範圍**: `/docs/02_design/function-specs/common/` 資料夾
|
||||
**文件總數**: 10個文件
|
||||
**總體評估**: 🟡 **中等品質** - 有明確架構但存在重疊和缺失
|
||||
|
||||
---
|
||||
|
||||
## 📁 現有文件清單與用途分析
|
||||
|
||||
### 🎯 **核心系統規格** (4個文件)
|
||||
|
||||
| 文件名 | 用途 | 品質評估 | 大小 |
|
||||
|--------|------|----------|------|
|
||||
| **progressive-stage-system.md** | 線性闖關學習系統的完整架構定義 | ✅ 優秀 | 9.9KB |
|
||||
| **business-rules.md** | 跨平台業務邏輯和規則(命條、付費、鑽石系統) | ✅ 優秀 | 29.7KB |
|
||||
| **data-models.md** | 所有核心數據實體結構和關係 | ✅ 優秀 | 37.4KB |
|
||||
| **api-specifications.md** | 完整API接口文檔和端點定義 | ✅ 優秀 | 22.8KB |
|
||||
|
||||
### 🤖 **AI系統規格** (3個文件)
|
||||
|
||||
| 文件名 | 用途 | 品質評估 | 大小 |
|
||||
|--------|------|----------|------|
|
||||
| **ai-algorithm-specs.md** | AI對話分析算法整合規格 | 🟡 中等 | 18.6KB |
|
||||
| **speaking-evaluation-specs.md** | 五維度口說評分系統詳細規格 | ✅ 優秀 | 3.0KB |
|
||||
| **pragmatic-analysis-specs.md** | 六維語用分析標準和建議系統 | ✅ 優秀 | 8.8KB |
|
||||
|
||||
### 📚 **內容管理** (1個文件)
|
||||
|
||||
| 文件名 | 用途 | 品質評估 | 大小 |
|
||||
|--------|------|----------|------|
|
||||
| **content-management-specs.md** | 學習內容管理和劇本架構 | 🟡 中等 | 14.0KB |
|
||||
|
||||
### 🔧 **系統架構** (1個文件)
|
||||
|
||||
| 文件名 | 用途 | 品質評估 | 大小 |
|
||||
|--------|------|----------|------|
|
||||
| **system_structure_design.json** | 結構化系統設計和模組定義 | ✅ 優秀 | 111KB |
|
||||
|
||||
---
|
||||
|
||||
## 🔍 **重複性分析**
|
||||
|
||||
### ✅ **無重複問題的文件組合**
|
||||
- **progressive-stage-system.md** ↔ **business-rules.md**: 前者定義學習架構,後者定義業務規則,職責清晰
|
||||
- **speaking-evaluation-specs.md** ↔ **pragmatic-analysis-specs.md**: 前者評分,後者建議,功能互補
|
||||
- **data-models.md** ↔ **api-specifications.md**: 前者定義數據結構,後者定義接口契約,標準分層
|
||||
|
||||
### 🟡 **輕微重疊但可接受**
|
||||
- **ai-algorithm-specs.md** 與其他AI文件: 作為整合規格引用其他模組,角色清晰
|
||||
- **content-management-specs.md** 與 **data-models.md**: 前者專注內容架構,後者涵蓋所有數據模型
|
||||
|
||||
### 🚨 **需要注意的潛在重複**
|
||||
- **system_structure_design.json** 包含所有系統模組定義,與其他文件可能存在信息重複,但作為系統總覽是必要的
|
||||
|
||||
---
|
||||
|
||||
## 📊 **行業標準對比分析**
|
||||
|
||||
### 🏆 **符合行業最佳實踐**
|
||||
|
||||
#### ✅ **架構分層清晰**
|
||||
```
|
||||
Business Rules → Data Models → API Specs
|
||||
↓ ↓ ↓
|
||||
業務邏輯 → 數據結構 → 接口定義
|
||||
```
|
||||
|
||||
#### ✅ **模組化設計**
|
||||
- 每個文件職責單一且明確
|
||||
- 支援跨文件引用和依賴管理
|
||||
- 遵循"關注點分離"原則
|
||||
|
||||
#### ✅ **完整性覆蓋**
|
||||
- **業務層**: business-rules.md
|
||||
- **應用層**: progressive-stage-system.md, ai-algorithm-specs.md
|
||||
- **數據層**: data-models.md
|
||||
- **接口層**: api-specifications.md
|
||||
- **內容層**: content-management-specs.md
|
||||
|
||||
### 🎯 **行業標準參考**
|
||||
|
||||
| 標準實踐 | Drama Ling 現狀 | 評估 |
|
||||
|----------|-----------------|------|
|
||||
| **業務規則文檔** | ✅ 完整的 business-rules.md | 符合 |
|
||||
| **數據模型規範** | ✅ 詳細的 data-models.md | 符合 |
|
||||
| **API契約文檔** | ✅ 完整的 api-specifications.md | 符合 |
|
||||
| **系統架構圖** | ✅ system_structure_design.json | 符合 |
|
||||
| **測試規格** | ❌ 缺失 | 需要 |
|
||||
| **安全規格** | ❌ 缺失 | 需要 |
|
||||
| **性能規格** | ❌ 缺失 | 需要 |
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ **缺失分析**
|
||||
|
||||
### 🚨 **高優先級缺失**
|
||||
|
||||
#### 1. **測試規格文檔** (`testing-specifications.md`)
|
||||
```yaml
|
||||
缺失內容:
|
||||
- 單元測試標準
|
||||
- 整合測試策略
|
||||
- E2E測試場景
|
||||
- 性能測試基準
|
||||
重要性: 🔴 高
|
||||
影響: 開發品質保證
|
||||
```
|
||||
|
||||
#### 2. **安全規格文檔** (`security-requirements.md`)
|
||||
```yaml
|
||||
缺失內容:
|
||||
- 數據加密標準
|
||||
- 用戶隱私保護
|
||||
- API安全規範
|
||||
- 漏洞防護策略
|
||||
重要性: 🔴 高
|
||||
影響: 系統安全風險
|
||||
```
|
||||
|
||||
#### 3. **錯誤處理規格** (`error-handling-specs.md`)
|
||||
```yaml
|
||||
缺失內容:
|
||||
- 統一錯誤碼定義
|
||||
- 錯誤回復策略
|
||||
- 用戶友好錯誤訊息
|
||||
- 日誌記錄標準
|
||||
重要性: 🟡 中
|
||||
影響: 用戶體驗和維護性
|
||||
```
|
||||
|
||||
### 🟡 **中優先級缺失**
|
||||
|
||||
#### 4. **性能規格文檔** (`performance-standards.md`)
|
||||
```yaml
|
||||
缺失內容:
|
||||
- 響應時間標準
|
||||
- 併發處理能力
|
||||
- 資源使用限制
|
||||
- 擴展性要求
|
||||
重要性: 🟡 中
|
||||
影響: 系統性能表現
|
||||
```
|
||||
|
||||
#### 5. **國際化規格** (`internationalization-specs.md`)
|
||||
```yaml
|
||||
缺失內容:
|
||||
- 多語言支援策略
|
||||
- 本地化內容管理
|
||||
- 時區和貨幣處理
|
||||
- 文化適應性設計
|
||||
重要性: 🟡 中
|
||||
影響: 全球化擴展
|
||||
```
|
||||
|
||||
### 🟢 **低優先級缺失**
|
||||
|
||||
#### 6. **監控與日誌規格** (`monitoring-logging-specs.md`)
|
||||
#### 7. **備份與恢復規格** (`backup-recovery-specs.md`)
|
||||
#### 8. **第三方整合規格** (`third-party-integration-specs.md`)
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ **結構優化建議**
|
||||
|
||||
### 📁 **建議的資料夾重組結構**
|
||||
|
||||
```
|
||||
docs/02_design/function-specs/common/
|
||||
├── 01_core-system/ # 核心系統規格
|
||||
│ ├── progressive-stage-system.md
|
||||
│ ├── business-rules.md
|
||||
│ ├── data-models.md
|
||||
│ └── system_structure_design.json
|
||||
├── 02_api-interfaces/ # 接口規格
|
||||
│ ├── api-specifications.md
|
||||
│ ├── error-handling-specs.md # 新增
|
||||
│ └── security-requirements.md # 新增
|
||||
├── 03_ai-systems/ # AI系統規格
|
||||
│ ├── ai-algorithm-specs.md
|
||||
│ ├── speaking-evaluation-specs.md
|
||||
│ └── pragmatic-analysis-specs.md
|
||||
├── 04_content-management/ # 內容管理
|
||||
│ └── content-management-specs.md
|
||||
├── 05_quality-assurance/ # 品質保證
|
||||
│ ├── testing-specifications.md # 新增
|
||||
│ ├── performance-standards.md # 新增
|
||||
│ └── monitoring-logging-specs.md # 新增
|
||||
└── 06_localization/ # 本地化
|
||||
└── internationalization-specs.md # 新增
|
||||
```
|
||||
|
||||
### 🔄 **遷移優先順序**
|
||||
|
||||
1. **Phase 1 (立即)**: 創建缺失的高優先級文檔
|
||||
2. **Phase 2 (短期)**: 重組資料夾結構,保持向後兼容
|
||||
3. **Phase 3 (長期)**: 添加中低優先級規格文檔
|
||||
|
||||
---
|
||||
|
||||
## 📈 **品質評估總結**
|
||||
|
||||
### 🎯 **強項**
|
||||
- ✅ **核心業務邏輯完整**: business-rules.md 和 progressive-stage-system.md 提供完整的系統規則
|
||||
- ✅ **數據架構清晰**: data-models.md 定義完整的數據關係
|
||||
- ✅ **API設計規範**: api-specifications.md 提供完整的接口契約
|
||||
- ✅ **AI系統專業**: 口說評分和語用分析規格詳細且專業
|
||||
|
||||
### ⚠️ **需要改善**
|
||||
- 🔶 **缺乏品質保證規格**: 測試、安全、性能規格缺失
|
||||
- 🔶 **錯誤處理不統一**: 缺乏統一的錯誤處理策略
|
||||
- 🔶 **監控機制不足**: 缺乏運營監控和日誌管理規格
|
||||
|
||||
### 📊 **總體分數**
|
||||
```
|
||||
內容完整性: ⭐⭐⭐⭐⚪ (4/5)
|
||||
結構組織性: ⭐⭐⭐⚪⚪ (3/5)
|
||||
專業標準性: ⭐⭐⭐⭐⚪ (4/5)
|
||||
維護便利性: ⭐⭐⭐⚪⚪ (3/5)
|
||||
|
||||
總體評分: 70/100 (🟡 中等品質)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **行動建議**
|
||||
|
||||
### 🔴 **立即行動 (本週)**
|
||||
1. **創建 `security-requirements.md`** - 定義基本安全標準
|
||||
2. **創建 `testing-specifications.md`** - 建立測試框架和標準
|
||||
3. **創建 `error-handling-specs.md`** - 統一錯誤處理策略
|
||||
|
||||
### 🟡 **短期計劃 (本月)**
|
||||
1. **重組資料夾結構** - 按照建議的6大分類重組
|
||||
2. **更新文檔間引用** - 確保所有交叉引用正確
|
||||
3. **建立文檔維護流程** - 定期更新和審查機制
|
||||
|
||||
### 🟢 **長期規劃 (三個月)**
|
||||
1. **完善品質保證體系** - 添加性能、監控等規格
|
||||
2. **國際化準備** - 創建本地化和國際化規格
|
||||
3. **建立文檔自動化** - 使用工具自動檢查文檔一致性
|
||||
|
||||
---
|
||||
|
||||
**報告結論**: Drama Ling 的 Common Function Specs 具有良好的核心基礎,業務邏輯和數據架構清晰完整。主要改善方向是補強品質保證相關規格,並優化文檔組織結構以提升維護效率。
|
||||
|
||||
---
|
||||
|
||||
**分析者**: Claude AI
|
||||
**審查建議**: 建議產品團隊基於此報告制定文檔改善計劃,優先處理安全和測試規格的缺失問題。
|
||||
|
|
@ -0,0 +1,483 @@
|
|||
# Drama Ling UI/UX 設計完整計劃
|
||||
|
||||
**制定日期**: 2025-09-12
|
||||
**計劃版本**: v1.0
|
||||
**基於架構**: function-specs v3.0 共用模組架構
|
||||
**設計規範**: ui-ux-guidelines.md v2.0
|
||||
|
||||
## 🎯 計劃概述
|
||||
|
||||
基於 `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs` 的完整規格文件,設計所有頁面的UI/UX原型。所有設計將嚴格遵循 `/Users/jettcheng1018/code/dramaling-app/docs/02_design/ui-ux/ui-ux-guidelines.md` 的設計規範,並在規範不足時先補充規範再進行設計。
|
||||
|
||||
## 📋 第一階段:UI/UX規範完善
|
||||
|
||||
### 1.1 現有規範分析與補充
|
||||
|
||||
**目標**: 確保UI/UX規範涵蓋所有功能設計需求
|
||||
|
||||
**參考文件**:
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/ui-ux/ui-ux-guidelines.md` (主要規範)
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/business-rules.md` (業務規則)
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/progressive-stage-system.md` (系統架構)
|
||||
|
||||
**需補充的設計規範**:
|
||||
|
||||
#### 1.1.1 組件規範補充 ✅ (待驗證)
|
||||
- [ ] **學習地圖組件**: 13階段×20劇本的地圖視覺化設計
|
||||
- 引用: `progressive-stage-system.md` - 線性闖關架構
|
||||
- 設計要素: 六角形關卡節點、連接線、狀態顏色、進度動畫
|
||||
- [ ] **命條系統組件**: 生命點數的視覺表現
|
||||
- 引用: `business-rules.md` - 命條系統規則
|
||||
- 設計要素: 心形圖標、數量顯示、恢復計時器、不足警告
|
||||
- [ ] **道具商店組件**: 鑽石和道具的購買界面
|
||||
- 引用: `business-rules.md` - 道具商店系統
|
||||
- 設計要素: 商品卡片、價格標籤、購買確認、餘額顯示
|
||||
|
||||
#### 1.1.2 互動設計規範補充
|
||||
- [ ] **語音輸入設計**: 語音優先的交互模式
|
||||
- 引用: `ai-algorithm-specs.md` - 語音處理規格
|
||||
- 設計要素: 語音波形、錄音狀態、即時轉換反饋
|
||||
- [ ] **AI輔助界面**: 智能提示和建議的展示方式
|
||||
- 引用: `ai-algorithm-specs.md` - AI算法規格
|
||||
- 設計要素: 對話氣泡、建議卡片、漸進式引導
|
||||
- [ ] **評分反饋系統**: 即時評分和建議的視覺化
|
||||
- 引用: `speaking-evaluation-specs.md` - 口說評分系統
|
||||
- 設計要素: 分數動畫、雷達圖、改進建議
|
||||
|
||||
#### 1.1.3 平台適配規範補充
|
||||
- [ ] **響應式設計規則**: Mobile和Web端的適配標準
|
||||
- 引用: `platform-feature-mapping.md` - 平台對應關係
|
||||
- 設計要素: 斷點設定、組件縮放、交互差異
|
||||
- [ ] **Web端專屬組件**: 桌面環境的特殊組件
|
||||
- 引用: `web/README.md` - Web端特色功能
|
||||
- 設計要素: 鍵盤快捷鍵、多視窗、批量操作
|
||||
|
||||
**輸出物**:
|
||||
- `ui-ux-guidelines.md` 的完整更新版本
|
||||
- 新增組件設計規範文檔
|
||||
- 設計系統組件庫更新
|
||||
|
||||
### 1.2 設計系統建立
|
||||
|
||||
**目標**: 建立可重用的設計系統和組件庫
|
||||
|
||||
**工作項目**:
|
||||
- [ ] **色彩系統**: 完整的色彩變數定義
|
||||
- [ ] **字體系統**: 響應式字體和行高規範
|
||||
- [ ] **間距系統**: 統一的空間和佈局規則
|
||||
- [ ] **組件庫**: 可重用的UI組件集合
|
||||
- [ ] **圖標系統**: 學習情境專用的圖標設計
|
||||
|
||||
**參考文件**:
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/ui-ux/dramaling-ui.css`
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/ui-ux/ui-showcase.html`
|
||||
|
||||
## 📱 第二階段:Mobile端頁面設計
|
||||
|
||||
### 2.1 核心學習功能頁面
|
||||
|
||||
#### 2.1.1 情境對話系統 (優先級: P0)
|
||||
|
||||
**規格參考**:
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/mobile/01_situational-dialogue-mobile.md`
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/ai-algorithm-specs.md`
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/speaking-evaluation-specs.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] `UI_Dialogue_Practice_Main` - 情境對話練習主界面
|
||||
- 語音輸入界面 (參考: ai-algorithm-specs.md 語音處理)
|
||||
- 即時AI反饋顯示 (參考: ai-algorithm-specs.md AI評估系統)
|
||||
- 劇情任務和詞彙任務雙重可視化
|
||||
- 300秒限時挑戰計時器
|
||||
- [ ] `UI_Dialogue_Character_Selection` - 角色選擇頁面
|
||||
- [ ] `UI_Dialogue_Scene_Setting` - 場景設定頁面
|
||||
- [ ] `UI_AI_Assistance_Panel` - AI輔助功能面板
|
||||
- 回覆提示道具使用界面
|
||||
- 語法即時檢測顯示
|
||||
- [ ] `UI_Dialogue_Results` - 對話練習結果頁面
|
||||
- 口說評分五維雷達圖 (參考: speaking-evaluation-specs.md)
|
||||
- 語用分析六維評估 (參考: pragmatic-analysis-specs.md)
|
||||
|
||||
#### 2.1.2 詞彙學習系統 (優先級: P0)
|
||||
|
||||
**規格參考**:
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/mobile/02_vocabulary-learning-mobile.md`
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/progressive-stage-system.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] `UI_Vocab_Learning_Enhanced` - 多媒體詞彙學習主界面
|
||||
- 詞彙展示 (音標、定義、例句)
|
||||
- 雙語音頻系統 (標準速度/慢速)
|
||||
- 智慧詞彙標註 (Source + Example)
|
||||
- 視覺輔助學習 (例句配圖)
|
||||
- [ ] `UI_Vocab_Choice_Practice` - 詞彙選擇練習頁面
|
||||
- [ ] `UI_Vocab_Fluency_Results` - 流暢度練習綜合結果
|
||||
- [ ] `UI_Vocab_Review_System` - 間隔複習系統界面
|
||||
|
||||
#### 2.1.3 學習地圖系統 (優先級: P0)
|
||||
|
||||
**規格參考**:
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/mobile/03_learning-map-mobile.md`
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/progressive-stage-system.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] `UI_Level_Map` - 學習地圖主畫面 (線性闖關版)
|
||||
- 13階段×20劇本的地圖視覺化
|
||||
- 四關進度指示器 (詞彙學習→詞彙熟悉→口說練習→情境對話)
|
||||
- 關卡狀態管理 (🔒鎖定/⏳可進行/🔄進行中/✅已完成)
|
||||
- [ ] `UI_Current_Level_Info` - 當前可進行關卡資訊面板
|
||||
- [ ] `UI_Level_Progress_Detail` - 關卡進度詳情頁面
|
||||
- [ ] `UI_Stage_Overview` - 階段總覽和劇本選擇
|
||||
- [ ] `UI_Level_Locked_Modal` - 關卡鎖定提示彈窗
|
||||
|
||||
### 2.2 商業功能頁面
|
||||
|
||||
#### 2.2.1 道具商店系統 (優先級: P1)
|
||||
|
||||
**規格參考**:
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/mobile/04_item-shop-mobile.md`
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/business-rules.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] `UI_Shop_Categories` - 道具商店分類主頁面
|
||||
- 鑽石購買區 (5個價格套餐)
|
||||
- 學習輔助道具區 (回覆提示、補命、加時)
|
||||
- 限時挑戰道具區 (時間暫停、時間加成)
|
||||
- [ ] `UI_Diamond_Purchase` - 鑽石購買頁面
|
||||
- [ ] `UI_Item_Details` - 單一道具詳情頁面
|
||||
- [ ] `UI_Shop_Item_Confirm` - 道具購買確認彈窗
|
||||
- [ ] `UI_Cost_Confirm_Popup` - 成本確認彈窗 (口說練習特別關卡)
|
||||
- [ ] `UI_Insufficient_Resources` - 資源不足提示頁面
|
||||
- [ ] `UI_Purchase_Success` - 購買成功頁面
|
||||
|
||||
#### 2.2.2 用戶認證系統 (優先級: P1)
|
||||
|
||||
**規格參考**:
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/mobile/05_user-authentication-mobile.md`
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/business-rules.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] `UI_Login_Main` - 登入主頁面
|
||||
- Email + 密碼登入
|
||||
- 第三方登入 (Google、Apple)
|
||||
- 記住登入功能
|
||||
- [ ] `UI_SignUp_Main` - 註冊主頁面
|
||||
- [ ] `UI_PasswordReset_Form` - 密碼重設頁面
|
||||
- [ ] `UI_Profile_Settings` - 用戶資料設定頁面
|
||||
- [ ] `UI_Subscription_Plans` - 訂閱方案頁面
|
||||
- 7天免費體驗
|
||||
- 月費/年費訂閱選項
|
||||
- [ ] `UI_Account_Security` - 帳戶安全設定頁面
|
||||
|
||||
### 2.3 支援功能頁面
|
||||
|
||||
#### 2.3.1 系統通知和反饋 (優先級: P2)
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] `UI_Achievement_Notification` - 成就通知彈窗
|
||||
- [ ] `UI_Level_Complete_Celebration` - 關卡完成慶祝頁面
|
||||
- [ ] `UI_Daily_Streak_Reward` - 每日連續學習獎勵
|
||||
- [ ] `UI_System_Maintenance` - 系統維護提示頁面
|
||||
- [ ] `UI_Network_Error` - 網路錯誤處理頁面
|
||||
|
||||
#### 2.3.2 學習分析和報告 (優先級: P2)
|
||||
|
||||
**規格參考**:
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/data-models.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] `UI_Learning_Analytics` - 學習分析報告頁面
|
||||
- [ ] `UI_Progress_Statistics` - 進度統計頁面
|
||||
- [ ] `UI_Vocabulary_Review_Schedule` - 詞彙複習排程
|
||||
- [ ] `UI_Speaking_Improvement_Report` - 口說能力改善報告
|
||||
|
||||
## 💻 第三階段:Web端頁面設計
|
||||
|
||||
### 3.1 核心功能Web端適配
|
||||
|
||||
#### 3.1.1 詞彙學習系統 (Web版)
|
||||
|
||||
**規格參考**:
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/web/vocabulary-learning-web.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] `Page_Vocab_Learning_W` - Web版詞彙學習主頁面
|
||||
- 大螢幕多詞彙並列展示
|
||||
- 鍵盤快捷鍵支援
|
||||
- 批量學習進度管理
|
||||
- [ ] `Page_Vocab_Batch_Practice_W` - 批量詞彙練習頁面
|
||||
- [ ] `Page_Vocab_Analytics_W` - 詞彙學習分析頁面
|
||||
|
||||
#### 3.1.2 情境對話系統 (Web版)
|
||||
|
||||
**規格參考**:
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/web/situational-dialogue-web.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] `Page_Dialogue_Practice_W` - Web版情境對話練習頁面
|
||||
- 桌面端語音輸入優化
|
||||
- 多螢幕支援
|
||||
- 詳細的即時分析面板
|
||||
- [ ] `Page_Dialogue_History_W` - 對話練習歷史記錄
|
||||
- [ ] `Page_Advanced_Analytics_W` - 進階對話分析頁面
|
||||
|
||||
#### 3.1.3 學習地圖系統 (Web版)
|
||||
|
||||
**規格參考**:
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/web/learning-map-web.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] `Page_Learning_Map_W` - Web版學習地圖主頁面
|
||||
- 完整的13階段×20劇本視覺化
|
||||
- 滑鼠懸停詳細資訊
|
||||
- 鍵盤導航支援
|
||||
- [ ] `Page_Stage_Management_W` - 階段管理頁面
|
||||
- [ ] `Page_Batch_Progress_W` - 批量進度管理頁面
|
||||
|
||||
### 3.2 Web端專屬功能
|
||||
|
||||
#### 3.2.1 企業級功能
|
||||
|
||||
**規格參考**:
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/web/user-authentication-web.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] `Page_SSO_Login_W` - 企業單點登入頁面
|
||||
- [ ] `Page_Two_Factor_Auth_W` - 雙因素認證設定頁面
|
||||
- [ ] `Page_Session_Management_W` - 會話管理頁面
|
||||
- [ ] `Page_Admin_Dashboard_W` - 管理員儀表板
|
||||
|
||||
#### 3.2.2 高級商店功能
|
||||
|
||||
**規格參考**:
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/web/item-shop-web.md`
|
||||
|
||||
**需設計的頁面**:
|
||||
- [ ] `Page_Shop_Main_W` - Web版道具商店主頁面
|
||||
- 大螢幕完整商店展示
|
||||
- 批量購買支援
|
||||
- 價格比較工具
|
||||
- [ ] `Page_Diamond_Purchase_W` - Web版鑽石購買頁面
|
||||
- [ ] `Page_Price_Comparison_W` - 價格比較分析頁面
|
||||
- [ ] `Page_Bulk_Purchase_W` - 批量購買頁面
|
||||
- [ ] `Page_Payment_Methods_W` - 支付方式管理頁面
|
||||
- [ ] `Page_Purchase_History_W` - 購買歷史頁面
|
||||
|
||||
## 🧩 第四階段:共用組件設計
|
||||
|
||||
### 4.1 核心功能組件
|
||||
|
||||
**規格參考**:
|
||||
- `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/business-rules.md`
|
||||
|
||||
**需設計的組件**:
|
||||
- [ ] `Component_LifePoints_Display` - 命條顯示組件
|
||||
- 心形生命值圖標
|
||||
- 數量和恢復時間顯示
|
||||
- 不足時的警告狀態
|
||||
- [ ] `Component_Diamond_Balance` - 鑽石餘額顯示組件
|
||||
- [ ] `Component_Progress_Indicator` - 學習進度指示器
|
||||
- [ ] `Component_Achievement_Badge` - 成就徽章組件
|
||||
- [ ] `Component_Star_Rating` - 星級評分組件
|
||||
|
||||
### 4.2 互動功能組件
|
||||
|
||||
**需設計的組件**:
|
||||
- [ ] `Component_Voice_Input` - 語音輸入組件
|
||||
- 錄音狀態指示
|
||||
- 語音波形顯示
|
||||
- 即時轉換反饋
|
||||
- [ ] `Component_AI_Suggestion` - AI建議組件
|
||||
- [ ] `Component_Timer_Display` - 計時器組件
|
||||
- [ ] `Component_Score_Animation` - 分數動畫組件
|
||||
- [ ] `Component_Celebration_Effect` - 慶祝動畫效果
|
||||
|
||||
### 4.3 購買流程組件
|
||||
|
||||
**需設計的組件**:
|
||||
- [ ] `Modal_Purchase_Confirm` - 購買確認模態視窗
|
||||
- 商品資訊展示
|
||||
- 支付方式選擇
|
||||
- 安全驗證流程
|
||||
- [ ] `Modal_Payment_Processing` - 支付處理模態視窗
|
||||
- [ ] `Component_Price_Tag` - 價格標籤組件
|
||||
- [ ] `Component_Discount_Badge` - 折扣標籤組件
|
||||
|
||||
## 🎨 第五階段:視覺設計精修
|
||||
|
||||
### 5.1 品牌視覺一致性
|
||||
|
||||
**工作項目**:
|
||||
- [ ] **圖標系統設計**: 學習情境專用圖標集合
|
||||
- [ ] **插圖系統設計**: 學習場景插圖和角色設計
|
||||
- [ ] **動畫效果設計**: 學習回饋和成就慶祝動畫
|
||||
- [ ] **色彩應用指南**: 各功能區域的色彩使用規範
|
||||
|
||||
### 5.2 用戶體驗優化
|
||||
|
||||
**工作項目**:
|
||||
- [ ] **微互動設計**: 按鈕點擊、狀態切換的細微動畫
|
||||
- [ ] **載入狀態設計**: 各種載入和等待狀態的友善提示
|
||||
- [ ] **錯誤處理設計**: 友善的錯誤提示和解決方案引導
|
||||
- [ ] **無障礙設計**: 色彩對比、鍵盤導航、螢幕閱讀器支援
|
||||
|
||||
## 📊 第六階段:原型開發與驗證
|
||||
|
||||
### 6.1 高保真原型開發
|
||||
|
||||
**工作項目**:
|
||||
- [ ] **Mobile端原型**: 完整的移動端交互原型
|
||||
- [ ] **Web端原型**: 桌面端功能完整原型
|
||||
- [ ] **響應式驗證**: 各種螢幕尺寸的適配測試
|
||||
- [ ] **交互流程驗證**: 完整用戶旅程的原型測試
|
||||
|
||||
### 6.2 設計系統文檔
|
||||
|
||||
**工作項目**:
|
||||
- [ ] **組件庫文檔**: 完整的組件使用說明
|
||||
- [ ] **設計規範手冊**: 設計師和開發者使用指南
|
||||
- [ ] **品牌指南**: 視覺識別和品牌應用規範
|
||||
- [ ] **無障礙設計指南**: WCAG 2.1 AA合規指南
|
||||
|
||||
## 🔧 執行方法與工具
|
||||
|
||||
### 工具選擇
|
||||
- **設計工具**: Figma (主要), Adobe XD (輔助)
|
||||
- **原型工具**: Figma Prototype, Principle
|
||||
- **協作工具**: Figma Team, Abstract (版本控制)
|
||||
- **開發交接**: Figma Dev Mode, Zeplin
|
||||
|
||||
### 版本控制
|
||||
- **設計檔案**: 統一命名規範和版本控制
|
||||
- **組件庫**: 版本化管理,向下相容性考量
|
||||
- **規範文檔**: Git版本控制,變更記錄追蹤
|
||||
|
||||
## ⏰ 時程規劃
|
||||
|
||||
### 第一階段:UI/UX規範完善 (1週)
|
||||
- 天數 1-2: 現有規範分析
|
||||
- 天數 3-5: 補充設計規範
|
||||
- 天數 6-7: 設計系統建立
|
||||
|
||||
### 第二階段:Mobile端設計 (3週)
|
||||
- 週1: 核心學習功能頁面設計
|
||||
- 週2: 商業功能頁面設計
|
||||
- 週3: 支援功能頁面設計
|
||||
|
||||
### 第三階段:Web端設計 (2週)
|
||||
- 週1: 核心功能Web端適配
|
||||
- 週2: Web端專屬功能設計
|
||||
|
||||
### 第四階段:組件設計 (1週)
|
||||
- 天數 1-3: 核心功能組件
|
||||
- 天數 4-5: 互動功能組件
|
||||
- 天數 6-7: 購買流程組件
|
||||
|
||||
### 第五階段:視覺精修 (1週)
|
||||
- 天數 1-4: 品牌視覺一致性
|
||||
- 天數 5-7: 用戶體驗優化
|
||||
|
||||
### 第六階段:原型驗證 (1週)
|
||||
- 天數 1-4: 高保真原型開發
|
||||
- 天數 5-7: 設計系統文檔
|
||||
|
||||
**總計**: 9週 (約2個月)
|
||||
|
||||
## 🎯 成功指標
|
||||
|
||||
### 設計品質指標
|
||||
- [ ] **規範完整度**: UI/UX規範涵蓋所有功能設計需求
|
||||
- [ ] **設計一致性**: 跨平台設計元素一致性達95%以上
|
||||
- [ ] **無障礙合規**: WCAG 2.1 AA標準100%合規
|
||||
- [ ] **響應式覆蓋**: 支援5種以上主要螢幕尺寸
|
||||
|
||||
### 用戶體驗指標
|
||||
- [ ] **學習效率**: 用戶完成學習任務的時間減少20%
|
||||
- [ ] **互動滿意度**: 用戶界面滿意度評分8分以上(10分制)
|
||||
- [ ] **轉換效率**: 付費轉換漏斗各環節流失率低於15%
|
||||
- [ ] **錯誤發生率**: 用戶操作錯誤率低於5%
|
||||
|
||||
### 開發支援指標
|
||||
- [ ] **設計交接效率**: 設計到開發的交接時間減少50%
|
||||
- [ ] **組件重用率**: 設計組件重用率達80%以上
|
||||
- [ ] **開發一致性**: 開發實現與設計稿一致性達95%以上
|
||||
- [ ] **維護效率**: 設計變更的維護時間減少60%
|
||||
|
||||
## 📋 風險管控
|
||||
|
||||
### 設計風險
|
||||
- **風險**: 規範更新導致已完成設計需要大幅修改
|
||||
- **應對**: 分階段驗證,及早發現問題
|
||||
- **風險**: 跨平台設計一致性難以維持
|
||||
- **應對**: 建立嚴格的設計系統和組件庫
|
||||
|
||||
### 時程風險
|
||||
- **風險**: 設計複雜度超出預期時程
|
||||
- **應對**: 設定優先級,核心功能優先完成
|
||||
- **風險**: 規格文件理解偏差導致返工
|
||||
- **應對**: 定期與產品團隊對齊確認
|
||||
|
||||
### 品質風險
|
||||
- **風險**: 用戶體驗測試反饋需要重大修改
|
||||
- **應對**: 早期進行用戶研究和可用性測試
|
||||
- **風險**: 無障礙設計要求影響視覺效果
|
||||
- **應對**: 從設計初期就考慮無障礙需求
|
||||
|
||||
## 📚 關鍵參考文件清單
|
||||
|
||||
### 核心規格文件 (必讀)
|
||||
1. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/README.md` - 總覽和架構說明
|
||||
2. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/business-rules.md` - 共同業務規則
|
||||
3. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/progressive-stage-system.md` - 線性闖關學習系統
|
||||
4. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/platform-feature-mapping.md` - 平台功能對應表
|
||||
|
||||
### Mobile端規格文件
|
||||
1. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/mobile/01_situational-dialogue-mobile.md`
|
||||
2. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/mobile/02_vocabulary-learning-mobile.md`
|
||||
3. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/mobile/03_learning-map-mobile.md`
|
||||
4. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/mobile/04_item-shop-mobile.md`
|
||||
5. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/mobile/05_user-authentication-mobile.md`
|
||||
|
||||
### Web端規格文件
|
||||
1. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/web/vocabulary-learning-web.md`
|
||||
2. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/web/situational-dialogue-web.md`
|
||||
3. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/web/learning-map-web.md`
|
||||
4. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/web/item-shop-web.md`
|
||||
5. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/web/user-authentication-web.md`
|
||||
|
||||
### 共用模組規格文件
|
||||
1. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/ai-algorithm-specs.md` - AI算法規格
|
||||
2. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/speaking-evaluation-specs.md` - 口說評分系統
|
||||
3. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/pragmatic-analysis-specs.md` - 語用分析系統
|
||||
4. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/content-management-specs.md` - 內容管理規格
|
||||
5. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/data-models.md` - 數據模型
|
||||
6. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/function-specs/common/api-specifications.md` - API規格
|
||||
|
||||
### UI/UX設計規範文件
|
||||
1. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/ui-ux/ui-ux-guidelines.md` - 主要設計規範
|
||||
2. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/ui-ux/dramaling-ui.css` - CSS設計系統
|
||||
3. `/Users/jettcheng1018/code/dramaling-app/docs/02_design/ui-ux/ui-showcase.html` - 組件展示
|
||||
|
||||
## 📞 溝通與協作
|
||||
|
||||
### 定期檢查點
|
||||
- **每週設計評審**: 與產品經理和開發團隊的設計進度檢視
|
||||
- **雙週用戶測試**: 關鍵功能的用戶可用性測試
|
||||
- **月度設計總結**: 設計成果和問題總結報告
|
||||
|
||||
### 協作方式
|
||||
- **設計協作**: Figma團隊協作,即時同步設計進展
|
||||
- **跨團隊溝通**: Slack頻道,重要決策留存記錄
|
||||
- **文檔協作**: 設計規範和說明的協作編輯
|
||||
|
||||
---
|
||||
|
||||
**計劃制定者**: Claude AI
|
||||
**審核狀態**: 待產品團隊確認
|
||||
**下次更新**: 根據第一階段執行結果調整
|
||||
|
||||
**重要提醒**:
|
||||
1. 所有設計必須嚴格遵循引用的規格文件內容
|
||||
2. UI/UX規範不足時必須先補充規範再進行設計
|
||||
3. 跨平台一致性是設計成功的關鍵指標
|
||||
4. 用戶學習效果始終是設計決策的第一優先考量
|
||||
|
|
@ -4,7 +4,8 @@
|
|||
|
||||
**文檔名稱**: Drama Ling 設計雛形畫面制作計劃
|
||||
**建立日期**: 2025-09-11
|
||||
**版本**: v1.0
|
||||
**最後更新**: 2025-09-12
|
||||
**版本**: v1.1 - 更新詞彙學習系統和文件路徑
|
||||
**目標**: 基於完整功能規格創建可視化雛形畫面,讓用戶能直觀體驗系統功能和流程
|
||||
|
||||
## 🎯 計劃目標與範圍
|
||||
|
|
@ -42,7 +43,7 @@
|
|||
- **訂閱服務**: 免費試用、付費方案、特權功能
|
||||
|
||||
### 🎨 設計系統規範
|
||||
**出處**: `/docs/02_design/ui-ux/dramaling-ui.css` & `/docs/02_design/function-specs/common/ui-ux-guidelines.md`
|
||||
**出處**: `/docs/02_design/ui-ux/dramaling-ui.css` & `/docs/02_design/ui-ux/ui-ux-guidelines.md`
|
||||
- **設計語言**: 色彩系統、字體規範、組件樣式
|
||||
- **Duolingo風格**: 厚實3D按鈕、12px圓角、下壓動畫效果
|
||||
- **響應式佈局**: 桌面和移動端的適配方案
|
||||
|
|
@ -89,9 +90,10 @@
|
|||
**基於**: `UI_Vocab_Level1_Learning`, `UI_Vocab_Level2_Mastery`, `UI_Vocab_Level2Plus_Speaking`, `UI_Dialogue_Practice_Main`
|
||||
|
||||
##### 第1關:詞彙學習畫面
|
||||
- **詞彙介紹界面** - 詞彙卡片設計、發音按鈕、示意圖展示
|
||||
- **選擇題測驗** - 4選1界面、即時反饋、錯誤重測機制
|
||||
- **進度指示** - 5個詞彙的學習進度條
|
||||
- **沉浸式詞彙瀏覽** - 多媒體詞彙展示,包含音標、定義、音檔
|
||||
- **雙語境展示** - Source句子(真實語境) + Example句子(教學例句)
|
||||
- **自由導航** - 用戶可自由前後瀏覽,無測試壓力的純學習體驗
|
||||
- **直接詞彙標註** - 使用originalHighlight/exampleHighlight進行精確標註
|
||||
|
||||
##### 第2關:詞彙熟悉畫面
|
||||
- **句子重組界面** - 拖拽操作、元素排列、提示系統
|
||||
|
|
@ -166,25 +168,16 @@
|
|||
|
||||
### 文件組織結構
|
||||
```
|
||||
prototype-screens/
|
||||
docs/02_design/prototypes/
|
||||
├── assets/ # 資源文件
|
||||
│ ├── css/
|
||||
│ │ ├── dramaling-ui.css # 現有設計系統
|
||||
│ │ └── prototype-theme.css # 雛形專用樣式
|
||||
│ ├── js/
|
||||
│ │ ├── prototype-core.js # 核心交互邏輯
|
||||
│ │ └── mock-data.js # 模擬數據
|
||||
│ ├── css/ # 樣式表
|
||||
│ ├── js/ # JavaScript文件
|
||||
│ └── images/ # 圖片資源
|
||||
├── components/ # 可重用組件庫
|
||||
├── screens/ # 雛形畫面
|
||||
│ ├── 01_authentication/ # 認證相關畫面
|
||||
│ ├── 02_learning_core/ # 核心學習畫面
|
||||
│ ├── 03_business/ # 商業功能畫面
|
||||
│ ├── 04_social/ # 社交功能畫面
|
||||
│ └── 05_system/ # 系統功能畫面
|
||||
├── flows/ # 流程演示
|
||||
│ ├── onboarding-flow.html # 新手引導流程
|
||||
│ ├── learning-flow.html # 學習流程演示
|
||||
│ └── purchase-flow.html # 購買流程演示
|
||||
│ ├── phase1/ # 第一階段:核心學習流程
|
||||
│ ├── phase2/ # 第二階段:商業功能與輔助系統
|
||||
│ └── phase3/ # 第三階段:社交與分析功能
|
||||
└── index.html # 主導覽頁面
|
||||
```
|
||||
|
||||
|
|
@ -270,11 +263,22 @@ prototype-screens/
|
|||
## 📊 預期成果與交付物
|
||||
|
||||
### 主要交付物
|
||||
1. **完整雛形系統** - 涵蓋所有主要功能的可互動原型
|
||||
1. **完整雛形系統** - 涵蓋所有主要功能的可互動原型 (`/docs/02_design/prototypes/`)
|
||||
2. **流程演示文檔** - 主要用戶旅程的視覺演示
|
||||
3. **設計規範文檔** - 雛形制作中確立的設計標準
|
||||
4. **技術實現文檔** - 前端實現的技術方案和代碼結構
|
||||
|
||||
### 原型檔案結構
|
||||
```
|
||||
docs/02_design/prototypes/
|
||||
├── screens/ # 具體功能畫面
|
||||
│ ├── phase1/ # 第一階段:核心學習流程
|
||||
│ ├── phase2/ # 第二階段:商業功能與輔助系統
|
||||
│ └── phase3/ # 第三階段:社交與分析功能
|
||||
├── components/ # 可重用組件庫
|
||||
└── assets/ # 共用資源文件
|
||||
```
|
||||
|
||||
### 驗證目標
|
||||
1. **業務邏輯驗證** - 功能規格的視覺化確認
|
||||
2. **用戶體驗驗證** - 設計決策的可用性測試
|
||||
|
|
@ -295,11 +299,69 @@ prototype-screens/
|
|||
3. **第一個畫面** - 從登入頁面開始制作第一個雛形
|
||||
4. **迭代優化** - 基於實際效果調整設計和技術方案
|
||||
|
||||
## 📋 完整頁面設計清單 (基於function-specs)
|
||||
|
||||
### 🎯 **Mobile端功能頁面** (基於 `/mobile/` 規格)
|
||||
1. **用戶認證系統** - 登入、註冊、社交登入 (`05_user-authentication-mobile.md`)
|
||||
2. **情境對話功能** - AI對話、評分反饋 (`01_situational-dialogue-mobile.md`)
|
||||
3. **詞彙學習系統** - 沉浸式學習體驗 (`02_vocabulary-learning-mobile.md`) ✅
|
||||
4. **學習地圖** - 關卡選擇、進度追蹤 (`03_learning-map-mobile.md`)
|
||||
5. **道具商店** - 商品購買、付費流程 (`04_item-shop-mobile.md`) ✅
|
||||
|
||||
### 🖥️ **Web端功能頁面** (基於 `/web/` 規格)
|
||||
1. **用戶認證系統** - 桌面端登入體驗 (`user-authentication-web.md`)
|
||||
2. **情境對話功能** - 大螢幕對話界面 (`situational-dialogue-web.md`)
|
||||
3. **詞彙學習系統** - 桌面端學習體驗 (`vocabulary-learning-web.md`)
|
||||
4. **學習地圖** - 桌面端地圖導覽 (`learning-map-web.md`)
|
||||
5. **道具商店** - 桌面端購買體驗 (`item-shop-web.md`)
|
||||
|
||||
### 🔧 **Common功能系統** (基於 `/common/` 規格)
|
||||
1. **AI算法展示** - 三維評分系統視覺化 (`ai-algorithm-specs.md`)
|
||||
2. **口說評分界面** - 五維度評分展示 (`speaking-evaluation-specs.md`)
|
||||
3. **語用分析界面** - 六維語用建議系統 (`pragmatic-analysis-specs.md`)
|
||||
4. **進度追蹤系統** - 線性闖關進度管理 (`progressive-stage-system.md`)
|
||||
5. **內容管理界面** - 劇本、詞彙管理 (`content-management-specs.md`)
|
||||
|
||||
### 🔄 **整合功能頁面** (基於綜合規格)
|
||||
1. **完整用戶流程** - 端到端學習旅程 (`comprehensive-user-flows-with-ui.md`)
|
||||
2. **平台功能映射** - 跨平台功能展示 (`platform-feature-mapping.md`)
|
||||
|
||||
## 🎨 **設計執行策略**
|
||||
|
||||
### Phase 1: UI/UX規範完善 ⭐ **當前重點**
|
||||
- **檢查現有規範** - 分析 `/ui-ux/ui-ux-guidelines.md` 完整性
|
||||
- **補充缺失規範** - 為缺少的組件添加設計規範
|
||||
- **統一設計語言** - 確保所有頁面遵循一致標準
|
||||
|
||||
### Phase 2: 核心學習系統頁面
|
||||
- **詞彙學習系統** - 沉浸式多媒體體驗 ✅
|
||||
- **情境對話系統** - AI互動與評分展示
|
||||
- **進度管理系統** - 四關闖關視覺化
|
||||
- **學習地圖** - 13階段×20劇本導覽
|
||||
|
||||
### Phase 3: 商業與輔助系統
|
||||
- **用戶認證流程** - 登入註冊完整體驗
|
||||
- **道具商店系統** - 完整購買生態 ✅
|
||||
- **命條與獎勵** - 遊戲化機制展示 ✅
|
||||
- **廣告與挑戰** - 額外收益機制 ✅
|
||||
|
||||
### Phase 4: AI智能系統
|
||||
- **口說評分界面** - 五維度專業評估
|
||||
- **語用分析展示** - 六維語用建議
|
||||
- **AI算法可視化** - 三維評估系統
|
||||
- **即時反饋系統** - 智能學習輔助
|
||||
|
||||
### Phase 5: 社交與分析
|
||||
- **社交排行榜** - 好友競爭系統
|
||||
- **學習分析** - 個人進度儀表板
|
||||
- **成就系統** - 徽章收集展示
|
||||
- **數據同步** - 跨平台進度管理
|
||||
|
||||
### 協作機制
|
||||
1. **每日進度更新** - 每天匯報制作進度和遇到的問題
|
||||
2. **週度檢查** - 每週進行設計品質和技術實現檢查
|
||||
3. **用戶反饋收集** - 定期收集用戶對雛形效果的反饋
|
||||
4. **迭代改進** - 根據反饋持續優化雛形質量
|
||||
1. **規範優先** - 每個頁面設計前先完善UI/UX規範
|
||||
2. **迭代設計** - 快速原型→測試→優化的循環
|
||||
3. **跨平台一致** - 確保mobile/web體驗的一致性
|
||||
4. **功能完整** - 每個頁面都要體現完整的用戶流程
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -0,0 +1,959 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-TW">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Drama Ling - 登入</title>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
/* Premium Design System V3.0 */
|
||||
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
--secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
--success-gradient: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
||||
--warning-gradient: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
|
||||
--error-gradient: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
|
||||
|
||||
--bg-primary: #0f0f23;
|
||||
--bg-secondary: #1a1a2e;
|
||||
--bg-card: rgba(255, 255, 255, 0.1);
|
||||
--bg-input: rgba(255, 255, 255, 0.08);
|
||||
|
||||
--text-primary: #ffffff;
|
||||
--text-secondary: #b8b8d4;
|
||||
--text-muted: #8a8aa8;
|
||||
|
||||
--border-radius: 16px;
|
||||
--border-radius-lg: 24px;
|
||||
--shadow-lg: 0 20px 60px rgba(0, 0, 0, 0.4);
|
||||
--shadow-xl: 0 25px 80px rgba(0, 0, 0, 0.6);
|
||||
|
||||
--font-family: 'SF Pro Display', system-ui, -apple-system, sans-serif;
|
||||
--font-size-xs: 0.75rem;
|
||||
--font-size-sm: 0.875rem;
|
||||
--font-size-base: 1rem;
|
||||
--font-size-lg: 1.125rem;
|
||||
--font-size-xl: 1.25rem;
|
||||
--font-size-2xl: 1.5rem;
|
||||
--font-size-3xl: 1.875rem;
|
||||
|
||||
--transition-all: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font-family);
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
line-height: 1.6;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 2rem 1rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.background-animation {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
background: var(--primary-gradient);
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
.background-animation::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: radial-gradient(circle at 20% 20%, rgba(102, 126, 234, 0.3) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 80%, rgba(118, 75, 162, 0.3) 0%, transparent 50%),
|
||||
radial-gradient(circle at 40% 60%, rgba(240, 147, 251, 0.2) 0%, transparent 50%);
|
||||
animation: backgroundPulse 6s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes backgroundPulse {
|
||||
from { opacity: 0.3; transform: scale(1); }
|
||||
to { opacity: 0.6; transform: scale(1.1); }
|
||||
}
|
||||
|
||||
.login-card {
|
||||
background: var(--bg-card);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: var(--border-radius-lg);
|
||||
padding: 2.5rem;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
box-shadow: var(--shadow-xl);
|
||||
animation: cardSlideIn 0.6s ease-out;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.login-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: var(--primary-gradient);
|
||||
}
|
||||
|
||||
@keyframes cardSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(40px) scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.app-logo {
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.logo-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background: var(--primary-gradient);
|
||||
border-radius: 50%;
|
||||
margin: 0 auto 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
box-shadow: var(--shadow-lg);
|
||||
animation: logoFloat 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes logoFloat {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-8px); }
|
||||
}
|
||||
|
||||
.app-title {
|
||||
font-size: var(--font-size-2xl);
|
||||
font-weight: 700;
|
||||
background: var(--primary-gradient);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.app-subtitle {
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.login-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: 1rem 1.25rem;
|
||||
background: var(--bg-input);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: var(--border-radius);
|
||||
color: var(--text-primary);
|
||||
font-size: var(--font-size-base);
|
||||
transition: var(--transition-all);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
outline: none;
|
||||
border-color: rgba(102, 126, 234, 0.5);
|
||||
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2);
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.form-input::placeholder {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.password-toggle {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
font-size: 1.2rem;
|
||||
transition: var(--transition-all);
|
||||
}
|
||||
|
||||
.password-toggle:hover {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.form-options {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.remember-me {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.custom-checkbox {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
transition: var(--transition-all);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.custom-checkbox.checked {
|
||||
background: var(--primary-gradient);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.custom-checkbox.checked::after {
|
||||
content: '✓';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.forgot-password {
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
transition: var(--transition-all);
|
||||
}
|
||||
|
||||
.forgot-password:hover {
|
||||
color: var(--text-primary);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.login-button {
|
||||
background: var(--primary-gradient);
|
||||
border: none;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 1rem 2rem;
|
||||
color: white;
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: var(--transition-all);
|
||||
box-shadow: var(--shadow-lg);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.login-button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 25px 80px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
.login-button:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.login-button.loading {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.login-button .spinner {
|
||||
display: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid transparent;
|
||||
border-top: 2px solid white;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.login-button.loading .spinner {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.divider {
|
||||
text-align: center;
|
||||
margin: 1.5rem 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.divider::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 1px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.divider span {
|
||||
background: var(--bg-secondary);
|
||||
padding: 0 1rem;
|
||||
color: var(--text-muted);
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.social-login {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.social-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.875rem 1rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--bg-input);
|
||||
color: var(--text-primary);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: var(--transition-all);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.social-button:hover {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.social-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.google-icon { background: #4285f4; color: white; }
|
||||
.facebook-icon { background: #1877f2; color: white; }
|
||||
.apple-icon { background: #000; color: white; }
|
||||
|
||||
.register-link {
|
||||
text-align: center;
|
||||
margin-top: 1.5rem;
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.register-link a {
|
||||
color: var(--text-primary);
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
background: var(--primary-gradient);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.register-link a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.guest-mode {
|
||||
text-align: center;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.guest-button {
|
||||
color: var(--text-muted);
|
||||
text-decoration: none;
|
||||
font-size: var(--font-size-sm);
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: var(--border-radius);
|
||||
transition: var(--transition-all);
|
||||
}
|
||||
|
||||
.guest-button:hover {
|
||||
color: var(--text-secondary);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: #fa709a;
|
||||
font-size: var(--font-size-sm);
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
background: rgba(250, 112, 154, 0.1);
|
||||
border-radius: var(--border-radius);
|
||||
border-left: 3px solid #fa709a;
|
||||
animation: errorShake 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes errorShake {
|
||||
0%, 100% { transform: translateX(0); }
|
||||
25% { transform: translateX(-5px); }
|
||||
75% { transform: translateX(5px); }
|
||||
}
|
||||
|
||||
.security-notice {
|
||||
text-align: center;
|
||||
margin-top: 1rem;
|
||||
padding: 0.75rem;
|
||||
background: rgba(67, 233, 123, 0.1);
|
||||
border-radius: var(--border-radius);
|
||||
border-left: 3px solid #43e97b;
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.login-card {
|
||||
padding: 2rem 1.5rem;
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
.app-title {
|
||||
font-size: var(--font-size-xl);
|
||||
}
|
||||
|
||||
.logo-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="background-animation"></div>
|
||||
|
||||
<div class="login-container">
|
||||
<div class="login-card">
|
||||
<div class="app-logo">
|
||||
<div class="logo-icon">DL</div>
|
||||
<h1 class="app-title">Drama Ling</h1>
|
||||
<p class="app-subtitle">沉浸式英語學習體驗</p>
|
||||
</div>
|
||||
|
||||
<form class="login-form" id="loginForm">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="username">電子郵件或用戶名</label>
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
class="form-input"
|
||||
placeholder="輸入您的電子郵件或用戶名"
|
||||
required
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="position: relative;">
|
||||
<label class="form-label" for="password">密碼</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
class="form-input"
|
||||
placeholder="輸入您的密碼"
|
||||
required
|
||||
>
|
||||
<button type="button" class="password-toggle" id="passwordToggle">👁</button>
|
||||
</div>
|
||||
|
||||
<div class="form-options">
|
||||
<label class="remember-me">
|
||||
<div class="custom-checkbox" id="rememberCheckbox"></div>
|
||||
<span>記住我</span>
|
||||
</label>
|
||||
<a href="#" class="forgot-password" id="forgotPassword">忘記密碼?</a>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="login-button" id="loginButton">
|
||||
<div class="spinner"></div>
|
||||
<span>登入</span>
|
||||
</button>
|
||||
|
||||
<div id="errorMessage" class="error-message" style="display: none;"></div>
|
||||
</form>
|
||||
|
||||
<div class="divider">
|
||||
<span>或者使用</span>
|
||||
</div>
|
||||
|
||||
<div class="social-login">
|
||||
<a href="#" class="social-button" id="googleLogin">
|
||||
<div class="social-icon google-icon">G</div>
|
||||
<span>使用 Google 登入</span>
|
||||
</a>
|
||||
|
||||
<a href="#" class="social-button" id="facebookLogin">
|
||||
<div class="social-icon facebook-icon">f</div>
|
||||
<span>使用 Facebook 登入</span>
|
||||
</a>
|
||||
|
||||
<a href="#" class="social-button" id="appleLogin">
|
||||
<div class="social-icon apple-icon">🍎</div>
|
||||
<span>使用 Apple 登入</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="register-link">
|
||||
還沒有帳戶? <a href="#" id="registerLink">立即註冊</a>
|
||||
</div>
|
||||
|
||||
<div class="guest-mode">
|
||||
<a href="#" class="guest-button" id="guestMode">遊客模式體驗</a>
|
||||
</div>
|
||||
|
||||
<div class="security-notice">
|
||||
🔒 您的資料受到 AES-256 加密保護
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
class LoginSystem {
|
||||
constructor() {
|
||||
this.initializeElements();
|
||||
this.bindEvents();
|
||||
this.initializeState();
|
||||
}
|
||||
|
||||
initializeElements() {
|
||||
this.loginForm = document.getElementById('loginForm');
|
||||
this.usernameInput = document.getElementById('username');
|
||||
this.passwordInput = document.getElementById('password');
|
||||
this.passwordToggle = document.getElementById('passwordToggle');
|
||||
this.rememberCheckbox = document.getElementById('rememberCheckbox');
|
||||
this.loginButton = document.getElementById('loginButton');
|
||||
this.errorMessage = document.getElementById('errorMessage');
|
||||
this.forgotPassword = document.getElementById('forgotPassword');
|
||||
this.registerLink = document.getElementById('registerLink');
|
||||
this.guestMode = document.getElementById('guestMode');
|
||||
this.googleLogin = document.getElementById('googleLogin');
|
||||
this.facebookLogin = document.getElementById('facebookLogin');
|
||||
this.appleLogin = document.getElementById('appleLogin');
|
||||
}
|
||||
|
||||
initializeState() {
|
||||
this.isRememberChecked = false;
|
||||
this.isPasswordVisible = false;
|
||||
this.loginAttempts = 0;
|
||||
this.maxLoginAttempts = 5;
|
||||
this.lockoutTime = 3600000; // 1 hour in milliseconds
|
||||
|
||||
// Load saved preferences
|
||||
this.loadSavedCredentials();
|
||||
this.checkLockoutStatus();
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.loginForm.addEventListener('submit', (e) => this.handleLogin(e));
|
||||
this.passwordToggle.addEventListener('click', () => this.togglePasswordVisibility());
|
||||
this.rememberCheckbox.addEventListener('click', () => this.toggleRememberMe());
|
||||
this.forgotPassword.addEventListener('click', (e) => this.handleForgotPassword(e));
|
||||
this.registerLink.addEventListener('click', (e) => this.handleRegister(e));
|
||||
this.guestMode.addEventListener('click', (e) => this.handleGuestMode(e));
|
||||
this.googleLogin.addEventListener('click', (e) => this.handleSocialLogin(e, 'google'));
|
||||
this.facebookLogin.addEventListener('click', (e) => this.handleSocialLogin(e, 'facebook'));
|
||||
this.appleLogin.addEventListener('click', (e) => this.handleSocialLogin(e, 'apple'));
|
||||
|
||||
// Real-time validation
|
||||
this.usernameInput.addEventListener('input', () => this.validateInput('username'));
|
||||
this.passwordInput.addEventListener('input', () => this.validateInput('password'));
|
||||
|
||||
// Keyboard shortcuts
|
||||
document.addEventListener('keydown', (e) => this.handleKeyboardShortcuts(e));
|
||||
}
|
||||
|
||||
togglePasswordVisibility() {
|
||||
this.isPasswordVisible = !this.isPasswordVisible;
|
||||
this.passwordInput.type = this.isPasswordVisible ? 'text' : 'password';
|
||||
this.passwordToggle.textContent = this.isPasswordVisible ? '🙈' : '👁';
|
||||
|
||||
// Add animation effect
|
||||
this.passwordToggle.style.transform = 'scale(0.9)';
|
||||
setTimeout(() => {
|
||||
this.passwordToggle.style.transform = 'scale(1)';
|
||||
}, 150);
|
||||
}
|
||||
|
||||
toggleRememberMe() {
|
||||
this.isRememberChecked = !this.isRememberChecked;
|
||||
this.rememberCheckbox.classList.toggle('checked', this.isRememberChecked);
|
||||
|
||||
// Save preference
|
||||
localStorage.setItem('rememberMe', this.isRememberChecked);
|
||||
}
|
||||
|
||||
validateInput(inputType) {
|
||||
const input = inputType === 'username' ? this.usernameInput : this.passwordInput;
|
||||
const value = input.value.trim();
|
||||
|
||||
// Remove previous validation states
|
||||
input.style.borderColor = '';
|
||||
input.style.boxShadow = '';
|
||||
|
||||
if (inputType === 'username') {
|
||||
const isEmail = this.isValidEmail(value);
|
||||
const isUsername = this.isValidUsername(value);
|
||||
|
||||
if (value && !isEmail && !isUsername) {
|
||||
this.setInputError(input, '請輸入有效的電子郵件或用戶名');
|
||||
return false;
|
||||
}
|
||||
} else if (inputType === 'password') {
|
||||
if (value && value.length < 8) {
|
||||
this.setInputError(input, '密碼至少需要8個字符');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (value) {
|
||||
this.setInputSuccess(input);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
setInputError(input, message) {
|
||||
input.style.borderColor = '#fa709a';
|
||||
input.style.boxShadow = '0 0 0 3px rgba(250, 112, 154, 0.2)';
|
||||
}
|
||||
|
||||
setInputSuccess(input) {
|
||||
input.style.borderColor = '#43e97b';
|
||||
input.style.boxShadow = '0 0 0 3px rgba(67, 233, 123, 0.2)';
|
||||
}
|
||||
|
||||
isValidEmail(email) {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return emailRegex.test(email);
|
||||
}
|
||||
|
||||
isValidUsername(username) {
|
||||
const usernameRegex = /^[a-zA-Z0-9_]{3,20}$/;
|
||||
return usernameRegex.test(username);
|
||||
}
|
||||
|
||||
async handleLogin(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (this.isAccountLocked()) {
|
||||
this.showError('帳戶已被鎖定,請稍後再試');
|
||||
return;
|
||||
}
|
||||
|
||||
const username = this.usernameInput.value.trim();
|
||||
const password = this.passwordInput.value;
|
||||
|
||||
// Validate inputs
|
||||
if (!this.validateInput('username') || !this.validateInput('password')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!username || !password) {
|
||||
this.showError('請填寫所有必填欄位');
|
||||
return;
|
||||
}
|
||||
|
||||
// Show loading state
|
||||
this.setLoadingState(true);
|
||||
this.hideError();
|
||||
|
||||
try {
|
||||
// Simulate API call
|
||||
await this.simulateLoginAPI(username, password);
|
||||
|
||||
// Success handling
|
||||
this.handleLoginSuccess(username);
|
||||
|
||||
} catch (error) {
|
||||
this.handleLoginError(error);
|
||||
} finally {
|
||||
this.setLoadingState(false);
|
||||
}
|
||||
}
|
||||
|
||||
async simulateLoginAPI(username, password) {
|
||||
// Simulate network delay
|
||||
await new Promise(resolve => setTimeout(resolve, 1500));
|
||||
|
||||
// Simulate different response scenarios
|
||||
const scenarios = {
|
||||
'demo@dramaling.com': { success: true, user: { name: 'Demo User', level: 'Advanced' } },
|
||||
'test@example.com': { success: true, user: { name: 'Test User', level: 'Beginner' } },
|
||||
'wrong@email.com': { success: false, error: '帳號或密碼錯誤' },
|
||||
'locked@account.com': { success: false, error: '帳戶已被鎖定' }
|
||||
};
|
||||
|
||||
const result = scenarios[username.toLowerCase()] || { success: false, error: '帳號或密碼錯誤' };
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
handleLoginSuccess(username) {
|
||||
// Reset login attempts
|
||||
this.loginAttempts = 0;
|
||||
localStorage.removeItem('loginAttempts');
|
||||
localStorage.removeItem('lockoutTime');
|
||||
|
||||
// Save credentials if remember me is checked
|
||||
if (this.isRememberChecked) {
|
||||
this.saveCredentials(username);
|
||||
}
|
||||
|
||||
// Show success animation
|
||||
this.showSuccessAnimation();
|
||||
|
||||
// Simulate navigation to main app
|
||||
setTimeout(() => {
|
||||
alert('登入成功!即將進入 Drama Ling 主應用...');
|
||||
// In real app: window.location.href = '/dashboard';
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
handleLoginError(error) {
|
||||
this.loginAttempts++;
|
||||
localStorage.setItem('loginAttempts', this.loginAttempts);
|
||||
|
||||
if (this.loginAttempts >= this.maxLoginAttempts) {
|
||||
const lockoutTime = Date.now() + this.lockoutTime;
|
||||
localStorage.setItem('lockoutTime', lockoutTime);
|
||||
this.showError(`登入失敗次數過多,帳戶已被鎖定 1 小時`);
|
||||
} else {
|
||||
const remainingAttempts = this.maxLoginAttempts - this.loginAttempts;
|
||||
this.showError(`${error.message} (剩餘嘗試次數: ${remainingAttempts})`);
|
||||
}
|
||||
|
||||
// Shake animation for error
|
||||
this.loginButton.style.animation = 'errorShake 0.5s ease-in-out';
|
||||
setTimeout(() => {
|
||||
this.loginButton.style.animation = '';
|
||||
}, 500);
|
||||
}
|
||||
|
||||
setLoadingState(isLoading) {
|
||||
this.loginButton.classList.toggle('loading', isLoading);
|
||||
this.loginButton.disabled = isLoading;
|
||||
|
||||
const span = this.loginButton.querySelector('span');
|
||||
span.textContent = isLoading ? '登入中...' : '登入';
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
this.errorMessage.textContent = message;
|
||||
this.errorMessage.style.display = 'block';
|
||||
this.errorMessage.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
|
||||
hideError() {
|
||||
this.errorMessage.style.display = 'none';
|
||||
}
|
||||
|
||||
showSuccessAnimation() {
|
||||
// Create success overlay
|
||||
const overlay = document.createElement('div');
|
||||
overlay.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
`;
|
||||
|
||||
overlay.innerHTML = '✓ 登入成功!';
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
// Animate in
|
||||
setTimeout(() => overlay.style.opacity = '1', 100);
|
||||
|
||||
// Remove after animation
|
||||
setTimeout(() => {
|
||||
overlay.style.opacity = '0';
|
||||
setTimeout(() => document.body.removeChild(overlay), 300);
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
handleSocialLogin(e, provider) {
|
||||
e.preventDefault();
|
||||
|
||||
this.showSocialLoginAnimation(provider);
|
||||
|
||||
// Simulate OAuth flow
|
||||
setTimeout(() => {
|
||||
alert(`正在使用 ${provider.toUpperCase()} 進行登入...`);
|
||||
// In real app: initiate OAuth flow
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
showSocialLoginAnimation(provider) {
|
||||
const button = e.currentTarget;
|
||||
const originalText = button.innerHTML;
|
||||
|
||||
button.innerHTML = `
|
||||
<div class="spinner" style="display: inline-block;"></div>
|
||||
<span>連接中...</span>
|
||||
`;
|
||||
|
||||
setTimeout(() => {
|
||||
button.innerHTML = originalText;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
handleForgotPassword(e) {
|
||||
e.preventDefault();
|
||||
alert('即將跳轉到密碼重置頁面...');
|
||||
// In real app: navigate to password reset page
|
||||
}
|
||||
|
||||
handleRegister(e) {
|
||||
e.preventDefault();
|
||||
alert('即將跳轉到註冊頁面...');
|
||||
// In real app: navigate to registration page
|
||||
}
|
||||
|
||||
handleGuestMode(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const confirmGuest = confirm('以遊客模式進入將限制部分功能,確定要繼續嗎?');
|
||||
if (confirmGuest) {
|
||||
alert('正在以遊客模式進入 Drama Ling...');
|
||||
// In real app: navigate to guest mode
|
||||
}
|
||||
}
|
||||
|
||||
loadSavedCredentials() {
|
||||
const savedUsername = localStorage.getItem('savedUsername');
|
||||
const rememberMe = localStorage.getItem('rememberMe') === 'true';
|
||||
|
||||
if (savedUsername && rememberMe) {
|
||||
this.usernameInput.value = savedUsername;
|
||||
this.isRememberChecked = true;
|
||||
this.rememberCheckbox.classList.add('checked');
|
||||
}
|
||||
}
|
||||
|
||||
saveCredentials(username) {
|
||||
localStorage.setItem('savedUsername', username);
|
||||
}
|
||||
|
||||
checkLockoutStatus() {
|
||||
const lockoutTime = localStorage.getItem('lockoutTime');
|
||||
const attempts = localStorage.getItem('loginAttempts');
|
||||
|
||||
if (lockoutTime && Date.now() < parseInt(lockoutTime)) {
|
||||
const remainingTime = Math.ceil((parseInt(lockoutTime) - Date.now()) / 60000);
|
||||
this.showError(`帳戶已被鎖定,請在 ${remainingTime} 分鐘後再試`);
|
||||
this.loginButton.disabled = true;
|
||||
} else {
|
||||
// Clear expired lockout
|
||||
localStorage.removeItem('lockoutTime');
|
||||
localStorage.removeItem('loginAttempts');
|
||||
this.loginAttempts = 0;
|
||||
}
|
||||
|
||||
if (attempts) {
|
||||
this.loginAttempts = parseInt(attempts);
|
||||
}
|
||||
}
|
||||
|
||||
isAccountLocked() {
|
||||
const lockoutTime = localStorage.getItem('lockoutTime');
|
||||
return lockoutTime && Date.now() < parseInt(lockoutTime);
|
||||
}
|
||||
|
||||
handleKeyboardShortcuts(e) {
|
||||
// Enter key to submit
|
||||
if (e.key === 'Enter' && (this.usernameInput.focused || this.passwordInput.focused)) {
|
||||
this.handleLogin(e);
|
||||
}
|
||||
|
||||
// Escape key to clear form
|
||||
if (e.key === 'Escape') {
|
||||
this.clearForm();
|
||||
}
|
||||
}
|
||||
|
||||
clearForm() {
|
||||
this.usernameInput.value = '';
|
||||
this.passwordInput.value = '';
|
||||
this.hideError();
|
||||
this.usernameInput.focus();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize login system when DOM is loaded
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
new LoginSystem();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||