xiaohongshu
xiaohongshu
designing-gnome-ui
Use when designing, implementing, or modifying UI for GNOME apps; before writing UI code; when reviewing existing UI for HIG compliance; when working with GTK 4/libadwaita or styling Qt/PySide6 for GNOME
Full skill instructions
Design GNOME UIs that are HIG-compliant, polished, and user-centered.
Core principle: No UI code without design decisions. Pattern selection and quality verification happen before implementation.
Quality layers: Compliance (follows HIG) → Polish (feels premium) → Rigor (handles edge cases)
Companion skill: For app architecture (lifecycle, threading, GSettings, actions, packaging), use developing-gtk-apps.
| Need | Widget/API | Notes |
|---|---|---|
| Exclusive toggles (view mode) | AdwToggleGroup | Replaces multiple GtkToggleButton |
| Loading indicator | AdwSpinner | Works with animations disabled |
| Persistent bottom controls | AdwBottomSheet | Music player, persistent actions |
| Wrapping content (tags) | AdwWrapBox | Auto-wraps like text |
| Inline view switching | AdwInlineViewSwitcher | For cards, sidebars |
| Keyboard shortcuts | AdwShortcutsDialog | Replaces deprecated GtkShortcutsWindow |
| System accent color | Automatic | Apps follow desktop preference via portal |
| System fonts | AdwStyleManager | Access monospace/document fonts |
Deprecations: .dim-label → use .dimmed class
# AdwToggleGroup - view mode switching
toggle_group = Adw.ToggleGroup()
toggle_group.add(Adw.Toggle(icon_name="view-grid-symbolic", name="grid"))
toggle_group.add(Adw.Toggle(icon_name="view-list-symbolic", name="list"))
toggle_group.connect("notify::active-name", lambda g, p: set_view(g.get_active_name()))
header.pack_start(toggle_group)
# AdwBottomSheet - music player controls
bottom_sheet = Adw.BottomSheet()
bottom_sheet.set_content(main_content)
bottom_sheet.set_sheet(player_controls)
bottom_sheet.set_open(True) # Show sheet
window.set_content(bottom_sheet)
# AdwWrapBox - tag display
wrap_box = Adw.WrapBox(spacing=6)
for tag in ["Python", "GTK", "GNOME", "libadwaita"]:
chip = Gtk.Label(label=tag)
chip.add_css_class("chip") # Custom styling
wrap_box.append(chip)
# System fonts (1.7+) - for code editors, document views
style_manager = Adw.StyleManager.get_default()
mono_font = style_manager.get_monospace_font_name() # User's preferred mono font
doc_font = style_manager.get_document_font_name() # User's preferred document font
# Also available as CSS: --monospace-font-family, --document-font-family
digraph gnome_ui_process {
rankdir=LR;
node [shape=box];
"UI Task" -> "1. Context" -> "2. Patterns" -> "3. Details" -> "4. Checklist" -> "Implement";
"4. Checklist" -> "2. Patterns" [label="issues" style=dashed];
}
digraph containers {
rankdir=TB;
node [shape=box];
"Building what?" [shape=diamond];
"AdwApplicationWindow + HeaderBar" [style=filled fillcolor=lightgreen];
"AdwPreferencesWindow" [style=filled fillcolor=lightgreen];
"AdwDialog" [style=filled fillcolor=lightgreen];
"Building what?" -> "AdwApplicationWindow + HeaderBar" [label="main window"];
"Building what?" -> "AdwPreferencesWindow" [label="settings"];
"Building what?" -> "AdwDialog" [label="modal action"];
}
| Scenario | Default | Notes |
|---|---|---|
| App window | AdwApplicationWindow + AdwHeaderBar | Remember user size, start ~800x600 |
| Settings | AdwPreferencesWindow | Handles groups, search, subpages |
| List of items | AdwPreferencesGroup with rows | Boxed list style |
| Primary action | Single button, header bar end | suggested-action class if emphasized |
| Destructive action | destructive-action class | Requires undo or confirmation |
| Structure | Default Pattern |
|---|---|
| Single view | None needed |
| 2-4 views | AdwViewSwitcher in header bar |
| Many/dynamic views | AdwNavigationSplitView (sidebar) |
| Hierarchical | AdwNavigationView (drill-down) |
| Need | Default | Avoid |
|---|---|---|
| On/Off | AdwSwitchRow | Checkbox for settings |
| Choose one (few) | AdwComboRow | Radio buttons outside dialogs |
| Choose one (many) | AdwComboRow + search | Long unsearchable dropdowns |
| Text input | AdwEntryRow | Bare GtkEntry |
| Multiline text | GtkTextView + card class | Bare unstyled text view |
| Number | AdwSpinRow | Text entry for numbers |
| Date | GtkCalendar in popover | Text entry for dates |
| Action in list | AdwActionRow + suffix button | Multiple buttons per row |
| Search | GtkSearchBar + toggle button | Always-visible search box |
# Search bar slides down from header, toggle with button or Ctrl+F
search_bar = Gtk.SearchBar()
search_entry = Gtk.SearchEntry()
search_bar.set_child(search_entry)
search_bar.connect_entry(search_entry)
search_bar.set_key_capture_widget(window) # Type-to-search
# Toggle button in header bar
search_btn = Gtk.ToggleButton(icon_name="system-search-symbolic")
search_btn.set_tooltip_text("Search")
search_bar.bind_property("search-mode-enabled", search_btn, "active",
GObject.BindingFlags.BIDIRECTIONAL | GObject.BindingFlags.SYNC_CREATE)
header.pack_end(search_btn)
toolbar_view.add_top_bar(search_bar)
# Use error CSS class on invalid fields
def validate_entry(row):
text = row.get_text()
if not text or len(text) < 3:
row.add_css_class("error")
row.set_tooltip_text("Name must be at least 3 characters")
return False
row.remove_css_class("error")
row.set_tooltip_text("")
return True
name_row.connect("changed", lambda r: validate_entry(r))
Validation timing: On change for format checks, on focus-out for expensive checks, on submit for final validation.
| Content | Widget | Why |
|---|---|---|
| Settings/preferences | AdwPreferencesGroup | Boxed list style, handles rows |
| Navigation list (sidebar) | GtkListBox | Selection support, activatable rows |
| Large/dynamic data | GtkListView | Virtual scrolling, performance |
| Grid of items | GtkGridView | Thumbnail grids, icon views |
Selection modes: Use Gtk.SingleSelection for navigation, Gtk.MultiSelection for bulk actions. Toggle selection mode with header bar button + action bar for bulk operations. See reference for code patterns.
Rules:
icon-library app)action-object-symbolic (e.g., list-add-symbolic)user-trash-symbolic → user-trash-full-symbolic)| Action | Icon |
|---|---|
| Add/New | list-add-symbolic |
| Delete | user-trash-symbolic |
| Settings | emblem-system-symbolic |
| Menu | open-menu-symbolic |
| Search | system-search-symbolic |
| Edit | document-edit-symbolic |
| Back | go-previous-symbolic |
| Drill-down | go-next-symbolic |
| Sync | emblem-synchronizing-symbolic |
| Offline | network-offline-symbolic |
| Warning | dialog-warning-symbolic |
| Error | dialog-error-symbolic |
| Select mode | selection-mode-symbolic |
| Check/Done | emblem-ok-symbolic |
| Close | window-close-symbolic |
| Refresh | view-refresh-symbolic |
digraph feedback {
rankdir=TB;
node [shape=box];
"What happened?" [shape=diamond];
"Transient or persistent?" [shape=diamond];
"AdwToast" [style=filled fillcolor=lightgreen label="AdwToast (default)"];
"AdwBanner" [style=filled fillcolor=lightyellow];
"AdwDialog" [style=filled fillcolor=lightpink];
"Progress/Spinner" [style=filled fillcolor=lightblue];
"What happened?" -> "Transient or persistent?" [label="state/error"];
"What happened?" -> "AdwDialog" [label="needs decision"];
"What happened?" -> "Progress/Spinner" [label="ongoing operation"];
"Transient or persistent?" -> "AdwToast" [label="transient event"];
"Transient or persistent?" -> "AdwBanner" [label="persistent state"];
}
| Scenario | Default | Details |
|---|---|---|
| Action done | AdwToast | Short message, optional undo |
| Destructive action | AdwToast + undo | Prefer over confirmation dialog |
| Error (recoverable) | AdwToast | Brief, auto-retry silently |
| Error (blocking) | AdwDialog | Explain problem and required fix |
| Persistent state | AdwBanner | Offline, degraded mode, auth required |
| Needs decision | AdwDialog | Conflicts, irreversible actions |
| Short wait (<5s) | AdwSpinner | No progress bar |
| Long operation (>30s) | Progress bar + text | "13 of 42 processed" |
Error escalation: Toast (transient) → Banner (persists) → Dialog (requires action)
Dialog rules:
destructive-action styleContext menus: Use GtkPopoverMenu for right-click actions (remove, rename, properties). Keep menus short; move complex actions to dialogs.
# Show placeholder when list is empty
empty_state = Adw.StatusPage(
icon_name="folder-symbolic",
title="No Projects",
description="Create a project to get started"
)
create_btn = Gtk.Button(label="Create Project")
create_btn.add_css_class("pill")
create_btn.add_css_class("suggested-action")
empty_state.set_child(create_btn)
# Use stack to switch between list and empty state
stack.add_named(list_view, "content")
stack.add_named(empty_state, "empty")
stack.set_visible_child_name("empty" if model.get_n_items() == 0 else "content")
Create TodoWrite items for each applicable check before implementing.
title-1, heading, body, caption)GTK_THEME=Adwaita:hc)# Test high contrast
GTK_THEME=Adwaita:hc ./myapp
# Test large text (set in GNOME Settings > Accessibility first)
# Test with screen reader
orca &
./myapp
# Keyboard-only: unplug mouse, navigate entire app with Tab/Enter/Space
Code: Set accessible labels for icon-only buttons and images:
button.update_property([Gtk.AccessibleProperty.LABEL], ["Add new item"])
image.update_property([Gtk.AccessibleProperty.LABEL], ["Project thumbnail"])
When styling Qt apps for GNOME:
| Need | File |
|---|---|
| Basic UI patterns | gnome-hig-reference.md |
| Advanced patterns | gnome-advanced-patterns.md |
gnome-hig-reference.md - Read for most apps:
gnome-advanced-patterns.md - Read when building:
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience