87 lines
4.0 KiB
TypeScript
87 lines
4.0 KiB
TypeScript
import React from 'react'
|
|
import type { Flashcard } from '@/lib/services/flashcards'
|
|
import { getPartOfSpeechDisplay, getCEFRColor } from '@/lib/utils/flashcardUtils'
|
|
import { TTSButton } from '@/components/shared/TTSButton'
|
|
|
|
interface FlashcardDetailHeaderProps {
|
|
flashcard: Flashcard
|
|
isPlayingWord: boolean
|
|
isPlayingExample: boolean
|
|
onToggleWordTTS: (text: string, lang?: string) => void
|
|
}
|
|
|
|
export const FlashcardDetailHeader: React.FC<FlashcardDetailHeaderProps> = ({
|
|
flashcard,
|
|
isPlayingWord,
|
|
isPlayingExample,
|
|
onToggleWordTTS
|
|
}) => {
|
|
return (
|
|
<div className="bg-gradient-to-br from-blue-50 to-indigo-50 p-6 border-b border-blue-200">
|
|
<div className="pr-16">
|
|
<h1 className="text-4xl font-bold text-gray-900 mb-3">{flashcard.word}</h1>
|
|
<div className="flex items-center gap-3">
|
|
<span className="text-sm bg-gray-100 text-gray-700 px-3 py-1 rounded-full">
|
|
{getPartOfSpeechDisplay(flashcard.partOfSpeech)}
|
|
</span>
|
|
<span className="text-lg text-gray-600">{flashcard.pronunciation}</span>
|
|
|
|
{/* TTS播放按鈕 - 使用新的TTSButton組件 */}
|
|
<button
|
|
onClick={() => onToggleWordTTS(flashcard.word, 'en-US')}
|
|
disabled={isPlayingExample}
|
|
title={isPlayingWord ? "點擊停止播放" : "點擊聽詞彙發音"}
|
|
aria-label={isPlayingWord ? `停止播放詞彙:${flashcard.word}` : `播放詞彙發音:${flashcard.word}`}
|
|
className={`group relative w-12 h-12 rounded-full shadow-lg transform transition-all duration-200
|
|
${isPlayingWord
|
|
? 'bg-gradient-to-br from-green-500 to-green-600 shadow-green-200 scale-105'
|
|
: 'bg-gradient-to-br from-blue-500 to-blue-600 hover:shadow-xl hover:scale-105 shadow-blue-200'
|
|
} ${isPlayingExample ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'}
|
|
`}
|
|
>
|
|
{/* 播放中波紋效果 */}
|
|
{isPlayingWord && (
|
|
<div className="absolute inset-0 bg-blue-400 rounded-full animate-ping opacity-40"></div>
|
|
)}
|
|
|
|
{/* 按鈕圖標 */}
|
|
<div className="relative z-10 flex items-center justify-center w-full h-full">
|
|
{isPlayingWord ? (
|
|
<svg className="w-6 h-6 text-white" fill="currentColor" viewBox="0 0 24 24">
|
|
<path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z"/>
|
|
</svg>
|
|
) : (
|
|
<svg className="w-6 h-6 text-white group-hover:scale-110 transition-transform" fill="currentColor" viewBox="0 0 24 24">
|
|
<path d="M8 5v14l11-7z"/>
|
|
</svg>
|
|
)}
|
|
</div>
|
|
|
|
{/* 懸停提示光環 */}
|
|
{!isPlayingWord && !isPlayingExample && (
|
|
<div className="absolute inset-0 rounded-full bg-white opacity-0 group-hover:opacity-20 transition-opacity duration-200"></div>
|
|
)}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 學習統計 */}
|
|
<div className="grid grid-cols-3 gap-4 text-center mt-4">
|
|
<div className="bg-white bg-opacity-60 rounded-lg p-3">
|
|
<div className="text-2xl font-bold text-gray-900">{flashcard.masteryLevel}%</div>
|
|
<div className="text-sm text-gray-600">掌握程度</div>
|
|
</div>
|
|
<div className="bg-white bg-opacity-60 rounded-lg p-3">
|
|
<div className="text-2xl font-bold text-gray-900">{flashcard.timesReviewed}</div>
|
|
<div className="text-sm text-gray-600">複習次數</div>
|
|
</div>
|
|
<div className="bg-white bg-opacity-60 rounded-lg p-3">
|
|
<div className="text-2xl font-bold text-gray-900">
|
|
{Math.ceil((new Date(flashcard.nextReviewDate).getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24))}
|
|
</div>
|
|
<div className="text-sm text-gray-600">天後複習</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
} |