diff --git a/note/複習系統/技術實作規格.md b/note/複習系統/技術實作規格.md index a12e9a7..9430d38 100644 --- a/note/複習系統/技術實作規格.md +++ b/note/複習系統/技術實作規格.md @@ -94,25 +94,172 @@ const confidenceToScore = { } ``` -### **階段2: 詞彙選擇題 (計劃中)** +### **階段2: 詞彙選擇題 (已設計完成)** + +**組件架構** (基於您的設計): +```typescript +interface VocabChoiceTestProps { + cardData: FlashcardData + options: string[] // 4選1選項 + onAnswer: (answer: string) => void + onReportError: () => void + disabled?: boolean +} + +// 組件分區設計 +const VocabChoiceTest = () => { + const questionArea = // 問題顯示區域 + const optionsArea = // 選項網格區域 + const resultArea = // 結果顯示區域 + + return ( + + ) +} +``` + +**問題顯示區域設計**: +```typescript +const questionArea = ( +
+
+

定義

+

+ {cardData.definition} +

+
+

+ 請選擇符合上述定義的英文詞彙: +

+
+) +``` + +**狀態管理設計**: +```typescript +const [selectedAnswer, setSelectedAnswer] = useState(null) +const [showResult, setShowResult] = useState(false) + +// 答案驗證邏輯 +const isCorrect = useMemo(() => + selectedAnswer === cardData.word, + [selectedAnswer, cardData.word] +) + +// 選擇處理 +const handleAnswerSelect = useCallback((answer: string) => { + if (disabled || showResult) return + setSelectedAnswer(answer) + setShowResult(true) + onAnswer(answer) +}, [disabled, showResult, onAnswer]) +``` **選項生成算法**: ```typescript -// 暫時使用固定選項 (MVP階段) -const mockOptions = ['apple', 'orange', 'banana', correctAnswer] -const shuffledOptions = shuffle(mockOptions) -``` +// MVP階段: 固定選項 +const generateSimpleOptions = (correctWord: string): string[] => { + const fixedDistractors = ['apple', 'orange', 'banana'] + return shuffle([correctWord, ...fixedDistractors]) +} -**未來升級方案**: -```typescript -// 基於詞性和CEFR等級生成干擾項 -const generateDistractors = (correctWord, allWords) => { +// 階段3升級方案: 智能干擾項 +const generateSmartOptions = (correctWord: Flashcard, allWords: Flashcard[]): string[] => { const samePOS = allWords.filter(w => w.partOfSpeech === correctWord.partOfSpeech) const sameCEFR = allWords.filter(w => w.cefr === correctWord.cefr) - return selectRandom([...samePOS, ...sameCEFR], 3) + const distractors = selectRandom([...samePOS, ...sameCEFR], 3) + return shuffle([correctWord.word, ...distractors.map(w => w.word)]) } ``` +**ChoiceGrid組件設計** (您的完整設計): +```typescript +interface ChoiceGridProps { + options: string[] // 4個選項 + selectedOption?: string | null + correctAnswer?: string + showResult?: boolean // 控制結果顯示 + onSelect: (option: string) => void + disabled?: boolean + className?: string +} + +// 響應式網格布局 +
+ {options.map((option, index) => ( + + ))} +
+``` + +**ChoiceOption樣式規格** (您的設計): +```typescript +// 選項按鈕狀態樣式 +const getOptionStyles = (isSelected, isCorrect, isIncorrect, showResult) => { + if (showResult) { + if (isCorrect) return 'border-green-500 bg-green-50 text-green-700' + if (isIncorrect && isSelected) return 'border-red-500 bg-red-50 text-red-700' + return 'border-gray-200 bg-gray-50 text-gray-500' + } + + if (isSelected) return 'border-blue-500 bg-blue-50 text-blue-700' + return 'border-gray-200 hover:border-blue-300 hover:bg-blue-50' +} + +// 按鈕基礎樣式 +className={`p-4 text-center rounded-lg border-2 transition-all ${getOptionStyles()}`} +``` + +**UI組件層次設計**: +```typescript +// 您設計的完整組件結構 + // 外層容器和錯誤處理 + + // 問題顯示區域 +
+

定義

+

{definition}

+
+

請選擇符合上述定義的英文詞彙:

+
+ // 選項區域 + + + // 結果顯示區域 + {showResult && ( + + )} + +
+``` + --- ## 🎨 **UI/UX實作規格**