From 87a7a4ae32a392767087f5a37616529c9b84c377 Mon Sep 17 00:00:00 2001 From: Kyle Pope Date: Wed, 25 Feb 2026 23:52:15 +0800 Subject: [PATCH] Reformat detail panel view modes to 2-column grid layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../components/calendar/EventDetailPanel.tsx | 152 ++++++++++-------- .../components/projects/TaskDetailPanel.tsx | 10 ++ .../reminders/ReminderDetailPanel.tsx | 130 ++++++++------- .../src/components/todos/TodoDetailPanel.tsx | 143 ++++++++-------- 4 files changed, 238 insertions(+), 197 deletions(-) diff --git a/frontend/src/components/calendar/EventDetailPanel.tsx b/frontend/src/components/calendar/EventDetailPanel.tsx index 0b71fd9..863cffb 100644 --- a/frontend/src/components/calendar/EventDetailPanel.tsx +++ b/frontend/src/components/calendar/EventDetailPanel.tsx @@ -807,79 +807,95 @@ export default function EventDetailPanel({ ) : ( /* View mode */ <> - {/* Calendar */} -
-

Calendar

-
-
- {event?.calendar_name} + {/* 2-column grid: Calendar, Starred, Start, End, Location, Recurrence */} +
+ {/* Calendar */} +
+
+ + Calendar +
+
+
+ {event?.calendar_name} +
+
+ + {/* Starred */} +
+
+ + Starred +
+ {event?.is_starred ? ( +

Starred

+ ) : ( +

+ )} +
+ + {/* Start */} +
+
+ + Start +
+ +
+ + {/* End */} +
+
+ + End +
+ {endStr ? ( + + ) : ( +

+ )} +
+ + {/* Location */} +
+
+ + Location +
+ {locationName ? ( + + ) : ( +

+ )} +
+ + {/* Recurrence */} +
+
+ + Recurrence +
+ {isRecurring && event?.recurrence_rule ? ( +

{formatRecurrenceRule(event.recurrence_rule)}

+ ) : isRecurring ? ( +

Recurring event

+ ) : ( +

+ )}
- {/* Start */} -
-

Start

- -
- - {/* End */} - {endStr && ( -
-

End

- -
- )} - - {/* Location */} - {locationName && ( -
-

Location

- -
- )} - - {/* Description */} + {/* Description — full width */} {event?.description && ( -
-

Description

-
- -

{event.description}

-
-
- )} - - {/* Starred */} - {event?.is_starred && ( -
-
- - Starred event -
-
- )} - - {/* Recurrence */} - {isRecurring && event?.recurrence_rule && ( -
-

Recurrence

-
- - {formatRecurrenceRule(event.recurrence_rule)} -
-
- )} - - {isRecurring && !event?.recurrence_rule && ( -
-

Recurrence

-
- - Recurring event +
+
+ + Description
+

{event.description}

)} diff --git a/frontend/src/components/projects/TaskDetailPanel.tsx b/frontend/src/components/projects/TaskDetailPanel.tsx index 9fe751d..f3a36f6 100644 --- a/frontend/src/components/projects/TaskDetailPanel.tsx +++ b/frontend/src/components/projects/TaskDetailPanel.tsx @@ -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({
+ + {/* Updated at footer */} + {task.updated_at && ( +
+ + {formatUpdatedAt(task.updated_at)} + +
+ )}
diff --git a/frontend/src/components/reminders/ReminderDetailPanel.tsx b/frontend/src/components/reminders/ReminderDetailPanel.tsx index 660c378..0a101e8 100644 --- a/frontend/src/components/reminders/ReminderDetailPanel.tsx +++ b/frontend/src/components/reminders/ReminderDetailPanel.tsx @@ -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 */} -
-

Status

-
+ {/* 2-column grid: Status, Recurrence, Remind At, Snoozed Until */} +
+ {/* Status */} +
+
+ {reminder!.is_dismissed ? ( + + ) : isOverdue ? ( + + ) : ( + + )} + Status +
{reminder!.is_dismissed ? ( - <> - - Dismissed - +

Dismissed

) : isOverdue ? ( - <> - - Overdue - +

Overdue

) : isDueToday ? ( - <> - - Due today - +

Due today

) : ( - <> - - Active - +

Active

+ )} +
+ + {/* Recurrence */} +
+
+ + Recurrence +
+ {reminder!.recurrence_rule ? ( +

{recurrenceLabels[reminder!.recurrence_rule] || reminder!.recurrence_rule}

+ ) : ( +

+ )} +
+ + {/* Remind At */} +
+
+ + Remind At +
+ {remindDate ? ( + + ) : ( +

+ )} +
+ + {/* Snoozed Until */} +
+
+ + Snoozed Until +
+ {reminder!.snoozed_until ? ( +

{format(parseISO(reminder!.snoozed_until), 'MMM d, h:mm a')}

+ ) : ( +

)}
- {/* Remind At */} - {remindDate && ( -
-

Remind At

- -
- )} - - {/* Snoozed */} - {reminder!.snoozed_until && ( -
-

Snoozed Until

-
- - - {format(parseISO(reminder!.snoozed_until), 'MMM d, h:mm a')} - -
-
- )} - - {/* Recurrence */} - {reminder!.recurrence_rule && ( -
-

Recurrence

-
- - - {recurrenceLabels[reminder!.recurrence_rule] || reminder!.recurrence_rule} - -
-
- )} - - {/* Description */} + {/* Description — full width */} {reminder!.description && ( -
-

Description

+
+
+ + Description +

{reminder!.description}

diff --git a/frontend/src/components/todos/TodoDetailPanel.tsx b/frontend/src/components/todos/TodoDetailPanel.tsx index ac629be..fd9a03a 100644 --- a/frontend/src/components/todos/TodoDetailPanel.tsx +++ b/frontend/src/components/todos/TodoDetailPanel.tsx @@ -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 */} -
-

Priority

-
- + {/* 2-column grid: Priority, Category, Due Date, Recurrence */} +
+ {/* Priority */} +
+
+ + Priority +
{todo!.priority}
-
- {/* Category */} - {todo!.category && ( -
-

Category

-
- + {/* Category */} +
+
+ + Category +
+ {todo!.category ? ( {todo!.category} + ) : ( +

+ )} +
+ + {/* Due Date */} +
+
+ {isOverdue ? : } + Due Date
+ {dueDate ? ( + + ) : todo!.due_time ? ( + + ) : ( +

+ )}
- )} - {/* Due Date */} - {dueDate && ( -
-

Due Date

- -
- )} - - {/* Due Time (if no date but has time) */} - {!dueDate && todo!.due_time && ( -
-

Due Time

- -
- )} - - {/* Recurrence */} - {todo!.recurrence_rule && ( -
-

Recurrence

-
- - {recurrenceLabels[todo!.recurrence_rule] || todo!.recurrence_rule} + {/* Recurrence */} +
+
+ + Recurrence
+ {todo!.recurrence_rule ? ( +

{recurrenceLabels[todo!.recurrence_rule] || todo!.recurrence_rule}

+ ) : ( +

+ )}
- )} +
- {/* Description */} - {todo!.description && ( -
-

Description

-

- {todo!.description} + {/* Completion status — full width */} + {todo!.completed && todo!.completed_at && ( +

+
+ + Completed +
+

+ {format(parseISO(todo!.completed_at), 'MMM d, yyyy · h:mm a')}

)} - {/* Completion status */} - {todo!.completed && todo!.completed_at && ( -
-

Completed

-
- - - {format(parseISO(todo!.completed_at), 'MMM d, yyyy · h:mm a')} - + {/* Reset info — full width */} + {todo!.completed && todo!.recurrence_rule && todo!.reset_at && ( +
+
+ + Resets
+

+ {format(parseISO(todo!.reset_at), 'EEE, MMM d')} + {todo!.next_due_date && ` · Next due ${format(parseISO(todo!.next_due_date), 'MMM d')}`} +

)} - {/* Reset info for recurring */} - {todo!.completed && todo!.recurrence_rule && todo!.reset_at && ( -
-

Resets

-
- - - {format(parseISO(todo!.reset_at), 'EEE, MMM d')} - {todo!.next_due_date && ` · Next due ${format(parseISO(todo!.next_due_date), 'MMM d')}`} - + {/* Description — full width */} + {todo!.description && ( +
+
+ + Description
+

+ {todo!.description} +

)}