--- 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; // Align the first milestone with the left edge of the page's content column // (matches the LatestDispatchBanner below). --content-max is 72rem = 1152px. const CONTENT_MAX = 1152; const DEFAULT_PADDING = 60; const paddingLeft = Math.max(DEFAULT_PADDING, (viewportWidth - CONTENT_MAX) / 2); const layout = computeRouteLayout({ itemCount: items.length, viewportWidth, paddingLeft, }); 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; } // Stringified x position of the 'you are here' milestone for the // initial-scroll logic in the nav script. -1 → 0 (no scroll offset). const initialShippingX = lastShippingIndex >= 0 ? layout.itemX[lastShippingIndex] : 0; ---
    {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. ))}