From 4c593ef4a41c7f6b6bc23fe38ba4b06fa68b8e47 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Wed, 9 Sep 2026 19:26:35 +0800 Subject: [PATCH] fix(panel): let the tab underline reach the rule that closes the row The bar is pinned to the bottom of the tile's own box, which only meets the hairline when that box is as tall as the row. On macOS it is; in `panel_title`, where Windows and Linux draw the same tiles, the wrapper around them is only as tall as a glyph, so the bar floated a few pixels above the line. Give that wrapper the row's height. Keep `occlude` on the tile rather than on the full-height frame the bar hangs off: over the whole row it would take the few pixels above and below each glyph out of the title bar's drag region and hand them to nothing. Claude-Session: https://claude.ai/code/session_01VuYUPiDEhQX6aQ4WQZbEGn --- src/ui/right_panel.rs | 6 ++++ src/ui/tab_strip.rs | 78 ++++++++++++++++++++++--------------------- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/ui/right_panel.rs b/src/ui/right_panel.rs index bc732e4d..10580ae9 100644 --- a/src/ui/right_panel.rs +++ b/src/ui/right_panel.rs @@ -639,6 +639,12 @@ impl Tty7App { this.child( h_flex() .flex_shrink_0() + // Full height, so the current tile's underline — pinned + // to the bottom of its own box — lands on the rule that + // closes this row, the way it does on macOS. Without it + // the tiles are only as tall as a glyph and the bar + // floats a few pixels above the line. + .h_full() .items_center() .gap(px(2.)) .when(has_trailing, |this| this.ml(px(6.))) diff --git a/src/ui/tab_strip.rs b/src/ui/tab_strip.rs index 1c4fb2d5..ea758c7f 100644 --- a/src/ui/tab_strip.rs +++ b/src/ui/tab_strip.rs @@ -1182,53 +1182,55 @@ impl Tty7App { .into_iter() .map(|(tab, icon, label_key)| { let current = active_tab == tab; + let tile = chrome_tile_marked( + Button::new(("right-panel-tab", tab as usize)).icon(icon), + current, + cx, + ) + .rounded_lg() + .tooltip(match (tab, changed) { + (RightPanelTab::Scm, Some(n)) => { + SharedString::from(format!("{} · {n}", t(label_key))) + } + _ => SharedString::from(t(label_key)), + }) + // A tile for another tab switches to it; the lit one puts + // the panel away, the way an activity bar behaves + // everywhere else. Pressing it used to do nothing at all + // — a dead click on the one control in the row that looks + // like it should undo itself. (These tiles only exist + // while the panel is open, so `ToggleRightPanel` and the + // chrome tile beside them are still what brings it back.) + .on_click(cx.listener(move |this, _, window, cx| { + match this.right_panel_open(cx) && this.right_panel_tab == tab { + true => { + this.toggle_right_panel(cx); + // These tiles live inside the panel, so + // closing from one destroys the element that + // holds the focus and leaves it nowhere — + // and a keymap whose bindings are scoped to a + // focused thing goes quiet with it, so the + // ⌘J that would undo this did nothing at all. + // Hand the terminal back what it lost. + this.focus_active(window, cx); + } + false => this.set_right_panel_tab(tab, cx), + } + })); div() - .occlude() .flex_shrink_0() // Full height and `relative` so the bar below can be pinned to // the row's own bottom edge, where it lands on the hairline // that closes the row rather than floating under the glyph. + // The `occlude` that keeps a press from dragging the window + // stays on the tile: grown to the whole row it would take the + // few pixels above and below each glyph out of the drag + // region and hand them to nothing. .h_full() .relative() .flex() .items_center() - .child( - chrome_tile_marked( - Button::new(("right-panel-tab", tab as usize)).icon(icon), - current, - cx, - ) - .rounded_lg() - .tooltip(match (tab, changed) { - (RightPanelTab::Scm, Some(n)) => { - SharedString::from(format!("{} · {n}", t(label_key))) - } - _ => SharedString::from(t(label_key)), - }) - // A tile for another tab switches to it; the lit one puts - // the panel away, the way an activity bar behaves - // everywhere else. Pressing it used to do nothing at all - // — a dead click on the one control in the row that looks - // like it should undo itself. (These tiles only exist - // while the panel is open, so `ToggleRightPanel` and the - // chrome tile beside them are still what brings it back.) - .on_click(cx.listener(move |this, _, window, cx| { - match this.right_panel_open(cx) && this.right_panel_tab == tab { - true => { - this.toggle_right_panel(cx); - // These tiles live inside the panel, so - // closing from one destroys the element that - // holds the focus and leaves it nowhere — - // and a keymap whose bindings are scoped to a - // focused thing goes quiet with it, so the - // ⌘J that would undo this did nothing at all. - // Hand the terminal back what it lost. - this.focus_active(window, cx); - } - false => this.set_right_panel_tab(tab, cx), - } - })), - ) + .child(div().occlude().flex_shrink_0().child(tile)) // Narrower than the tile so it reads as underlining the glyph // rather than as the edge of a box around it. .children(current.then(|| {