feat: 重構例句填空與例句重組功能
## 例句填空重大改進 - 實現真正的例句挖空功能,支援點擊輸入 - 添加例句圖片顯示,提供視覺化學習輔助 - 重新設計答案回饋為滿版左對齊布局 - 優化提示功能顯示詞彙定義而非字母提示 - 移除例句中文翻譯,專注於英文理解 ## 例句重組功能增強 - 添加例句圖片顯示功能 - 保持與例句填空一致的視覺設計 ## 其他優化 - 修復翻卡記憶標題置中問題 - 優化詞彙聽力模式,移除定義和翻譯干擾 - 統一所有測驗模式的標題和布局格式 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
a39ef4ba6f
commit
a20fa9004d
|
|
@ -391,16 +391,34 @@ export default function LearnPage() {
|
|||
<div className="card-front">
|
||||
<div
|
||||
ref={cardFrontRef}
|
||||
className="bg-white rounded-xl shadow-lg text-center cursor-pointer hover:shadow-xl transition-shadow"
|
||||
className="bg-white rounded-xl shadow-lg cursor-pointer hover:shadow-xl transition-shadow p-8"
|
||||
>
|
||||
<h2 className="text-4xl font-bold text-gray-900 mb-6">
|
||||
{currentCard.word}
|
||||
</h2>
|
||||
<div className="flex items-center justify-center gap-3">
|
||||
<span className="text-lg text-gray-500">
|
||||
{currentCard.pronunciation}
|
||||
{/* Title and Instructions */}
|
||||
<div className="flex justify-between items-start mb-6">
|
||||
<h2 className="text-2xl font-bold text-gray-900">
|
||||
翻卡記憶
|
||||
</h2>
|
||||
<span className="bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded-full">
|
||||
{currentCard.difficulty}
|
||||
</span>
|
||||
<AudioPlayer text={currentCard.word} />
|
||||
</div>
|
||||
<p className="text-lg text-gray-700 mb-2 text-left">
|
||||
點擊卡片翻面,根據你對單字的熟悉程度進行自我評估:
|
||||
</p>
|
||||
|
||||
{/* Word Display */}
|
||||
<div className="flex-1 flex items-center justify-center mt-6">
|
||||
<div className="bg-gray-50 rounded-lg p-8 w-full text-center">
|
||||
<h3 className="text-4xl font-bold text-gray-900 mb-6">
|
||||
{currentCard.word}
|
||||
</h3>
|
||||
<div className="flex items-center justify-center gap-3">
|
||||
<span className="text-lg text-gray-500">
|
||||
{currentCard.pronunciation}
|
||||
</span>
|
||||
<AudioPlayer text={currentCard.word} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -599,87 +617,124 @@ export default function LearnPage() {
|
|||
{currentCard.difficulty}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-lg text-gray-700 mb-2 text-left">
|
||||
請根據定義和翻譯,輸入對應的英文單字:
|
||||
</p>
|
||||
|
||||
<div className="text-center mb-8">
|
||||
<div className="bg-gray-50 rounded-lg p-6 mb-6">
|
||||
<p className="text-lg text-gray-700 mb-4">
|
||||
<strong>定義:</strong>{currentCard.definition}
|
||||
</p>
|
||||
<p className="text-lg text-gray-700">
|
||||
<strong>中文翻譯:</strong>{currentCard.translation}
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-lg text-gray-700 mb-4">
|
||||
請輸入對應的英文單字:
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="max-w-md mx-auto">
|
||||
<input
|
||||
type="text"
|
||||
value={fillAnswer}
|
||||
onChange={(e) => setFillAnswer(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' && !showResult && fillAnswer.trim()) {
|
||||
handleFillAnswer()
|
||||
}
|
||||
}}
|
||||
placeholder="輸入英文單字..."
|
||||
disabled={showResult}
|
||||
className="w-full p-4 text-center text-xl border-2 border-gray-200 rounded-lg focus:border-blue-500 focus:outline-none disabled:bg-gray-100"
|
||||
/>
|
||||
|
||||
<div className="flex gap-2 mt-4">
|
||||
{!showResult && fillAnswer.trim() && (
|
||||
<button
|
||||
onClick={handleFillAnswer}
|
||||
className="flex-1 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary-dark transition-colors"
|
||||
>
|
||||
確認答案
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => setShowHint(!showHint)}
|
||||
className="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600 transition-colors"
|
||||
>
|
||||
{showHint ? '隱藏提示' : '顯示提示'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{showHint && (
|
||||
<div className="mt-4 p-4 bg-yellow-50 border border-yellow-200 rounded-lg">
|
||||
<p className="text-yellow-800">
|
||||
<strong>提示:</strong>這個詞有 {currentCard.word.length} 個字母,
|
||||
開頭是 "{currentCard.word[0].toUpperCase()}"
|
||||
</p>
|
||||
{/* Example Image */}
|
||||
{currentCard.exampleImage && (
|
||||
<div className="mb-6">
|
||||
<div className="bg-gray-50 rounded-lg p-4">
|
||||
<img
|
||||
src={currentCard.exampleImage}
|
||||
alt="Example illustration"
|
||||
className="w-full max-w-md mx-auto rounded-lg cursor-pointer"
|
||||
onClick={() => setModalImage(currentCard.exampleImage)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<p className="text-lg text-gray-700 mb-2 text-left">
|
||||
請點擊例句中的空白處輸入正確的單字:
|
||||
</p>
|
||||
{/* Example Sentence with Blanks */}
|
||||
<div className="mb-6">
|
||||
<div className="bg-gray-50 rounded-lg p-6">
|
||||
<div className="text-lg text-gray-700 leading-relaxed">
|
||||
{currentCard.example.split(new RegExp(`(${currentCard.word})`, 'gi')).map((part, index) => {
|
||||
const isTargetWord = part.toLowerCase() === currentCard.word.toLowerCase();
|
||||
return isTargetWord ? (
|
||||
<span key={index} className="relative inline-block mx-1">
|
||||
<input
|
||||
type="text"
|
||||
value={fillAnswer}
|
||||
onChange={(e) => setFillAnswer(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' && !showResult && fillAnswer.trim()) {
|
||||
handleFillAnswer()
|
||||
}
|
||||
}}
|
||||
placeholder=""
|
||||
disabled={showResult}
|
||||
className={`inline-block px-2 py-1 text-center bg-transparent focus:outline-none disabled:bg-gray-100 ${
|
||||
fillAnswer
|
||||
? 'border-b-2 border-blue-500'
|
||||
: 'border-b-2 border-dashed border-gray-400 focus:border-blue-400 focus:border-solid'
|
||||
}`}
|
||||
style={{ width: `${Math.max(100, Math.max(currentCard.word.length * 12, fillAnswer.length * 12 + 20))}px` }}
|
||||
/>
|
||||
{!fillAnswer && (
|
||||
<span
|
||||
className="absolute inset-0 flex items-center justify-center text-gray-400 pointer-events-none"
|
||||
style={{ paddingBottom: '8px' }}
|
||||
>
|
||||
____
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
) : (
|
||||
<span key={index}>{part}</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<div className="flex gap-3 mb-4">
|
||||
{!showResult && fillAnswer.trim() && (
|
||||
<button
|
||||
onClick={handleFillAnswer}
|
||||
className="px-6 py-2 bg-primary text-white rounded-lg hover:bg-primary-dark transition-colors"
|
||||
>
|
||||
確認答案
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => setShowHint(!showHint)}
|
||||
className="px-6 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600 transition-colors"
|
||||
>
|
||||
{showHint ? '隱藏提示' : '顯示提示'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Hint Section */}
|
||||
{showHint && (
|
||||
<div className="mb-4 p-4 bg-yellow-50 border border-yellow-200 rounded-lg">
|
||||
<h4 className="font-semibold text-yellow-800 mb-2">詞彙定義:</h4>
|
||||
<p className="text-yellow-800">{currentCard.definition}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showResult && (
|
||||
<div className={`mt-6 p-4 rounded-lg max-w-md mx-auto ${
|
||||
<div className={`mt-6 p-6 rounded-lg w-full ${
|
||||
fillAnswer.toLowerCase().trim() === currentCard.word.toLowerCase()
|
||||
? 'bg-green-50 border border-green-200'
|
||||
: 'bg-red-50 border border-red-200'
|
||||
}`}>
|
||||
<p className={`font-semibold text-center ${
|
||||
<p className={`font-semibold text-left text-xl mb-4 ${
|
||||
fillAnswer.toLowerCase().trim() === currentCard.word.toLowerCase()
|
||||
? 'text-green-700'
|
||||
: 'text-red-700'
|
||||
}`}>
|
||||
{fillAnswer.toLowerCase().trim() === currentCard.word.toLowerCase() ? '正確!' : '錯誤!'}
|
||||
</p>
|
||||
|
||||
{fillAnswer.toLowerCase().trim() !== currentCard.word.toLowerCase() && (
|
||||
<p className="text-gray-700 mt-2 text-center">
|
||||
正確答案是:<strong>{currentCard.word}</strong>
|
||||
</p>
|
||||
<div className="mb-4">
|
||||
<p className="text-gray-700 text-left">
|
||||
正確答案是:<strong className="text-lg">{currentCard.word}</strong>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-4 text-center">
|
||||
<p className="text-gray-600 mb-2">發音:{currentCard.pronunciation}</p>
|
||||
<AudioPlayer text={currentCard.word} />
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="text-left">
|
||||
<p className="text-gray-600">
|
||||
<span className="mx-2">{currentCard.pronunciation}</span>
|
||||
<AudioPlayer text={currentCard.word} />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="text-left">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -732,23 +787,15 @@ export default function LearnPage() {
|
|||
請聽發音並選擇正確的英文單字:
|
||||
</p>
|
||||
|
||||
<div className="text-center mb-8">
|
||||
|
||||
<div className="bg-gray-50 rounded-lg p-6 mb-6">
|
||||
<p className="text-lg text-gray-700 mb-4">
|
||||
<strong>中文翻譯:</strong>{currentCard.translation}
|
||||
</p>
|
||||
<p className="text-lg text-gray-700">
|
||||
<strong>定義:</strong>{currentCard.definition}
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-lg text-gray-700 mb-6">
|
||||
請聽發音並選擇正確的英文單字:
|
||||
</p>
|
||||
<div className="mb-8">
|
||||
<AudioPlayer
|
||||
text={currentCard.word}
|
||||
/>
|
||||
{/* Content Sections */}
|
||||
<div className="space-y-4 mb-8">
|
||||
{/* Audio */}
|
||||
<div className="bg-gray-50 rounded-lg p-4">
|
||||
<h3 className="font-semibold text-gray-900 mb-2 text-left">發音</h3>
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-gray-700">{currentCard.pronunciation}</span>
|
||||
<AudioPlayer text={currentCard.word} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -1009,12 +1056,26 @@ export default function LearnPage() {
|
|||
{currentCard.difficulty}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-lg text-gray-700 mb-2 text-left">
|
||||
|
||||
|
||||
{/* Example Image */}
|
||||
{currentCard.exampleImage && (
|
||||
<div className="mb-6">
|
||||
<div className="bg-gray-50 rounded-lg p-4">
|
||||
<img
|
||||
src={currentCard.exampleImage}
|
||||
alt="Example illustration"
|
||||
className="w-full max-w-md mx-auto rounded-lg cursor-pointer"
|
||||
onClick={() => setModalImage(currentCard.exampleImage)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<p className="text-lg text-gray-700 mb-2 text-left">
|
||||
請將下方的單字重新排列成正確的句子:
|
||||
</p>
|
||||
|
||||
|
||||
<div className="text-center mb-8">
|
||||
|
||||
<div className="bg-gray-50 rounded-lg p-6 mb-6">
|
||||
<p className="text-lg text-gray-700 mb-4">
|
||||
<strong>詞彙:</strong>{currentCard.word}
|
||||
|
|
@ -1023,7 +1084,6 @@ export default function LearnPage() {
|
|||
<strong>翻譯:</strong>{currentCard.exampleTranslation}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="mb-6">
|
||||
|
|
@ -1174,8 +1234,8 @@ export default function LearnPage() {
|
|||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
padding: 2rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue