feat: resizable columns, nav rail overhaul, multi-select & drag-drop, UI polish
Resizable Columns - Add ResizeHandle component with mouse drag, keyboard (Arrow keys), and double-click to reset to default width - Add sidebarWidth/emailListWidth to ui-store with clamping + persistence - Wire resize handles between sidebar/email-list panels on desktop Navigation Rail Overhaul - Move StorageQuotaCircle, push-status, sign-out from Sidebar to NavigationRail - Interactive SVG ring with popover breakdown (used/free/total) - Sidebar collapse state lifted to ui-store - Show total email count per mailbox alongside unread badge Email Multi-Selection & Drag-and-Drop - Ctrl+Click (toggle) and Shift+Click (range) on all list items - Add selectRangeEmails and lastSelectedEmailId to email-store - Enable drag-and-drop on thread items and thread headers - useEmailDrag accepts optional threadEmails for full-thread drag Email Viewer Layout - Remove card wrapper for cleaner full-width reading - Always render HTML body when available - Adjust skeleton loader to match flat layout Modal & UI Polish - Standardise backdrops, close buttons, padding, border-radius, transitions - Migrate template-string classNames to cn() in settings - Unify focus-ring token to ring-ring on form controls i18n - Add storage_used/free/total keys to all 8 locales Dev Mock JMAP Server (new, gated by DEV_MOCK_JMAP=true) - Session, Mailbox/Email/Thread/Identity CRUD, back-references, upload - GET /download with Content-Disposition, GET /eventsource SSE Tests (46 new) - ui-store (13), email-selection (10), resize-handle (9), mock-server (14)
This commit is contained in:
@@ -8,6 +8,7 @@ import { useDragDropContext } from "@/contexts/drag-drop-context";
|
||||
interface UseEmailDragOptions {
|
||||
email: Email;
|
||||
sourceMailboxId: string;
|
||||
threadEmails?: Email[];
|
||||
}
|
||||
|
||||
interface UseEmailDragReturn {
|
||||
@@ -42,18 +43,19 @@ function createDragPreview(count: number): HTMLElement {
|
||||
return preview;
|
||||
}
|
||||
|
||||
export function useEmailDrag({ email, sourceMailboxId }: UseEmailDragOptions): UseEmailDragReturn {
|
||||
export function useEmailDrag({ email, sourceMailboxId, threadEmails }: UseEmailDragOptions): UseEmailDragReturn {
|
||||
const { selectedEmailIds, emails } = useEmailStore();
|
||||
const { startDrag, endDrag, isDragging, draggedEmails } = useDragDropContext();
|
||||
|
||||
const handleDragStart = useCallback((e: DragEvent<HTMLDivElement>) => {
|
||||
// Determine which emails to drag:
|
||||
// - If current email is selected, drag all selected
|
||||
// - If threadEmails provided (thread header), drag all thread emails
|
||||
// - Otherwise, drag only this email
|
||||
const isSelected = selectedEmailIds.has(email.id);
|
||||
const emailsToDrag = isSelected
|
||||
? emails.filter(em => selectedEmailIds.has(em.id))
|
||||
: [email];
|
||||
: threadEmails || [email];
|
||||
|
||||
// Set data transfer
|
||||
e.dataTransfer.effectAllowed = "move";
|
||||
@@ -76,7 +78,7 @@ export function useEmailDrag({ email, sourceMailboxId }: UseEmailDragOptions): U
|
||||
});
|
||||
|
||||
startDrag(emailsToDrag, sourceMailboxId);
|
||||
}, [email, selectedEmailIds, emails, sourceMailboxId, startDrag]);
|
||||
}, [email, selectedEmailIds, emails, sourceMailboxId, startDrag, threadEmails]);
|
||||
|
||||
const handleDragEnd = useCallback(() => {
|
||||
endDrag();
|
||||
|
||||
Reference in New Issue
Block a user