Reformat detail panel view modes to 2-column grid layout
Match TaskDetailPanel gold standard: short fields use grid grid-cols-2 with icon+label headers, full-width fields (description) below the grid. All grid slots render with "—" fallback to keep alignment consistent. - Todo: Priority, Category, Due Date, Recurrence in grid - Reminder: Status, Recurrence, Remind At, Snoozed Until in grid - Calendar: Calendar, Starred, Start, End, Location, Recurrence in grid - Task: Add "Updated X ago" footer (was missing) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2e2466bfa6
commit
87a7a4ae32
@ -807,79 +807,95 @@ export default function EventDetailPanel({
|
||||
) : (
|
||||
/* View mode */
|
||||
<>
|
||||
{/* Calendar */}
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Calendar</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-2 h-2 rounded-full shrink-0"
|
||||
style={{ backgroundColor: event?.calendar_color || 'hsl(var(--accent-color))' }}
|
||||
/>
|
||||
<span className="text-sm">{event?.calendar_name}</span>
|
||||
{/* 2-column grid: Calendar, Starred, Start, End, Location, Recurrence */}
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
{/* Calendar */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<Calendar className="h-3 w-3" />
|
||||
Calendar
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-2 h-2 rounded-full shrink-0"
|
||||
style={{ backgroundColor: event?.calendar_color || 'hsl(var(--accent-color))' }}
|
||||
/>
|
||||
<span className="text-sm">{event?.calendar_name}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Starred */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<Star className="h-3 w-3" />
|
||||
Starred
|
||||
</div>
|
||||
{event?.is_starred ? (
|
||||
<p className="text-sm text-amber-200/90">Starred</p>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">—</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Start */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<Clock className="h-3 w-3" />
|
||||
Start
|
||||
</div>
|
||||
<CopyableField value={startStr} icon={Clock} label="Start time" />
|
||||
</div>
|
||||
|
||||
{/* End */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<Clock className="h-3 w-3" />
|
||||
End
|
||||
</div>
|
||||
{endStr ? (
|
||||
<CopyableField value={endStr} icon={Clock} label="End time" />
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">—</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Location */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<MapPin className="h-3 w-3" />
|
||||
Location
|
||||
</div>
|
||||
{locationName ? (
|
||||
<CopyableField value={locationName} icon={MapPin} label="Location" />
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">—</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Recurrence */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<Repeat className="h-3 w-3" />
|
||||
Recurrence
|
||||
</div>
|
||||
{isRecurring && event?.recurrence_rule ? (
|
||||
<p className="text-sm">{formatRecurrenceRule(event.recurrence_rule)}</p>
|
||||
) : isRecurring ? (
|
||||
<p className="text-sm">Recurring event</p>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">—</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Start */}
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Start</p>
|
||||
<CopyableField value={startStr} icon={Clock} label="Start time" />
|
||||
</div>
|
||||
|
||||
{/* End */}
|
||||
{endStr && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">End</p>
|
||||
<CopyableField value={endStr} icon={Clock} label="End time" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Location */}
|
||||
{locationName && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Location</p>
|
||||
<CopyableField value={locationName} icon={MapPin} label="Location" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Description */}
|
||||
{/* Description — full width */}
|
||||
{event?.description && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Description</p>
|
||||
<div className="flex items-start gap-2">
|
||||
<AlignLeft className="h-3.5 w-3.5 text-muted-foreground shrink-0 mt-0.5" />
|
||||
<p className="text-sm whitespace-pre-wrap">{event.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Starred */}
|
||||
{event?.is_starred && (
|
||||
<div className="space-y-0.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<Star className="h-3.5 w-3.5 text-amber-400 fill-amber-400 shrink-0" />
|
||||
<span className="text-sm text-amber-200/90">Starred event</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Recurrence */}
|
||||
{isRecurring && event?.recurrence_rule && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Recurrence</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<Repeat className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
||||
<span className="text-sm">{formatRecurrenceRule(event.recurrence_rule)}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isRecurring && !event?.recurrence_rule && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Recurrence</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<Repeat className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
||||
<span className="text-sm">Recurring event</span>
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<AlignLeft className="h-3 w-3" />
|
||||
Description
|
||||
</div>
|
||||
<p className="text-sm whitespace-pre-wrap">{event.description}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
Calendar, User, Flag, Activity, Send, X, Save,
|
||||
} from 'lucide-react';
|
||||
import api, { getErrorMessage } from '@/lib/api';
|
||||
import { formatUpdatedAt } from '@/components/shared/utils';
|
||||
import type { ProjectTask, TaskComment, Person } from '@/types';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
@ -558,6 +559,15 @@ export default function TaskDetailPanel({
|
||||
<Send className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Updated at footer */}
|
||||
{task.updated_at && (
|
||||
<div className="pt-2 border-t border-border">
|
||||
<span className="text-[11px] text-muted-foreground">
|
||||
{formatUpdatedAt(task.updated_at)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -3,7 +3,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { toast } from 'sonner';
|
||||
import { format, parseISO, isPast, isToday } from 'date-fns';
|
||||
import {
|
||||
X, Pencil, Trash2, Save, Bell, BellOff, Clock, Repeat, AlertCircle,
|
||||
X, Pencil, Trash2, Save, Bell, BellOff, Clock, Repeat, AlertCircle, AlignLeft,
|
||||
} from 'lucide-react';
|
||||
import api, { getErrorMessage } from '@/lib/api';
|
||||
import type { Reminder } from '@/types';
|
||||
@ -377,76 +377,82 @@ export default function ReminderDetailPanel({
|
||||
) : (
|
||||
/* View mode */
|
||||
<>
|
||||
{/* Status */}
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Status</p>
|
||||
<div className="flex items-center gap-2">
|
||||
{/* 2-column grid: Status, Recurrence, Remind At, Snoozed Until */}
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
{/* Status */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
{reminder!.is_dismissed ? (
|
||||
<BellOff className="h-3 w-3" />
|
||||
) : isOverdue ? (
|
||||
<AlertCircle className="h-3 w-3" />
|
||||
) : (
|
||||
<Bell className="h-3 w-3" />
|
||||
)}
|
||||
Status
|
||||
</div>
|
||||
{reminder!.is_dismissed ? (
|
||||
<>
|
||||
<BellOff className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
||||
<span className="text-sm text-muted-foreground">Dismissed</span>
|
||||
</>
|
||||
<p className="text-sm text-muted-foreground">Dismissed</p>
|
||||
) : isOverdue ? (
|
||||
<>
|
||||
<AlertCircle className="h-3.5 w-3.5 text-red-400 shrink-0" />
|
||||
<span className="text-sm text-red-400">Overdue</span>
|
||||
</>
|
||||
<p className="text-sm text-red-400">Overdue</p>
|
||||
) : isDueToday ? (
|
||||
<>
|
||||
<Bell className="h-3.5 w-3.5 text-yellow-400 shrink-0" />
|
||||
<span className="text-sm text-yellow-400">Due today</span>
|
||||
</>
|
||||
<p className="text-sm text-yellow-400">Due today</p>
|
||||
) : (
|
||||
<>
|
||||
<Bell className="h-3.5 w-3.5 text-orange-400 shrink-0" />
|
||||
<span className="text-sm text-orange-400">Active</span>
|
||||
</>
|
||||
<p className="text-sm text-orange-400">Active</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Recurrence */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<Repeat className="h-3 w-3" />
|
||||
Recurrence
|
||||
</div>
|
||||
{reminder!.recurrence_rule ? (
|
||||
<p className="text-sm">{recurrenceLabels[reminder!.recurrence_rule] || reminder!.recurrence_rule}</p>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">—</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Remind At */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<Clock className="h-3 w-3" />
|
||||
Remind At
|
||||
</div>
|
||||
{remindDate ? (
|
||||
<CopyableField
|
||||
value={format(remindDate, 'EEEE, MMMM d, yyyy · h:mm a')}
|
||||
icon={Clock}
|
||||
label="Remind at"
|
||||
/>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">—</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Snoozed Until */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<Clock className="h-3 w-3" />
|
||||
Snoozed Until
|
||||
</div>
|
||||
{reminder!.snoozed_until ? (
|
||||
<p className="text-sm">{format(parseISO(reminder!.snoozed_until), 'MMM d, h:mm a')}</p>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">—</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Remind At */}
|
||||
{remindDate && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Remind At</p>
|
||||
<CopyableField
|
||||
value={format(remindDate, 'EEEE, MMMM d, yyyy · h:mm a')}
|
||||
icon={Clock}
|
||||
label="Remind at"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Snoozed */}
|
||||
{reminder!.snoozed_until && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Snoozed Until</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<Clock className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
||||
<span className="text-sm">
|
||||
{format(parseISO(reminder!.snoozed_until), 'MMM d, h:mm a')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Recurrence */}
|
||||
{reminder!.recurrence_rule && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Recurrence</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<Repeat className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
||||
<span className="text-sm">
|
||||
{recurrenceLabels[reminder!.recurrence_rule] || reminder!.recurrence_rule}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Description */}
|
||||
{/* Description — full width */}
|
||||
{reminder!.description && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Description</p>
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<AlignLeft className="h-3 w-3" />
|
||||
Description
|
||||
</div>
|
||||
<p className="text-sm whitespace-pre-wrap text-muted-foreground leading-relaxed">
|
||||
{reminder!.description}
|
||||
</p>
|
||||
|
||||
@ -3,7 +3,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { toast } from 'sonner';
|
||||
import { format, parseISO, isToday } from 'date-fns';
|
||||
import {
|
||||
X, Pencil, Trash2, Save, Clock, Calendar, Flag, Tag, Repeat, CheckSquare, AlertCircle,
|
||||
X, Pencil, Trash2, Save, Clock, Calendar, Flag, Tag, Repeat, CheckSquare, AlertCircle, AlignLeft,
|
||||
} from 'lucide-react';
|
||||
import api, { getErrorMessage } from '@/lib/api';
|
||||
import type { Todo } from '@/types';
|
||||
@ -433,95 +433,104 @@ export default function TodoDetailPanel({
|
||||
) : (
|
||||
/* View mode */
|
||||
<>
|
||||
{/* Priority */}
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Priority</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<Flag className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
||||
{/* 2-column grid: Priority, Category, Due Date, Recurrence */}
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
{/* Priority */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<Flag className="h-3 w-3" />
|
||||
Priority
|
||||
</div>
|
||||
<Badge className={`text-[9px] px-1.5 py-0.5 rounded-full ${priorityColors[todo!.priority] ?? ''}`}>
|
||||
{todo!.priority}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Category */}
|
||||
{todo!.category && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Category</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<Tag className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
||||
{/* Category */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<Tag className="h-3 w-3" />
|
||||
Category
|
||||
</div>
|
||||
{todo!.category ? (
|
||||
<Badge className="text-[9px] px-1.5 py-0.5 bg-blue-500/15 text-blue-400">
|
||||
{todo!.category}
|
||||
</Badge>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">—</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Due Date */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
{isOverdue ? <AlertCircle className="h-3 w-3" /> : <Calendar className="h-3 w-3" />}
|
||||
Due Date
|
||||
</div>
|
||||
{dueDate ? (
|
||||
<CopyableField
|
||||
value={`${isOverdue ? 'Overdue · ' : isDueToday ? 'Today · ' : ''}${format(dueDate, 'EEEE, MMMM d, yyyy')}${todo!.due_time ? ` at ${todo!.due_time.slice(0, 5)}` : ''}`}
|
||||
icon={isOverdue ? AlertCircle : Calendar}
|
||||
label="Due date"
|
||||
/>
|
||||
) : todo!.due_time ? (
|
||||
<CopyableField value={todo!.due_time.slice(0, 5)} icon={Clock} label="Due time" />
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">—</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Due Date */}
|
||||
{dueDate && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Due Date</p>
|
||||
<CopyableField
|
||||
value={`${isOverdue ? 'Overdue · ' : isDueToday ? 'Today · ' : ''}${format(dueDate, 'EEEE, MMMM d, yyyy')}${todo!.due_time ? ` at ${todo!.due_time.slice(0, 5)}` : ''}`}
|
||||
icon={isOverdue ? AlertCircle : Calendar}
|
||||
label="Due date"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Due Time (if no date but has time) */}
|
||||
{!dueDate && todo!.due_time && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Due Time</p>
|
||||
<CopyableField value={todo!.due_time.slice(0, 5)} icon={Clock} label="Due time" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Recurrence */}
|
||||
{todo!.recurrence_rule && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Recurrence</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<Repeat className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
||||
<span className="text-sm">{recurrenceLabels[todo!.recurrence_rule] || todo!.recurrence_rule}</span>
|
||||
{/* Recurrence */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<Repeat className="h-3 w-3" />
|
||||
Recurrence
|
||||
</div>
|
||||
{todo!.recurrence_rule ? (
|
||||
<p className="text-sm">{recurrenceLabels[todo!.recurrence_rule] || todo!.recurrence_rule}</p>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">—</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
{todo!.description && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Description</p>
|
||||
<p className="text-sm whitespace-pre-wrap text-muted-foreground leading-relaxed">
|
||||
{todo!.description}
|
||||
{/* Completion status — full width */}
|
||||
{todo!.completed && todo!.completed_at && (
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<CheckSquare className="h-3 w-3" />
|
||||
Completed
|
||||
</div>
|
||||
<p className="text-sm text-green-400">
|
||||
{format(parseISO(todo!.completed_at), 'MMM d, yyyy · h:mm a')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Completion status */}
|
||||
{todo!.completed && todo!.completed_at && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Completed</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<CheckSquare className="h-3.5 w-3.5 text-green-400 shrink-0" />
|
||||
<span className="text-sm text-green-400">
|
||||
{format(parseISO(todo!.completed_at), 'MMM d, yyyy · h:mm a')}
|
||||
</span>
|
||||
{/* Reset info — full width */}
|
||||
{todo!.completed && todo!.recurrence_rule && todo!.reset_at && (
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<Repeat className="h-3 w-3" />
|
||||
Resets
|
||||
</div>
|
||||
<p className="text-sm text-purple-400">
|
||||
{format(parseISO(todo!.reset_at), 'EEE, MMM d')}
|
||||
{todo!.next_due_date && ` · Next due ${format(parseISO(todo!.next_due_date), 'MMM d')}`}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Reset info for recurring */}
|
||||
{todo!.completed && todo!.recurrence_rule && todo!.reset_at && (
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-[11px] uppercase tracking-wider text-muted-foreground">Resets</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<Repeat className="h-3.5 w-3.5 text-purple-400 shrink-0" />
|
||||
<span className="text-sm text-purple-400">
|
||||
{format(parseISO(todo!.reset_at), 'EEE, MMM d')}
|
||||
{todo!.next_due_date && ` · Next due ${format(parseISO(todo!.next_due_date), 'MMM d')}`}
|
||||
</span>
|
||||
{/* Description — full width */}
|
||||
{todo!.description && (
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
|
||||
<AlignLeft className="h-3 w-3" />
|
||||
Description
|
||||
</div>
|
||||
<p className="text-sm whitespace-pre-wrap text-muted-foreground leading-relaxed">
|
||||
{todo!.description}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user