mirror of
https://github.com/karatektus/pl_mail.git
synced 2026-10-25 01:54:10 +00:00
Five reported defects in the compose editor, and one the mobile specs were
never going to catch.
The clock. formatWallClock() asked Intl for an hour and never said which
kind, so the send-later presets followed the LOCALE's default rather than the
user's twelve-or-twenty-four-hour setting — "8:00 AM" beside server-rendered
timestamps reading 08:00. The setting is now stamped on <html> once per render
and read back through assets/clock_format.js, which is a module rather than a
Stimulus value because the snooze menu had the identical bug and shares no
template with compose. Both pass hour12 explicitly now.
The link button. It raised prompt('Enter URL:') — one unthemed field, no way
to say what the link should read as, and a bare "example.com" going in as a
relative link to a path inside the app. It is now a popover with a URL field
and a text field, the text prefilled from the selection. The selection
survives because the toolbar's saved range is FROZEN while the popover is
open: focusing the URL field blurs the editor, and a blur allowed to re-read
the selection would record the collapsed one. URLs are normalised and screened
against MailBodySanitizer's own allowLinkSchemes list, so nothing the editor
accepts is silently dropped on save, and "example.com" becomes https://.
Links in the editor. A click in a contenteditable places a caret and nothing
else, so a link just written was unreachable. Clicking one now shows the same
popover's other face — the address, Open, Change, Remove — and it dismisses on
Escape, on an outside click, and when the caret moves off the link. It does
not take focus and does not restore any range, because that face appears
beside a caret the user placed themselves. Anchors in the editor are also
styled as links again: Tailwind's preflight resets `a` to inherit, which left
a freshly inserted link indistinguishable from the words around it.
The emoji picker's "weird black borders". --rgb-line is `0 0 0` in every light
theme and `255 255 255` in every dark one — a hue whose weight lives in
--line-alpha — and the picker was handed it with no alpha, so its hairlines
resolved to pure black. Its search field and scrollbar were black for a second
reason: emoji-picker-element declares color-scheme on its own :host from
prefers-color-scheme, the OS setting this app uses for nothing. Both fixed,
the second with `color-scheme: inherit` so a runtime theme switch carries the
picker with it.
The plain-text warning. window.confirm() becomes a popover over the editor,
with the same rule (only when there is formatting to lose) and the same
reversibility. Refusable by Cancel, Escape or an outside click.
And the one nobody reported: the More-options menu was UNREACHABLE on a phone.
Its button sits in .compose-scroll-x, whose overflow-x:auto computes
overflow-y:auto too, so a menu opening upwards out of a 36px strip was clipped
to nothing — plain text, priority and read receipt could be tapped open and
never seen. Pinned to the viewport below md, as the emoji panel already was.
compose-mobile.spec.ts now measures every one of these against the viewport at
393px AND 320px, in both axes and with a minimum size, because the last round
shipped an off-screen emoji panel past a spec that only asserted the panel
existed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
37 lines
1.3 KiB
JavaScript
37 lines
1.3 KiB
JavaScript
/**
|
|
* The user's twelve-or-twenty-four-hour choice, on the browser side.
|
|
*
|
|
* Every time Twig prints goes through ClockGlobal, which resolves the setting
|
|
* (`clock.time`, `clock.timeCompact`, `clock.hour`). Nothing in the browser
|
|
* can reach it: `Intl.DateTimeFormat` asked for an hour and not told which
|
|
* kind falls back to the LOCALE's default, so an en-GB user who had chosen a
|
|
* 12-hour clock got 24-hour labels and an en-US user who had chosen 24 got
|
|
* "8:00 AM" — in the send-later menu and the snooze menu, next to timestamps
|
|
* the server had drawn the other way round.
|
|
*
|
|
* Its own module rather than a Stimulus value because the two menus that want
|
|
* it share no template and no controller, and the list of surfaces that print
|
|
* a time from JavaScript only grows. templates/_layout/app.html.twig stamps
|
|
* the setting on <html> once per render; this reads it back.
|
|
*/
|
|
|
|
/**
|
|
* @param {Document} [doc]
|
|
* @returns {boolean|undefined} `undefined` — meaning "let the locale decide" —
|
|
* when there is no preference on the page, which is a document rendered
|
|
* outside the app layout or a unit test.
|
|
*/
|
|
export function prefersHour12(doc = document) {
|
|
const flag = doc?.documentElement?.dataset?.clockHour12;
|
|
|
|
if ("true" === flag) {
|
|
return true;
|
|
}
|
|
|
|
if ("false" === flag) {
|
|
return false;
|
|
}
|
|
|
|
return undefined;
|
|
}
|