--- import type { RoadmapItemWithAttribution, UserPublic } from '../../lib/db'; interface Props { items: RoadmapItemWithAttribution[]; editing: RoadmapItemWithAttribution | null; cabUsers: UserPublic[]; } const { items, editing, cabUsers } = Astro.props; const STATUS_LABEL = { shipping: 'Shipping', in_beta: 'In beta', exploring: 'Exploring', considering: 'Considering', } as const; const formAction = editing ? 'update_roadmap' : 'create_roadmap'; const attributedSet = new Set((editing?.attributed ?? []).map(a => a.id)); // Group items by status for display type Status = 'shipping' | 'in_beta' | 'exploring' | 'considering'; const grouped: Record = { shipping: items.filter(i => i.status === 'shipping' ).sort((a,b) => a.display_order - b.display_order), in_beta: items.filter(i => i.status === 'in_beta' ).sort((a,b) => a.display_order - b.display_order), exploring: items.filter(i => i.status === 'exploring' ).sort((a,b) => a.display_order - b.display_order), considering: items.filter(i => i.status === 'considering').sort((a,b) => a.display_order - b.display_order), }; ---

{editing ? 'Edit roadmap item' : 'New roadmap item'}

{editing && }
For shipping items: the first sentence appears on /roadmap as the "In motion right now" line. Make it count.
A short narrative cue shown on hover in /roadmap. Optional.
Attributed members (who shaped this) {cabUsers.map(u => ( ))} {cabUsers.length === 0 && No council members yet.}
{editing && Cancel}
{(['shipping','in_beta','exploring','considering'] as const).map(status => (

{STATUS_LABEL[status]} · {grouped[status].length}

{grouped[status].length === 0 ? (

Nothing here yet.

) : ( {grouped[status].map((item, idx) => ( ))}
Title Target Attributed Order Actions
{item.title} {item.target ?? '—'} {item.attributed.length === 0 ? '—' : item.attributed.map(a => a.name.split(' ')[0]).join(', ')} {item.display_order} {idx > 0 && (
)} {idx < grouped[status].length - 1 && (
)} Edit
)}
))}