Typing @ at the start of a word in the rich-text body offers the To and
Cc recipients (contact groups expanded) and inserts the chosen one's
first name as plain text. The name comes from the display name; with a
firstname.lastname@ address, the address tells which word of the name is
the first name, and without a name the address supplies it. A bare
initial keeps the mailbox name (@m.mustermann), and recipients who share
a first name get their full name. Bcc recipients are never offered -
naming one in the text would disclose them to everyone else.
The list only opens while a recipient matches, so Enter and Escape
otherwise keep their usual meaning. While it is open, Escape closes the
list rather than the composer, which handles Escape in the capture phase,
and the list closes when the editor loses focus.
Built on @tiptap/suggestion, at the version of the other TipTap packages.
Remove packages nothing imports any more (`@tiptap/extension-image`,
`asn1js`, `pkijs`, `pvtsutils`, `sonner`, `webcrypto-liner`) and the
`elliptic` override, which only applied through `webcrypto-liner`.
`sharp`, `undici`, `@tiptap/extension-paragraph` and
`@tiptap/extension-heading` were imported directly but only resolved as
transitive dependencies of next, jsdom and starter-kit. List them
explicitly and point the `undici` override at `$undici` so both stay in
step.
Keep the latest Docker tags on the stable release when a GitHub release is marked as a pre-release, so auto-updating deployments on :latest do not pick up beta builds.
`npm run typecheck` failed with 8 TS2307 errors from Next's generated
route validators referencing old page paths (e.g. calendar/page.js) after
routes moved to catch-all segments. Two causes:
- The production validator (.next/types) was stale. Prepend `next typegen`
so `tsc` always runs against freshly generated route types.
- The dev validator (.next/dev/types) is a turbopack-dev-only artifact that
is absent from clean/CI checkouts and goes stale locally. `next typegen`
force-re-adds it to tsconfig `include`, so exclude it instead (exclude
overrides include), leaving route typing to the maintained .next/types.
tsc still catches real type errors; verified `npm run typecheck` is clean
and idempotent.
- tailwind.config.ts is not actually being used so removed
- moved animate-fade-in to globals.css
- added tw-animate-css package to make animate-in work
- added a definition for animate-shake as it doesn't exist in tw-animate-css
Add an end-to-end integration harness that runs the webmail against a real
Stalwart mail server in Docker and drives it with Playwright, focused on the
mail/folder synchronisation behaviour (unread/total counters, folder-list
sync, account-scoped Unified Mailbox) that the unified-mailbox work touches.
- integration/ stack: Stalwart (declarative bootstrap: alice/bob/carol,
submission + IMAP listeners, permissive CORS) + webmail (dev mode, so the
browser's plaintext cross-origin JMAP calls aren't blocked by the prod CSP).
- Helpers: dependency-free SMTP submit client, JMAP client for seeding /
inspecting server state, and page helpers (login, add/switch account,
locale-independent folder-counter reads).
- Specs: login, single-account sync (receive/read/move/delete/folder-create/
burst) and multi-account (per-account isolation + cross-account Unified
Inbox aggregation + background-account delivery). 12 tests, all green.
- Add focused data-testid hooks to the mail UI (folder rows + counters, email
list items, account switcher, composer) for stable selectors.
- Exclude examples/ and integration/ from tsconfig/eslint/.dockerignore.
* feat: add Jalali (Persian/Shamsi) calendar support with Saturday as week start
- Add jalaali-js library for Gregorian ↔ Jalali date conversion
- Create lib/jalali-utils.ts with Jalali calendar utilities
- Create hooks/use-calendar-locale.ts for unified calendar locale handling
- Expand FirstDayOfWeek type to include 6 (Saturday)
- Update all calendar views (month, week, day, mini, toolbar) to support
Jalali calendar display and Saturday-first week ordering
- Add Jalali month names (Farvardin … Esfand) to all locale files
- Add Persian (fa) locale with full translations
- Update settings UI to include Saturday as first day of week option
- Update useFormatEventDate to show Jalali dates when locale is fa
- Auto-detect Jalali calendar when fa locale is active
The calendar system automatically switches to Jalali when the locale is
set to Persian (fa). All internal date handling remains Gregorian (ISO
8601) for JMAP protocol compatibility; Jalali conversion is purely at
the display layer.
* Add PR template for Jalali calendar feature
* chore: remove accidentally added PR template
* fix: add image_too_large key to fa locale for PR #462 compatibility
Next 16 removed the `next lint` subcommand, so `npm run lint` failed with
"Invalid project directory provided, no such directory: .../lint". Point the
lint and lint:fix scripts at ESLint directly, using the existing flat config
(eslint.config.mjs).
- MIME: Stalwart's download endpoint often returns application/octet-stream, so
blob: previews silently downloaded (UUID filename) instead of rendering.
Resolve the most specific MIME (attachment type -> filename ext -> blob type)
and re-wrap the blob; also fixes inline preview for images and video.
- Desktop PDF: render via <iframe> (reliable for blob: PDFs) instead of <object>.
- Mobile PDF: no usable inline viewer (Android shows a blank frame / silent
download; iOS Safari renders only the first page of a PDF in an <iframe>), so
render with pdf.js (canvas, dynamic-imported so it stays off the desktop
bundle; iOS-safe canvas cap). Double-tap zoom (fit -> 2x -> 3x -> fit) and
2-finger pinch zoom (to 4x), both centred on the gesture and pannable via
native scrolling.
- Route to pdf.js when navigator.pdfViewerEnabled is false (Android) and on iOS
(incl. iPadOS, which reports true yet shows only the first page in a frame).
- Modal header gains an open-in-new-tab icon (next to download/close); the
Android/browser Back button closes the preview instead of navigating the page.
- On a pdf.js render failure, offer an open-in-new-tab action as fallback.