// 08 — Grid de noticias con filtros y buscador function CNews() { const [, t] = window.useLang(); const [filter, setFilter] = React.useState(0); const [q, setQ] = React.useState(''); const [open, setOpen] = React.useState(null); React.useEffect(() => { if (open == null) return; const onKey = (e) => { if (e.key === 'Escape') setOpen(null); }; document.body.style.overflow = 'hidden'; window.addEventListener('keydown', onKey); return () => { document.body.style.overflow = ''; window.removeEventListener('keydown', onKey); }; }, [open]); const filterKeys = ['all', 'jornadas', 'investigacion', 'divulgacion', 'convocatorias']; const items = t.news.items; const filtered = items.filter(it => { const matchesFilter = filter === 0 || it.k === filterKeys[filter]; const matchesQ = !q || (it.t + ' ' + it.place).toLowerCase().includes(q.toLowerCase()); return matchesFilter && matchesQ; }); const colorFor = (k) => ({ jornadas: 'var(--c-green-deep)', investigacion: 'var(--c-aubergine)', divulgacion: 'var(--c-saffron)', convocatorias: 'var(--c-red)', }[k] || 'var(--c-ink)'); return (
{t.news.kicker}

{t.news.title}

setQ(e.target.value)} />
{t.news.filters.map((f, i) => ( ))}
{filtered.length === 0 ? (
{t.news.empty}
) : (
{filtered.map((it, i) => ( ))}
)} {open && (
setOpen(null)} role="dialog" aria-modal="true">
e.stopPropagation()}> {open.img &&
}
{open.c}

{open.t}

{open.d} · {open.place}
{(open.body || '').split('\n\n').map((p, i) => (

{p}

))}
)}
); } window.CNews = CNews;