ux: 優化學習頁面用戶體驗和互動設計
- 修正翻卡模式卡片翻轉動畫和版面配置 - 改善選擇題模式答案顯示和回饋機制 - 優化語音錄音組件狀態管理 - 加強用戶交互體驗和視覺回饋 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
da85bb8f42
commit
31e3fe9fa8
File diff suppressed because it is too large
Load Diff
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import { useState, useRef, useCallback, useEffect } from 'react';
|
||||
import { Mic, Square, Play, Upload } from 'lucide-react';
|
||||
import AudioPlayer from './AudioPlayer';
|
||||
|
||||
export interface PronunciationScore {
|
||||
overall: number;
|
||||
|
|
@ -21,6 +22,8 @@ export interface PhonemeScore {
|
|||
|
||||
export interface VoiceRecorderProps {
|
||||
targetText: string;
|
||||
targetTranslation?: string;
|
||||
exampleImage?: string;
|
||||
onScoreReceived?: (score: PronunciationScore) => void;
|
||||
onRecordingComplete?: (audioBlob: Blob) => void;
|
||||
maxDuration?: number;
|
||||
|
|
@ -30,6 +33,8 @@ export interface VoiceRecorderProps {
|
|||
|
||||
export default function VoiceRecorder({
|
||||
targetText,
|
||||
targetTranslation,
|
||||
exampleImage,
|
||||
onScoreReceived,
|
||||
onRecordingComplete,
|
||||
maxDuration = 30, // 30 seconds default
|
||||
|
|
@ -233,20 +238,44 @@ export default function VoiceRecorder({
|
|||
}, [audioUrl]);
|
||||
|
||||
return (
|
||||
<div className={`voice-recorder p-6 border-2 border-dashed border-gray-300 rounded-xl ${className}`}>
|
||||
<div className={`voice-recorder ${className}`}>
|
||||
{/* 隱藏的音頻元素 */}
|
||||
<audio ref={audioRef} />
|
||||
|
||||
{/* 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>
|
||||
)}
|
||||
|
||||
{/* 目標文字顯示 */}
|
||||
<div className="text-center mb-6">
|
||||
<h3 className="text-lg font-semibold mb-2">請朗讀以下內容:</h3>
|
||||
<p className="text-2xl font-medium text-gray-800 p-4 bg-blue-50 rounded-lg">
|
||||
{targetText}
|
||||
</p>
|
||||
<div className="mb-6">
|
||||
<div className="p-4 bg-gray-50 rounded-lg">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="flex-1">
|
||||
<div className="text-gray-800 text-lg mb-2">{targetText}</div>
|
||||
{targetTranslation && (
|
||||
<div className="text-gray-600 text-base">{targetTranslation}</div>
|
||||
)}
|
||||
</div>
|
||||
<AudioPlayer
|
||||
text={targetText}
|
||||
className="flex-shrink-0 mt-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 錄音控制區 */}
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
<div className="p-6 border-2 border-dashed border-gray-300 rounded-xl">
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
{/* 錄音按鈕 */}
|
||||
<button
|
||||
onClick={isRecording ? stopRecording : startRecording}
|
||||
|
|
@ -360,6 +389,7 @@ export default function VoiceRecorder({
|
|||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue