'use client' import { useState } from 'react' // 更新的詞彙分析介面 interface WordAnalysis { word: string translation: string definition: string partOfSpeech: string pronunciation: string synonyms: string[] antonyms?: string[] isPhrase: boolean isHighValue: boolean // 高學習價值標記 learningPriority: 'high' | 'medium' | 'low' // 學習優先級 phraseInfo?: { phrase: string meaning: string warning: string colorCode: string // 片語顏色代碼 } difficultyLevel: string costIncurred?: number // 點擊此詞彙的成本 } interface ClickableTextProps { text: string analysis?: Record highValueWords?: string[] // 高價值詞彙列表 phrasesDetected?: Array<{ phrase: string words: string[] colorCode: string }> onWordClick?: (word: string, analysis: WordAnalysis) => void onWordCostConfirm?: (word: string, cost: number) => Promise // 收費確認 remainingUsage?: number // 剩餘使用次數 } export function ClickableTextV2({ text, analysis, highValueWords = [], phrasesDetected = [], onWordClick, onWordCostConfirm, remainingUsage = 5 }: ClickableTextProps) { const [selectedWord, setSelectedWord] = useState(null) const [popupPosition, setPopupPosition] = useState({ x: 0, y: 0 }) const [showCostConfirm, setShowCostConfirm] = useState<{ word: string cost: number position: { x: number, y: number } } | null>(null) // 將文字分割成單字 const words = text.split(/(\s+|[.,!?;:])/g).filter(word => word.trim()) const handleWordClick = async (word: string, event: React.MouseEvent) => { const cleanWord = word.toLowerCase().replace(/[.,!?;:]/g, '') const wordAnalysis = analysis?.[cleanWord] if (wordAnalysis) { const rect = event.currentTarget.getBoundingClientRect() const position = { x: rect.left + rect.width / 2, y: rect.top - 10 } // 檢查是否為高價值詞彙(免費) if (wordAnalysis.isHighValue) { setPopupPosition(position) setSelectedWord(cleanWord) onWordClick?.(cleanWord, wordAnalysis) } else { // 低價值詞彙需要收費確認 setShowCostConfirm({ word: cleanWord, cost: 1, position }) } } } const handleCostConfirm = async () => { if (!showCostConfirm) return const confirmed = await onWordCostConfirm?.(showCostConfirm.word, showCostConfirm.cost) if (confirmed) { const wordAnalysis = analysis?.[showCostConfirm.word] if (wordAnalysis) { setPopupPosition(showCostConfirm.position) setSelectedWord(showCostConfirm.word) onWordClick?.(showCostConfirm.word, wordAnalysis) } } setShowCostConfirm(null) } const closePopup = () => { setSelectedWord(null) } const getWordClass = (word: string) => { const cleanWord = word.toLowerCase().replace(/[.,!?;:]/g, '') const wordAnalysis = analysis?.[cleanWord] if (!wordAnalysis) return "cursor-default" const baseClass = "cursor-pointer transition-all duration-200 rounded relative mx-0.5 px-1 py-0.5" // 高價值片語(黃色系) if (wordAnalysis.isHighValue && wordAnalysis.isPhrase) { return `${baseClass} bg-yellow-100 border-2 border-yellow-400 hover:bg-yellow-200 hover:shadow-sm transform hover:-translate-y-0.5` } // 高價值單字(綠色系) if (wordAnalysis.isHighValue && !wordAnalysis.isPhrase) { return `${baseClass} bg-green-100 border-2 border-green-400 hover:bg-green-200 hover:shadow-sm transform hover:-translate-y-0.5` } // 普通單字(藍色系) return `${baseClass} border-b border-blue-300 hover:bg-blue-100 hover:border-blue-400` } const renderWordWithStar = (word: string, className: string) => { const cleanWord = word.toLowerCase().replace(/[.,!?;:]/g, '') const wordAnalysis = analysis?.[cleanWord] const isHighValue = wordAnalysis?.isHighValue return ( handleWordClick(word, e)} > {word} {isHighValue && ( )} ) } return (
{/* 點擊區域遮罩 */} {selectedWord && (
)} {/* 文字內容 */}
{words.map((word, index) => { if (word.trim() === '') return {word} return renderWordWithStar(word, getWordClass(word)) })}
{/* 單字資訊彈窗 */} {selectedWord && analysis?.[selectedWord] && (
{/* 標題 */}

{analysis[selectedWord].word}

{/* 高價值標記 */} {analysis[selectedWord].isHighValue && (
高價值詞彙(免費查詢)
學習價值:{analysis[selectedWord].learningPriority === 'high' ? '⭐⭐⭐⭐⭐' : analysis[selectedWord].learningPriority === 'medium' ? '⭐⭐⭐' : '⭐'}
)} {/* 片語警告 */} {analysis[selectedWord].isPhrase && analysis[selectedWord].phraseInfo && (
⚠️
注意:這個單字屬於片語!
片語:{analysis[selectedWord].phraseInfo.phrase}
意思:{analysis[selectedWord].phraseInfo.meaning}
{analysis[selectedWord].phraseInfo.warning}
)} {/* 詞性和發音 */}
{analysis[selectedWord].partOfSpeech} {analysis[selectedWord].pronunciation}
{/* 翻譯 */}
翻譯
{analysis[selectedWord].translation}
{/* 定義 */}
定義
{analysis[selectedWord].definition}
{/* 同義詞 */} {analysis[selectedWord].synonyms.length > 0 && (
同義詞
{analysis[selectedWord].synonyms.map((synonym, idx) => ( {synonym} ))}
)} {/* 反義詞 */} {analysis[selectedWord].antonyms && analysis[selectedWord].antonyms.length > 0 && (
反義詞
{analysis[selectedWord].antonyms.map((antonym, idx) => ( {antonym} ))}
)} {/* 難度等級 */}
難度等級
CEFR {analysis[selectedWord].difficultyLevel} ({analysis[selectedWord].difficultyLevel === 'A1' || analysis[selectedWord].difficultyLevel === 'A2' ? '基礎' : analysis[selectedWord].difficultyLevel === 'B1' || analysis[selectedWord].difficultyLevel === 'B2' ? '中級' : '高級'})
)} {/* 收費確認對話框 */} {showCostConfirm && ( <>
setShowCostConfirm(null)} />

{showCostConfirm.word}

💰
低價值詞彙(需消耗額度)
此查詢將消耗 {showCostConfirm.cost} 次 使用額度
剩餘額度:{remainingUsage}
)}
) }