Files
webmail/components/calendar/task-chip.tsx
T

81 lines
2.9 KiB
TypeScript

"use client";
import { useTranslations } from "next-intl";
import { cn } from "@/lib/utils";
import { Check } from "@/components/icons";
import type { Calendar, CalendarTask } from "@/lib/jmap/types";
import { useCvdColor } from "@/hooks/use-cvd-color";
interface CalendarTaskChipProps {
task: CalendarTask;
calendar?: Calendar;
onToggleComplete?: (task: CalendarTask) => void;
onSelect?: (task: CalendarTask) => void;
/** A full row for a finger: 44px tall, a bigger circle with a 44px hit area (phone day view). */
touch?: boolean;
/** False for a day scrolled out of view: Tab skips it. */
tabbable?: boolean;
className?: string;
}
/**
* A task on its due day in the month and week grids (#1107). The circle
* toggles completion; the title opens the task in the editor.
*/
export function CalendarTaskChip({ task, calendar, onToggleComplete, onSelect, touch = false, tabbable = true, className }: CalendarTaskChipProps) {
const t = useTranslations("calendar");
const paint = useCvdColor();
const isCompleted = task.progress === "completed";
const color = paint(calendar?.color || "#3b82f6");
const title = task.title || t("tasks.no_title");
return (
<div
data-calendar-task={task.id}
className={cn(
"start-bar ps-[3px] rounded font-medium flex items-center overflow-hidden",
touch ? "min-h-11 text-xs" : "h-full text-[0.625rem]",
className,
)}
style={{ backgroundColor: `${color}20`, "--start-bar": color } as React.CSSProperties}
>
<button
type="button"
tabIndex={tabbable ? undefined : -1}
onClick={(e) => { e.stopPropagation(); onToggleComplete?.(task); }}
className={cn(
"group flex items-center flex-shrink-0",
// 24px wide, so the circle keeps a 24px target next to the title.
touch ? "self-stretch w-11 justify-center" : "h-full w-6 justify-center",
)}
aria-label={isCompleted ? t("tasks.mark_incomplete") : t("tasks.mark_complete")}
>
<span
className={cn(
"rounded-full border flex items-center justify-center",
touch ? "w-4 h-4" : "w-2.5 h-2.5",
isCompleted ? "bg-success border-success text-success-foreground" : "group-hover:bg-background",
)}
style={isCompleted ? undefined : { borderColor: color }}
>
{isCompleted && <Check className={touch ? "h-3 w-3" : "h-2 w-2"} />}
</span>
</button>
<button
type="button"
tabIndex={tabbable ? undefined : -1}
onClick={(e) => { e.stopPropagation(); onSelect?.(task); }}
className={cn(
"flex-1 min-w-0 truncate text-start pe-1 hover:opacity-80",
touch ? "self-stretch" : "h-full",
isCompleted && "line-through text-muted-foreground",
)}
title={title}
dir="auto"
>
{title}
</button>
</div>
);
}