feat: let readers record where they are and how much work it is
The done checkbox now cycles untouched → doing → done, in the order people actually move through. Effort, status and a note are set from the detail sheet. Rows carry chips for what the reader said, and a "tight" or "running out of time" flag when the remaining time no longer covers the effort they recorded. The detail sheet shows the arithmetic behind that rather than just asserting it, and calls it a rough guide. Imports from before this change are mapped forward rather than dropped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
2f7e5bdf79
commit
89df140c00
4 files changed
+218
-18
No files matched your search
@@ -2,26 +2,42 @@ import { useEffect } from "react";
|
||||
import { gameMeta } from "../../shared/games.ts";
|
||||
import { formatAbsolute, formatRemaining } from "../../shared/time.ts";
|
||||
import type { RowEvent } from "./EventRow.tsx";
|
||||
import { pressure, pressureReason, type Effort } from "../../shared/effort.ts";
|
||||
import type { Status } from "../state/useProgress.ts";
|
||||
import { ProgressControls } from "./ProgressControls.tsx";
|
||||
import { Meter, URGENCY_COLOR } from "./Meter.tsx";
|
||||
|
||||
export function EventDetail({
|
||||
row,
|
||||
completed,
|
||||
ignored,
|
||||
status,
|
||||
effort,
|
||||
note,
|
||||
onToggle,
|
||||
onIgnore,
|
||||
onStatus,
|
||||
onEffort,
|
||||
onNote,
|
||||
onClose,
|
||||
}: {
|
||||
row: RowEvent;
|
||||
completed: boolean;
|
||||
ignored: boolean;
|
||||
status: Status | undefined;
|
||||
effort: Effort | undefined;
|
||||
note: string;
|
||||
onToggle: (id: string) => void;
|
||||
onIgnore: (id: string) => void;
|
||||
onStatus: (id: string, s: Status | undefined) => void;
|
||||
onEffort: (id: string, e: Effort | undefined) => void;
|
||||
onNote: (id: string, n: string) => void;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
const { event, clock } = row;
|
||||
const game = gameMeta(event.game);
|
||||
const heat = URGENCY_COLOR[clock.urgency];
|
||||
const risk = status === "done" ? "fine" : pressure(effort, clock.msRemaining);
|
||||
|
||||
useEffect(() => {
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
@@ -85,6 +101,32 @@ export function EventDetail({
|
||||
<Field label="Type">{event.type}</Field>
|
||||
</dl>
|
||||
|
||||
{risk !== "fine" && effort !== undefined && clock.msRemaining !== null && (
|
||||
<p
|
||||
className="mt-4 rounded-lg border px-3 py-2 text-xs leading-relaxed"
|
||||
style={{
|
||||
borderColor:
|
||||
risk === "unlikely"
|
||||
? "color-mix(in srgb, var(--color-critical) 40%, transparent)"
|
||||
: "color-mix(in srgb, var(--color-soon) 40%, transparent)",
|
||||
color:
|
||||
risk === "unlikely" ? "var(--color-critical)" : "var(--color-soon)",
|
||||
}}
|
||||
>
|
||||
{pressureReason(effort, clock.msRemaining)} It is a rough guide, not a
|
||||
verdict — you know your own schedule.
|
||||
</p>
|
||||
)}
|
||||
|
||||
<ProgressControls
|
||||
status={status}
|
||||
effort={effort}
|
||||
note={note}
|
||||
onStatus={(s) => onStatus(event.id, s)}
|
||||
onEffort={(e) => onEffort(event.id, e)}
|
||||
onNote={(n) => onNote(event.id, n)}
|
||||
/>
|
||||
|
||||
{event.endPrecision === "day" && event.endsAt !== null && (
|
||||
<p className="mt-3 text-xs leading-relaxed text-faint">
|
||||
The source gave a date but no time of day, so this end is accurate to
|
||||
|
||||
Reference in new issue
Block a user