mirror of
https://github.com/karatektus/pl_mail.git
synced 2026-10-25 01:54:10 +00:00
A per-user Reading pane setting, Off or Right. Right shows the message
list and the open message side by side when the mail card is at least
52rem wide, with a divider that is dragged, moved with the arrow keys or
reset with a double-click. The message's share of the card is stored as
a percentage, 25 to 75, so it keeps its meaning when the calendar pane
opens or is resized. Off is the default and changes nothing.
The mode and the share live in the user's settings bag, not in the
Appearance embeddable: where a message is drawn is not part of a theme
somebody might export. A config backup carries both. No migration.
A message opened by its own address has no list behind it, so beside
the list it is shown next to the Inbox.
Review added, in the same change:
Divider one pixel of layout with the grip laid over it, so no
strip of bare card sits between the list and the line.
Toolbars the list's and the open message's are the same height.
Selection Archive, Delete and Move to stay above a selection; the
other six actions are under More.
Shortcuts a key acts on ticked rows wherever the list is on
screen, and ticking a row with the mouse no longer
leaves every key after it dead.
Settings a Features group with a page each for the reading pane
and the keyboard shortcuts.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
87 lines
5.0 KiB
Twig
87 lines
5.0 KiB
Twig
{#
|
|
_label_menu.html.twig
|
|
─────────────────────────────────────────────────────────────────────────────
|
|
"Label as" dropdown for the list toolbar and the thread view toolbar.
|
|
|
|
Variables:
|
|
labels Label[] flat list of the user's custom labels (role null),
|
|
pre-ordered; indentation derives from label.depth
|
|
targetType string "thread" | "message"
|
|
targetId int|null when null the Stimulus controller resolves selected
|
|
rows from the list instead (bulk mode)
|
|
activeLabels int[] ids of labels currently attached (single-target mode)
|
|
trigger bool false where something else opens the panel — the list
|
|
toolbar's "More" menu has a row for it. The button is
|
|
still rendered, and still has a box: it is what that
|
|
row and the `l` key press, so there is one way in, and
|
|
it is what the panel is placed against, so it cannot
|
|
be `display: none` — a button with no box measures as
|
|
a point in the window's corner, and the panel opened
|
|
there. Invisible, unfocusable, and filling whatever
|
|
positioned box the include sits in. Default true.
|
|
align string "right" (default) | "left": which edge of the trigger
|
|
the panel hangs from. Left where the trigger sits near
|
|
the start of a toolbar, so the panel opens into the
|
|
pane and not off its edge.
|
|
#}
|
|
{% set trigger = trigger is defined ? trigger : true %}
|
|
<div data-controller="mail--label-menu"
|
|
data-mail--label-menu-target-type-value="{{ targetType }}"
|
|
{% if targetId is defined and targetId is not null %}data-mail--label-menu-target-id-value="{{ targetId }}"{% endif %}
|
|
class="{{ trigger ? 'relative' : 'absolute inset-0' }}">
|
|
|
|
<button type="button"
|
|
data-action="click->mail--label-menu#toggle"
|
|
{% if false == trigger %}data-toolbar-flyout="label" tabindex="-1" aria-hidden="true"{% endif %}
|
|
aria-label="{{ 'toolbar.actions.label'|trans }}"
|
|
class="{{ trigger
|
|
? 'group relative 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'
|
|
: 'block w-full h-full invisible' }}">
|
|
<i class="fa-solid fa-tag text-sm" aria-hidden="true"></i>
|
|
</button>
|
|
|
|
<div data-mail--label-menu-target="panel"
|
|
data-align="{{ align|default('right') }}"
|
|
class="hidden absolute {{ 'left' == align|default('right') ? 'left-0' : 'right-0' }} top-full mt-1 z-30 w-56 max-h-72 pointer-events-auto overflow-y-auto rounded-pane
|
|
bg-pane-soft backdrop-blur-sm
|
|
border border-line
|
|
shadow-pop py-1">
|
|
|
|
{% if labels|length == 0 %}
|
|
<p class="px-3 py-2 text-xs text-ink-faint">{{ 'label.menu.empty'|trans }}</p>
|
|
{% else %}
|
|
{% for label in labels %}
|
|
<button type="button"
|
|
data-action="click->mail--label-menu#toggleLabel"
|
|
data-mail--label-menu-label-id-param="{{ label.id }}"
|
|
data-label-id="{{ label.id }}"
|
|
data-attached="{{ activeLabels is defined and label.id in activeLabels ? 'true' : 'false' }}"
|
|
class="w-full flex items-center gap-2 px-3 py-1.5 text-sm text-left
|
|
text-ink-soft
|
|
hover:bg-hover transition-colors cursor-pointer"
|
|
style="padding-left: {{ 12 + label.depth * 14 }}px">
|
|
<i data-mail--label-menu-target="check"
|
|
class="fa-solid fa-check w-3.5 text-accent
|
|
{{ activeLabels is defined and label.id in activeLabels ? '' : 'invisible' }}"
|
|
aria-hidden="true"></i>
|
|
<span class="truncate">{{ label|label_name }}</span>
|
|
</button>
|
|
{% endfor %}
|
|
{% endif %}
|
|
|
|
<div class="border-t border-line mt-1 pt-1">
|
|
<button type="button"
|
|
data-controller="ui--modal"
|
|
data-action="click->ui--modal#open click->mail--label-menu#close"
|
|
data-ui--modal-title-value="{{ 'sidebar.labels.add'|trans }}"
|
|
data-ui--modal-src-value="{{ path('app_label_new') }}"
|
|
class="w-full flex items-center gap-2 px-3 py-1.5 text-sm text-left
|
|
text-ink-soft
|
|
hover:bg-hover transition-colors cursor-pointer">
|
|
<i class="fa-solid fa-plus w-3.5" aria-hidden="true"></i>
|
|
{{ 'label.menu.create'|trans }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|