import { Link } from "react-router"; import type { AgendaMove } from "../../../hooks/lib/agenda-store"; import type { HandoffCard } from "../data"; import type { MatrixItem } from "../matrix"; import { Badge } from "./components/badge"; import { NativeSelect } from "./components/input"; import { age } from "./format"; import { Empty } from "./frame"; import { cn } from "./lib/cn"; import { setPlacement, setServes } from "./lib/write"; const SERVES_KINDS = ["goal", "revenue", "fun"] as const; function ServesSelect({ item, onSaved }: { item: MatrixItem; onSaved: () => void }) { if (item.kind !== "project") return null; return ( { void setServes(item.id, e.target.value).then(onSaved); }} className={cn( "h-auto py-0.5 text-[10px]", item.servesBy === "user" && "border-accent bg-accent-100 text-accent-900" )} > {SERVES_KINDS.map((kind) => ( ))} ); } const PLACEMENTS = [ { value: "", label: "let PAL place it" }, { value: "now", label: "Do now" }, { value: "plan", label: "Give it a slot" }, { value: "noise", label: "Loud, not load-bearing" }, { value: "later", label: "Let it sit" }, ] as const; /** Overrules the grid's own reading. The correction survives the next guess. */ function PlacementSelect({ item, onSaved }: { item: MatrixItem; onSaved: () => void }) { if (item.kind !== "project") return null; return ( { void setPlacement(item.id, e.target.value || null).then(onSaved); }} className={cn( "h-auto py-0.5 text-[10px]", item.placed && "border-accent bg-accent-100 text-accent-900" )} > {PLACEMENTS.map((p) => ( ))} ); } export function ReasonTags({ item }: { item: MatrixItem }) { return (
{item.urgentBecause.map((reason) => ( {reason} ))} {item.importantBecause}
); } export function ItemCard({ item, onSaved }: { item: MatrixItem; onSaved: () => void }) { const isProject = item.kind === "project"; return (
{isProject ? ( {item.label} ) : ( {item.label} )} {isProject ? ( ) : ( goal )} {item.due ?? ""}
{item.waitingOn && (

waiting on you · {item.waitingOn}

)} {item.detail &&

{item.detail}

} {isProject && (
placed
)}
); } export function MovesList({ moves, size = "compact", }: { moves: AgendaMove[]; size?: "compact" | "large"; }) { if (moves.length === 0) { return ( No moves yet. They are written when a session ends — finish one and come back. ); } return (
    {moves.map((move, i) => (
  1. {String(i + 1).padStart(2, "0")} {move.move} {move.because}
  2. ))}
); } export function HandoffList({ cards }: { cards: HandoffCard[] }) { if (cards.length === 0) { return Nothing in progress. Every handoff is closed.; } return (
{cards.map((h) => (
{h.slug ? ( {h.label} ) : ( {h.label} )} {h.source} · {age(h.ageDays)} {h.sentence}
))}
); } export function GoalsList({ goals }: { goals: MatrixItem[] }) { if (goals.length === 0) return No goals written down yet.; return (
{goals.map((goal) => (
{goal.label} {goal.due ?? goal.detail}
{goal.progress ? `${goal.progress.closed} of ${goal.progress.written} criteria closed · served by ${goal.progress.projects.join(", ")}` : "no project serves this yet"} {goal.urgentBecause.length > 0 && ` · ${goal.urgentBecause.join(" · ")}`}
))}
); }