71 lines
2.3 KiB
TypeScript
71 lines
2.3 KiB
TypeScript
import React from 'react'
|
|
import { ContentBlock } from '@/components/shared/ContentBlock'
|
|
import { compareCEFRLevels } from '@/lib/utils/cefrUtils'
|
|
|
|
interface IdiomAnalysis {
|
|
idiom: string
|
|
translation: string
|
|
meaning: string
|
|
cefrLevel?: string
|
|
frequency?: string
|
|
[key: string]: any
|
|
}
|
|
|
|
interface IdiomDisplaySectionProps {
|
|
idioms: IdiomAnalysis[]
|
|
onIdiomClick: (idiom: IdiomAnalysis, position: { x: number; y: number }) => void
|
|
className?: string
|
|
}
|
|
|
|
export const IdiomDisplaySection: React.FC<IdiomDisplaySectionProps> = ({
|
|
idioms,
|
|
onIdiomClick,
|
|
className = ''
|
|
}) => {
|
|
if (!idioms || idioms.length === 0) {
|
|
return null
|
|
}
|
|
|
|
const handleIdiomClick = (idiom: IdiomAnalysis, event: React.MouseEvent<HTMLSpanElement>) => {
|
|
const rect = event.currentTarget.getBoundingClientRect()
|
|
const position = {
|
|
x: rect.left + rect.width / 2,
|
|
y: rect.bottom + 10
|
|
}
|
|
onIdiomClick(idiom, position)
|
|
}
|
|
|
|
const shouldShowStar = (idiom: IdiomAnalysis) => {
|
|
const userLevel = localStorage.getItem('userEnglishLevel') || 'A2'
|
|
const isHighFrequency = idiom?.frequency === 'high'
|
|
const idiomCefr = idiom?.cefrLevel || 'A1'
|
|
const isNotSimpleIdiom = !compareCEFRLevels(userLevel, idiomCefr, '>')
|
|
|
|
return isHighFrequency && isNotSimpleIdiom
|
|
}
|
|
|
|
return (
|
|
<ContentBlock title="慣用語" variant="gray" className={className}>
|
|
<div className="flex flex-wrap gap-2">
|
|
{idioms.map((idiom: IdiomAnalysis, index: number) => (
|
|
<span
|
|
key={index}
|
|
className="cursor-pointer transition-all duration-200 rounded-lg relative mx-0.5 px-1 py-0.5 inline-flex items-center gap-1 bg-blue-50 border border-blue-200 hover:bg-blue-100 hover:shadow-lg transform hover:-translate-y-0.5 text-blue-700 font-medium"
|
|
onClick={(e) => handleIdiomClick(idiom, e)}
|
|
title={`${idiom.idiom}: ${idiom.translation}`}
|
|
>
|
|
{idiom.idiom}
|
|
{shouldShowStar(idiom) && (
|
|
<span
|
|
className="absolute -top-1 -right-1 text-xs pointer-events-none z-10"
|
|
style={{ fontSize: '8px', lineHeight: 1 }}
|
|
>
|
|
⭐
|
|
</span>
|
|
)}
|
|
</span>
|
|
))}
|
|
</div>
|
|
</ContentBlock>
|
|
)
|
|
} |