// Projects index — filterable grid with animated re-layout function ProjectsIndex({ initialSector }) { const all = window.HORTON.projects; const sectors = window.HORTON.sectors; // read sector from hash query if provided const getSectorFromHash = () => { const m = window.location.hash.match(/sector=([\w-]+)/); return m ? m[1] : "all"; }; const [active, setActive] = useState(initialSector || getSectorFromHash()); const [hovered, setHovered] = useState(null); useEffect(() => { const onHash = () => setActive(getSectorFromHash()); window.addEventListener("hashchange", onHash); return () => window.removeEventListener("hashchange", onHash); }, []); const filtered = useMemo(() => active === "all" ? all : all.filter(p => p.sector === active), [active, all] ); // assign visual spans deterministically so layout is rich but stable const layoutFor = (idx) => { const cycle = idx % 6; if (cycle === 0) return "span-8"; if (cycle === 1) return "span-4"; if (cycle === 2) return "span-4"; if (cycle === 3) return "span-4"; if (cycle === 4) return "span-4"; return "span-8"; }; const onChip = (id) => { setActive(id); if (id === "all") { window.history.replaceState(null, "", "#/projects"); } else { window.history.replaceState(null, "", `#/projects?sector=${id}`); } }; return (
{/* Header */}
Projects index · 40+ named projects

Twelve years of commercial fit-out.

Workplace HQs, restaurants, retail, healthcare campuses and university interiors — designed, built and handed over by one team. Filter by sector below.

Showing
{filtered.length.toString().padStart(2, "0")}
of {all.length}
{[...all, ...all].map((p, i) => ( {p.name}· ))}
{/* Chips */}
{sectors.map(s => { const c = all.filter(p => p.sector === s.id).length; return ( ); })}
{/* Grid */}
{filtered.map((p, i) => ( setHovered(p.slug)} onMouseLeave={() => setHovered(null)} >
{p.name}
{p.name}
{p.year}
{p.sectorName} · {p.location} · {p.scope}
))}
{filtered.length === 0 && (
Nothing to show yet

This sector is named on our roster but not yet showcased here.
Get in touch and we'll send the full project list.

)}
); } window.ProjectsIndex = ProjectsIndex;