feat: make clarify prompt collapsible

This commit is contained in:
Michael Lam
2026-05-21 20:16:50 -07:00
committed by nesquena-hermes
parent e08eecefb1
commit 581da3da2b
7 changed files with 44 additions and 1 deletions
+4
View File
@@ -3,6 +3,10 @@
## [Unreleased]
### Added
- **PR #2731** by @Michaelyklam — Clarification prompts now include a compact Collapse/Expand control so users can temporarily shrink a blocking decision card and reread the chat context behind it before responding.
## [v0.51.114] — 2026-05-22 — Release CL (stage-407 — 1-PR — update-check recovery from remote re-tags)
### Fixed
Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

+1
View File
@@ -488,6 +488,7 @@
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 17h.01"/><path d="M9.09 9a3 3 0 1 1 5.82 1c0 2-3 2-3 4"/><circle cx="12" cy="12" r="10"/></svg>
<span id="clarifyHeading" data-i18n="clarify_heading">Clarification needed</span>
<span class="clarify-countdown" id="clarifyCountdown"></span>
<button type="button" class="clarify-collapse" id="clarifyCollapse" aria-expanded="true" aria-controls="clarifyQuestion clarifyChoices clarifyInput clarifyHint" onclick="toggleClarifyCardCollapsed()" title="Collapse clarification">Collapse</button>
</div>
<div class="clarify-question" id="clarifyQuestion"></div>
<div class="clarify-choices" id="clarifyChoices"></div>
+22
View File
@@ -2502,6 +2502,7 @@ function _ensureClarifyCardDom() {
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 17h.01"/><path d="M9.09 9a3 3 0 1 1 5.82 1c0 2-3 2-3 4"/><circle cx="12" cy="12" r="10"/></svg>
<span id="clarifyHeading" data-i18n="clarify_heading">Clarification needed</span>
<span class="clarify-countdown" id="clarifyCountdown"></span>
<button type="button" class="clarify-collapse" id="clarifyCollapse" aria-expanded="true" aria-controls="clarifyQuestion clarifyChoices clarifyInput clarifyHint" onclick="toggleClarifyCardCollapsed()" title="Collapse clarification">Collapse</button>
</div>
<div class="clarify-question" id="clarifyQuestion"></div>
<div class="clarify-choices" id="clarifyChoices"></div>
@@ -2515,10 +2516,29 @@ function _ensureClarifyCardDom() {
host.appendChild(card);
const submit = $("clarifySubmit");
if (submit) submit.onclick = () => respondClarify();
const collapse = $("clarifyCollapse");
if (collapse) collapse.onclick = () => toggleClarifyCardCollapsed();
if (typeof applyLocaleToDOM === "function") applyLocaleToDOM();
return card;
}
function _syncClarifyCollapseButton(card) {
const collapse = $("clarifyCollapse");
if (!collapse || !card) return;
const collapsed = card.classList.contains("collapsed");
collapse.setAttribute("aria-expanded", collapsed ? "false" : "true");
collapse.textContent = collapsed ? "Expand" : "Collapse";
collapse.title = collapsed ? "Expand clarification" : "Collapse clarification";
}
function toggleClarifyCardCollapsed(forceCollapsed) {
const card = $("clarifyCard");
if (!card) return;
const collapsed = typeof forceCollapsed === "boolean" ? forceCollapsed : !card.classList.contains("collapsed");
card.classList.toggle("collapsed", collapsed);
_syncClarifyCollapseButton(card);
}
function _clearClarifyHideTimer() {
if (_clarifyHideTimer) {
clearTimeout(_clarifyHideTimer);
@@ -2685,6 +2705,7 @@ function showClarifyCard(pending) {
if (!sameClarify) {
_clarifyVisibleSince = Date.now();
_clearClarifyHideTimer();
card.classList.remove("collapsed");
}
if (questionEl) questionEl.textContent = question;
if (choicesEl) {
@@ -2745,6 +2766,7 @@ function showClarifyCard(pending) {
}
_clarifySetControlsDisabled(false, false);
card.classList.add("visible");
_syncClarifyCollapseButton(card);
if (typeof applyLocaleToDOM === "function") applyLocaleToDOM();
if (input && !sameClarify) setTimeout(() => input.focus({preventScroll: true}), 50);
}
+7 -1
View File
@@ -963,11 +963,13 @@
/* ── Clarify card ── */
.clarify-card{position:absolute;left:0;right:0;bottom:-24px;max-width:var(--msg-max);margin:0 auto;padding:0 20px;box-sizing:border-box;width:100%;overflow:hidden;pointer-events:none;max-height:min(calc(100vh - 280px),420px);}
.clarify-card.visible{pointer-events:auto;}
.clarify-card .clarify-inner{max-height:min(calc(100vh - 280px),420px);overflow-y:auto;transform:translateY(100%);opacity:0;transition:transform .4s cubic-bezier(.32,.72,.16,1),opacity .25s ease;}
.clarify-card .clarify-inner{max-height:min(calc(100vh - 280px),420px);overflow-y:auto;transform:translateY(100%);opacity:0;transition:transform .4s cubic-bezier(.32,.72,.16,1),opacity .25s ease,max-height .2s ease;}
.clarify-card.visible .clarify-inner{transform:translateY(0);opacity:1;}
.clarify-inner{background:var(--surface);backdrop-filter:blur(8px);border:1px solid var(--accent-bg-strong);border-radius:12px;padding:12px 14px 36px;box-shadow:0 1px 0 rgba(255,255,255,.02) inset;}
.clarify-header{display:flex;align-items:center;gap:8px;margin-bottom:10px;font-size:12px;font-weight:700;color:var(--blue);letter-spacing:.01em;}
.clarify-countdown{margin-left:auto;min-width:42px;text-align:right;color:var(--muted);font-variant-numeric:tabular-nums;font-weight:700;}
.clarify-collapse{margin-left:4px;border:1px solid var(--border2);border-radius:999px;background:var(--surface);color:var(--muted);font:inherit;font-size:11px;font-weight:700;line-height:1;padding:5px 8px;cursor:pointer;}
.clarify-collapse:hover,.clarify-collapse:focus-visible{color:var(--text);border-color:var(--accent-bg-strong);outline:none;}
.clarify-countdown.urgent{color:var(--error);box-shadow:inset 0 -2px 0 var(--error);border-radius:2px;}
.clarify-question{font-size:14px;color:var(--text);line-height:1.7;white-space:pre-wrap;margin-bottom:12px;}
.clarify-choices{display:flex;flex-direction:column;gap:8px;margin-bottom:12px;}
@@ -988,6 +990,10 @@
.clarify-submit.loading{opacity:.75;cursor:wait;}
.clarify-hint{margin-top:8px;font-size:11px;line-height:1.45;color:var(--muted);}
.clarify-card.visible .clarify-question{padding-left:1px;}
.clarify-card.collapsed{max-height:72px;}
.clarify-card.collapsed .clarify-inner{max-height:56px;overflow:hidden;padding-bottom:12px;}
.clarify-card.collapsed .clarify-header{margin-bottom:0;}
.clarify-card.collapsed .clarify-question,.clarify-card.collapsed .clarify-choices,.clarify-card.collapsed .clarify-response,.clarify-card.collapsed .clarify-hint{display:none;}
/* Left rail (desktop primary navigation) */
.rail{display:none;width:48px;flex-shrink:0;flex-direction:column;align-items:center;gap:4px;padding:8px 0;background:var(--sidebar);border-right:1px solid var(--border);}
.rail-btn{width:36px;height:36px;border-radius:8px;border:none;background:none;color:var(--muted);cursor:pointer;display:flex;align-items:center;justify-content:center;position:relative;transition:color .15s,background .15s;flex-shrink:0;padding:0;}
+10
View File
@@ -98,6 +98,7 @@ class TestClarifyCardHTML:
assert 'id="clarifyChoices"' in html, "clarify choices container missing"
assert 'id="clarifyInput"' in html, "clarify input missing"
assert 'id="clarifySubmit"' in html, "clarify submit button missing"
assert 'id="clarifyCollapse"' in html, "clarify collapse button missing"
def test_clarify_card_has_data_i18n(self):
html = read(REPO / "static/index.html")
@@ -167,7 +168,9 @@ class TestClarifyCardCSS:
".clarify-response",
".clarify-input",
".clarify-submit",
".clarify-collapse",
".clarify-hint",
".clarify-card.collapsed",
):
assert cls in css, f"CSS class '{cls}' missing"
@@ -317,6 +320,13 @@ class TestClarifyMessagesJS:
for token in ("startClarifyPolling", "stopClarifyPolling", "hideClarifyCard", "_clarifySessionId"):
assert token in src, f"{token} missing from messages.js"
def test_clarify_card_can_collapse_without_hiding_prompt(self):
src = read(REPO / "static/messages.js")
assert "function toggleClarifyCardCollapsed" in src, "clarify collapse toggle missing"
assert "aria-expanded" in src, "clarify collapse button should expose expanded state"
assert "card.classList.remove(\"collapsed\")" in src, \
"new clarification prompts should reopen rather than stay collapsed"
# ── boot.js keyboard shortcut ────────────────────────────────────────────────