mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-16 09:45:24 -04:00
AI reply menu: click Fast/Full → context input → OK
Restructured flow:
1. Click Fast or Full → reveals an optional context textarea
("Add context (optional)") below
2. Type optional steering note or leave blank
3. Click OK → triggers the draft with the chosen mode + note
Dropped the standalone … note-toggle button — the textarea is now
gated on picking a mode, which makes it easier to discover.
This commit is contained in:
+27
-27
@@ -5923,8 +5923,8 @@ 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 = `
|
||||
<div class="email-ai-reply-row" style="display:flex;flex-direction:column;gap:6px;min-width:180px;">
|
||||
<div style="display:flex;align-items:center;gap:4px;">
|
||||
<div class="email-ai-reply-row" data-step="choose" style="display:flex;flex-direction:column;gap:6px;min-width:180px;">
|
||||
<div data-mode-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
|
||||
@@ -5933,39 +5933,39 @@ function _showAiReplyChoice(btn, em, data) {
|
||||
<svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" style="color:var(--accent, var(--red));"><circle cx="12" cy="12" r="6"/></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;margin-left:auto;">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="5" cy="12" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="19" cy="12" r="2"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div data-note-panel hidden>
|
||||
<textarea data-note-input rows="2" placeholder="e.g. reply nicely but say no" style="width:100%;box-sizing:border-box;resize:vertical;min-height:38px;font-family:inherit;font-size:11px;padding:5px 6px;border-radius:5px;border:1px solid var(--border,#333);background:var(--bg-elev,#1a1a1a);color:var(--fg);"></textarea>
|
||||
<div data-note-panel hidden style="display:flex;flex-direction:column;gap:6px;">
|
||||
<textarea data-note-input rows="2" placeholder="Add context (optional)" style="width:100%;box-sizing:border-box;resize:vertical;min-height:42px;font-family:inherit;font-size:11px;padding:5px 6px;border-radius:5px;border:1px solid var(--border,#333);background:var(--bg-elev,#1a1a1a);color:var(--fg);"></textarea>
|
||||
<button data-act="note-ok" class="memory-toolbar-btn" style="display:inline-flex;align-items:center;justify-content:center;gap:5px;">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
const modeRow = menu.querySelector('[data-mode-row]');
|
||||
const notePanel = menu.querySelector('[data-note-panel]');
|
||||
const noteInput = menu.querySelector('[data-note-input]');
|
||||
menu.querySelector('[data-act="note-toggle"]').addEventListener('click', (ev) => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const opening = notePanel.hasAttribute('hidden');
|
||||
if (opening) {
|
||||
notePanel.removeAttribute('hidden');
|
||||
setTimeout(() => noteInput.focus(), 0);
|
||||
} else {
|
||||
notePanel.setAttribute('hidden', '');
|
||||
}
|
||||
});
|
||||
let pendingMode = null;
|
||||
menu.addEventListener('click', async (ev) => {
|
||||
const choice = ev.target.closest('[data-mode]');
|
||||
if (!choice) return;
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const mode = choice.getAttribute('data-mode') || 'ai-reply';
|
||||
// Always pick up whatever's in the textarea — empty = no note,
|
||||
// typed = passed through as steering context.
|
||||
const noteHint = (noteInput.value || '').trim();
|
||||
_closeAiReplyChoice();
|
||||
await _runAiReplyFromButton(btn, em, data, mode, noteHint);
|
||||
if (choice) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
// First click reveals the optional-context textarea; the actual
|
||||
// draft runs on OK. Empty context just runs the chosen mode.
|
||||
pendingMode = choice.getAttribute('data-mode') || 'ai-reply';
|
||||
modeRow.setAttribute('hidden', '');
|
||||
notePanel.removeAttribute('hidden');
|
||||
setTimeout(() => noteInput.focus(), 0);
|
||||
return;
|
||||
}
|
||||
const ok = ev.target.closest('[data-act="note-ok"]');
|
||||
if (ok) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const noteHint = (noteInput.value || '').trim();
|
||||
const mode = pendingMode || 'ai-reply';
|
||||
_closeAiReplyChoice();
|
||||
await _runAiReplyFromButton(btn, em, data, mode, noteHint);
|
||||
}
|
||||
});
|
||||
// Esc closes the popover; ignore plain clicks inside the menu so the
|
||||
// textarea stays focused.
|
||||
|
||||
Reference in New Issue
Block a user