Files
jmap-webmail/docs/ARCHITECTURE.md
T
Matthieu MALVACHE 82a27a1f52 feat(calendar): add drag-create, resize, recurring scope, quick-create, and duplication
Address GitHub issue #13 (events not spanning real duration, hour label alignment)
and add five standard calendar UX features:

- Click-drag on empty time slots to create events with pre-filled time range
- Resize events by dragging bottom edge handle (15-min snap, optimistic JMAP update)
- Recurring event edit/delete scope dialog (this/following/all occurrences)
- Double-click quick create with inline title input (PT1H default)
- Event duplication button in modal (clones +1 day, opens for editing)

Shared interaction logic extracted to hooks/use-time-grid-interactions.ts.
All features include i18n (8 locales), accessibility (ARIA, pointer events),
and proper error handling with toast feedback.
2026-02-22 17:31:16 +01:00

165 lines
8.3 KiB
Markdown

# JMAP Webmail - Architecture Reference
> Implementation details, file locations, and feature documentation.
> Last verified: 2026-02-22
## Settings Integration Status
All settings are properly wired to their functionality:
| Setting | Store Location | UI Control | Integration |
|---------|---------------|------------|-------------|
| deleteAction | settings-store.ts:26 | email-settings.tsx | Moves to trash or permanently deletes |
| showPreview | settings-store.ts:27 | email-settings.tsx | Conditionally renders preview in email list |
| externalContentPolicy | settings-store.ts:29 | email-settings.tsx | Controls external content blocking (ask/block/allow) |
| debugMode | settings-store.ts:40 | advanced-settings.tsx | Conditional logging via lib/debug.ts |
| animationsEnabled | settings-store.ts:17 | appearance-settings.tsx | Works via CSS variable |
| markAsReadDelay | settings-store.ts:25 | email-settings.tsx | Fully integrated |
## Email Features
### Drag-and-Drop
- Native HTML5 DnD API — drag emails to mailbox folders in sidebar
- Files: `contexts/drag-drop-context.tsx`, `hooks/use-email-drag.ts`, `hooks/use-mailbox-drop.ts`
- Multi-select support, permission validation, visual feedback
### Context Menus
- Right-click on email list items
- Files: `components/ui/context-menu.tsx`, `components/email/email-context-menu.tsx`, `hooks/use-context-menu.ts`
- Reply, Forward, Move to, Color tags, Delete — supports batch operations
### Mobile Responsive
- Adaptive single/multi-pane layout
- Files: `stores/ui-store.ts`, `hooks/use-media-query.ts`, `components/layout/mobile-header.tsx`
- Hamburger menu navigation, view switching, safe area support
### Keyboard Shortcuts
- Hook: `hooks/use-keyboard-shortcuts.ts`
- Modal: `components/keyboard-shortcuts-modal.tsx`
- Navigation: j/k or arrows (next/prev email), Enter/o (open), Esc (close)
- Actions: r (reply), R/a (reply all), f (forward), s (star), e (archive), #/Del (delete), u (unread)
- Global: c (compose), / (search), ? (help), Shift+G (refresh), Ctrl+A (select all)
- Threads: x (expand/collapse thread)
- Disabled when typing in inputs or when composer is open
### Email Threading
- Gmail-style inline expansion (desktop), full-screen conversation view (mobile)
- Files:
- `lib/thread-utils.ts` — Thread grouping utilities
- `lib/jmap/types.ts` — ThreadGroup interface
- `lib/jmap/client.ts` — getThread(), getThreadEmails() methods
- `stores/email-store.ts` — Thread expansion state
- `components/email/thread-list-item.tsx` — Collapsed/expanded thread view
- `components/email/thread-email-item.tsx` — Compact email within thread
- `components/email/thread-conversation-view.tsx` — Full-screen mobile conversation view
- `components/email/email-list.tsx` — Groups emails by threadId
### Dark Mode Email Readability
- Intelligent color transformation during HTML sanitization
- Files: `lib/color-transform.ts`, `components/email/email-viewer.tsx`
- Luminance < 0.4 (very dark): Inverted and brightened
- Luminance 0.4-0.6 (medium): Lightened by 40-50%
- Luminance > 0.6 (light): Preserved as-is
### Newsletter Unsubscribe (RFC 2369)
- Files: `lib/validation.ts`, `lib/email-headers.ts`, `components/email/unsubscribe-banner.tsx`
- URL validation blocks XSS vectors, two-step confirmation, localStorage persistence
- Supports both HTTP (one-click) and mailto methods
### Email Layout & Blocked Content Fix
- Removed `width: max-content` / `display: inline-block` from email content wrappers
- Files: `app/globals.css`, `lib/email-sanitization.ts`, `components/email/email-viewer.tsx`
- Blocked images: walks up DOM to collapse empty containers
## Identity Management & Sub-Addressing
- Full CRUD: `stores/identity-store.ts`, `lib/jmap/client.ts` (Identity/get, Identity/set)
- Components: `components/identity/identity-manager-modal.tsx`, `components/identity/identity-form.tsx`
- Sub-addressing: `lib/sub-addressing.ts` (parse, generate, suggest)
- Visual badges: `components/email/email-identity-badge.tsx`
## Calendar Integration
### Core
- JMAP Calendars: Full CalendarEvent CRUD with RFC 8984 types
- Files: `lib/jmap/types.ts`, `lib/jmap/client.ts`, `stores/calendar-store.ts`
- Capability detection: `urn:ietf:params:jmap:calendars` in auth-store.ts
- UI: `components/calendar/` (month-view, week-view, day-view, agenda-view, toolbar, event-modal, event-detail-popover, event-card, mini-calendar, calendar-sidebar-panel)
- Settings: `components/settings/calendar-settings.tsx`
- Keyboard: m (month), w (week), d (day), a (agenda), t (today), n (new event), arrows (navigate)
### Drag-and-Drop Rescheduling
- Week/day views: 15-min snap with visual indicator
- Month view: date move with blue ring highlight
- HTML5 DnD API with `application/x-calendar-event` payload
### Click-Drag to Create
- Pointer events, 5px movement threshold
- Shared hook: `hooks/use-time-grid-interactions.ts`
### Event Resize
- Drag bottom edge, 15-min snap, optimistic JMAP update
- `role="separator"` with aria-label
### Recurring Event Edit Scope
- "This event only" / "This and following" / "All events" dialog
- Files: `components/calendar/recurrence-scope-dialog.tsx`
### Event Detail Popover (Read-Only View)
- Click event → read-only popover (instead of edit form)
- Component: `components/calendar/event-detail-popover.tsx`
- Displays: title, calendar, date/time, location (URL-aware with `target="_blank" rel="noreferrer"`), virtual meeting link, participants with status badges, recurrence, reminder, description
- Actions: Edit (opens modal), Delete (with confirmation), Duplicate
- Quick note: inline input appends timestamped note to description
- RSVP bar for attendees (Accept/Tentative/Decline)
- Smart positioning: right → left → below → above, stays in viewport
- Portal-rendered, CSS transition entrance, dismisses on Escape/click-outside/scroll
### Double-Click Quick Create
- Inline title input, PT1H default, timer-based click disambiguation
- Component: `components/calendar/quick-event-input.tsx`
### iCalendar Import
- Files: `lib/jmap/client.ts` (parseCalendarEvents), `components/calendar/ical-import-modal.tsx`
- Multi-step flow: file select → preview list → calendar selector → import (5MB max)
## Email Filters & Sieve Rules (RFC 9661)
- Types: `lib/jmap/sieve-types.ts`
- Client: `lib/jmap/client.ts` (12 Sieve methods)
- Generator/Parser: `lib/sieve/generator.ts`, `lib/sieve/parser.ts`
- Store: `stores/filter-store.ts`
- UI: `components/settings/filter-settings.tsx`, `components/filters/filter-rule-modal.tsx`, `components/filters/sieve-editor-modal.tsx`
- Conditions: From, To, Cc, Subject, Custom Header, Size, Body
- Actions: Move, Copy, Forward, Mark read, Star, Label, Discard, Reject, Keep, Stop
## Email Templates
- Local storage via Zustand persist middleware
- Files: `lib/template-types.ts`, `stores/template-store.ts`, `lib/template-utils.ts`
- Components: `components/templates/` (template-manager-modal, template-form, template-picker, placeholder-fill-modal)
- Placeholder variables: `{{variable}}` syntax with auto-fill from composer context
- Composer shortcut: Ctrl+Shift+T
## Accessibility (WCAG 2.0 AA)
- Color contrast rules documented in CLAUDE.md
- All color via CSS variables or Tailwind classes
- ARIA roles on calendar grids, event cards, modals
- Focus trap in all modals, 44px mobile touch targets
- Reduced-motion media query, sr-only live region
## Dependency Versions (2026-02-16)
- next 16.1.6, react 19.2.4, next-intl 4.8.3, zustand 5.0.11, vitest 4.0.18
- @types/node 25, jsdom 28, lucide-react 0.564
## Feature Completeness Summary
- **Authentication**: Complete (Basic Auth + TOTP 2FA)
- **Email Operations**: Complete (threading, unsubscribe, templates)
- **Real-time Updates**: Complete (EventSource push)
- **UI**: Settings integrated, DnD, context menus, mobile, keyboard, WCAG AA
- **Identity Management**: Complete (CRUD, sub-addressing, signatures)
- **Contacts/Address Book**: Complete (groups, vCard, bulk ops)
- **Advanced Search**: Complete (JMAP filters, search chips)
- **Vacation Responder**: Complete (JMAP VacationResponse)
- **Calendar**: Phase 5 complete (event detail popover, quick notes, drag-create, resize, recurring scope, quick create, duplication, import, notifications)
- **Email Filters**: Complete (Sieve RFC 9661, visual + raw editor)
- **Security**: CSP Report-Only + all P0 headers
- **Testing**: 669 tests passing