Repository navigation
Conversation
Lets a pane be split into two independent tab strips with a draggable
divider, so two files (or a file and a directory listing) can be open
side by side - e.g. reference one macro while editing another.
Implementation keeps the existing flat `tabs` array and URL/drag/close
logic largely intact by annotating each tab with which pane (group) it
belongs to, rather than restructuring tabs into per-pane arrays:
- groups: [{ id, activeTabId }], capped at exactly two fixed ids so
there's nothing to grow or clean up
- setActiveTab() replaces direct activeTab.value writes and tracks
which pane last had focus (focusedGroupId), which the URL sync,
scroll-restore watcher, and new-tab placement all key off
- moveTabToGroup()/splitRight()/closeSplit() handle pane transitions,
reusing closeTab's fallback-tab selection logic
- Per-pane thumbnail fetchers (useGcodeThumbnails is single-flight)
so two panes browsing different /gcodes directories don't cancel
each other's fetch
- The non-focused pane collapses via CSS on narrow viewports rather
than unmounting, since MonacoEditor.dispose() has no unsaved-content
flush path
- Browser back/forward ordinal resolution is scoped to the focused
pane's own tabs so it can never reveal into or steal focus from the
other, non-focused pane
Divider drag mirrors the existing nav-drawer resize handle in
layouts/builtin.vue; the split ratio persists via a new
cacheStore.explorerSplitRatio field the same way menuWidth does.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two side-by-side tab strips need more room than the md threshold (840px) gives them on a typical tablet-width window; lg leaves the split controls and pane collapse gated on a genuinely wide viewport. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
recheck |
|
Thanks for the PR, but I can't merge this as it is. Every pane transition (split right, close split, dragging a tab across, and the group id rename in To make this work the Monaco model needs to belong to the tab rather than the editor instance (a model cache keyed by filename, |
chrishamm
left a comment
There was a problem hiding this comment.
Setting this to changes requested so the state matches my comment above. The Monaco
model has to belong to the tab before the pane moves are safe, and this is too big
for the 3.7 rc phase regardless, so please rebase on next once that is sorted.
…lit panes - workspace: collapseEmptyGroup removes an emptied pane without changing any tab id - workspace header documents the rule that keeps editors mounted across pane moves: render tabs as one flat list keyed by id, in id order, placed by CSS grid column (the remount flaw Duet3D/DuetWebControl#517 was sent back for) - 358 tests Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…v0.13.0) Split right / Close split, a draggable divider, drag a tab across, focus follows a click. Every tab renders flat in one CSS grid (never nested per pane) so an editor is never remounted when its tab changes pane - unsaved edits, undo and scroll survive (Duet3D/DuetWebControl#517 was sent back for exactly that). The URL follows the focused pane's file and resolves by path. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Summary
Adds a split view to the Explorer page: a pane can be split into two independent tab strips with a draggable divider between them, so two files (or a file and a directory listing) can be open side by side - e.g. reference one macro while editing another, or compare two config files.
cacheStore.explorerSplitRatio), mirroring the existing nav-drawer resize handle.lgbreakpoint the non-focused pane is hidden (not unmounted) and the split controls are hidden, so it degrades to the current single-pane behaviour on narrower viewports without losing state. (Originally gated onmd; raised tolgsince two side-by-side tab strips need more room than a typical tablet-width window gives them.)Implementation notes
tabsarray and its URL-sync/drag/close logic largely intact by annotating each tab with agroupId(which pane it's in), rather than restructuring into per-pane arrays.groupsis capped at exactly two fixed ids, so there's nothing to grow or clean up.setActiveTab()replaces directactiveTab.valuewrites and tracks which pane last had focus (focusedGroupId); the URL sync, scroll-restore watcher, and new-tab placement all key off it.moveTabToGroup()/splitRight()/closeSplit()handle pane transitions, reusing the existingcloseTabfallback-tab-selection logic so closing/moving the active tab in a pane always lands on a sensible sibling.useGcodeThumbnails()is single-flight internally, so it's now instantiated once per pane rather than once for the whole page - otherwise two panes browsing different/gcodesdirectories would cancel each other's fetch and share one progress bar.v-if, sinceMonacoEditor's unmount has no unsaved-content flush path - unmounting a dirty editor would silently lose the edits.Testing
vue-tsc --noEmitandnpm run buildboth pass, including after themd->lgbreakpoint change.md->lgchange; the collapse behaviour itself is unchanged, just the threshold it fires at, but it hasn't been re-run specifically againstlg./gcodesdirectories in split panes, and the dirty-editor-survives-a-resize case.🤖 Generated with Claude Code