dramaling-vocab-learning/frontend/hooks/word/useWordAnalysis.ts

87 lines
2.8 KiB
TypeScript

import { useMemo, useCallback } from 'react'
import { getCEFRColor } from '@/lib/utils/flashcardUtils'
import type { WordAnalysis } from '@/lib/types/word'
export function useWordAnalysis() {
const getWordProperty = useCallback((analysis: WordAnalysis, property: keyof WordAnalysis, fallback: any = 'N/A') => {
if (!analysis) return fallback
const value = analysis[property]
if (value === undefined || value === null || value === '') {
return fallback
}
if (Array.isArray(value) && value.length === 0) {
return fallback
}
return value
}, [])
const findWordAnalysis = useCallback((word: string, analysis: Record<string, WordAnalysis> = {}) => {
const cleanWord = word.toLowerCase().replace(/[^\w]/g, '')
const directMatch = analysis[word] || analysis[cleanWord]
if (directMatch) return directMatch
const keys = Object.keys(analysis)
const matchKey = keys.find(key =>
key.toLowerCase().replace(/[^\w]/g, '') === cleanWord
)
return matchKey ? analysis[matchKey] : null
}, [])
const getWordClass = useCallback((word: string, analysis: Record<string, WordAnalysis> = {}) => {
const wordAnalysis = findWordAnalysis(word, analysis)
if (!wordAnalysis) return 'cursor-default text-gray-900'
// 基礎按鈕樣式 - 類似慣用語區塊
let classes = 'cursor-pointer transition-all duration-200 rounded px-1 py-0.5 border font-medium hover:shadow-md transform hover:-translate-y-0.5 '
if (wordAnalysis.isIdiom) {
classes += 'bg-purple-50 text-purple-700 border-purple-200 hover:bg-purple-100'
} else {
// 根據 CEFR 等級設置顏色主題
const cefr = wordAnalysis.cefr || 'A1'
switch (cefr) {
case 'A1':
case 'A2':
classes += 'bg-green-50 text-green-700 border-green-200 hover:bg-green-100'
break
case 'B1':
case 'B2':
classes += 'bg-blue-50 text-blue-700 border-blue-200 hover:bg-blue-100'
break
case 'C1':
case 'C2':
classes += 'bg-red-50 text-red-700 border-red-200 hover:bg-red-100'
break
default:
classes += 'bg-gray-50 text-gray-700 border-gray-200 hover:bg-gray-100'
}
}
return classes
}, [findWordAnalysis])
const shouldShowStar = useCallback((analysis: WordAnalysis) => {
if (!analysis) return false
const conditions = [
analysis.isHighValue,
analysis.learningPriority === 'high',
analysis.cefr && ['B2', 'C1', 'C2'].includes(analysis.cefr),
analysis.frequency === 'high'
]
return conditions.some(Boolean)
}, [])
return {
getWordProperty,
findWordAnalysis,
getWordClass,
shouldShowStar
}
}