- Extract word type color logic into shared wordTypeColors.ts utility - Update TokenTray to use centralized color utility - Remove duplicate color logic from WordCard and SortableToken - Add color legend to Layout header for better UX - Simplify Znakopis page component
95 lines
3.0 KiB
TypeScript
95 lines
3.0 KiB
TypeScript
import { Info, Plus } from 'lucide-react';
|
|
import { Term, CefrLevel } from '../../types/term';
|
|
import { Button } from '../ui/button';
|
|
import { wordTypeColors, wordTypeLabels } from '../../lib/wordTypeColors';
|
|
|
|
interface WordCardProps {
|
|
term: Term;
|
|
onInfo: (term: Term) => void;
|
|
onAddToSentence?: (term: Term) => void;
|
|
}
|
|
|
|
const cefrColors: Record<CefrLevel, string> = {
|
|
[CefrLevel.A1]: 'bg-green-500',
|
|
[CefrLevel.A2]: 'bg-green-400',
|
|
[CefrLevel.B1]: 'bg-yellow-500',
|
|
[CefrLevel.B2]: 'bg-yellow-400',
|
|
[CefrLevel.C1]: 'bg-orange-500',
|
|
[CefrLevel.C2]: 'bg-red-500',
|
|
};
|
|
|
|
export function WordCard({ term, onInfo, onAddToSentence }: WordCardProps) {
|
|
const videoMedia = term.media?.find(m => m.kind === 'VIDEO');
|
|
const imageMedia = term.media?.find(m => m.kind === 'IMAGE' || m.kind === 'ILLUSTRATION');
|
|
|
|
return (
|
|
<div className="bg-white rounded-lg shadow hover:shadow-lg transition-shadow p-4 flex flex-col">
|
|
{/* CEFR Level Indicator */}
|
|
<div className="flex justify-between items-start mb-3">
|
|
<span className={`${cefrColors[term.cefrLevel]} text-white text-xs font-bold px-2 py-1 rounded`}>
|
|
{term.cefrLevel}
|
|
</span>
|
|
<span className="text-xs text-gray-500">
|
|
{wordTypeLabels[term.wordType] || term.wordType}
|
|
</span>
|
|
</div>
|
|
|
|
{/* Icon/Image */}
|
|
<div className="flex-1 flex items-center justify-center mb-4 min-h-[120px]">
|
|
{imageMedia ? (
|
|
<img
|
|
src={imageMedia.url}
|
|
alt={term.wordText}
|
|
className="max-h-[120px] max-w-full object-contain"
|
|
/>
|
|
) : videoMedia ? (
|
|
<div className="w-full h-[120px] bg-gray-100 rounded flex items-center justify-center">
|
|
<span className="text-gray-400 text-sm">Video</span>
|
|
</div>
|
|
) : (
|
|
<div className="w-full h-[120px] bg-gray-100 rounded flex items-center justify-center">
|
|
<span className="text-4xl">📝</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Word Text with colored background based on word type */}
|
|
<div className={`${wordTypeColors[term.wordType] || 'bg-gray-600'} text-white text-lg font-semibold px-4 py-2 rounded text-center mb-3`}>
|
|
{term.wordText}
|
|
</div>
|
|
|
|
{/* Short Description */}
|
|
{term.shortDescription && (
|
|
<p className="text-sm text-gray-600 text-center mb-4 line-clamp-2">
|
|
{term.shortDescription}
|
|
</p>
|
|
)}
|
|
|
|
{/* Actions - Dodaj on left, Info on right */}
|
|
<div className="flex gap-2 mt-auto">
|
|
{onAddToSentence && (
|
|
<Button
|
|
variant="default"
|
|
size="sm"
|
|
className="flex-1"
|
|
onClick={() => onAddToSentence(term)}
|
|
>
|
|
<Plus className="h-4 w-4 mr-1" />
|
|
Dodaj
|
|
</Button>
|
|
)}
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
className="flex-1"
|
|
onClick={() => onInfo(term)}
|
|
>
|
|
<Info className="h-4 w-4 mr-1" />
|
|
Info
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|