更新至 v0.6.0_20251125 版本
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { Language, ReadingLesson, ReadingDifficulty, ChatMessage, Role, MessageType, ReadingLessonRecord } from '../types';
|
||||
import { geminiService, decodeAudioData } from '../services/geminiService';
|
||||
import { processAndDownloadAudio } from '../utils/audioUtils';
|
||||
import { BookOpen, Loader2, Send, ToggleLeft, ToggleRight, List, HelpCircle, ChevronLeft, RotateCcw, History, Trash2, X, PanelRightClose, PanelRightOpen, Volume2, Square, MessageCircle, FileText, PenTool, Download } from 'lucide-react';
|
||||
import { BookOpen, Loader2, Send, ToggleLeft, ToggleRight, List, HelpCircle, ChevronLeft, RotateCcw, History, Trash2, X, PanelRightClose, PanelRightOpen, Volume2, Square, MessageCircle, FileText, PenTool, Download, Copy, Check } from 'lucide-react';
|
||||
import { translations } from '../utils/localization';
|
||||
import ChatBubble from '../components/ChatBubble';
|
||||
|
||||
@@ -15,6 +16,28 @@ interface ReadingViewProps {
|
||||
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 ReadingView: React.FC<ReadingViewProps> = ({ language, history, onSaveToHistory, onUpdateHistory, onClearHistory, onDeleteHistoryItem }) => {
|
||||
const t = translations[language].reading;
|
||||
const tCommon = translations[language].common;
|
||||
@@ -502,6 +525,9 @@ const ReadingView: React.FC<ReadingViewProps> = ({ language, history, onSaveToHi
|
||||
<span className="hidden sm:inline">{t.translationLabel}</span>
|
||||
</button>
|
||||
|
||||
{/* Copy Content Button - New */}
|
||||
<CopyButton text={lesson.japaneseContent || ''} label={tCommon.copy} />
|
||||
|
||||
{/* Sidebar Toggle In Lesson View */}
|
||||
<button
|
||||
onClick={() => setIsHistoryOpen(!isHistoryOpen)}
|
||||
@@ -524,26 +550,31 @@ const ReadingView: React.FC<ReadingViewProps> = ({ language, history, onSaveToHi
|
||||
</p>
|
||||
</div>
|
||||
{showTranslation && (
|
||||
<div className="mb-12 p-6 bg-slate-50 rounded-2xl border border-slate-200 animate-scale-in">
|
||||
<h4 className="text-xs font-bold text-slate-400 uppercase mb-3">{t.translationLabel}</h4>
|
||||
<div className="mb-12 p-6 bg-slate-50 rounded-2xl border border-slate-200 animate-scale-in relative">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h4 className="text-xs font-bold text-slate-400 uppercase">{t.translationLabel}</h4>
|
||||
<CopyButton text={lesson.translation || ''} label={tCommon.copy} />
|
||||
</div>
|
||||
<p className="text-lg leading-relaxed text-slate-600">{lesson.translation || <span className="text-slate-400 italic">{t.translationMissing}</span>}</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="bg-emerald-50/50 rounded-2xl p-6 border border-emerald-100/50 animate-fade-in-up delay-300">
|
||||
|
||||
{/* Vocabulary Section */}
|
||||
<div className="bg-white rounded-2xl p-6 border border-slate-200 shadow-sm animate-fade-in-up delay-300">
|
||||
<h4 className="text-sm font-bold text-emerald-800 mb-4 flex items-center gap-2">
|
||||
<List size={18} /> {t.vocabTitle}
|
||||
</h4>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{lesson.vocabulary?.map((v, i) => (
|
||||
<div key={i} className="bg-white p-3 rounded-xl shadow-sm border border-emerald-100 hover:shadow-md transition-shadow relative group">
|
||||
<div className="flex items-baseline justify-between mb-1">
|
||||
<div className="flex items-baseline gap-2">
|
||||
<div key={i} className="bg-emerald-50 p-3 rounded-xl border border-emerald-100 flex flex-col group relative">
|
||||
<div className="flex justify-between items-start mb-1">
|
||||
<div className="flex flex-wrap items-baseline gap-x-2 gap-y-0">
|
||||
<span className="text-lg font-bold text-slate-800">{v.word}</span>
|
||||
<span className="text-sm text-slate-500">({v.reading})</span>
|
||||
{v.reading && <span className="text-sm text-slate-500">({v.reading})</span>}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => playVocab(v.word)}
|
||||
className={`p-1.5 rounded-full transition-colors ${playingVocabWord === v.word ? 'bg-pink-100 text-pink-500' : 'text-slate-300 hover:bg-emerald-50 hover:text-emerald-600'}`}
|
||||
className={`p-1.5 rounded-full transition-colors flex-shrink-0 ml-2 ${playingVocabWord === v.word ? 'bg-pink-100 text-pink-500' : 'text-emerald-300 hover:bg-emerald-100 hover:text-emerald-600'}`}
|
||||
>
|
||||
{playingVocabWord === v.word ? <Loader2 size={14} className="animate-spin" /> : <Volume2 size={14} />}
|
||||
</button>
|
||||
@@ -556,13 +587,13 @@ const ReadingView: React.FC<ReadingViewProps> = ({ language, history, onSaveToHi
|
||||
|
||||
{/* Grammar Section */}
|
||||
{lesson.grammarPoints && lesson.grammarPoints.length > 0 && (
|
||||
<div className="bg-emerald-50/50 rounded-2xl p-6 border border-emerald-100/50 animate-fade-in-up delay-400 mt-6">
|
||||
<div className="bg-white rounded-2xl p-6 border border-slate-200 shadow-sm animate-fade-in-up delay-400 mt-6">
|
||||
<h4 className="text-sm font-bold text-emerald-800 mb-4 flex items-center gap-2">
|
||||
<PenTool size={18} /> {t.grammarHeader}
|
||||
</h4>
|
||||
<div className="space-y-4">
|
||||
{lesson.grammarPoints.map((g, i) => (
|
||||
<div key={i} className="bg-white p-4 rounded-xl border border-emerald-100">
|
||||
<div key={i} className="bg-emerald-50/50 p-4 rounded-xl border border-emerald-100">
|
||||
<h5 className="font-bold text-emerald-900 mb-1">{g.point}</h5>
|
||||
<p className="text-sm text-emerald-700 leading-relaxed">{g.explanation}</p>
|
||||
</div>
|
||||
@@ -642,4 +673,4 @@ const ReadingView: React.FC<ReadingViewProps> = ({ language, history, onSaveToHi
|
||||
);
|
||||
};
|
||||
|
||||
export default ReadingView;
|
||||
export default ReadingView;
|
||||
|
||||
Reference in New Issue
Block a user