mirror of
https://github.com/karatektus/pl_mail.git
synced 2026-10-25 10:04:18 +00:00
Snooze the open conversation from its toolbar, and with b
Every row offered a snooze menu and the conversation itself did not, so "not now" after reading a mail meant going back to the list to find its row. It was also the last key in #36 with nothing to press: b did nothing in an open conversation. The toolbar gets the clock button and the same menu, handled by mail--message-actions. Snoozing closes the pane, as archiving does, since the conversation has left the list it was opened from; clearing a snooze leaves the reader where they are. Offered where the row offers it, not for mail in the bin or in Spam. The menu opens from the button's left edge there. It opened from the right everywhere, which suits a button at the end of a row and would run off the pane from one at the start of a toolbar. Refs #36 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7d54acf4d2
commit
1bae047d77
9 files changed
+96
-5
No files matched your search
+2
-1
@@ -19,7 +19,8 @@ them off per person. No migration.
|
||||
|
||||
`a` replies on a message that has only one recipient, where there is no Reply to all to press. The
|
||||
toolbar above a selection has a **Star** button, and `s` presses it; before, `s` did nothing with
|
||||
rows ticked.
|
||||
rows ticked. An open conversation has a **Snooze** button in its toolbar, which is what `b` presses
|
||||
there.
|
||||
|
||||
**A config backup now carries how each person sorts their mail.** Settings → Categories — rules or
|
||||
the assistant, whether that overrules the provider's own categories, and whether the inbox has tabs
|
||||
|
||||
@@ -77,6 +77,30 @@ export default class extends Controller {
|
||||
this._closePane();
|
||||
}
|
||||
|
||||
/**
|
||||
* Snooze the open conversation, from its own toolbar.
|
||||
*
|
||||
* The wake time arrives as a param from mail--snooze-menu, which works it
|
||||
* out in the browser — the server has no timezone for the session. Absent,
|
||||
* this clears the snooze, exactly as the row's does.
|
||||
*
|
||||
* A snoozed conversation has left the list it was opened from, so the pane
|
||||
* closes, as it does after Archive. Clearing a snooze moves nothing the
|
||||
* reader is looking at, and they stay where they are.
|
||||
*/
|
||||
async snooze(event) {
|
||||
const { until = null } = event.params;
|
||||
event.stopPropagation();
|
||||
|
||||
if (false === await this._post(this._url("snooze"), { until })) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null !== until) {
|
||||
this._closePane();
|
||||
}
|
||||
}
|
||||
|
||||
async archive(event) {
|
||||
event.stopPropagation();
|
||||
this._close();
|
||||
|
||||
@@ -51,6 +51,7 @@ export default class extends Controller {
|
||||
// than teaching this controller which surface it is on.
|
||||
element.setAttribute("data-mail--message-row-until-param", at.toISOString());
|
||||
element.setAttribute("data-mail--list-toolbar-until-param", at.toISOString());
|
||||
element.setAttribute("data-mail--message-actions-until-param", at.toISOString());
|
||||
|
||||
const when = element.querySelector("[data-snooze-when]");
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ const OPEN = {
|
||||
star: "[data-action*='mail--message-actions#star']",
|
||||
label: "[data-action='click->mail--label-menu#toggle']",
|
||||
move: "[data-action='click->mail--move-menu#toggle']",
|
||||
snooze: "[data-shortcut='snooze']",
|
||||
back: "[data-action='click->mail--mail-pane#close']",
|
||||
reply: "[data-shortcut='reply']",
|
||||
replyAll: "[data-shortcut='reply-all']",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- translated-from: features/mail.md sha1:15c2febd1a3f8601aa57a89a38c29946ef9718cb -->
|
||||
<!-- translated-from: features/mail.md sha1:52f9fcdc53048f91fd103d949726d5cb242ac80f -->
|
||||
|
||||
# Mail
|
||||
|
||||
@@ -656,7 +656,8 @@ der Anbieter. Ein Filter ist der Weg, es hier dauerhaft zu machen.
|
||||
|
||||
Zurückstellen ist Archivieren mit Wecker. Die Konversation verlässt den Posteingang sofort —
|
||||
auch beim Anbieter, nicht nur in plMails Sicht darauf —, bekommt das Label Zurückgestellt und
|
||||
kommt zurück, wenn ihre Zeit um ist.
|
||||
kommt zurück, wenn ihre Zeit um ist. Den Uhr-Knopf gibt es in jeder Zeile, über einer Auswahl und
|
||||
in der Leiste einer geöffneten Unterhaltung.
|
||||
|
||||
Das Menü bietet **Später heute**, **Morgen**, **Dieses Wochenende**, **Nächste Woche**, **Datum
|
||||
und Uhrzeit wählen** und, bei bereits Zurückgestelltem, **Zurückholen**. Später heute ist 18:00
|
||||
|
||||
@@ -598,7 +598,8 @@ is how you make it stick here.
|
||||
## Snooze
|
||||
|
||||
Snoozing is archiving with a timer. The conversation leaves the Inbox now — at the provider too,
|
||||
not only in plMail's view of it — gains the Snoozed label, and comes back when its time is up.
|
||||
not only in plMail's view of it — gains the Snoozed label, and comes back when its time is up. The
|
||||
clock button is on every row, above a selection and in the toolbar of an open conversation.
|
||||
|
||||
The menu offers **Later today**, **Tomorrow**, **This weekend**, **Next week**, **Pick a date and
|
||||
time**, and **Unsnooze** on something already snoozed. Later today is 18:00 and is offered only
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
derives per-row URLs itself
|
||||
snoozed — whether the target is currently snoozed, which is the only
|
||||
thing that puts "Unsnooze" on the menu
|
||||
align — "left" to open from the button's left edge. The default
|
||||
opens from its right, which suits a button at the end of a
|
||||
row and runs off the pane from one at the start of a toolbar
|
||||
#}
|
||||
{% set snoozed = snoozed|default(false) %}
|
||||
{% set url = url|default(null) %}
|
||||
@@ -23,7 +26,7 @@
|
||||
<div data-ui--dropdown-target="menu" hidden
|
||||
data-controller="mail--snooze-menu"
|
||||
data-action="ui--dropdown:opened->mail--snooze-menu#refresh"
|
||||
class="absolute top-full mt-1 right-0 z-20 min-w-56 popover py-1">
|
||||
class="absolute top-full mt-1 {{ 'left' == align|default('right') ? 'left-0' : 'right-0' }} z-20 min-w-56 popover py-1">
|
||||
|
||||
<p class="px-3 py-1 text-[10px] font-semibold uppercase tracking-wide text-ink-faint">
|
||||
{{ 'thread_row.actions.snooze'|trans }}
|
||||
|
||||
@@ -64,6 +64,37 @@ self-contained: no {% extends %}, no block dependencies.
|
||||
{% endif %}
|
||||
|
||||
{{ tbtn('click->mail--message-actions#markUnread', 'fa-regular fa-envelope', 'toolbar.actions.mark_unread'|trans) }}
|
||||
|
||||
{# Snooze, which every row offered and the conversation itself did not:
|
||||
deciding "not now" is something done after reading a mail at least
|
||||
as often as before opening it, and from here it meant going back to
|
||||
the list to find the row again. It is also what `b` presses — see
|
||||
ui--shortcuts, whose keys do nothing where there is no control.
|
||||
|
||||
Where the row offers it and for the row's reason: not for mail that
|
||||
is already put away. Written out rather than through tbtn() for the
|
||||
one attribute the macro has no room for. #}
|
||||
{% if placement == 'normal' %}
|
||||
<div class="relative" data-controller="ui--dropdown">
|
||||
<button type="button"
|
||||
data-action="click->ui--dropdown#toggle"
|
||||
data-shortcut="snooze"
|
||||
aria-label="{{ 'toolbar.actions.snooze'|trans }}"
|
||||
title="{{ 'toolbar.actions.snooze'|trans }}"
|
||||
class="flex items-center justify-center w-8 h-8 rounded-full
|
||||
text-ink-muted hover:text-ink hover:bg-hover
|
||||
transition-colors duration-100 cursor-pointer">
|
||||
<i class="fa-solid fa-clock text-[15px]" aria-hidden="true"></i>
|
||||
</button>
|
||||
|
||||
{% include '_partials/_snooze_menu.html.twig' with {
|
||||
controller: 'mail--message-actions',
|
||||
method: 'snooze',
|
||||
snoozed: thread.isSnoozed,
|
||||
align: 'left',
|
||||
} only %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% include '_partials/_label_menu.html.twig' with {
|
||||
|
||||
@@ -211,6 +211,34 @@ test.describe("keyboard shortcuts", () => {
|
||||
await expect(page.locator(".compose-window").first()).toBeVisible();
|
||||
});
|
||||
|
||||
/**
|
||||
* `b` snoozes the conversation that is open.
|
||||
*
|
||||
* It did nothing there: every row had a snooze menu and the open
|
||||
* conversation had none, so there was no control for the key to press. The
|
||||
* toolbar has one now, and the mail leaves the inbox for Snoozed.
|
||||
*/
|
||||
test("b snoozes the open conversation", async ({ page }) => {
|
||||
await inbox(page);
|
||||
|
||||
const subject = INBOX_SUBJECTS.read;
|
||||
await mailRow(page, subject).click();
|
||||
await expect(page.locator('[data-shortcut="reply"]')).toBeVisible();
|
||||
|
||||
await page.keyboard.press("b");
|
||||
|
||||
const option = page.locator('[data-surface="reading"] [data-snooze-key="tomorrow"]');
|
||||
await expect(option).toBeVisible();
|
||||
await option.click();
|
||||
|
||||
// Back on the list, without it.
|
||||
await expect(page.locator(ROWS).first()).toBeVisible();
|
||||
await expect(mailRow(page, subject)).toHaveCount(0);
|
||||
|
||||
await page.goto("/mail/snoozed");
|
||||
await expect(mailRow(page, subject)).toHaveCount(1);
|
||||
});
|
||||
|
||||
test("switched off, a key is only a key", async ({ page }) => {
|
||||
await setShortcuts(page, "Off");
|
||||
|
||||
|
||||
Reference in new issue
Block a user