/* P.E.S.T Web App — Projects (multi-category filter + search + recently added + pin) */ function Projects({ onNavigate }) { const store = useStore(); const [cat, setCat] = useState("All"); const [q, setQ] = useState(""); const cats = ["All", "Pinned", ...window.PEST_APP.CATEGORIES]; const pinnedSet = new Set(store.user.pinned); const full = store.user.pinned.length >= window.PEST_APP.MAX_PINS; // Cats live as array on each project; fall back to legacy single `category` if present. const projCats = (p) => (p.categories && p.categories.length) ? p.categories : (p.category ? [p.category] : []); const filtered = store.projects.filter((p) => { const pc = projCats(p); const okCat = cat === "All" ? true : cat === "Pinned" ? pinnedSet.has(p.id) : pc.indexOf(cat) !== -1; const okQ = !q.trim() || (p.name + " " + (p.desc || "") + " " + pc.join(" ")).toLowerCase().includes(q.trim().toLowerCase()); return okCat && okQ; }); const recent = [...store.projects].sort((a, b) => b.addedAt - a.addedAt).slice(0, 6); const showShelf = cat === "All" && !q.trim(); const togglePin = (p) => { if (pinnedSet.has(p.id)) { store.unpinProject(p.id); toast(p.name + " unpinned"); } else if (full) { toast("Dashboard is full (" + window.PEST_APP.MAX_PINS + " max)", "err"); } else { store.pinProject(p.id); toast(p.name + " pinned to dashboard"); } }; return (
Curated by P.E.S.T. Pin the ones you use most — they orbit your dashboard for one-tap access ({store.user.pinned.length}/{window.PEST_APP.MAX_PINS} pinned).