From 2ff4a39e046d88a080c7cb7e3f951398efe61ff3 Mon Sep 17 00:00:00 2001 From: Pavel Baksy Date: Tue, 23 Dec 2025 10:27:40 +0100 Subject: [PATCH] Polish tab UI styling with enhanced visual design Document tabs (header bar): - Add rounded corners with subtle backgrounds - Highlight active tabs with accent color and bottom border - Improve hover states with smooth 200ms transitions - Enhance close button visibility and hover effects - Reduce spacing for more compact appearance - Increase tab name truncation limit to 25 chars Stack switchers (Headers/Body tabs): - Add pill-style rounded buttons (6px radius) - Style active tabs with accent colors and bold text - Add smooth crossfade transitions (150ms) - Improve spacing with 8px top/bottom margins All styling uses GNOME color tokens for consistent theming across light and dark modes. --- src/window.py | 106 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 4 deletions(-) diff --git a/src/window.py b/src/window.py index 335521e..6176dc0 100644 --- a/src/window.py +++ b/src/window.py @@ -83,6 +83,9 @@ class RosterWindow(Adw.ApplicationWindow): # Create window actions self._create_actions() + # Setup custom CSS + self._setup_custom_css() + # Setup UI self._setup_method_dropdown() self._setup_request_tabs() @@ -158,6 +161,88 @@ class RosterWindow(Adw.ApplicationWindow): # User confirmed - close the window self.destroy() + def _setup_custom_css(self): + """Setup custom CSS for enhanced tab styling.""" + css_provider = Gtk.CssProvider() + css_provider.load_from_data(b""" + /* Document tabs in header bar */ + .tab-button { + margin: 0 2px; + padding: 0; + border-radius: 6px; + background: alpha(@window_fg_color, 0.08); + transition: all 200ms ease; + } + + .tab-button:hover { + background: alpha(@window_fg_color, 0.12); + } + + .tab-button-active { + background: alpha(@accent_bg_color, 0.2); + box-shadow: inset 0 -2px 0 0 @accent_bg_color; + } + + .tab-button-active:hover { + background: alpha(@accent_bg_color, 0.25); + } + + /* Tab label button */ + .tab-label-btn { + padding: 4px 12px; + min-height: 28px; + border-radius: 6px 0 0 6px; + } + + .tab-button-active .tab-label-btn { + font-weight: 600; + } + + /* Tab close button */ + .tab-close-btn { + padding: 4px 8px; + min-width: 24px; + min-height: 24px; + margin: 2px 4px 2px 0; + border-radius: 0 6px 6px 0; + opacity: 0.7; + } + + .tab-close-btn:hover { + opacity: 1; + background: alpha(@window_fg_color, 0.1); + } + + .tab-button-active .tab-close-btn:hover { + background: alpha(@accent_bg_color, 0.3); + } + + /* Stack switchers styling (Headers/Body tabs) */ + stackswitcher button { + padding: 6px 16px; + min-height: 32px; + border-radius: 6px; + margin: 0 2px; + } + + stackswitcher button:checked { + background: @accent_bg_color; + color: @accent_fg_color; + font-weight: 600; + } + + /* Add some polish to the tab bar container */ + #tab_bar_container { + margin: 0 6px; + } + """) + + Gtk.StyleContext.add_provider_for_display( + self.get_display(), + css_provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + ) + def _setup_sourceview_theme(self): """Set up GtkSourceView theme based on system color scheme.""" # Get the style manager to detect dark mode @@ -355,18 +440,22 @@ class RosterWindow(Adw.ApplicationWindow): # Add tab buttons with close button for tab in self.tab_manager.tabs: # Create a box for tab label + close button - tab_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) + tab_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0) + tab_box.add_css_class("tab-button") + + # Add active styling if this is the current tab + if tab.id == self.current_tab_id: + tab_box.add_css_class("tab-button-active") # Tab label with modified indicator - tab_label = tab.name[:20] # Truncate long names + tab_label = tab.name[:25] # Truncate long names if tab.is_modified(): tab_label += " •" # Add dot for unsaved changes # Tab label button tab_label_btn = Gtk.Button(label=tab_label) tab_label_btn.add_css_class("flat") - if tab.id == self.current_tab_id: - tab_label_btn.add_css_class("suggested-action") + tab_label_btn.add_css_class("tab-label-btn") tab_label_btn.connect("clicked", lambda btn, tid=tab.id: self._switch_to_tab(tid)) tab_box.append(tab_label_btn) @@ -375,6 +464,7 @@ class RosterWindow(Adw.ApplicationWindow): close_btn.set_icon_name("window-close-symbolic") close_btn.add_css_class("flat") close_btn.add_css_class("circular") + close_btn.add_css_class("tab-close-btn") close_btn.set_tooltip_text("Close tab") close_btn.connect("clicked", lambda btn, tid=tab.id: self._close_tab(tid)) tab_box.append(close_btn) @@ -532,11 +622,15 @@ class RosterWindow(Adw.ApplicationWindow): # Create stack for switching between pages self.request_stack = Gtk.Stack() self.request_stack.set_vexpand(True) + self.request_stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE) + self.request_stack.set_transition_duration(150) # Create stack switcher for the tabs request_switcher = Gtk.StackSwitcher() request_switcher.set_stack(self.request_stack) request_switcher.set_halign(Gtk.Align.CENTER) + request_switcher.set_margin_top(8) + request_switcher.set_margin_bottom(8) # Add switcher and stack to container self.request_tabs_container.append(request_switcher) @@ -634,11 +728,15 @@ class RosterWindow(Adw.ApplicationWindow): # Create stack for switching between pages self.response_stack = Gtk.Stack() self.response_stack.set_vexpand(True) + self.response_stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE) + self.response_stack.set_transition_duration(150) # Create stack switcher for the tabs response_switcher = Gtk.StackSwitcher() response_switcher.set_stack(self.response_stack) response_switcher.set_halign(Gtk.Align.CENTER) + response_switcher.set_margin_top(8) + response_switcher.set_margin_bottom(8) # Add switcher and stack to container self.response_tabs_container.append(response_switcher)