Shared roadmap list surface component that renders roadmap items either as a flat two-column grid or grouped into collapsible per-quarter accordions, with centralized voting state management. ## Key Components ### `RoadmapGrid` (main export) The top-level component that orchestrates both rendering modes and shared voting state. **Props:** | Prop | Type | Default | Description | |---|---|---|---| | `items` | `RoadmapItem[]` | — | Roadmap items to display | | `groupByQuarter` | `boolean` | `false` | Enables accordion quarter grouping | | `hasActiveFilters` | `boolean` | `false` | Expands all quarters when filters are active | | `quartersToKeepClosed` | `number` | `2` | Past quarter collapse window | | `showLeftMargin` | `boolean` | `true` | Desktop alignment margin (~120px) | | `buildRefreshUrl` | `(taskId: string) => string` | `/api/roadmap/:id` | URL builder for post-vote refresh | | `votingOptions` | `UseRoadmapVotingOptions` | — | Vote endpoint + storage key config | | `onItemUpdate` | `(item: RoadmapItem) => void` | — | Callback after successful vote refresh | ### `RoadmapGridSingle` (internal) Flat 2-column grid for a single set of items. Receives voting handlers from the parent to avoid split state across quarters. ### Quarter Helpers (pure functions) - `parseQuarterString(q)` — parses `"Q "` labels - `compareQuarters(a, b)` — chronological sort comparator - `computeDefaultExpandedQuarters(quarters, quartersToKeepClosed)` — determines which quarters open by default - `getStatusPriority(status)` — sorts items within a quarter by status (Complete → Working → Review → To-Do) ## Usage Example ```typescript // Grouped by quarter (full roadmap page) 0} quartersToKeepClosed={2} onItemUpdate={(updated) => patchItem(updated)} votingOptions={{ endpoint: '/api/vote', storageKey: 'roadmap-votes' }} /> // Flat mode (related-content rail) ``` ## Hydration Strategy `expandedQuarters` initializes to `[]` on the server and is populated in a client-only `useEffect`, ensuring SSR markup matches the first client paint before accordion state is applied. **Source:** [`roadmap-grid.tsx`](https://github.com/flamingo-stack/openframe-oss-lib/blob/main/roadmap-grid.tsx)