From f1b5645e9d0a286a9055b8869aeb65374eabf0c9 Mon Sep 17 00:00:00 2001 From: Kamil Krzywda Date: Fri, 2 Oct 2026 21:02:37 +0000 Subject: [PATCH] =?UTF-8?q?feat(ui):=20active-tasks=20strip=20bottom-left?= =?UTF-8?q?=20=E2=80=94=20active=20first,=20pending=20dimmed=20(#44)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/mission-control.tsx | 7 +++++ components/task-strip.tsx | 54 ++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 components/task-strip.tsx diff --git a/components/mission-control.tsx b/components/mission-control.tsx index a579712..d45cfba 100644 --- a/components/mission-control.tsx +++ b/components/mission-control.tsx @@ -16,6 +16,7 @@ import { MissionPanel } from '@/components/missions' import { NextTurnButton } from '@/components/next-turn-button' import { ShipSystemsPanel } from '@/components/ship-systems' import { SkillTreePanel } from '@/components/skill-tree' +import { TaskStrip } from '@/components/task-strip' import { WorldMapPanel } from '@/components/world-map' import { CREW_CAPACITY } from '@/lib/game/ship-costs' import type { CrewState, SystemState } from '@/lib/game/save' @@ -562,6 +563,12 @@ export function MissionControl() { stays visible on every tab (Radix unmounts inactive tabs — the button only refreshes the snapshots this shell owns) */} + + {/* #44 — the active-tasks strip: fixed bottom-left (same mount convention as the button — + outside the tab grid so it stays visible on every tab). Data: the shell's system + snapshot (JC-15) — refreshAll re-runs /api/system on every turn, so it updates on + every shell refresh with no fetch of its own. */} + ) } diff --git a/components/task-strip.tsx b/components/task-strip.tsx new file mode 100644 index 0000000..92294c2 --- /dev/null +++ b/components/task-strip.tsx @@ -0,0 +1,54 @@ +'use client' + +import type { QueueDto } from '@/lib/game/save' + +// TASK STRIP — the save's task queue, fixed bottom-left next to the NEXT TURN button (#44). +// The array arrives pre-ordered from the snapshot builder (Task 6: ACTIVE block, then PENDING +// block, each by (queuedAtTurn, id)) — the strip renders it as-is, dimming the PENDING rows, +// and never fetches or re-sorts. Empty queue → null, no box at all. The shell re-renders it on +// every refreshAll (Task 7) — a pure display of the array it is handed. + +export function TaskStrip({ tasks }: { tasks: QueueDto[] }) { + if (tasks.length === 0) return null + + return ( +
+ + ACTIVE TASKS + + {tasks.map((t) => ( +
+ + {t.type} // {t.targetLabel} + + + {t.leadName} + {t.helperNames.length > 0 ? ` +${t.helperNames.join(' +')}` : ''} + {' — '} + {t.status === 'ACTIVE' ? `${t.remaining} turn(s) left` : 'queued'} + +
+ ))} +
+ ) +}