import { useMemo, useState } from 'react'; import type { VocabularyEntry } from '../../types/stats'; import { PosBadge } from './pos-helpers'; interface WordListProps { words: VocabularyEntry[]; selectedKey?: string | null; onSelectWord?: (word: VocabularyEntry) => void; search?: string; } type SortKey = 'frequency' | 'lastSeen' | 'firstSeen'; function toWordKey(word: VocabularyEntry): string { return `${word.headword}\u0000${word.word}\u0000${word.reading}`; } const PAGE_SIZE = 100; export function WordList({ words, selectedKey = null, onSelectWord, search = '' }: WordListProps) { const [sortBy, setSortBy] = useState('frequency'); const [page, setPage] = useState(0); const titleBySort: Record = { frequency: 'Most Seen Words', lastSeen: 'Recently Seen Words', firstSeen: 'First Seen Words', }; const filtered = useMemo(() => { const needle = search.trim().toLowerCase(); if (!needle) return words; return words.filter( (w) => w.headword.toLowerCase().includes(needle) || w.word.toLowerCase().includes(needle) || w.reading.toLowerCase().includes(needle), ); }, [words, search]); const sorted = useMemo(() => { const copy = [...filtered]; if (sortBy === 'frequency') copy.sort((a, b) => b.frequency - a.frequency); else if (sortBy === 'lastSeen') copy.sort((a, b) => b.lastSeen - a.lastSeen); else copy.sort((a, b) => b.firstSeen - a.firstSeen); return copy; }, [filtered, sortBy]); const totalPages = Math.ceil(sorted.length / PAGE_SIZE); const paged = sorted.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE); const maxFreq = words.reduce((max, word) => Math.max(max, word.frequency), 1); const getFrequencyColor = (freq: number) => { const ratio = freq / maxFreq; if (ratio > 0.5) return 'text-ctp-blue bg-ctp-blue/10'; if (ratio > 0.2) return 'text-ctp-green bg-ctp-green/10'; return 'text-ctp-mauve bg-ctp-mauve/10'; }; return (

{titleBySort[sortBy]} {search && ( ({filtered.length} matches) )}

{paged.map((w) => ( ))}
{totalPages > 1 && (
{page + 1} / {totalPages}
)}
); } export { toWordKey };