Email reader: two-row action layout — Summary+More above, Reply/Forward/AI reply below

Restructure the action cluster so it stays as two visible rows inside
.email-reader-actions instead of flattening via display:contents:
- Top row: Summary, More
- Bottom row: Reply, Reply all (conditional), Forward, AI reply
Dropped the Search button — wasn't part of the requested layout.

CSS: .email-reader-actions becomes flex column with both rows
right-aligned; .email-reader-actions-row becomes a real flex row
(no more display:contents flattening) so each row stays on its own
line. Whole block continues to sit beside the From/To meta inside
.email-reader-header.
This commit is contained in:
pewdiepie-archdaemon
2026-06-11 18:40:16 +09:00
parent 7b3bc598f4
commit 6a392542f3
2 changed files with 61 additions and 33 deletions
+52 -20
View File
@@ -2559,17 +2559,16 @@ async function _toggleCardPreview(card, em) {
</div>
<div class="email-reader-actions">
<div class="email-reader-actions-row email-reader-actions-row-primary">
<button class="memory-toolbar-btn reader-icon-btn" data-act="reply" title="Reply"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 17 4 12 9 7"/><path d="M20 18v-2a4 4 0 0 0-4-4H4"/></svg><span class="reader-btn-label">Reply</span></button>
${_hasMultipleRecipients(data) ? `<button class="memory-toolbar-btn reader-icon-btn" data-act="reply-all" title="Reply All"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="7 17 2 12 7 7"/><polyline points="12 17 7 12 12 7"/><path d="M22 18v-2a4 4 0 0 0-4-4H7"/></svg><span class="reader-btn-label">Reply all</span></button>` : ''}
<button class="memory-toolbar-btn reader-icon-btn" data-act="forward" title="Forward"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 17 20 12 15 7"/><path d="M4 18v-2a4 4 0 0 1 4-4h12"/></svg><span class="reader-btn-label">Forward</span></button>
<button class="memory-toolbar-btn reader-icon-btn" data-act="from-sender" title="Search text in this thread"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg><span class="reader-btn-label">Search</span></button>
<button class="memory-toolbar-btn reader-icon-btn" data-act="summarize" title="Summarize">${_summaryIcon(data)}<span class="reader-btn-label">Summary</span></button>
<div class="email-reader-more-wrap" style="position:relative">
<button class="memory-toolbar-btn reader-icon-btn" data-act="more" title="More actions"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="5" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="19" r="2"/></svg><span class="reader-btn-label">More</span></button>
</div>
</div>
<div class="email-reader-actions-row email-reader-actions-row-secondary">
<button class="memory-toolbar-btn reader-icon-btn" data-act="reply" title="Reply"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 17 4 12 9 7"/><path d="M20 18v-2a4 4 0 0 0-4-4H4"/></svg><span class="reader-btn-label">Reply</span></button>
${_hasMultipleRecipients(data) ? `<button class="memory-toolbar-btn reader-icon-btn" data-act="reply-all" title="Reply All"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="7 17 2 12 7 7"/><polyline points="12 17 7 12 12 7"/><path d="M22 18v-2a4 4 0 0 0-4-4H7"/></svg><span class="reader-btn-label">Reply all</span></button>` : ''}
<button class="memory-toolbar-btn reader-icon-btn" data-act="forward" title="Forward"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 17 20 12 15 7"/><path d="M4 18v-2a4 4 0 0 1 4-4h12"/></svg><span class="reader-btn-label">Forward</span></button>
<button class="memory-toolbar-btn reader-icon-btn" data-act="ai-reply" title="${data.cached_ai_reply ? 'AI Reply (cached draft ready)' : 'AI Reply (suggest a draft)'}">${_aiReplyIcon(data)}<span class="reader-btn-label">AI reply</span></button>
<button class="memory-toolbar-btn reader-icon-btn" data-act="summarize" title="Summarize">${_summaryIcon(data)}<span class="reader-btn-label">Summary</span></button>
</div>
</div>
</div>
@@ -4409,17 +4408,16 @@ async function _openEmailWindow(em, folder) {
</div>
<div class="email-reader-actions">
<div class="email-reader-actions-row email-reader-actions-row-primary">
<button class="memory-toolbar-btn reader-icon-btn" data-act="reply" title="Reply"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 17 4 12 9 7"/><path d="M20 18v-2a4 4 0 0 0-4-4H4"/></svg><span class="reader-btn-label">Reply</span></button>
${_hasMultipleRecipients(data) ? `<button class="memory-toolbar-btn reader-icon-btn" data-act="reply-all" title="Reply All"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="7 17 2 12 7 7"/><polyline points="12 17 7 12 12 7"/><path d="M22 18v-2a4 4 0 0 0-4-4H7"/></svg><span class="reader-btn-label">Reply all</span></button>` : ''}
<button class="memory-toolbar-btn reader-icon-btn" data-act="forward" title="Forward"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 17 20 12 15 7"/><path d="M4 18v-2a4 4 0 0 1 4-4h12"/></svg><span class="reader-btn-label">Forward</span></button>
<button class="memory-toolbar-btn reader-icon-btn" data-act="from-sender" title="Search text in this thread"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg><span class="reader-btn-label">Search</span></button>
<button class="memory-toolbar-btn reader-icon-btn" data-act="summarize" title="Summarize">${_summaryIcon(data)}<span class="reader-btn-label">Summary</span></button>
<div class="email-reader-more-wrap" style="position:relative">
<button class="memory-toolbar-btn reader-icon-btn" data-act="more" title="More actions"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="5" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="19" r="2"/></svg><span class="reader-btn-label">More</span></button>
</div>
</div>
<div class="email-reader-actions-row email-reader-actions-row-secondary">
<button class="memory-toolbar-btn reader-icon-btn" data-act="reply" title="Reply"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 17 4 12 9 7"/><path d="M20 18v-2a4 4 0 0 0-4-4H4"/></svg><span class="reader-btn-label">Reply</span></button>
${_hasMultipleRecipients(data) ? `<button class="memory-toolbar-btn reader-icon-btn" data-act="reply-all" title="Reply All"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="7 17 2 12 7 7"/><polyline points="12 17 7 12 12 7"/><path d="M22 18v-2a4 4 0 0 0-4-4H7"/></svg><span class="reader-btn-label">Reply all</span></button>` : ''}
<button class="memory-toolbar-btn reader-icon-btn" data-act="forward" title="Forward"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 17 20 12 15 7"/><path d="M4 18v-2a4 4 0 0 1 4-4h12"/></svg><span class="reader-btn-label">Forward</span></button>
<button class="memory-toolbar-btn reader-icon-btn" data-act="ai-reply" title="${data.cached_ai_reply ? 'AI Reply (cached draft ready)' : 'AI Reply (suggest a draft)'}">${_aiReplyIcon(data)}<span class="reader-btn-label">AI reply</span></button>
<button class="memory-toolbar-btn reader-icon-btn" data-act="summarize" title="Summarize">${_summaryIcon(data)}<span class="reader-btn-label">Summary</span></button>
</div>
</div>
</div>
@@ -5359,7 +5357,7 @@ function _summaryIcon(data) {
return `<svg width="14" height="14" viewBox="0 0 24 24" fill="${fill}"><path d="M12 0L14.59 8.41L23 12L14.59 15.59L12 24L9.41 15.59L1 12L9.41 8.41Z"/></svg>`;
}
async function _runAiReplyFromButton(btn, em, data, mode) {
async function _runAiReplyFromButton(btn, em, data, mode, noteHint = '') {
_snapEmailModalToLeftSidebar(btn.closest('.modal'));
btn.disabled = true;
const orig = btn.innerHTML;
@@ -5371,7 +5369,7 @@ async function _runAiReplyFromButton(btn, em, data, mode) {
btn.appendChild(wp.element);
} catch (_) {}
try {
if (state._onEmailClick) await state._onEmailClick({ email: em, emailData: data, mode });
if (state._onEmailClick) await state._onEmailClick({ email: em, emailData: data, mode, noteHint });
} finally {
try { wp && wp.stop(); } catch (_) {}
btn.disabled = false;
@@ -5406,16 +5404,47 @@ function _showAiReplyChoice(btn, em, data) {
// Full = layered concentric circles to suggest "more, deeper" — not a fully
// filled circle so it reads as a complement to the lightning, not as a "stop".
menu.innerHTML = `
<button class="memory-toolbar-btn" data-mode="ai-reply-fast" title="Shorter, faster draft" style="display:inline-flex;align-items:center;gap:5px;">
<svg width="11" height="11" viewBox="0 0 24 24" fill="var(--accent, var(--red))" aria-hidden="true"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
Fast
</button>
<button class="memory-toolbar-btn" data-mode="ai-reply-full" title="Uses the fuller reply context" style="display:inline-flex;align-items:center;gap:5px;">
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="var(--accent, var(--red))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5" fill="var(--accent, var(--red))"/></svg>
Full
</button>
<div class="email-ai-reply-row" style="display:flex;align-items:center;gap:4px;">
<button class="memory-toolbar-btn" data-mode="ai-reply-fast" title="Shorter, faster draft" style="display:inline-flex;align-items:center;gap:5px;">
<svg width="11" height="11" viewBox="0 0 24 24" fill="var(--accent, var(--red))" aria-hidden="true"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
Fast
</button>
<button class="memory-toolbar-btn" data-mode="ai-reply-full" title="Uses the fuller reply context" style="display:inline-flex;align-items:center;gap:5px;">
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="var(--accent, var(--red))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5" fill="var(--accent, var(--red))"/></svg>
Full
</button>
<button class="memory-toolbar-btn" data-act="note-toggle" title="Add a note about how to reply" style="display:inline-flex;align-items:center;justify-content:center;padding:4px 6px;line-height:1;">
<svg width="14" height="4" viewBox="0 0 14 4" fill="var(--accent, var(--red))" aria-hidden="true"><circle cx="2" cy="2" r="1.4"/><circle cx="7" cy="2" r="1.4"/><circle cx="12" cy="2" r="1.4"/></svg>
</button>
</div>
<div class="email-ai-reply-note" hidden style="display:flex;flex-direction:column;gap:5px;padding-top:6px;border-top:1px solid var(--border);margin-top:6px;">
<textarea class="email-ai-reply-note-text" placeholder="Tell the AI how to reply (e.g. 'thank them and confirm Tuesday at 2', 'decline politely')" rows="3" style="resize:vertical;width:100%;min-width:240px;font-family:inherit;font-size:12px;padding:6px 8px;border:1px solid var(--border);border-radius:5px;background:var(--bg);color:var(--fg);box-sizing:border-box;"></textarea>
<div style="display:flex;justify-content:flex-end;">
<button class="memory-toolbar-btn" data-act="note-send" title="Draft using this note" style="display:inline-flex;align-items:center;gap:5px;color:var(--accent, var(--red));border-color:color-mix(in srgb, var(--accent, var(--red)) 45%, var(--border));">
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
Draft with note
</button>
</div>
</div>
`;
menu.addEventListener('click', async (ev) => {
const noteToggle = ev.target.closest('[data-act="note-toggle"]');
if (noteToggle) {
ev.preventDefault(); ev.stopPropagation();
const panel = menu.querySelector('.email-ai-reply-note');
const wasHidden = panel.hidden;
panel.hidden = !wasHidden;
if (wasHidden) panel.querySelector('textarea')?.focus();
return;
}
const noteSend = ev.target.closest('[data-act="note-send"]');
if (noteSend) {
ev.preventDefault(); ev.stopPropagation();
const note = (menu.querySelector('.email-ai-reply-note-text')?.value || '').trim();
_closeAiReplyChoice();
await _runAiReplyFromButton(btn, em, data, 'ai-reply-full', note);
return;
}
const choice = ev.target.closest('[data-mode]');
if (!choice) return;
ev.preventDefault();
@@ -5424,6 +5453,9 @@ function _showAiReplyChoice(btn, em, data) {
_closeAiReplyChoice();
await _runAiReplyFromButton(btn, em, data, mode);
});
// Esc closes the popover; ignore plain clicks inside the menu so the
// textarea stays focused.
menu.addEventListener('mousedown', (ev) => ev.stopPropagation());
document.body.appendChild(menu);
setTimeout(() => document.addEventListener('click', _closeAiReplyChoice, true), 0);
}
+9 -13
View File
@@ -28078,23 +28078,19 @@ button .spinner-whirlpool {
.recipient-chip { flex-shrink: 0; }
}
.email-reader-actions {
display: flex; gap: 4px; flex-wrap: wrap; align-items: center;
display: flex; flex-direction: column; gap: 4px; align-items: flex-end;
flex-shrink: 0;
justify-content: flex-end;
margin-top: -4px;
}
/* The HTML wraps the buttons in two .email-reader-actions-row divs (primary
+ secondary). On mobile those flatten via `display: contents` inside the
max-width:768px block; apply the same here so the whole row stays on one
line on desktop too. */
/* Two stacked rows inside .email-reader-actions:
primary Summary + More (top)
secondary Reply / Reply all / Forward / AI reply (bottom) */
.email-reader-actions-row {
display: contents;
}
/* Pin the More button to the far right of the flattened flex row it
sits at position 5 in the primary row's source order, so without an
explicit order the secondary AI/Summary buttons land after it. */
.email-reader-actions .email-reader-more-wrap {
order: 99;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
gap: 4px;
}
.email-reader-atts {
display: flex; flex-wrap: wrap; gap: 6px;