Skip to content

feat: add panel zoom toggle (z key) in monitor mode - #109

Open
shnayder wants to merge 2 commits into
marcus:mainfrom
shnayder:feature/panel-zoom
Open

feat: add panel zoom toggle (z key) in monitor mode#109
shnayder wants to merge 2 commits into
marcus:mainfrom
shnayder:feature/panel-zoom

Conversation

@shnayder

@shnayder shnayder commented Apr 4, 2026

Copy link
Copy Markdown

Summary

  • motivation: I'm finding it hard to manage a backlog while seeing only ~10 items at a time.

  • Adds a z keybinding that zooms the active panel to full screen height, hiding the other two panels. Press z again to restore the original layout.

  • Works in both main and board contexts (so backlog view can be zoomed too).

  • Follows the existing fullscreen toggle pattern used by the kanban view.

Changes

  • model.go: Added ZoomedPanel and PanelZoomed state fields
  • keymap/: New CmdTogglePanelZoom command bound to z in ContextMain and ContextBoard
  • view.go: Zoomed panel gets 100% of available height; non-zoomed panels are skipped
  • input.go: Same zoom-aware height calculation for mouse hit-testing
  • keymap/help.go: Added z:zoom to footer help strings

Test plan

  • make fmt — clean (note: found pre-existing gofmt issues in several files across the repo; the second commit includes only the fmt fixes for our changed files)
  • make test — all tests pass except TestUndoRestore_ReDeletePropagates in test/syncharness which is a pre-existing failure unrelated to this change
  • Manual testing: zoom/unzoom works on all three panels (Current Work, Task List/Backlog, Activity)
  • Verified backlog view in board mode zooms correctly (required ContextBoard binding)

🤖 Generated with Claude Code

shnayder and others added 2 commits April 4, 2026 14:58
Press z to zoom the active panel to full screen height, hiding
the other two panels. Press z again to restore the original layout.
Works in both main and board contexts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@marcus

marcus commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Thanks for this, @shnayder — and apologies for the long silence. We're working through a large PR backlog and this one deserved a proper look rather than a quick verdict.

The motivation lands: managing a backlog through a ~10-item window is genuinely painful, and zoom is the right shape of fix.

I checked it out, merged it against current main and ran it. Things you got right that are worth calling out, because they're the parts people usually miss:

  • You registered the binding properly everywhere instead of hardcoding a keypress check — DefaultBindings() for both contexts, commandMetadata in export.go (so it flows into sidecar's exported bindings and generated help), and both FooterHelp() / BoardFooterHelp().
  • Adding the ContextBoard binding so the backlog view zooms too was the correct instinct.
  • z is genuinely free — I enumerated every binding in ContextMain, ContextBoard and ContextGlobal and there's no conflict.

Also, good news on one thing you flagged: TestUndoRestore_ReDeletePropagates passes on current main. I ran it repeatedly on both main and your merged branch. Whatever you hit has since been fixed, so it's not something you need to work around.

Two things to sort out before this can land:

1. It needs a real rebase, not just a merge. Main has since done a Bubble Tea v1 → v2 migration, which turned tea.KeyMsg from a concrete struct into an interface. Your edit in keymap/registry_test.go uses the old form and won't compile:

// old (won't build on current main)
tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'9'}}

// new
tea.KeyPressMsg{Code: '9', Text: ""}

Context for why that line needed touching at all: main independently added a test that uses 'z' as an example of an unbound key. That's a coincidence, not a rejection of your keybinding — it just needs a different unbound key, and '9' is free.

There are also small conflicts in keymap/help.go and keymap/registry.go from an unrelated V:record binding that landed in the same regions.

2. There's a panel-switch bug. cycleFocusPanel in focus.go isn't zoom-aware. Zoom a panel, then press tab: ActivePanel moves to the next panel but ZoomedPanel stays pinned to the original, so you're looking at one panel while the arrow keys drive a different, hidden one — with no visual cue. Easy to hit in normal use.

Three reasonable ways to resolve it, your call on which feels right:

  • clear zoom on panel change,
  • have the zoom follow ActivePanel, or
  • block cycling while zoomed, with a hint in the status line.

Two smaller notes:

  • Could you add a test covering zoom on, zoom off, and zoom-then-switch-panel? It's a small state machine that will likely accrete more interactions later.
  • ZoomedPanel Panel // Which panel is zoomed (-1 = none) — there's no PanelNone = -1 constant, and nothing sets it to -1 (Panel's zero value is PanelCurrentWork). Harmless today since PanelZoomed gates every read, but either drop the comment or introduce a real sentinel.

Optional, entirely up to you: the zoom layout math is duplicated between input.go:updatePanelBounds and view.go:renderBaseView. That split predates your PR, so no obligation — but if you felt like factoring it into one helper both call, it'd be a welcome cleanup.

Worth noting there's a lint pass landing on main shortly, so you may want to wait a day or two before rebasing to avoid doing it twice.

Happy to take another look whenever you push. Thanks for the careful writeup on the original PR — the test plan and the note about pre-existing failures made this much easier to evaluate.

— (AI assistant helping Marcus work through the PR backlog)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants