--- import type { RoadmapItemWithAttribution, RoadmapStatus } from '../lib/db'; import { computeRouteLayout, travelledStopFor } from '../lib/roadmap-layout'; interface Props { items: RoadmapItemWithAttribution[]; viewportWidth?: number; // SSR fallback for the layout math } const { items, viewportWidth = 1100 } = Astro.props; const layout = computeRouteLayout({ itemCount: items.length, viewportWidth }); const travelledStop = travelledStopFor(items.map(i => i.status)); const STATUS_LABEL: Record = { shipping: 'SHIPPING', in_beta: 'IN BETA', exploring: 'EXPLORING', considering: 'CONSIDERING', }; const STATUS_LABEL_COLOR: Record = { shipping: '#6d8c7c', in_beta: '#b96b58', exploring: '#b4b2a9', considering: '#b4b2a9', }; const STATUS_DOT_COLOR: Record = { shipping: '#6d8c7c', in_beta: '#b96b58', exploring: '#b4b2a9', considering: '#d4d2c8', }; // "You are here" — the most recent shipping item. -1 if nothing has shipped yet. let lastShippingIndex = -1; items.forEach((it, i) => { if (it.status === 'shipping') lastShippingIndex = i; }); function trailingLine(item: RoadmapItemWithAttribution): string | null { if (item.metadata_text && item.metadata_text.trim().length > 0) return item.metadata_text; if (item.attributed.length > 0) { const names = item.attributed.map(a => a.name.split(' ')[0]); if (names.length === 1) return `Shaped by ${names[0]}`; if (names.length === 2) return `Shaped by ${names[0]} and ${names[1]}`; return `Shaped by ${names.slice(0, -1).join(', ')} and ${names.at(-1)}`; } return null; } // Progress dots — between 2 and 6, scaling with item count. const progressDots = Math.max(2, Math.min(6, Math.ceil(items.length / 2))); // JSON-stringified ids for the nav script's initial-scroll logic. const itemXByIndex = layout.itemX; const initialShippingX = lastShippingIndex >= 0 ? itemXByIndex[lastShippingIndex] : 0; ---

The route

  • Shipping
  • In beta
  • Exploring
  • Considering
    {items.map((item, i) => (
  1. {item.target ? `${item.target.toUpperCase()} · ` : ''}{STATUS_LABEL[item.status]}

    {item.title}

    {item.description &&

    {item.description}

    } {trailingLine(item) &&

    {trailingLine(item)}

    }
  2. ))}