ux: 重構學習模式設計與導航體驗
- 改進選擇題模式:顯示定義讓用戶選擇對應英文詞彙 - 優化選項生成邏輯:動態從卡片組生成選項並隨機排序 - 新增翻卡背面例句播放功能,提升學習效果 - 統一所有學習模式導航按鈕位置和樣式 - 實現全版導航按鈕設計,改善觸控體驗 - 修正結果顯示邏輯和音頻回饋功能 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
c1e296c860
commit
5bd823ee91
|
|
@ -112,14 +112,14 @@ export default function LearnPage() {
|
|||
setMounted(true)
|
||||
const currentWord = cards[currentCardIndex].word;
|
||||
|
||||
// Fixed options based on current card index
|
||||
const optionSets = [
|
||||
[currentWord, 'determine', 'achieve', 'consider'], // for index 0
|
||||
[currentWord, 'brought', 'achieve', 'negotiate'], // for index 1
|
||||
[currentWord, 'brought', 'instincts', 'determine'] // for index 2
|
||||
];
|
||||
// Generate quiz options with current word and other words from the deck
|
||||
const otherWords = cards
|
||||
.filter((_, idx) => idx !== currentCardIndex)
|
||||
.map(card => card.word)
|
||||
.slice(0, 3); // Take 3 other words
|
||||
|
||||
const options = optionSets[currentCardIndex] || [currentWord, 'determine', 'achieve', 'consider'];
|
||||
// Add the current word and shuffle
|
||||
const options = [currentWord, ...otherWords].sort(() => Math.random() - 0.5);
|
||||
setQuizOptions(options);
|
||||
|
||||
// Reset quiz state when card changes
|
||||
|
|
@ -163,7 +163,7 @@ export default function LearnPage() {
|
|||
setSelectedAnswer(answer)
|
||||
setShowResult(true)
|
||||
|
||||
const isCorrect = answer === currentCard.translation
|
||||
const isCorrect = answer === currentCard.word
|
||||
setScore(prev => ({
|
||||
correct: isCorrect ? prev.correct + 1 : prev.correct,
|
||||
total: prev.total + 1
|
||||
|
|
@ -386,7 +386,12 @@ export default function LearnPage() {
|
|||
{/* Example */}
|
||||
<div className="bg-gray-50 rounded-lg p-4">
|
||||
<h3 className="font-semibold text-gray-900 mb-2 text-left">例句</h3>
|
||||
<p className="text-gray-700 italic mb-2 text-left">"{currentCard.example}"</p>
|
||||
<div className="relative">
|
||||
<p className="text-gray-700 italic mb-2 text-left pr-12">"{currentCard.example}"</p>
|
||||
<div className="absolute bottom-0 right-0">
|
||||
<AudioPlayer text={currentCard.example} />
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-gray-600 text-sm text-left">"{currentCard.exampleTranslation}"</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -411,17 +416,17 @@ export default function LearnPage() {
|
|||
</div>
|
||||
|
||||
{/* Navigation */}
|
||||
<div className="flex justify-between mt-6">
|
||||
<div className="flex gap-4 mt-6">
|
||||
<button
|
||||
onClick={handlePrevious}
|
||||
disabled={currentCardIndex === 0}
|
||||
className="px-4 py-2 bg-gray-500 text-white rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-600 transition-colors"
|
||||
className="flex-1 py-3 bg-gray-500 text-white rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-600 transition-colors font-medium"
|
||||
>
|
||||
上一張
|
||||
</button>
|
||||
<button
|
||||
onClick={handleNext}
|
||||
className="px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary-dark transition-colors"
|
||||
className="flex-1 py-3 bg-primary text-white rounded-lg hover:bg-primary-dark transition-colors font-medium"
|
||||
>
|
||||
{currentCardIndex === cards.length - 1 ? '完成' : '下一張'}
|
||||
</button>
|
||||
|
|
@ -444,28 +449,13 @@ export default function LearnPage() {
|
|||
</div>
|
||||
|
||||
<div className="bg-white rounded-xl shadow-lg p-8">
|
||||
<div className="text-center mb-8">
|
||||
<div className="mb-4">
|
||||
<span className="inline-block bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded-full">
|
||||
{currentCard.difficulty}
|
||||
</span>
|
||||
</div>
|
||||
<h2 className="text-3xl font-bold text-gray-900 mb-4">
|
||||
{currentCard.word}
|
||||
</h2>
|
||||
<p className="text-gray-600 mb-4">
|
||||
{currentCard.partOfSpeech} {currentCard.pronunciation}
|
||||
</p>
|
||||
<div className="mb-6">
|
||||
<AudioPlayer text={currentCard.word} />
|
||||
</div>
|
||||
<div className="mb-8">
|
||||
<div className="bg-gray-50 rounded-lg p-4 mb-6">
|
||||
<p className="text-gray-700 text-lg">
|
||||
{currentCard.definition}
|
||||
</p>
|
||||
<h3 className="font-semibold text-gray-900 mb-2 text-left">定義</h3>
|
||||
<p className="text-gray-700 text-left">{currentCard.definition}</p>
|
||||
</div>
|
||||
<p className="text-lg text-gray-700 mb-2">
|
||||
這個詞的中文翻譯是?
|
||||
<p className="text-lg text-gray-700 mb-2 text-center">
|
||||
請選擇符合上述定義的英文詞彙:
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -475,9 +465,9 @@ export default function LearnPage() {
|
|||
key={idx}
|
||||
onClick={() => !showResult && handleQuizAnswer(option)}
|
||||
disabled={showResult}
|
||||
className={`w-full p-4 text-left rounded-lg border-2 transition-all ${
|
||||
className={`w-full p-4 text-center rounded-lg border-2 transition-all ${
|
||||
showResult
|
||||
? option === currentCard.translation
|
||||
? option === currentCard.word
|
||||
? 'border-green-500 bg-green-50 text-green-700'
|
||||
: option === selectedAnswer
|
||||
? 'border-red-500 bg-red-50 text-red-700'
|
||||
|
|
@ -492,41 +482,47 @@ export default function LearnPage() {
|
|||
|
||||
{showResult && (
|
||||
<div className={`mt-6 p-4 rounded-lg ${
|
||||
selectedAnswer === currentCard.translation
|
||||
selectedAnswer === currentCard.word
|
||||
? 'bg-green-50 border border-green-200'
|
||||
: 'bg-red-50 border border-red-200'
|
||||
}`}>
|
||||
<p className={`font-semibold ${
|
||||
selectedAnswer === currentCard.translation
|
||||
selectedAnswer === currentCard.word
|
||||
? 'text-green-700'
|
||||
: 'text-red-700'
|
||||
}`}>
|
||||
{selectedAnswer === currentCard.translation ? '正確!' : '錯誤!'}
|
||||
{selectedAnswer === currentCard.word ? '正確!' : '錯誤!'}
|
||||
</p>
|
||||
{selectedAnswer !== currentCard.translation && (
|
||||
{selectedAnswer !== currentCard.word && (
|
||||
<p className="text-gray-700 mt-2">
|
||||
正確答案是:{currentCard.translation}
|
||||
正確答案是:<strong>{currentCard.word}</strong>
|
||||
</p>
|
||||
)}
|
||||
<div className="mt-3 text-center">
|
||||
<p className="text-gray-600 text-sm mb-2">
|
||||
翻譯:{currentCard.translation}
|
||||
</p>
|
||||
<AudioPlayer text={currentCard.word} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Navigation */}
|
||||
<div className="flex justify-between mt-8">
|
||||
<button
|
||||
onClick={handlePrevious}
|
||||
disabled={currentCardIndex === 0}
|
||||
className="px-4 py-2 bg-gray-500 text-white rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-600 transition-colors"
|
||||
>
|
||||
上一張
|
||||
</button>
|
||||
<button
|
||||
onClick={handleNext}
|
||||
className="px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary-dark transition-colors"
|
||||
>
|
||||
{currentCardIndex === cards.length - 1 ? '完成' : '下一張'}
|
||||
</button>
|
||||
</div>
|
||||
{/* Navigation */}
|
||||
<div className="flex gap-4 mt-6">
|
||||
<button
|
||||
onClick={handlePrevious}
|
||||
disabled={currentCardIndex === 0}
|
||||
className="flex-1 py-3 bg-gray-500 text-white rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-600 transition-colors font-medium"
|
||||
>
|
||||
上一張
|
||||
</button>
|
||||
<button
|
||||
onClick={handleNext}
|
||||
className="flex-1 py-3 bg-primary text-white rounded-lg hover:bg-primary-dark transition-colors font-medium"
|
||||
>
|
||||
{currentCardIndex === cards.length - 1 ? '完成' : '下一張'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : mode === 'fill' ? (
|
||||
|
|
@ -634,23 +630,23 @@ export default function LearnPage() {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Navigation */}
|
||||
<div className="flex justify-between mt-8">
|
||||
<button
|
||||
onClick={handlePrevious}
|
||||
disabled={currentCardIndex === 0}
|
||||
className="px-4 py-2 bg-gray-500 text-white rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-600 transition-colors"
|
||||
>
|
||||
上一張
|
||||
</button>
|
||||
<button
|
||||
onClick={handleNext}
|
||||
className="px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary-dark transition-colors"
|
||||
>
|
||||
{currentCardIndex === cards.length - 1 ? '完成' : '下一張'}
|
||||
</button>
|
||||
</div>
|
||||
{/* Navigation */}
|
||||
<div className="flex gap-4 mt-6">
|
||||
<button
|
||||
onClick={handlePrevious}
|
||||
disabled={currentCardIndex === 0}
|
||||
className="flex-1 py-3 bg-gray-500 text-white rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-600 transition-colors font-medium"
|
||||
>
|
||||
上一張
|
||||
</button>
|
||||
<button
|
||||
onClick={handleNext}
|
||||
className="flex-1 py-3 bg-primary text-white rounded-lg hover:bg-primary-dark transition-colors font-medium"
|
||||
>
|
||||
{currentCardIndex === cards.length - 1 ? '完成' : '下一張'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : mode === 'listening' ? (
|
||||
|
|
@ -744,23 +740,23 @@ export default function LearnPage() {
|
|||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Navigation */}
|
||||
<div className="flex justify-between mt-8">
|
||||
<button
|
||||
onClick={handlePrevious}
|
||||
disabled={currentCardIndex === 0}
|
||||
className="px-4 py-2 bg-gray-500 text-white rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-600 transition-colors"
|
||||
>
|
||||
上一張
|
||||
</button>
|
||||
<button
|
||||
onClick={handleNext}
|
||||
className="px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary-dark transition-colors"
|
||||
>
|
||||
{currentCardIndex === cards.length - 1 ? '完成' : '下一張'}
|
||||
</button>
|
||||
</div>
|
||||
{/* Navigation */}
|
||||
<div className="flex gap-4 mt-6">
|
||||
<button
|
||||
onClick={handlePrevious}
|
||||
disabled={currentCardIndex === 0}
|
||||
className="flex-1 py-3 bg-gray-500 text-white rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-600 transition-colors font-medium"
|
||||
>
|
||||
上一張
|
||||
</button>
|
||||
<button
|
||||
onClick={handleNext}
|
||||
className="flex-1 py-3 bg-primary text-white rounded-lg hover:bg-primary-dark transition-colors font-medium"
|
||||
>
|
||||
{currentCardIndex === cards.length - 1 ? '完成' : '下一張'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : mode === 'speaking' ? (
|
||||
|
|
@ -839,23 +835,23 @@ export default function LearnPage() {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Navigation */}
|
||||
<div className="flex justify-between mt-8">
|
||||
<button
|
||||
onClick={handlePrevious}
|
||||
disabled={currentCardIndex === 0}
|
||||
className="px-4 py-2 bg-gray-500 text-white rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-600 transition-colors"
|
||||
>
|
||||
上一張
|
||||
</button>
|
||||
<button
|
||||
onClick={handleNext}
|
||||
className="px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary-dark transition-colors"
|
||||
>
|
||||
{currentCardIndex === cards.length - 1 ? '完成' : '下一張'}
|
||||
</button>
|
||||
</div>
|
||||
{/* Navigation */}
|
||||
<div className="flex gap-4 mt-6">
|
||||
<button
|
||||
onClick={handlePrevious}
|
||||
disabled={currentCardIndex === 0}
|
||||
className="flex-1 py-3 bg-gray-500 text-white rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-600 transition-colors font-medium"
|
||||
>
|
||||
上一張
|
||||
</button>
|
||||
<button
|
||||
onClick={handleNext}
|
||||
className="flex-1 py-3 bg-primary text-white rounded-lg hover:bg-primary-dark transition-colors font-medium"
|
||||
>
|
||||
{currentCardIndex === cards.length - 1 ? '完成' : '下一張'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
|
|
|||
Loading…
Reference in New Issue