Skip to content

Commit ad73053

Browse files
authored
Swap tab groups to render icon only to match tabs (warpdotdev#13105)
## Description When tabs shrink to a certain size in the horizontal tab bar, they stop displaying the tab name and just show their icon. This PR modifies tab group headers to follow the same behavior. ## How it works - Wrapped the group header in a `SizeConstraintSwitch` that swaps the full layout (collage + name) for a compact, icon-only collage below `COMPACT_TAB_WIDTH_THRESHOLD` (42px) — the same mechanism and threshold `TabComponent` already uses, so headers and tabs go compact at the same width. - The compact collage renders at the tab's compact icon size (`TAB_INDICATOR_HEIGHT`, 14px), centered ## Linked Issue https://linear.app/warpdotdev/issue/APP-4777/tab-group-header-icon-collage-is-clipped-when-many-tabs-open ## Testing <!-- How did you test this change? What automated tests did you add? If you didn't add any new tests, what's your justification for not adding any? Manual testing is required for changes that can be manually tested, and almost all changes can be manually tested. If your change can be manually tested, please include screenshots or a screen recording that show it working end to end. You can run the app locally using `./script/run` - see AGENTS.md for more details on how to get set up. --> - [x] I have manually tested my changes locally with `./script/run` ### Screenshots / Videos <!-- Attach screenshots or a short video demonstrating the change, where appropriate. Remove this section if it is not relevant to your PR. --> [Demo before](https://www.loom.com/share/c1af83499c9349a8a59249deb8c5c335) [Demo after](https://www.loom.com/share/6ad23f13cacb4a8f9c1d8f5dd7d474a9)
1 parent d45528a commit ad73053

2 files changed

Lines changed: 48 additions & 18 deletions

File tree

app/src/tab.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use crate::workspace::{
5555
use crate::BlocklistAIHistoryModel;
5656

5757
pub const TAB_BAR_BORDER_HEIGHT: f32 = 1.0;
58-
const TAB_INDICATOR_HEIGHT: f32 = 14.0;
58+
pub(crate) const TAB_INDICATOR_HEIGHT: f32 = 14.0;
5959

6060
/// Label for the tab right-click menu's "Move to group" submenu parent.
6161
pub const MOVE_TO_GROUP_LABEL: &str = "Move to group";
@@ -77,7 +77,7 @@ pub(crate) const TAB_PIN_INDICATOR_ICON_SIZE: f32 = 16.0;
7777
const TAB_INDICATOR_SYNCED_COLOR: u32 = 0x4A93FFFF;
7878

7979
// Width threshold (in px) below which we render an icon-only tab
80-
const COMPACT_TAB_WIDTH_THRESHOLD: f32 = 42.0;
80+
pub(crate) const COMPACT_TAB_WIDTH_THRESHOLD: f32 = 42.0;
8181
// Horizontal inset for the tab close button
8282
const TAB_CLOSE_BUTTON_HORIZONTAL_INSET: f32 = 2.0;
8383

app/src/workspace/view.rs

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ use warpui::elements::{
9696
Highlight, Hoverable, Icon as WarpUiIcon, Image, MainAxisAlignment, MainAxisSize,
9797
MouseInBehavior, MouseStateHandle, OffsetPositioning, ParentAnchor, ParentElement,
9898
ParentOffsetBounds, PositionedElementAnchor, PositionedElementOffsetBounds, Radius, Rect,
99-
SavePosition, Shrinkable, Stack, Text,
99+
SavePosition, Shrinkable, SizeConstraintCondition, SizeConstraintSwitch, Stack, Text,
100100
};
101101
use warpui::fonts::{Properties, Weight};
102102
use warpui::geometry::vector::{vec2f, Vector2F};
@@ -354,8 +354,8 @@ use crate::settings_view::{flags, SettingsSection, SettingsView, SettingsViewEve
354354
use crate::shell_indicator::ShellIndicatorType;
355355
use crate::tab::{
356356
tab_position_id, uses_vertical_tabs, NewSessionMenuItem, PaneNameMenuTarget, SelectedTabColor,
357-
TabBarState, TabComponent, TabData, TabTelemetryAction, MOVE_TO_GROUP_LABEL,
358-
TAB_BAR_BORDER_HEIGHT, TAB_PIN_INDICATOR_ICON_SIZE,
357+
TabBarState, TabComponent, TabData, TabTelemetryAction, COMPACT_TAB_WIDTH_THRESHOLD,
358+
MOVE_TO_GROUP_LABEL, TAB_BAR_BORDER_HEIGHT, TAB_INDICATOR_HEIGHT, TAB_PIN_INDICATOR_ICON_SIZE,
359359
};
360360
use crate::tab_configs::action_sidecar::SidecarItemKind;
361361
use crate::tab_configs::remove_confirmation_dialog::{
@@ -19708,8 +19708,6 @@ impl Workspace {
1970819708
let header_selected = is_collapsed && any_member_active;
1970919709

1971019710
let member_kinds = self.compute_group_member_kinds(group.id, ctx);
19711-
let icon_circle =
19712-
render_group_member_icon_collage(&member_kinds, GROUP_ICON_COLLAGE_SIZE, appearance);
1971319711

1971419712
let is_being_renamed = self
1971519713
.current_workspace_state
@@ -19736,21 +19734,56 @@ impl Workspace {
1973619734
.finish()
1973719735
};
1973819736

19739-
let mut row = Flex::row()
19737+
// Full header: collage + name, with the horizontal padding inside it so
19738+
// the size switch below measures the full slot width, like a tab.
19739+
let mut full_row = Flex::row()
1974019740
// Fill the slot and center the icon + title.
1974119741
.with_main_axis_size(MainAxisSize::Max)
1974219742
.with_main_axis_alignment(MainAxisAlignment::Center)
1974319743
.with_cross_axis_alignment(CrossAxisAlignment::Center)
1974419744
.with_spacing(6.)
19745-
.with_child(icon_circle)
19745+
.with_child(render_group_member_icon_collage(
19746+
&member_kinds,
19747+
GROUP_ICON_COLLAGE_SIZE,
19748+
appearance,
19749+
))
1974619750
.with_child(Shrinkable::new(1.0, name_element).finish());
1974719751
// Collapsed + pinned: pin indicator to the right of the name, where an
1974819752
// ungrouped tab would show its close button. Expanded groups show the
1974919753
// pin after their last member instead.
1975019754
if FeatureFlag::PinnedTabs.is_enabled() && group.pinned && is_collapsed {
19751-
row.add_child(render_horizontal_group_pin_indicator(appearance));
19755+
full_row.add_child(render_horizontal_group_pin_indicator(appearance));
1975219756
}
19753-
let row = row.finish();
19757+
let full_content = Container::new(full_row.finish())
19758+
.with_padding_left(8.)
19759+
.with_padding_right(if is_collapsed { 8. } else { 9. })
19760+
.finish();
19761+
19762+
// Compact header (narrow slot): just the collage at the tab's compact
19763+
// icon size, centered and clipped, like a tab dropping its title.
19764+
let compact_content = Clipped::new(
19765+
Flex::row()
19766+
.with_main_axis_size(MainAxisSize::Max)
19767+
.with_main_axis_alignment(MainAxisAlignment::Center)
19768+
.with_cross_axis_alignment(CrossAxisAlignment::Center)
19769+
.with_child(render_group_member_icon_collage(
19770+
&member_kinds,
19771+
TAB_INDICATOR_HEIGHT,
19772+
appearance,
19773+
))
19774+
.finish(),
19775+
)
19776+
.finish();
19777+
19778+
// Go compact at the same width as a tab, so headers and tabs shrink in step.
19779+
let content = SizeConstraintSwitch::new(
19780+
full_content,
19781+
vec![(
19782+
SizeConstraintCondition::WidthLessThan(COMPACT_TAB_WIDTH_THRESHOLD),
19783+
compact_content,
19784+
)],
19785+
)
19786+
.finish();
1975419787

1975519788
let header_active_bg = internal_colors::fg_overlay_2(theme);
1975619789
let header_hover_bg = internal_colors::fg_overlay_1(theme);
@@ -19764,13 +19797,10 @@ impl Workspace {
1976419797
ElementFill::None
1976519798
};
1976619799

19767-
// Tab-style border: left edge if first; right edge only when collapsed
19768-
// (the divider). Expanded, the divider moves to the container's far
19769-
// edge, so swap that 1px border for 1px right padding so the title
19770-
// doesn't shift.
19771-
Container::new(row)
19772-
.with_padding_left(8.)
19773-
.with_padding_right(if is_collapsed { 8. } else { 9. })
19800+
// Tab-style border: left edge if first, right edge only when
19801+
// collapsed (the divider). Expanded swaps that right border for
19802+
// padding so the title doesn't shift on collapse/expand.
19803+
Container::new(content)
1977419804
.with_vertical_padding(6.)
1977519805
.with_background(bg)
1977619806
.with_border(

0 commit comments

Comments
 (0)