feat(tui): add per-screen responsive layout helpers
Introduce breakpoint-aware helper functions in layout.rs that centralize per-screen responsive decisions. Each function maps a Breakpoint to a screen-specific value, replacing scattered hardcoded checks across view modules: - detail_side_panel: show discussions side panel at Lg+ - info_screen_columns: 1 column on Xs/Sm, 2 on Md+ - search_show_project: hide project path column on narrow terminals - timeline_time_width: compact time on Xs (5), full on Md+ (12) - who_abbreviated_tabs: shorten tab labels on Xs/Sm - sync_progress_bar_width: scale progress bar 15→50 with width All functions are const fn with exhaustive match arms. Includes 6 unit tests covering every breakpoint variant.
This commit is contained in:
@@ -44,6 +44,84 @@ pub const fn show_preview_pane(bp: Breakpoint) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Per-screen responsive helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Whether detail views (issue/MR) should show a side panel for discussions.
|
||||
///
|
||||
/// At `Lg`+ widths, enough room exists for a 60/40 or 50/50 split with
|
||||
/// description on the left and discussions/cross-refs on the right.
|
||||
#[inline]
|
||||
pub const fn detail_side_panel(bp: Breakpoint) -> bool {
|
||||
match bp {
|
||||
Breakpoint::Lg | Breakpoint::Xl => true,
|
||||
Breakpoint::Xs | Breakpoint::Sm | Breakpoint::Md => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Number of stat columns for the Stats/Doctor screens.
|
||||
///
|
||||
/// - `Xs` / `Sm`: 1 column (full-width stacked)
|
||||
/// - `Md`+: 2 columns (side-by-side sections)
|
||||
#[inline]
|
||||
pub const fn info_screen_columns(bp: Breakpoint) -> u16 {
|
||||
match bp {
|
||||
Breakpoint::Xs | Breakpoint::Sm => 1,
|
||||
Breakpoint::Md | Breakpoint::Lg | Breakpoint::Xl => 2,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether to show the project path column in search results.
|
||||
///
|
||||
/// On narrow terminals, the project path is dropped to give the title
|
||||
/// more room.
|
||||
#[inline]
|
||||
pub const fn search_show_project(bp: Breakpoint) -> bool {
|
||||
match bp {
|
||||
Breakpoint::Xs | Breakpoint::Sm => false,
|
||||
Breakpoint::Md | Breakpoint::Lg | Breakpoint::Xl => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Width allocated for the relative-time column in timeline events.
|
||||
///
|
||||
/// Narrow terminals get a compact time (e.g., "2h"), wider terminals
|
||||
/// get the full relative time (e.g., "2 hours ago").
|
||||
#[inline]
|
||||
pub const fn timeline_time_width(bp: Breakpoint) -> u16 {
|
||||
match bp {
|
||||
Breakpoint::Xs => 5,
|
||||
Breakpoint::Sm => 8,
|
||||
Breakpoint::Md | Breakpoint::Lg | Breakpoint::Xl => 12,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether to use abbreviated mode-tab labels in the Who screen.
|
||||
///
|
||||
/// On narrow terminals, tabs are shortened to 3-char abbreviations
|
||||
/// (e.g., "Exp" instead of "Expert") to fit all 5 modes.
|
||||
#[inline]
|
||||
pub const fn who_abbreviated_tabs(bp: Breakpoint) -> bool {
|
||||
match bp {
|
||||
Breakpoint::Xs | Breakpoint::Sm => true,
|
||||
Breakpoint::Md | Breakpoint::Lg | Breakpoint::Xl => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Width of the progress bar in the Sync screen.
|
||||
///
|
||||
/// Scales with terminal width to use available space effectively.
|
||||
#[inline]
|
||||
pub const fn sync_progress_bar_width(bp: Breakpoint) -> u16 {
|
||||
match bp {
|
||||
Breakpoint::Xs => 15,
|
||||
Breakpoint::Sm => 25,
|
||||
Breakpoint::Md => 35,
|
||||
Breakpoint::Lg | Breakpoint::Xl => 50,
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -99,4 +177,60 @@ mod tests {
|
||||
fn test_lore_breakpoints_matches_defaults() {
|
||||
assert_eq!(LORE_BREAKPOINTS, Breakpoints::DEFAULT);
|
||||
}
|
||||
|
||||
// -- Per-screen responsive helpers ----------------------------------------
|
||||
|
||||
#[test]
|
||||
fn test_detail_side_panel() {
|
||||
assert!(!detail_side_panel(Breakpoint::Xs));
|
||||
assert!(!detail_side_panel(Breakpoint::Sm));
|
||||
assert!(!detail_side_panel(Breakpoint::Md));
|
||||
assert!(detail_side_panel(Breakpoint::Lg));
|
||||
assert!(detail_side_panel(Breakpoint::Xl));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_info_screen_columns() {
|
||||
assert_eq!(info_screen_columns(Breakpoint::Xs), 1);
|
||||
assert_eq!(info_screen_columns(Breakpoint::Sm), 1);
|
||||
assert_eq!(info_screen_columns(Breakpoint::Md), 2);
|
||||
assert_eq!(info_screen_columns(Breakpoint::Lg), 2);
|
||||
assert_eq!(info_screen_columns(Breakpoint::Xl), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_search_show_project() {
|
||||
assert!(!search_show_project(Breakpoint::Xs));
|
||||
assert!(!search_show_project(Breakpoint::Sm));
|
||||
assert!(search_show_project(Breakpoint::Md));
|
||||
assert!(search_show_project(Breakpoint::Lg));
|
||||
assert!(search_show_project(Breakpoint::Xl));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timeline_time_width() {
|
||||
assert_eq!(timeline_time_width(Breakpoint::Xs), 5);
|
||||
assert_eq!(timeline_time_width(Breakpoint::Sm), 8);
|
||||
assert_eq!(timeline_time_width(Breakpoint::Md), 12);
|
||||
assert_eq!(timeline_time_width(Breakpoint::Lg), 12);
|
||||
assert_eq!(timeline_time_width(Breakpoint::Xl), 12);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_who_abbreviated_tabs() {
|
||||
assert!(who_abbreviated_tabs(Breakpoint::Xs));
|
||||
assert!(who_abbreviated_tabs(Breakpoint::Sm));
|
||||
assert!(!who_abbreviated_tabs(Breakpoint::Md));
|
||||
assert!(!who_abbreviated_tabs(Breakpoint::Lg));
|
||||
assert!(!who_abbreviated_tabs(Breakpoint::Xl));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sync_progress_bar_width() {
|
||||
assert_eq!(sync_progress_bar_width(Breakpoint::Xs), 15);
|
||||
assert_eq!(sync_progress_bar_width(Breakpoint::Sm), 25);
|
||||
assert_eq!(sync_progress_bar_width(Breakpoint::Md), 35);
|
||||
assert_eq!(sync_progress_bar_width(Breakpoint::Lg), 50);
|
||||
assert_eq!(sync_progress_bar_width(Breakpoint::Xl), 50);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user