Render an answer in full instead of folding it behind a control

The fold saved a scroll and cost a click on every long answer, and what it hid
was usually the part worth reading. Follow already handles holding your place
while an answer arrives.
This commit is contained in:
Gmer4Lfe
2026-08-21 08:44:08 -04:00
parent 81abc5adee
commit 7c4f881b57
+5 -30
View File
@@ -209,8 +209,6 @@ function vv_ai_chat_assets(): void {
/* Folded answers cap at a readable height with a hard bottom edge rather than a fade — a fade /* Folded answers cap at a readable height with a hard bottom edge rather than a fade — a fade
over a code block reads as a rendering fault. */ over a code block reads as a rendering fault. */
.vv-ai-fold { max-height:420px; overflow:hidden; }
.vv-ai-more { display:block; margin:4px 0 2px; }
.vv-ai-last { display:flex; gap:10px; padding:0 2px 4px; } .vv-ai-last { display:flex; gap:10px; padding:0 2px 4px; }
.vv-ai-lnk { background:none; border:none; padding:0; font-size:10px; color:#4a4a4a; .vv-ai-lnk { background:none; border:none; padding:0; font-size:10px; color:#4a4a4a;
@@ -1002,9 +1000,6 @@ vv_ai_profiles_script();
} }
const node = el(h + '</div>'); const node = el(h + '</div>');
chatEl().appendChild(node); chatEl().appendChild(node);
// Measured after it is in the DOM — scrollHeight is 0 on a detached node, so a fold decided
// before appending would either never fire or fire on everything.
foldIfLong(node);
// Obeys Follow like every other write. This was the one place that did not, and it was the // Obeys Follow like every other write. This was the one place that did not, and it was the
// worst place for it: unticking the box to hold your place while an answer arrives, only to // worst place for it: unticking the box to hold your place while an answer arrives, only to
// be dragged to the bottom the instant it lands. // be dragged to the bottom the instant it lands.
@@ -1012,19 +1007,11 @@ vv_ai_profiles_script();
syncJump(); syncJump();
} }
// A long answer buries the composer on a 15" panel, and the composer is where the next thing // Answers render in full. They used to fold at 420px behind a "Show the rest" control, on the
// happens. Folded to a readable height with the control always visible — never hover-revealed, // reasoning that a long answer buries the composer on a 15" panel — true, but the cost was
// because the surfaces this runs on have no pointer near them. // paid on every answer to save a scroll, and the fold hid the part of a long answer that is
const FOLD_PX = 420; // usually the point. Scrolling is cheaper than a click plus a scroll, and Follow already
function foldIfLong(node) { // handles keeping your place while an answer arrives.
const body = node.querySelector('.vv-ai-body');
if (!body || body.scrollHeight <= FOLD_PX) return;
body.classList.add('vv-ai-fold');
body.insertAdjacentHTML('afterend',
`<button type="button" class="vv-ai-lnk vv-ai-more" data-more>Show the rest`
+ ` (${Math.round(body.scrollHeight / 20)} lines)</button>`);
}
function addError(msg) { function addError(msg) {
const p = $('pending'); if (p) p.remove(); const p = $('pending'); if (p) p.remove();
chatEl().appendChild(el(`<div class="vv-ai-msg bot"><div class="vv-ai-role">Varaverk</div>` chatEl().appendChild(el(`<div class="vv-ai-msg bot"><div class="vv-ai-role">Varaverk</div>`
@@ -1076,14 +1063,6 @@ vv_ai_profiles_script();
} }
return; return;
} }
const more = e.target.closest('[data-more]');
if (more) {
const body = more.previousElementSibling;
if (body) body.classList.remove('vv-ai-fold');
more.remove();
return;
}
const stog = e.target.closest('[data-src-toggle]'); const stog = e.target.closest('[data-src-toggle]');
if (stog) { if (stog) {
const box = stog.parentElement; const box = stog.parentElement;
@@ -1558,10 +1537,6 @@ vv_ai_profiles_script();
+ `<div class="vv-ai-body">${fmt(m.content)}</div>` + `<div class="vv-ai-body">${fmt(m.content)}</div>`
+ (m.offer ? offerHtml(m.offer, i) : '') + `</div>`); + (m.offer ? offerHtml(m.offer, i) : '') + `</div>`);
c.appendChild(node); c.appendChild(node);
// Folded here too, not only on arrival. A reopened thread carrying several long answers
// is exactly the case the fold exists for — it is what buries the composer on a 15"
// panel. Measured after the append, because scrollHeight is 0 on a detached node.
foldIfLong(node);
}); });
scroll(); scroll();
syncLast(); syncLast();