/* 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 (
Projects

The directory

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).

setQ(e.target.value)} />
{cats.map((c) => ( ))}
{showShelf && (
Recently added
{recent.map((p) => { const pc = projCats(p); return (
{p.name} {window.timeAgo(p.addedAt)} · {pc[0] || ""}
); })}
)} {filtered.length === 0 ? (
{cat === "Pinned" ? "No pinned projects yet — hit Pin on any project to add it here for one-tap access." : ("No projects match \"" + q + "\"" + (cat !== "All" ? " in " + cat : "") + ".")}
) : (
{filtered.map((p) => { const isPinned = pinnedSet.has(p.id); const links = Object.keys(p.links || {}).filter((k) => p.links[k]); const pc = projCats(p); return (

{p.name}

{pc.map((c) => {c})}

{p.desc}

{links.map((k) => { const meta = window.A_SOCIAL[k]; if (!meta) return null; const I = meta.icon; return ; })}
); })}
)}
); } window.Projects = Projects;