From a78fb495a2c7d470bcf178c36ad65b83bfe90e5b Mon Sep 17 00:00:00 2001 From: Kyle Pope Date: Tue, 17 Mar 2026 18:46:40 +0800 Subject: [PATCH 1/4] Improve event panel UX: fix scroll bleed, auto-grow description, compact layout P0 - Scroll bleed: onWheel stopPropagation on panel root prevents wheel events from navigating calendar months while editing. P1 - Description textarea: auto-grows with content (min 80px, max 200px), manually resizable via resize-y handle. Applied to both EventDetailPanel and EventForm. P2 - Space utilization: moved All Day checkbox inline above date row, combined Recurrence + Star into a 2-col row, description now fills remaining vertical space with flex-1. P3 - Removed duplicate footer Save/Cancel buttons from edit mode (header icon buttons are sufficient). P4 - Description field now shows dash placeholder in view mode when empty, consistent with other fields. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../components/calendar/EventDetailPanel.tsx | 196 ++++++++++-------- .../src/components/calendar/EventForm.tsx | 15 +- 2 files changed, 120 insertions(+), 91 deletions(-) diff --git a/frontend/src/components/calendar/EventDetailPanel.tsx b/frontend/src/components/calendar/EventDetailPanel.tsx index b8e08e8..211d796 100644 --- a/frontend/src/components/calendar/EventDetailPanel.tsx +++ b/frontend/src/components/calendar/EventDetailPanel.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback, useMemo } from 'react'; +import { useState, useEffect, useCallback, useMemo, useRef } from 'react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { toast } from 'sonner'; import { format, parseISO } from 'date-fns'; @@ -284,6 +284,15 @@ export default function EventDetailPanel({ const [scopeStep, setScopeStep] = useState<'edit' | 'delete' | null>(null); const [editScope, setEditScope] = useState<'this' | 'this_and_future' | null>(null); const [locationSearch, setLocationSearch] = useState(''); + const descRef = useRef(null); + + // Auto-resize description textarea to fit content + useEffect(() => { + const el = descRef.current; + if (!el) return; + el.style.height = 'auto'; + el.style.height = `${Math.min(el.scrollHeight, 200)}px`; + }, [editState.description, isEditing]); // Poll lock status in view mode for shared events (Stream A: real-time lock awareness) // lockInfo is only set from the 423 error path; poll data (viewLockQuery.data) is used directly. @@ -539,7 +548,7 @@ export default function EventDetailPanel({ : event?.title || ''; return ( -
+
e.stopPropagation()}> {/* Header */}
@@ -721,7 +730,7 @@ export default function EventDetailPanel({
) : (isEditing || isCreating) ? ( /* Edit / Create mode */ -
+
{/* Title (only shown in body for create mode; edit mode has it in header) */} {isCreating && (
@@ -737,58 +746,49 @@ export default function EventDetailPanel({
)} -
- -