更新至 v0.6.0_20251125 版本
This commit is contained in:
@@ -1,10 +1,8 @@
|
||||
|
||||
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { Language, ListeningLesson, ListeningLessonRecord, ReadingDifficulty, ChatMessage, Role, MessageType } from '../types';
|
||||
import { geminiService, decodeAudioData } from '../services/geminiService';
|
||||
import { processAndDownloadAudio } from '../utils/audioUtils';
|
||||
import { Headphones, Loader2, Send, Eye, EyeOff, List, HelpCircle, ChevronLeft, History, Trash2, X, PanelRightClose, PanelRightOpen, Volume2, Square, Play, Pause, CheckCircle, AlertCircle, FileText, MessageCircle, Download, RotateCcw } from 'lucide-react';
|
||||
import { Headphones, Loader2, Send, Eye, EyeOff, List, HelpCircle, ChevronLeft, History, Trash2, X, PanelRightClose, PanelRightOpen, Volume2, Square, Play, Pause, CheckCircle, AlertCircle, FileText, MessageCircle, Download, RotateCcw, Copy, Check } from 'lucide-react';
|
||||
import { translations } from '../utils/localization';
|
||||
import ChatBubble from '../components/ChatBubble';
|
||||
|
||||
@@ -17,6 +15,28 @@ interface ListeningViewProps {
|
||||
onDeleteHistoryItem: (id: string) => void;
|
||||
}
|
||||
|
||||
// Internal Copy Button Component
|
||||
const CopyButton: React.FC<{ text: string; label?: string }> = ({ text, label }) => {
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const handleCopy = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
navigator.clipboard.writeText(text);
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={handleCopy}
|
||||
className="p-1.5 rounded-lg text-slate-400 hover:bg-slate-100 hover:text-slate-600 transition-colors flex items-center gap-1"
|
||||
title={label || "Copy"}
|
||||
>
|
||||
{copied ? <Check size={16} className="text-emerald-500" /> : <Copy size={16} />}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
const ListeningView: React.FC<ListeningViewProps> = ({ language, history, onSaveToHistory, onUpdateHistory, onClearHistory, onDeleteHistoryItem }) => {
|
||||
const t = translations[language].listening;
|
||||
const tCommon = translations[language].common;
|
||||
@@ -603,15 +623,21 @@ const ListeningView: React.FC<ListeningViewProps> = ({ language, history, onSave
|
||||
{/* Script Reveal */}
|
||||
{showScript && (
|
||||
<div className="animate-fade-in-up">
|
||||
<div className="bg-white p-6 md:p-8 rounded-2xl border border-slate-200 shadow-sm mb-6">
|
||||
<h4 className="text-xs font-bold text-slate-400 uppercase tracking-wider mb-4">{t.scriptTitle}</h4>
|
||||
<div className="bg-white p-6 md:p-8 rounded-2xl border border-slate-200 shadow-sm mb-6 relative">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h4 className="text-xs font-bold text-slate-400 uppercase tracking-wider">{t.scriptTitle}</h4>
|
||||
<CopyButton text={lesson.script || ''} label={tCommon.copy} />
|
||||
</div>
|
||||
<p className="text-lg md:text-xl leading-loose font-serif text-slate-800 whitespace-pre-wrap">
|
||||
{lesson.script || <span className="text-red-400 italic">{t.scriptMissing}</span>}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-slate-50 p-6 rounded-2xl border border-slate-200 mb-6">
|
||||
<h4 className="text-xs font-bold text-slate-400 uppercase tracking-wider mb-2">{translations[language].reading.translationLabel}</h4>
|
||||
<div className="bg-slate-50 p-6 rounded-2xl border border-slate-200 mb-6 relative">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h4 className="text-xs font-bold text-slate-400 uppercase tracking-wider">{translations[language].reading.translationLabel}</h4>
|
||||
<CopyButton text={lesson.translation || ''} label={tCommon.copy} />
|
||||
</div>
|
||||
<p className="text-slate-700 leading-relaxed">{lesson.translation}</p>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user