// ============================================================ // Browse.html — filterable listing grid with sticky QC map. // Apple-Maps-meets-Airbnb-Explore: chips to filter, list+map split. // ============================================================ const ALL_TAGS = ["River View", "Patio", "Date Night", "Hidden Gem", "Free", "Live Music", "Family Friendly", "Outdoors"]; function Browse() { const initialCat = param("cat") || "all"; const [cat, setCat] = React.useState(initialCat); const [tag, setTag] = React.useState(null); const [sort, setSort] = React.useState("featured"); const [view, setView] = React.useState("grid"); // split | grid const [hover, setHover] = React.useState(null); const [dataVersion, setDataVersion] = React.useState(0); // Re-render when live data loads from fetch React.useEffect(() => { const handler = () => setDataVersion((v) => v + 1); window.addEventListener("qc:data-loaded", handler); return () => window.removeEventListener("qc:data-loaded", handler); }, []); const CATEGORIES = window.QC.CATEGORIES; const LISTINGS = window.QC.LISTINGS; let results = LISTINGS.filter((l) => (cat === "all" || l.categoryId === cat)); if (tag) results = results.filter((l) => l.tags.includes(tag)); if (sort === "az") results = [...results].sort((a, b) => a.name.localeCompare(b.name)); if (sort === "city") results = [...results].sort((a, b) => a.city.localeCompare(b.city)); const catName = cat === "all" ? "Everything" : (CATEGORIES.find((c) => c.id === cat)?.name || "Everything"); return ( <> {/* compact header */}
Directory / Browse

Browse {catName} in the QC

{/* sticky filter bar */}
{CATEGORIES.map((c) => ( ))}
{results.length} places
{/* secondary tag row */}
Filter: {ALL_TAGS.map((t) => ( ))}
{/* results */} {view === "split" ? (
{results.map((l) => (
setHover(l.id)} onMouseLeave={() => setHover(null)}>
))}
{results.length === 0 && }
) : (
{results.map((l) => )}
{results.length === 0 && }
)} ); } function Empty() { return (
Nothing matches that yet.

Try clearing a filter — the QC is bigger than this prototype’s sample data.

); } ReactDOM.createRoot(document.getElementById("root")).render();