diff --git a/src/components/roadmap/band-view.tsx b/src/components/roadmap/band-view.tsx new file mode 100644 index 0000000..4fe8626 --- /dev/null +++ b/src/components/roadmap/band-view.tsx @@ -0,0 +1,66 @@ +import { RoadmapCard } from "@/components/roadmap/roadmap-card"; +import type { Band } from "@/lib/roadmap/band"; +import type { RoadmapCard as Card } from "@/lib/roadmap/load"; + +const BANDS: Array<{ key: Band; title: string; blurb: string }> = [ + { key: "now", title: "Now", blurb: "In flight, critical, or due within a week" }, + { key: "next", title: "Next", blurb: "Queued up" }, + { key: "later", title: "Later", blurb: "Not started" }, +]; + +export function BandView({ + cards, + inboxCount, +}: { + cards: Card[]; + inboxCount: number; +}) { + return ( +
+ {inboxCount > 0 && ( + // Counted, not placed: an unaccepted request is not committed work, + // but it should not be invisible either. +

+ {inboxCount}{" "} + {inboxCount === 1 ? "request is" : "requests are"} waiting in an Inbox. +

+ )} + +
+ {BANDS.map((band) => { + const inBand = cards.filter((card) => card.band === band.key); + + return ( +
+
+
+

+ {band.title} +

+ + {inBand.length} + +
+

{band.blurb}

+
+ + {inBand.length === 0 ? ( +

+ Nothing here +

+ ) : ( +
    + {inBand.map((card) => ( +
  • + +
  • + ))} +
+ )} +
+ ); + })} +
+
+ ); +} diff --git a/src/components/roadmap/roadmap-card.tsx b/src/components/roadmap/roadmap-card.tsx new file mode 100644 index 0000000..3cbedc8 --- /dev/null +++ b/src/components/roadmap/roadmap-card.tsx @@ -0,0 +1,55 @@ +import Link from "next/link"; + +import { Pill } from "@/components/ui/pill"; +import { classifyDueDate, formatDueDate } from "@/lib/board/dates"; +import type { RoadmapCard as Card } from "@/lib/roadmap/load"; + +const PRIORITY_TONE = { + critical: "critical", + high: "high", + medium: "medium", + low: "low", +} as const; + +export function RoadmapCard({ card }: { card: Card }) { + const due = classifyDueDate(card.targetDate); + const dueLabel = formatDueDate(card.targetDate); + + return ( + +
+ {/* The client's own colour, so a cross-client page is scannable. */} + +
+

+ {card.title} +

+

+ {card.clientName} ยท {card.projectName} +

+
+ {card.percent !== null && ( + + {card.percent}% + + )} +
+ +
+ {card.priority} + {dueLabel && ( + + {dueLabel} + + )} +
+ + ); +}