Organize/components/board/todo-progress-pie.tsx

55 lines
2.1 KiB
TypeScript

"use client";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
/**
* Small pie-chart badge pinned to a Group card's bottom-right corner,
* showing what fraction of its to-dos are complete. `completed`/`total`
* come straight from the group's own to-do list, so it's recalculated and
* redrawn on every render -- any add/toggle/delete that changes those
* numbers repaints this automatically, with no separate update path to
* keep in sync.
*/
export function TodoProgressPie({
completed,
total,
accentColor,
}: {
completed: number;
total: number;
accentColor: string;
}) {
if (total === 0) return null;
const pct = Math.round((completed / total) * 100);
// Same hue as the stroke and the "completed" wedge, just faded into the
// card surface -- so the remaining wedge reads as an absence of
// progress rather than a second, competing color.
const emptyColor = `color-mix(in srgb, ${accentColor} 22%, var(--card))`;
return (
<Tooltip>
<TooltipTrigger
render={
<div
role="img"
aria-label={`${pct}% of to-dos completed`}
tabIndex={0}
// z-10: this badge pokes outside its own card's bottom-right
// corner, into the gap where the *next* card down starts. That
// next card is a later DOM sibling with its own stacking
// context (see hover:-translate-y-0.5 in GroupCard), so
// without an explicit z-index here it paints on top and crops
// the badge's overlapping edge.
className="absolute -right-1.5 -bottom-1.5 z-10 size-7 shrink-0 cursor-default rounded-full border-2 shadow-sm outline-none transition-transform hover:scale-110 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1"
style={{
borderColor: accentColor,
background: `conic-gradient(${accentColor} ${pct}%, ${emptyColor} ${pct}% 100%)`,
}}
/>
}
/>
<TooltipContent side="top">{pct}% To-Dos Completed</TooltipContent>
</Tooltip>
);
}