From f56fa559296cdfd2dfbdf47b83cf751a97be71e0 Mon Sep 17 00:00:00 2001 From: Patrick Buckley Date: Tue, 7 Jul 2026 22:03:56 -0700 Subject: [PATCH] fix(ui): unsplit skips redundant refresh after closing an ephemeral pane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit unsplit() closed each doomed (ephemeral) pane via close() — which already renders/persists/notifies — then repeated that trio, firing intermediate persist/notify passes mid-operation. A 2-cell split fully collapses inside close(), so bail there; only a 3+-cell split (or an empty doom list) still needs the trailing exit + refresh. The all-conversation path is unchanged. Also reword the cell-chip CSS comment so it names the reversible hide vs destructive close glyphs, now that an ephemeral pane can show the close glyph in split mode. --- turnstone/shared_static/pane.js | 8 ++++++-- turnstone/shared_static/shell.css | 10 +++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/turnstone/shared_static/pane.js b/turnstone/shared_static/pane.js index 3faf5bbe..e5afcbe2 100644 --- a/turnstone/shared_static/pane.js +++ b/turnstone/shared_static/pane.js @@ -636,8 +636,12 @@ export class PaneManager { const p = this._panes.get(id); return id !== keep && p && p.ephemeral; }); - for (const id of doomed) this.close(id); // collapses its cell, then destroys - if (this._layout) this._exitLayout(keep); // a close() may have already exited + // close() destroys the pane AND renders/persists/notifies; a 2-cell split + // fully collapses inside it, so bail before repeating that work. Only a + // 3+-cell split (or an empty doom list) still needs the exit + refresh here. + for (const id of doomed) this.close(id); + if (!this._layout) return; + this._exitLayout(keep); this._renderTabs(); this._persist(); this._notifyActive(); diff --git a/turnstone/shared_static/shell.css b/turnstone/shared_static/shell.css index fb9d17e0..9ac2ecaa 100644 --- a/turnstone/shared_static/shell.css +++ b/turnstone/shared_static/shell.css @@ -827,11 +827,11 @@ z-index: 13; /* above the ring overlay — a clean bar, not bar-plus-ring-line */ pointer-events: none; } -/* per-pane ✕ — on every visible pane. Split mode: "hide this cell" (the TAB - stays — closeCell), but an ephemeral pane (the preview) closes outright; - single-pane: "close pane" (withheld from the unclosable Dashboard). The - destructive modes flip the glyph to ✕ and wear .cell-unsplit--close. - Shell chrome floating over pane content: elevated panel + +/* per-pane dismiss chip (.cell-unsplit) — on every visible pane. Split mode: + "−" hides this cell (the TAB stays — closeCell), but an ephemeral pane (the + preview) shows "✕" and closes outright; single-pane: "✕" closes the pane + (withheld from the unclosable Dashboard). The destructive "✕" modes wear + .cell-unsplit--close. Shell chrome floating over pane content: elevated panel + hairline so it reads as the shell's, not the conversation's; sits clear of the 2px focus bar and the cell corner. */ .cell-unsplit {