/**
* Today, laid out on a clock: every interval in its real place.
*
* Three categories (focus / short / long break) so a legend is mandatory, and
* each block is also labelled on hover — colour never carries identity alone.
*/
import { Box, Stack, Tooltip, Typography } from "@mui/material";
import { KIND_LABEL } from "../../lib/format";
import { kindColor, type VizPalette } from "../../lib/viz";
import ChartFrame from "./ChartFrame";
interface Session {
id: number;
kind: string;
status: string;
started_at: string;
minutes: number;
task: string | null;
}
const LANE = 34;
export default function SessionTimeline({
sessions,
palette,
}: {
sessions: Session[];
palette: VizPalette;
}) {
const done = sessions.filter((item) => item.minutes > 0);
if (!done.length) {
return (
);
}
const hourOf = (iso: string) => {
const date = new Date(iso);
return date.getHours() + date.getMinutes() / 60;
};
const first = Math.floor(Math.min(...done.map((item) => hourOf(item.started_at))));
const last = Math.ceil(
Math.max(...done.map((item) => hourOf(item.started_at) + item.minutes / 60)),
);
const span = Math.max(last - first, 1);
return (
{done.map((item) => {
const start = (hourOf(item.started_at) - first) / span;
const width = item.minutes / 60 / span;
return (
{KIND_LABEL[item.kind] ?? item.kind} · {item.minutes} min
{new Date(item.started_at).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}
{item.task ? ` · ${item.task}` : ""}
{item.status === "abandoned" ? " · abandoned" : ""}
}
>
);
})}
{String(first).padStart(2, "0")}:00
{String(last).padStart(2, "0")}:00
);
}