import { useState, useMemo, useCallback, useEffect } from 'react'; import type { CardData } from './types'; import cardDataRaw from '../card_data.json?raw'; import { AE_LABELS, MFL_LABELS, SDG_LABELS } from './data/labels'; import IconBar from './components/IconBar'; import IconColumn from './components/IconColumn'; import CardField from './components/CardField'; import CardFocusOverlay from './components/CardFocusOverlay'; import './styles/app.css'; const cards: CardData[] = JSON.parse(cardDataRaw); const AE_COUNT = 13; const MFL_COUNT = 12; const SDG_COUNT = 17; function matchesAll(card: CardData, selectedAE: Set, selectedMFL: Set, selectedSDG: Set): boolean { for (const v of selectedAE) if (!card.ae.includes(v)) return false; for (const v of selectedMFL) if (!card.mfl.includes(v)) return false; for (const v of selectedSDG) if (!card.sdgs.includes(v)) return false; return true; } export default function App() { const [selectedAE, setSelectedAE] = useState>(new Set()); const [selectedMFL, setSelectedMFL] = useState>(new Set()); const [selectedSDG, setSelectedSDG] = useState>(new Set()); const [focusedCardId, setFocusedCardId] = useState(null); useEffect(() => { const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') setFocusedCardId(null); }; window.addEventListener('keydown', handler); return () => window.removeEventListener('keydown', handler); }, []); const toggleSet = useCallback((value: number, set: Set, setter: (s: Set) => void) => { const next = new Set(set); if (next.has(value)) next.delete(value); else next.add(value); setter(next); setFocusedCardId(null); }, []); const filteredCards = useMemo(() => { const total = selectedAE.size + selectedMFL.size + selectedSDG.size; if (total === 0) return []; return cards.filter((c) => matchesAll(c, selectedAE, selectedMFL, selectedSDG)); }, [selectedAE, selectedMFL, selectedSDG]); const active = { ae: selectedAE.size > 0, mfl: selectedMFL.size > 0, sdg: selectedSDG.size > 0 }; const handleFocus = useCallback((id: number | null) => { setFocusedCardId(id); }, []); const focusedCard = focusedCardId !== null ? cards.find((c) => c.id === focusedCardId) ?? null : null; return (
{focusedCard && setFocusedCardId(null)} />}
toggleSet(v, selectedAE, setSelectedAE)} />
toggleSet(v, selectedSDG, setSelectedSDG)} />
toggleSet(v, selectedMFL, setSelectedMFL)} />
{active.ae ? 'AE' : ''} {active.mfl ? 'MFL' : ''} {active.sdg ? 'SDG' : ''} {filteredCards.length} cards
); }