refactor: 優化例句口說功能設計與用戶體驗
## VoiceRecorder 組件改進 - 添加自定義說明文字 prop (instructionText) - 調整布局順序:圖片 → 說明 → 例句 - 統一圖片容器樣式與其他模式一致 ## 例句口說頁面優化 - 移除重複的例句和圖片顯示 - 簡化錄音完成回饋區域 - 移除不必要的目標單字和發音顯示 - 調整回饋訊息為分行顯示,提升可讀性 - 實現滿版寬度布局 ## 用戶體驗改進 - 消除重複內容,介面更簡潔 - 統一設計語言,視覺一致性更好 - 優化訊息層次,重點更突出 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
7203346134
commit
d1c5f2e31c
|
|
@ -937,42 +937,12 @@ export default function LearnPage() {
|
|||
</span>
|
||||
</div>
|
||||
|
||||
{/* 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="space-y-4 mb-8">
|
||||
{/* Example Sentence */}
|
||||
<div className="bg-gray-50 rounded-lg p-4">
|
||||
<h3 className="font-semibold text-gray-900 mb-2 text-left">例句</h3>
|
||||
<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>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="max-w-md mx-auto">
|
||||
<div className="w-full">
|
||||
<VoiceRecorder
|
||||
targetText={currentCard.example}
|
||||
targetTranslation={currentCard.exampleTranslation}
|
||||
exampleImage={currentCard.exampleImage}
|
||||
instructionText="請看例句圖片並大聲說出完整的例句:"
|
||||
onRecordingComplete={() => {
|
||||
// 簡化處理:直接顯示結果
|
||||
handleSpeakingAnswer(currentCard.example)
|
||||
|
|
@ -981,21 +951,13 @@ export default function LearnPage() {
|
|||
</div>
|
||||
|
||||
{showResult && (
|
||||
<div className="mt-6 p-4 rounded-lg bg-blue-50 border border-blue-200 max-w-md mx-auto">
|
||||
<p className="text-blue-700 text-center">
|
||||
錄音完成!系統正在評估你的發音...
|
||||
<div className="mt-6 p-6 rounded-lg bg-blue-50 border border-blue-200 w-full">
|
||||
<p className="text-blue-700 text-left text-xl font-semibold mb-2">
|
||||
錄音完成!
|
||||
</p>
|
||||
<p className="text-gray-600 text-left">
|
||||
系統正在評估你的發音...
|
||||
</p>
|
||||
<div className="mt-4 text-center">
|
||||
<p className="text-gray-700">
|
||||
目標單字:<strong>{currentCard.word}</strong>
|
||||
</p>
|
||||
<p className="text-gray-600 mt-1">
|
||||
發音:{currentCard.pronunciation}
|
||||
</p>
|
||||
<div className="mt-2">
|
||||
<AudioPlayer text={currentCard.word} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export interface VoiceRecorderProps {
|
|||
targetText: string;
|
||||
targetTranslation?: string;
|
||||
exampleImage?: string;
|
||||
instructionText?: string;
|
||||
onScoreReceived?: (score: PronunciationScore) => void;
|
||||
onRecordingComplete?: (audioBlob: Blob) => void;
|
||||
maxDuration?: number;
|
||||
|
|
@ -35,6 +36,7 @@ export default function VoiceRecorder({
|
|||
targetText,
|
||||
targetTranslation,
|
||||
exampleImage,
|
||||
instructionText,
|
||||
onScoreReceived,
|
||||
onRecordingComplete,
|
||||
maxDuration = 30, // 30 seconds default
|
||||
|
|
@ -245,13 +247,23 @@ export default function VoiceRecorder({
|
|||
{/* Example Image */}
|
||||
{exampleImage && (
|
||||
<div className="mb-4">
|
||||
<img
|
||||
src={exampleImage}
|
||||
alt="Example context"
|
||||
className="w-full rounded-lg shadow-md cursor-pointer hover:shadow-lg transition-shadow"
|
||||
style={{ maxHeight: '400px', objectFit: 'contain' }}
|
||||
/>
|
||||
<div className="text-xs text-gray-500 mt-2 text-center">點擊圖片可放大查看</div>
|
||||
<div className="bg-gray-50 rounded-lg p-4">
|
||||
<img
|
||||
src={exampleImage}
|
||||
alt="Example context"
|
||||
className="w-full max-w-md mx-auto rounded-lg cursor-pointer"
|
||||
style={{ maxHeight: '400px', objectFit: 'contain' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Instruction Text */}
|
||||
{instructionText && (
|
||||
<div className="mb-6">
|
||||
<p className="text-lg text-gray-700 text-left">
|
||||
{instructionText}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue