Skip to content

Split view: two documents side by side in one window #28

Description

@criptogus

Summary

Add split view — open two documents side by side in the same window. This is the "compare" primitive (Word's View side by side): review a contract against its previous version, a proposal against its template, a deck against the brief.

Motivation

  • Document work is inherently comparative; today the only options are switching tabs (loses context) or opening a second window.
  • The tab system already keeps every tab as its own WebContentsView (apps/shell/src/main/tab-manager.ts) — only the active one is visible. Split view is a layout change on top of that model: two views visible with a draggable divider. No engine work, no new document model.
  • Familiar pattern for office users (Word, Google Docs both have side-by-side) → does not hurt intuitiveness; it reduces context-switch friction.

Proposed UX

  • Drag a tab onto the edge of the editor area → splits horizontally or vertically (drop indicator shows which).
  • Alternatively: right-click tab → "Split left / Split right / Split above / Split below".
  • Divider draggable; double-click resets to 50/50. Active split highlighted in the tab bar; each split shows its own scroll/zoom state.
  • Close a split by dragging its tab back to the tab bar or via the tab's close button (closes the pane, not the file).
  • Keyboard: Cmd/Ctrl+\ toggles split of the current tab; Cmd/Ctrl+1/2 focuses first/second pane (proposal).
  • State is per-window and not persisted across restarts (v1) — keep it simple.

Implementation notes

  • Layout model: extend apps/shell/src/main/tab-manager.ts (or add a layout-manager.ts) from "one active visible view" to "a split tree" — minimal viable v1: a single split (2 panes), each pane holding one TabRecord. Reuse existing setBounds/resize logic (contentBounds(), trackHtmlFullScreen).
  • Renderer: apps/shell/src/renderer/src/TabBar.tsx needs drop-target affordances; AppFrame.tsx renders the split state (which tabs are visible + divider position).
  • IPC: extend TABS_CHANNELS (tabs:split, tabs:unsplit, tabs:set-divider, focus events) in apps/shell/src/shared/tabs-api.ts + preload.
  • The AI panel: with a split, the panel should attach to the focused pane (session continuity per document already works via chatId — verify the panel doesn't assume a single active doc).
  • Do not touch the apps (apps/{docs,sheets,slides,pdf}) unless the AI-panel focus issue forces a small, well-scoped change.

Acceptance criteria

  • Any two tabs can be shown side by side (drag + context-menu paths both work).
  • Both panes are independently scrollable/zoomable; divider drag resizes both smoothly.
  • Closing/unsplitting returns to single-tab layout without losing either file.
  • AI panel follows the focused pane (its session id stays per-document).
  • No regression in single-tab behavior (tab switching, fullscreen slideshow covers the whole window).

Out of scope

  • More than 2 panes, persisted layouts, split-scrolling sync (scroll one, mirrors other), side-by-side inside a single document (diff view) — those are follow-ups.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions