feat(tui): #127 responsive/adaptive layout #154
No reviewers
Labels
No labels
area:agents
area:ai
area:config
area:dashboard
area:design
area:design-review
area:devtools
area:entities
area:gallery
area:generate
area:image
area:infra
area:meta
area:model-browser
area:navigation
area:presets
area:security
area:sessions
area:settings
area:sharing
area:test
area:ux
area:webhook
area:workdir
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/loom!154
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "tui/responsive-layout"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes charles/loom#127
Summary
TermLayoutbreakpoint system (Compact/Medium/Widewidth,Short/Normalheight) threaded throughAppCtxand recomputed each framecentered_rect()now clamps to min 40x10 / max 120x40, never overflows terminal(width / 20).clamp(1, 6)instead of hardcoded 4Test plan
cargo fmt --allcargo build(full workspace)cargo test -p loom-tui— 211 tests pass (193 lib + 18 integration), including new TermLayout unit testscargo clippy -p loom-tui -- -D warnings🤖 Generated with Claude Code
Overall this is a solid implementation — the centralized
TermLayoutbreakpoint system is clean and each screen adapts well. No blockers, but a few suggestions below for consistency and robustness.@ -203,0 +266,4 @@/// Sidebar should auto-hide when terminal is narrow.pub fn sidebar_auto_hidden(&self) -> bool {self.width < 100sidebar_auto_hidden()triggers atwidth < 100, butWidthClass::Mediumstarts at 80. This means Medium terminals 80–99 cols get auto-hidden sidebar while 100–119 don't — a threshold that doesn't align with the breakpoint system. Consider usingWidthClass::Compactfor auto-hide, or adding a doc comment explaining why 100 was chosen independently of the breakpoints.@ -815,0 +797,4 @@.map(|(i, k)| {let style = if *k == self.kind {Style::default().bg(Color::DarkGray)The kind-item style computation and rendering is duplicated between the wide branch (ListItem construction) and the non-wide branch (tab spans). ~30 lines could be saved by extracting the shared "is this kind selected" style into a small helper.
@ -692,2 +692,4 @@fn render(&mut self, ctx: &AppCtx, frame: &mut Frame<'_>, area: Rect) {// Adaptive column count based on terminal width.self.columns = ctx.term.gallery_columns() as u8;Mutating
self.columnsduringrender()is a side-effect that could cause issues ifcolumnsis read between frames (e.g.move_selectionfor grid wrap-around — the column count would be stale until the next render). Consider makinggallery_columns()the authoritative source at point-of-use rather than caching it here, or at minimum documenting this coupling.@ -1610,1 +1604,4 @@};let seed_display = if screen.params.seed == -1 {"random".to_string()} else {This uses a raw
inner.width < 60check instead of the centralized breakpoint system. Other screens usectx.term.width_class. For consistency, consider checkingWidthClass::Compacthere or adding a method toTermLayoutfor compact-panel detection. Same applies tosettings.rs:463.