// Catalog.jsx — the §7 left pane. // // One scrollable flat list of every super-draft and active entry, // state-styled rather than grouped. Filter chips are AND-combined per // §7.1; search is fuzzy over title + slug + id. The "Pending ideas" // disclosure per §7.3 lives at the bottom, above the "+ Propose New RFC" // button. import { useEffect, useMemo, useState } from 'react' import { useParams, Link } from 'react-router-dom' import { listRFCs, listProposals } from '../api' import { entryPath, proposalPath, useProjectId } from '../lib/entryPaths' const STATE_CHIPS = [ { id: 'super-draft', label: 'Super-draft' }, { id: 'active', label: 'Active' }, ] const SORT_OPTIONS = [ { id: 'recent', label: 'Recently active' }, { id: 'title', label: 'Title' }, { id: 'id', label: 'ID' }, { id: 'state', label: 'State' }, ] export default function Catalog({ viewer, onProposeRFC, version }) { const [rfcs, setRfcs] = useState([]) const [proposals, setProposals] = useState([]) const [search, setSearch] = useState('') const [sort, setSort] = useState('recent') const [activeChips, setActiveChips] = useState(new Set()) const [pendingOpen, setPendingOpen] = useState(true) const { slug, prNumber } = useParams() const pid = useProjectId() useEffect(() => { listRFCs().then(d => setRfcs(d.items)).catch(() => setRfcs([])) listProposals().then(d => setProposals(d.items)).catch(() => setProposals([])) }, [version]) const filtered = useMemo(() => { const needle = search.trim().toLowerCase() let items = rfcs.filter(r => { if (activeChips.size > 0 && !activeChips.has(r.state)) return false if (!needle) return true const hay = [r.title, r.slug, r.id || ''].join(' ').toLowerCase() return hay.includes(needle) }) items = [...items].sort((a, b) => { // Starred items pin to the top of the current sort per §7.2. if (a.starred_by_me !== b.starred_by_me) return a.starred_by_me ? -1 : 1 if (sort === 'title') return a.title.localeCompare(b.title) if (sort === 'id') return (a.id || 'zzz').localeCompare(b.id || 'zzz') if (sort === 'state') return a.state.localeCompare(b.state) // recent return (b.last_active_at || '').localeCompare(a.last_active_at || '') }) return items }, [rfcs, search, sort, activeChips]) function toggleChip(id) { const next = new Set(activeChips) next.has(id) ? next.delete(id) : next.add(id) setActiveChips(next) } return ( ) }