feat(chat): stop an in-flight answer — Send becomes Stop, the partial is kept and persisted, the model stream is torn down

This commit is contained in:
2026-08-29 17:27:04 -04:00
parent 6bf7f456d4
commit 1a60ecbd8b
186 changed files with 1738 additions and 7796 deletions
+26
View File
@@ -623,6 +623,23 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
.tune-btn svg { width: 14px; height: 14px; display: block; }
.tune-btn:hover { background: var(--brand-soft); color: var(--brand-ink); }
/* Phase 48: the "Stopped" note in a stopped brain bubble's meta row:
ink-soft on the surface bubble ≈6.9:1, the 10px filled-square glyph
centered with the row (the Tune button shares the row), and
non-interactive — no hover, no focus (pointer-events: none). The text
carries the accessible meaning; the glyph is aria-hidden in the JS. */
.stopped-note {
display: inline-flex;
align-items: center;
gap: 0.3rem;
color: var(--ink-soft);
font-size: 0.75rem;
font-weight: 600;
white-space: nowrap;
pointer-events: none;
}
.stopped-note svg { width: 10px; height: 10px; display: block; fill: currentColor; }
/* Inline tuning form under the bubble: labeled textarea + Save/Cancel
(both ≥44px). Save = brand button (dark ink 5.2:1), Cancel = ghost. */
.tune-form {
@@ -1065,6 +1082,15 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
.send-btn:hover:not(:disabled) { background: #7d88f5; }
.send-btn:disabled { background: #a5b4fc; cursor: not-allowed; }
/* Phase 48 (2026-08-29, TODO.md L3): the in-flight Stop treatment — one
button, two roles. Rose-700 #be123c (the brand rose #f43f5e darkened)
with a #fff label = 6.3:1 (WCAG AA); the hover step #9f1239 holds
8.0:1. Same radius/height/hit target as the Send state and the shared
:focus-visible ring — the .is-stop class rides the same .send-btn
element, and the later rules win the hover specificity tie. */
.send-btn.is-stop { background: #be123c; color: #fff; }
.send-btn.is-stop:hover { background: #9f1239; }
/* Busy spinner: dark arc (--bg) on the #a5b4fc busy button = 9.7:1. */
.spinner {
width: 16px; height: 16px;