Email: bookmark icon everywhere for favorites; subject matches in suggestions

Star → bookmark banner SVG also in the card title row (em.is_flagged
glyph) and the inbox toolbar's _starIcon / _starFilledIcon, so every
favorites affordance matches the chats sidebar bookmark.

Search dropdown gains a third suggestion kind:
- kind: 'email' rows surface emails from the snapshot whose subject or
  sender name match the typed term (top 4, scored by startsWith vs
  substring). Render row carries a small envelope glyph + bolded
  subject + 'from name' on the right.
- Picking one closes the dropdown and expands that exact card via
  _toggleCardPreview, scrolling it into view.
This commit is contained in:
pewdiepie-archdaemon
2026-06-11 19:46:45 +09:00
parent 39331fafb5
commit 0aa8d17d6c
2 changed files with 24 additions and 2 deletions
+2 -2
View File
@@ -22,8 +22,8 @@ const _replyIcon = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none"
const _archiveIcon = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="5" rx="1"/><path d="M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8"/><path d="M10 12h4"/></svg>';
const _deleteIcon = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/></svg>';
const _unreadIcon = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="3" fill="currentColor"/></svg>';
const _starIcon = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>';
const _starFilledIcon = '<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>';
const _starIcon = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>';
const _starFilledIcon = '<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>';
const _bellIcon = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>';
const _icon = (svg) => `<span class="dropdown-icon">${svg}</span>`;
const _replySeparator = '---------- Previous message ----------';
+22
View File
@@ -1992,6 +1992,13 @@ function _renderSearchSuggestions(items) {
<span style="font-weight:600;">${esc(s.label)}</span>
</div>`;
}
if (s.kind === 'email') {
return `<div class="email-lib-suggest-item" data-idx="${i}" style="display:flex;align-items:center;gap:6px;padding:6px 10px;cursor:pointer;font-size:12px;${highlight}">
<span style="display:inline-flex;align-items:center;width:13px;height:13px;color:var(--fg-muted, var(--fg));opacity:0.55;flex-shrink:0;"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><polyline points="2 6 12 13 22 6"/></svg></span>
<span style="font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${esc(s.subject)}</span>
${s.from_name ? `<span style="opacity:0.55;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">— ${esc(s.from_name)}</span>` : ''}
</div>`;
}
return `<div class="email-lib-suggest-item" data-idx="${i}" style="display:flex;align-items:center;gap:6px;padding:6px 10px;cursor:pointer;font-size:12px;${highlight}">
<span style="font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${esc(s.name || s.email)}</span>
${s.name ? `<span style="opacity:0.55;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${esc(s.email)}</span>` : ''}
@@ -2019,6 +2026,21 @@ function _acceptSuggestion(s) {
const input = document.getElementById('email-lib-search');
if (s.kind === 'filter') {
_addSearchPill({ type: 'filter', value: s.value, label: s.label });
} else if (s.kind === 'email') {
// Clear the draft + dropdown and open the matching card directly.
if (input) input.value = '';
state._libSearchDraft = '';
_hideSearchSuggestions();
_applyPillFilter();
const grid = document.getElementById('email-lib-grid');
const card = grid?.querySelector(`.doclib-card[data-uid="${CSS.escape(String(s.uid))}"]`);
const em = (state._libEmails || []).find(x => String(x.uid) === String(s.uid))
|| (_libPreSearchEmails || []).find(x => String(x.uid) === String(s.uid));
if (card && em) {
card.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
_toggleCardPreview(card, em);
}
return;
} else {
_addSearchPill({ type: 'contact', name: s.name, email: s.email });
}