diff --git a/app/[locale]/calendar/page.tsx b/app/[locale]/calendar/page.tsx index 94fb0b9d..5ded7c39 100644 --- a/app/[locale]/calendar/page.tsx +++ b/app/[locale]/calendar/page.tsx @@ -30,6 +30,8 @@ import { ICalImportModal } from "@/components/calendar/ical-import-modal"; import { ICalSubscriptionModal } from "@/components/calendar/ical-subscription-modal"; import { RecurrenceScopeDialog, type RecurrenceEditScope } from "@/components/calendar/recurrence-scope-dialog"; import { NavigationRail } from "@/components/layout/navigation-rail"; +import { ResizeHandle } from "@/components/layout/resize-handle"; +import { cn } from "@/lib/utils"; import type { CalendarEvent, CalendarParticipant } from "@/lib/jmap/types"; import { getUserParticipantId } from "@/lib/calendar-participants"; import { debug } from "@/lib/debug"; @@ -76,6 +78,13 @@ export default function CalendarPage() { const [detailAnchorRect, setDetailAnchorRect] = useState(null); const hasFetched = useRef(false); + // Sidebar resize state + const [calSidebarWidth, setCalSidebarWidth] = useState(() => { + try { const v = localStorage.getItem("calendar-sidebar-width"); return v ? Number(v) : 256; } catch { return 256; } + }); + const [isResizing, setIsResizing] = useState(false); + const dragStartWidth = useRef(256); + // Swipe navigation ref (handlers defined after navigatePrev/navigateNext) const touchStartRef = useRef<{ x: number; y: number; time: number } | null>(null); @@ -721,26 +730,43 @@ export default function CalendarPage() { onTouchEnd={handleTouchEnd} > {!isMobile && ( -
- +
+ + { + updateCalendar(client, calendarId, { color }); + } : undefined} + onSubscribe={() => setShowSubscriptionModal(true)} + client={client} + /> +
+ { dragStartWidth.current = calSidebarWidth; setIsResizing(true); }} + onResize={(delta) => setCalSidebarWidth(Math.max(180, Math.min(400, dragStartWidth.current + delta)))} + onResizeEnd={() => { + setIsResizing(false); + localStorage.setItem("calendar-sidebar-width", String(calSidebarWidth)); + }} + onDoubleClick={() => { setCalSidebarWidth(256); localStorage.setItem("calendar-sidebar-width", "256"); }} /> - { - updateCalendar(client, calendarId, { color }); - } : undefined} - onSubscribe={() => setShowSubscriptionModal(true)} - client={client} - /> -
+ )} {renderView()} diff --git a/app/[locale]/contacts/page.tsx b/app/[locale]/contacts/page.tsx index 11ba0385..9c7f16cd 100644 --- a/app/[locale]/contacts/page.tsx +++ b/app/[locale]/contacts/page.tsx @@ -20,6 +20,7 @@ import { useEmailStore } from "@/stores/email-store"; import { toast } from "@/stores/toast-store"; import { cn } from "@/lib/utils"; import { NavigationRail } from "@/components/layout/navigation-rail"; +import { ResizeHandle } from "@/components/layout/resize-handle"; import { useIsMobile } from "@/hooks/use-media-query"; import type { ContactCard } from "@/lib/jmap/types"; @@ -75,6 +76,13 @@ export default function ContactsPage() { const { dialogProps: confirmDialogProps, confirm: confirmDialog } = useConfirmDialog(); const isMobile = useIsMobile(); + // Sidebar resize state + const [contactsSidebarWidth, setContactsSidebarWidth] = useState(() => { + try { const v = localStorage.getItem("contacts-sidebar-width"); return v ? Number(v) : 256; } catch { return 256; } + }); + const [isResizing, setIsResizing] = useState(false); + const dragStartWidth = useRef(256); + // Check auth on mount useEffect(() => { checkAuth().finally(() => { @@ -442,10 +450,15 @@ export default function ContactsPage() {
{showListPanel && ( -
+ <> +
+ {!isMobile && ( + { dragStartWidth.current = contactsSidebarWidth; setIsResizing(true); }} + onResize={(delta) => setContactsSidebarWidth(Math.max(180, Math.min(400, dragStartWidth.current + delta)))} + onResizeEnd={() => { + setIsResizing(false); + localStorage.setItem("contacts-sidebar-width", String(contactsSidebarWidth)); + }} + onDoubleClick={() => { setContactsSidebarWidth(256); localStorage.setItem("contacts-sidebar-width", "256"); }} + /> + )} + )} {showRightPanel && ( diff --git a/app/[locale]/settings/page.tsx b/app/[locale]/settings/page.tsx index 94fe2bf2..11a1dfc5 100644 --- a/app/[locale]/settings/page.tsx +++ b/app/[locale]/settings/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect } from 'react'; +import { useState, useEffect, useRef } from 'react'; import { useRouter } from '@/i18n/navigation'; import { useTranslations } from 'next-intl'; import { @@ -44,6 +44,7 @@ import { useAuthStore } from '@/stores/auth-store'; import { useEmailStore } from '@/stores/email-store'; import { useIsDesktop } from '@/hooks/use-media-query'; import { NavigationRail } from '@/components/layout/navigation-rail'; +import { ResizeHandle } from '@/components/layout/resize-handle'; import { useConfig } from '@/hooks/use-config'; import { cn } from '@/lib/utils'; @@ -94,6 +95,13 @@ export default function SettingsPage() { const [mobileShowContent, setMobileShowContent] = useState(false); const isDesktop = useIsDesktop(); + // Sidebar resize state + const [settingsSidebarWidth, setSettingsSidebarWidth] = useState(() => { + try { const v = localStorage.getItem('settings-sidebar-width'); return v ? Number(v) : 256; } catch { return 256; } + }); + const [isResizing, setIsResizing] = useState(false); + const dragStartWidth = useRef(256); + // Check auth on mount useEffect(() => { checkAuth().finally(() => { @@ -286,7 +294,13 @@ export default function SettingsPage() {
{/* Settings Sidebar */} -
+
{/* Header */}
+ {/* Sidebar resize handle */} + { dragStartWidth.current = settingsSidebarWidth; setIsResizing(true); }} + onResize={(delta) => setSettingsSidebarWidth(Math.max(180, Math.min(400, dragStartWidth.current + delta)))} + onResizeEnd={() => { + setIsResizing(false); + localStorage.setItem('settings-sidebar-width', String(settingsSidebarWidth)); + }} + onDoubleClick={() => { setSettingsSidebarWidth(256); localStorage.setItem('settings-sidebar-width', '256'); }} + /> + {/* Settings Content */}
diff --git a/components/files/file-browser.tsx b/components/files/file-browser.tsx index 2dfc7bd4..e62042f8 100644 --- a/components/files/file-browser.tsx +++ b/components/files/file-browser.tsx @@ -348,10 +348,10 @@ export function FileBrowser({ const saved = localStorage.getItem("files-sidebar-width"); if (saved) return Math.max(180, Math.min(400, Number(saved))); } - return 220; + return 256; }); const [isResizing, setIsResizing] = useState(false); - const dragStartWidth = useRef(220); + const dragStartWidth = useRef(256); const [dragTarget, setDragTarget] = useState(null); // Sync showThumbnails and folderLayout when settings change @@ -1104,7 +1104,7 @@ export function FileBrowser({ setIsResizing(false); localStorage.setItem("files-sidebar-width", String(sidebarWidth)); }} - onDoubleClick={() => { setSidebarWidth(220); localStorage.setItem("files-sidebar-width", "220"); }} + onDoubleClick={() => { setSidebarWidth(256); localStorage.setItem("files-sidebar-width", "256"); }} /> )} diff --git a/components/files/folder-tree-sidebar.tsx b/components/files/folder-tree-sidebar.tsx index 7feaf921..5809db0f 100644 --- a/components/files/folder-tree-sidebar.tsx +++ b/components/files/folder-tree-sidebar.tsx @@ -26,7 +26,7 @@ interface FolderTreeSidebarProps { isResizing?: boolean; } -export function FolderTreeSidebar({ currentPath, onNavigate, listByParentId, width = 220, isResizing }: FolderTreeSidebarProps) { +export function FolderTreeSidebar({ currentPath, onNavigate, listByParentId, width = 256, isResizing }: FolderTreeSidebarProps) { const t = useTranslations("files"); const client = useFileStore(s => s.client); const [rootChildren, setRootChildren] = useState(null);