-
Notifications
You must be signed in to change notification settings - Fork 13
Description
Parent
Part of #204 (Phase 4: Hardening)
Problem
The terminal bar (Status, Mayor, and Agent tabs) is hardcoded as a fixed-position panel at the bottom of the viewport with a non-resizable 300px content area. Users can't:
- Move it to the top, left, or right
- Resize it by dragging
- Have the page content adjust dynamically (the layout uses a static
pb-[340px]that doesn't respond to collapse state, wasting ~300px of vertical space when collapsed)
For users on wide monitors, a vertical orientation (terminal on the right) would be far more natural — similar to VS Code's panel system. Users on smaller screens might want a shorter terminal. The current one-size-fits-all layout doesn't serve anyone well.
Current Architecture
The terminal bar is position: fixed; right: 0; bottom: 0 with a dynamic left that tracks the sidebar width. Height toggles between 38px (collapsed) and 338px (expanded) via two hardcoded constants. Page content reserves space via a static pb-[340px] Tailwind class that never changes regardless of collapse state — meaning ~300px of dead space when collapsed.
Key files:
src/components/gastown/TerminalBar.tsx— the entire terminal bar component (position, tabs, content panes)src/components/gastown/TerminalBarContext.tsx— state management (tabs, activeTab, collapsed)src/app/(app)/gastown/[townId]/layout.tsx— staticpb-[340px]paddingsrc/app/(app)/organizations/[id]/gastown/[townId]/layout.tsx— same static padding
Solution
1. Configurable orientation and position
Users can place the terminal bar in any of four positions:
| Position | Orientation | Terminal attaches to | Content adjusts |
|---|---|---|---|
| Bottom (default) | Horizontal | Bottom edge of viewport | padding-bottom |
| Top | Horizontal | Top edge of viewport (below any app header) | padding-top |
| Right | Vertical | Right edge of viewport | padding-right |
| Left | Vertical | Left edge of viewport (right of sidebar) | padding-left |
A position picker (4-way toggle or dropdown) in the terminal bar's tab row lets users switch. Preference persisted to localStorage.
2. Drag-to-resize
A resize handle at the inner edge of the terminal bar (the edge facing the page content):
- Bottom: horizontal handle at the top edge, cursor
ns-resize - Top: horizontal handle at the bottom edge, cursor
ns-resize - Right: vertical handle at the left edge, cursor
ew-resize - Left: vertical handle at the right edge, cursor
ew-resize
Drag events update the size in context. The xterm.js ResizeObserver in useXtermPty.ts already auto-fits the terminal when its container resizes — no additional xterm handling needed.
Min/max constraints to prevent the terminal from consuming the entire viewport:
- Horizontal: min 100px, max 70% of viewport height
- Vertical: min 200px, max 50% of viewport width
3. Dynamic page padding
Replace the static pb-[340px] with a dynamic inline style that responds to position, size, and collapse state:
const padding = collapsed ? COLLAPSED_SIZE : size + COLLAPSED_SIZE;
const style = {
paddingBottom: position === 'bottom' ? `${padding}px` : undefined,
paddingTop: position === 'top' ? `${padding}px` : undefined,
paddingRight: position === 'right' ? `${padding}px` : undefined,
paddingLeft: position === 'left' ? `${padding}px` : undefined,
};This requires the layout's padding wrapper to consume TerminalBarContext. The layout is currently a Server Component — the padding div needs to be extracted into a client component wrapper.
When collapsed, only COLLAPSED_SIZE (the tab bar strip) is reserved — no dead space.
4. New state in TerminalBarContext
Add to context:
position: 'bottom' | 'top' | 'right' | 'left'(default:'bottom')size: number(px — height for horizontal, width for vertical; default: 300)setPosition(position)— updates position, persists to localStoragesetSize(size)— updates size, persists to localStorage
5. Vertical orientation adaptations
When the terminal is vertical (left/right), several sub-components need layout adjustments:
| Component | Horizontal layout | Vertical layout |
|---|---|---|
| Tab bar | Horizontal flex row, overflow-x-auto |
Vertical flex-col stack, overflow-y-auto |
| Tab items | Compact horizontal labels | Rotated text or icon-only with tooltip |
Status pane (AlarmStatusPane) |
Two-column layout (340px left + flex-1 right) | Single-column stacked layout |
| Terminal content | Full width, fixed height | Fixed width, full height |
| Collapse toggle | Up/down chevron | Left/right chevron |
6. Sidebar conflict for left position
Placing the terminal on the left conflicts with the existing sidebar. The terminal should be positioned inside SidebarInset (the content area right of the sidebar), not outside it. For left position: left: sidebarWidth, same as the current bottom position calculates. This means the terminal pushes content right, not the sidebar.
7. DrawerStack interaction
The stackable drawers (DrawerStack.tsx) are fixed top-0 right-0 bottom-0 z-[61]. When the terminal is on the right, drawers need to respect the terminal's width — their right offset should be terminalSize + COLLAPSED_SIZE when the terminal is on the right. The terminal bar is z-50, drawers are z-61+, so layering is already correct.
Acceptance Criteria
- Terminal bar can be positioned at bottom, top, right, or left
- Position picker UI in the terminal bar
- Drag-to-resize handle on the inner edge, with min/max constraints
- Page content adjusts dynamically — no content hidden behind the terminal
- Collapsed state only reserves the tab bar strip, not the full expanded size
- Position and size persisted to localStorage
- Vertical orientation: tab bar stacks vertically, status pane stacks single-column
- DrawerStack respects terminal position when terminal is on the right
- xterm.js auto-refits on resize (already handled by existing
ResizeObserver)
Notes
- No data migration needed
- The existing
ResizeObserver+fitAddon.fit()debounce inuseXtermPty.tsmeans xterm terminals will auto-adapt to any resize — this is already working - The
MayorTerminalPaneduplicated xterm setup (identified in Fix terminal stability — WebSocket reconnection, resize debounce, control frame filtering #1195) should ideally be deduplicated before or alongside this work to avoid applying orientation changes in two places - Consider a keyboard shortcut to toggle collapse (e.g.,
Cmd+Jlike VS Code's panel toggle) - The position picker could use a visual icon showing the four options (like VS Code's panel position buttons)