Herdr Mobile Touch UI Threshold and Layout Adaptation: A Complete Guide
Herdr switches to a touch-friendly mobile layout when the terminal width drops to 64 columns or below, using configurable thresholds and precise hit-area calculations defined in src/ui/mobile.rs.
The Herdr terminal workspace manager automatically adapts its interface for touchscreen and small-screen devices through a deterministic width-based detection system. When the terminal viewport shrinks past a configurable threshold, the application abandons its desktop sidebar layout in favor of full-screen panels with enlarged touch targets. This mechanism relies on simple geometric comparisons and rectangular hit-area calculations that prioritize performance and responsiveness.
How Herdr Detects Mobile Terminal Width
Herdr uses a single integer comparison to determine when to render the mobile touch interface rather than the standard desktop layout. This approach avoids expensive layout recalculations and ensures immediate responsiveness to terminal resizing.
The Default 64-Column Threshold
The default mobile threshold is defined in src/config.rs as a constant value:
// src/config.rs#L34
pub const DEFAULT_MOBILE_WIDTH_THRESHOLD: u16 = 64;
This value is loaded into AppState at startup and stored in the mobile_width_threshold field (src/app/state.rs#L1330). Users can override this default by specifying a custom value in their configuration file, allowing the mobile layout to activate at wider or narrower terminal sizes as needed.
The is_mobile_width Helper Function
The actual detection logic resides in src/ui/mobile.rs within the is_mobile_width function:
// src/ui/mobile.rs#L44-L46
pub(crate) fn is_mobile_width(area: Rect, threshold: u16) -> bool {
area.width > 0 && area.width <= threshold
}
This helper returns true when the terminal area.width is greater than zero and less than or equal to the configured threshold. The check against zero ensures graceful handling of zero-size frames during initialization or minimization events. When this function returns true, Herdr sets ViewState.layout to Mobile; otherwise, it retains the Desktop layout.
Mobile Layout Adaptation Components
When the mobile layout activates, Herdr replaces the traditional sidebar with a full-screen switcher panel and responsive header bar. The geometry for these components is calculated dynamically based on the current terminal dimensions.
Mobile Header and Hit Areas
The mobile header displays the workspace name, current tab number, and a menu button. Its interactive geometry is computed by compute_mobile_header_hit_areas (src/ui/mobile.rs#L48-L62), which returns a MobileHeaderHitAreas struct containing the clickable rectangle for the menu button.
The header spans the full width of the terminal and reserves specific coordinate ranges for touch targets, ensuring that fingertip interactions register reliably even on high-resolution displays.
Switcher Panel Geometry
The switcher panel occupies the remaining screen real estate below the header and presents a vertically scrolling list of workspaces, tabs, agents, and global menu items. The function mobile_switcher_areas (src/ui/mobile.rs#L64-L86) defines:
- The scrollable viewport rectangle that bounds the content area
- The close button location within each list item
- The left-hand scrollbar thumb position calculated by
render_left_scrollbar(src/ui/mobile.rs#L76-L86)
These areas are stored as ratatui::layout::Rect objects that map physical screen coordinates to logical UI elements.
Touch Hit-Testing Implementation
Touch and mouse events are mapped to UI actions through mobile_switcher_target_at (src/ui/mobile.rs#L101-L158). This function accepts a physical coordinate pair and returns a MobileSwitcherTarget enum variant indicating which element was touched:
pub enum MobileSwitcherTarget {
NewWorkspace,
Workspace(usize),
NewTab,
Tab(usize),
Agent(usize),
GlobalMenu,
// ... additional variants
}
The hit-testing algorithm performs simple rectangle containment checks against the pre-calculated hit areas, making touch response instantaneous even with large numbers of workspaces or tabs.
Configuring the Mobile Width Threshold
Users can customize when the mobile layout activates by editing the Herdr configuration file. To change the threshold from the default 64 columns to a custom value, add the following to $HOME/.config/herdr/config.toml:
[ui]
mobile_width_threshold = 80 # Switch to mobile at 80 columns instead of 64
The load_live_config function reads this value during startup and propagates it to AppState.mobile_width_threshold. This field is then passed to every call to is_mobile_width throughout the application lifecycle.
To force a specific layout mode programmatically during testing or development:
let mut app = AppState::test_new();
app.mobile_width_threshold = 100; // Require 100+ columns for desktop layout
Touch UI Implementation Details
Hit Area Calculations with ratatui
Herdr leverages the ratatui crate's Rect type for all geometric calculations. These rectangles define the exact screen coordinates (x, y, width, height) of interactive elements. The mobile_screen_rect function (src/ui/mobile.rs#L44-L53) computes the union of the header and terminal areas to ensure the switcher covers the full available space when the terminal dimensions are constrained.
Rendering utilizes low-level drawing primitives such as fill_rect (src/ui/mobile.rs#L96-L108) and draw_horizontal_rule to create high-contrast touch targets using simple Unicode symbols (│, ▌, "switch", "close") that remain legible across different terminal emulators and color schemes.
Scroll Handling in Mobile View
The mobile switcher supports vertical scrolling through the mobile_switcher_scroll field stored in AppState. The helper function mobile_switcher_max_scroll_for_height calculates the maximum valid scroll offset based on the total content height versus visible rows, ensuring the viewport never scrolls beyond the available content.
Summary
- Herdr uses a 64-column default threshold defined in
src/config.rsto determine when to switch from desktop to mobile layout, stored inAppState.mobile_width_threshold(src/app/state.rs#L1330). - The
is_mobile_widthfunction (src/ui/mobile.rs#L44-L46) performs a simple width comparison to detect mobile terminals, guarding against zero-size areas. - Mobile layout components include a compact header with menu button hit areas and a full-screen switcher panel with calculated scrollable viewports (
src/ui/mobile.rs#L48-L86). - Touch hit-testing maps physical coordinates to logical actions using
mobile_switcher_target_at(src/ui/mobile.rs#L101-L158) and rectangular collision detection againstRecthit areas. - Users can customize the threshold via the
mobile_width_thresholdsetting inconfig.toml, with changes loaded at startup byload_live_config.
Frequently Asked Questions
What is the default mobile width threshold in Herdr?
Herdr defaults to 64 columns for the mobile width threshold, defined as DEFAULT_MOBILE_WIDTH_THRESHOLD in src/config.rs#L34. When the terminal width is less than or equal to this value (and greater than zero), the application renders the touch-optimized mobile interface instead of the desktop sidebar layout.
How does Herdr calculate touch hit areas for mobile UI?
Hit areas are calculated as ratatui::layout::Rect structures that define the exact screen coordinates of interactive elements. The functions compute_mobile_header_hit_areas and mobile_switcher_areas (src/ui/mobile.rs#L48-L86) generate these rectangles based on current terminal dimensions, which mobile_switcher_target_at then uses to map touch coordinates to specific actions like selecting workspaces or tabs.
Where is the mobile layout configuration stored in Herdr?
The mobile width threshold configuration resides in the user's TOML config file at $HOME/.config/herdr/config.toml under the [ui] section as mobile_width_threshold. This value is read during startup by load_live_config and stored in AppState.mobile_width_threshold (src/app/state.rs#L1330) for runtime access by the layout detection logic.
Can I force Herdr to always use desktop layout regardless of terminal size?
While there is no explicit "disable mobile" flag, you can effectively force desktop layout by setting mobile_width_threshold to 1 or 0 in your config.toml. Since is_mobile_width requires area.width > 0, setting the threshold to 0 ensures the function always returns false, keeping the layout in Desktop mode even on very small terminals.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →