fix: reserve space for clarify dialogs

This commit is contained in:
Frank Song committed 2026-05-25 15:58:27 +08:00
1 parent 4ea762ae0d
commit 85e13a6121
4 files changed
+106

No files matched your search

+4
View File
@@ -3,6 +3,10 @@
## [Unreleased]
### Fixed
- Clarification dialogs now reserve transcript space while open or collapsed, so the question prompt no longer covers the assistant text needed to answer it.
## [v0.51.134] — 2026-05-25 — Release DF (stage-batch16 — single-PR Windows path defaults)
### Fixed
+54
View File
@@ -2677,12 +2677,63 @@ function _syncClarifyCollapseButton(card) {
collapse.title = label;
}
let _clarifyResizeListenerReady = false;
function _clarifyMessagesNearBottom(messages) {
if (!messages) return false;
return messages.scrollHeight - messages.scrollTop - messages.clientHeight < 150;
}
function _syncClarifyTranscriptSpace(card, opts) {
opts = opts || {};
const messages = $("messages");
if (!messages) return;
const wasNearBottom = _clarifyMessagesNearBottom(messages);
if (!card || !card.classList.contains("visible")) {
messages.classList.remove("clarify-open");
messages.classList.remove("clarify-collapsed");
messages.style.removeProperty("--clarify-card-height");
messages.style.removeProperty("--clarify-dock-height");
if (wasNearBottom && typeof scrollToBottom === "function" && typeof requestAnimationFrame === "function") {
requestAnimationFrame(scrollToBottom);
}
return;
}
const collapsed = card.classList.contains("collapsed");
messages.classList.add("clarify-open");
messages.classList.toggle("clarify-collapsed", collapsed);
const measure = () => {
if (!card.classList.contains("visible")) return;
const target = collapsed ? card : (card.querySelector(".clarify-inner") || card);
const h = target && target.getBoundingClientRect().height;
if (h > 0) {
messages.style.setProperty(collapsed ? "--clarify-dock-height" : "--clarify-card-height", Math.ceil(h + 24) + "px");
}
if (wasNearBottom && typeof scrollToBottom === "function") scrollToBottom();
};
if (opts.immediate) measure();
if (typeof requestAnimationFrame === "function") requestAnimationFrame(measure);
setTimeout(measure, 420);
}
function _ensureClarifyResizeListener() {
if (_clarifyResizeListenerReady || typeof window === "undefined") return;
_clarifyResizeListenerReady = true;
window.addEventListener("resize", () => {
const card = $("clarifyCard");
if (card && card.classList.contains("visible")) {
_syncClarifyTranscriptSpace(card, {immediate: true});
}
}, {passive: true});
}
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);
_syncClarifyTranscriptSpace(card, {immediate: true});
}
function _clearClarifyHideTimer() {
@@ -2797,6 +2848,7 @@ function hideClarifyCard(force=false, reason="dismissed") {
_clarifySessionId = null;
_resetClarifyCardState();
card.classList.remove("visible");
_syncClarifyTranscriptSpace(null);
if (typeof unlockComposerForClarify === "function") unlockComposerForClarify();
$("clarifyQuestion").textContent = "";
$("clarifyChoices").innerHTML = "";
@@ -2911,8 +2963,10 @@ function showClarifyCard(pending) {
lockComposerForClarify(question ? `Clarification needed: ${question}` : "Clarification needed");
}
_clarifySetControlsDisabled(false, false);
_ensureClarifyResizeListener();
card.classList.add("visible");
_syncClarifyCollapseButton(card);
_syncClarifyTranscriptSpace(card, {immediate: true});
if (typeof applyLocaleToDOM === "function") applyLocaleToDOM();
// Move focus to clarify input synchronously (not in setTimeout) and
// only if the user wasn't mid-type in the composer textarea.
+2
View File
@@ -984,6 +984,8 @@
.messages.terminal-open{padding-bottom:var(--terminal-card-height,320px);scroll-padding-bottom:var(--terminal-card-height,320px);transition:padding-bottom .26s cubic-bezier(.2,.8,.2,1);}
.messages.terminal-collapsed{padding-bottom:var(--terminal-dock-height,72px);scroll-padding-bottom:var(--terminal-dock-height,72px);transition:padding-bottom .22s cubic-bezier(.2,.8,.2,1);}
.messages.handoff-dock-visible{padding-bottom:var(--handoff-dock-height,72px);scroll-padding-bottom:var(--handoff-dock-height,72px);transition:padding-bottom .22s cubic-bezier(.2,.8,.2,1);}
.messages.clarify-open{padding-bottom:var(--clarify-card-height,320px);scroll-padding-bottom:var(--clarify-card-height,320px);transition:padding-bottom .22s cubic-bezier(.2,.8,.2,1);}
.messages.clarify-collapsed{padding-bottom:var(--clarify-dock-height,72px);scroll-padding-bottom:var(--clarify-dock-height,72px);}
.messages.terminal-expanding-from-dock{transition:none!important;}
.queue-card-inner{background:var(--surface);border:1px solid var(--border);border-bottom:none;border-radius:14px 14px 0 0;contain:paint;transform:translateY(100%);opacity:0;transition:transform .35s cubic-bezier(.32,.72,.16,1),opacity .2s ease;overflow:hidden;max-height:240px;overflow-y:auto;padding-bottom:4px;}
.queue-card.visible .queue-card-inner{transform:translateY(0);opacity:1;}
+46
View File
@@ -0,0 +1,46 @@
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
MESSAGES_JS = (ROOT / "static" / "messages.js").read_text(encoding="utf-8")
STYLE_CSS = (ROOT / "static" / "style.css").read_text(encoding="utf-8")
def _compact(text: str) -> str:
return "".join(text.split())
def test_clarify_card_reserves_transcript_space():
compact_css = _compact(STYLE_CSS)
assert ".messages.clarify-open" in STYLE_CSS
assert "padding-bottom:var(--clarify-card-height,320px)" in compact_css
assert "scroll-padding-bottom:var(--clarify-card-height,320px)" in compact_css
def test_clarify_collapse_uses_smaller_transcript_space():
compact_css = _compact(STYLE_CSS)
compact_js = _compact(MESSAGES_JS)
assert ".messages.clarify-collapsed" in STYLE_CSS
assert "padding-bottom:var(--clarify-dock-height,72px)" in compact_css
assert 'classList.toggle("clarify-collapsed",collapsed)' in compact_js
assert "--clarify-dock-height" in MESSAGES_JS
def test_clarify_show_hide_toggle_messages_padding_classes():
compact_js = _compact(MESSAGES_JS)
assert "_syncClarifyTranscriptSpace(card,{immediate:true})" in compact_js
assert "_syncClarifyTranscriptSpace(null)" in compact_js
assert 'classList.add("clarify-open")' in MESSAGES_JS
assert 'classList.remove("clarify-open")' in MESSAGES_JS
assert "--clarify-card-height" in MESSAGES_JS
def test_clarify_padding_remeasures_on_resize():
compact_js = _compact(MESSAGES_JS)
assert "function_ensureClarifyResizeListener()" in compact_js
assert 'window.addEventListener("resize"' in MESSAGES_JS
assert "_ensureClarifyResizeListener();" in MESSAGES_JS