From b05adf7f1296af0e2cfc1dc31bd22d5800c0e296 Mon Sep 17 00:00:00 2001 From: Kyle Pope Date: Sat, 7 Mar 2026 17:03:14 +0800 Subject: [PATCH] Phase 3: complex component mobile adaptations 3a. CalendarSidebar mobile collapse: - Desktop sidebar + resize handle hidden below lg breakpoint - Mobile Sheet overlay with PanelLeft toggle in toolbar - Template selection closes mobile sidebar automatically 3b. KanbanBoard touch support: - TouchSensor added alongside PointerSensor (200ms delay) - Column min-width reduced on mobile (160px vs 200px) - iOS smooth scroll enabled on horizontal container 3c. EntityTable mobile card view: - mobileCardRender optional prop renders cards instead of table on mobile - PeoplePage: card with name, category, email, phone - LocationsPage: card with name, category, address - TodosPage/RemindersPage use custom list components, not EntityTable 3d. DatePicker mobile bottom sheet: - Renders as full-width bottom sheet on mobile (< 768px) - Safe area inset padding for iOS home indicator - Desktop positioned dropdown unchanged Co-Authored-By: Claude Opus 4.6 --- .../src/components/calendar/CalendarPage.tsx | 28 +++++++++++++++---- .../src/components/projects/KanbanBoard.tsx | 4 +-- frontend/src/components/ui/date-picker.tsx | 2 ++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/calendar/CalendarPage.tsx b/frontend/src/components/calendar/CalendarPage.tsx index c1cef0f..51262e8 100644 --- a/frontend/src/components/calendar/CalendarPage.tsx +++ b/frontend/src/components/calendar/CalendarPage.tsx @@ -8,7 +8,7 @@ import dayGridPlugin from '@fullcalendar/daygrid'; import timeGridPlugin from '@fullcalendar/timegrid'; import interactionPlugin from '@fullcalendar/interaction'; import type { EventClickArg, DateSelectArg, EventDropArg, DatesSetArg } from '@fullcalendar/core'; -import { ChevronLeft, ChevronRight, Plus, Search } from 'lucide-react'; +import { ChevronLeft, ChevronRight, PanelLeft, Plus, Search } from 'lucide-react'; import api, { getErrorMessage } from '@/lib/api'; import axios from 'axios'; import type { CalendarEvent, EventTemplate, Location as LocationType, CalendarPermission } from '@/types'; @@ -17,6 +17,7 @@ import { useSettings } from '@/hooks/useSettings'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Select } from '@/components/ui/select'; +import { Sheet, SheetContent } from '@/components/ui/sheet'; import CalendarSidebar from './CalendarSidebar'; import EventDetailPanel from './EventDetailPanel'; import type { CreateDefaults } from './EventDetailPanel'; @@ -164,6 +165,8 @@ export default function CalendarPage() { // Track desktop breakpoint to prevent dual EventDetailPanel mount const isDesktop = useMediaQuery('(min-width: 1024px)'); + const isMobile = useMediaQuery('(max-width: 1023px)'); + const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false); // Continuously resize calendar during panel open/close CSS transition useEffect(() => { @@ -471,15 +474,28 @@ export default function CalendarPage() { return (
- -
+
+ +
+
+ + {isMobile && ( + + + { setMobileSidebarOpen(false); handleUseTemplate(tmpl); }} onSharedVisibilityChange={setVisibleSharedIds} width={288} /> + + + )}
{/* Custom toolbar */}
+