Add M2 splits-tree layout
- src/lib/layout/tree.ts: pure helpers + types (newLeaf, splitLeaf, closeLeaf, replaceById, serialize/deserialize with shape-checking). - SplitNode.svelte: flex container with pointer-captured gutter drag. - LeafPane.svelte: per-pane toolbar (split-right ⇥, split-down ⇣, close ×) over the existing XtermPane. - Pane.svelte: recursive dispatcher between SplitNode and LeafPane, keyed on leaf.id so swaps unmount XtermPane cleanly (kills PTY). - App.svelte: tree-as-state with split/close handlers, auto-save to localStorage on every \$effect tick. Titlebar shows clickable distro buttons setting the default for new panes; existing panes keep theirs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9beab64e00
commit
efcdf6a9ce
7 changed files with 531 additions and 59 deletions
125
src/lib/layout/LeafPane.svelte
Normal file
125
src/lib/layout/LeafPane.svelte
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
<script lang="ts">
|
||||
import type { LeafNode, NodeId, Orientation } from "./tree";
|
||||
import XtermPane from "../../components/XtermPane.svelte";
|
||||
|
||||
let {
|
||||
leaf,
|
||||
onSplit,
|
||||
onClose,
|
||||
}: {
|
||||
leaf: LeafNode;
|
||||
onSplit: (leafId: NodeId, orientation: Orientation) => void;
|
||||
onClose: (leafId: NodeId) => void;
|
||||
} = $props();
|
||||
|
||||
let status = $state("starting…");
|
||||
let statusOk = $state(true);
|
||||
</script>
|
||||
|
||||
<div class="leaf">
|
||||
<div class="pane-toolbar">
|
||||
<span class="pane-label">
|
||||
{leaf.label ?? leaf.distro ?? "(default)"}
|
||||
</span>
|
||||
<span class="pane-status {statusOk ? 'ok' : 'err'}">{status}</span>
|
||||
<span class="pane-actions">
|
||||
<button
|
||||
class="pane-btn"
|
||||
title="Split right"
|
||||
onclick={() => onSplit(leaf.id, "h")}
|
||||
aria-label="Split right"
|
||||
>⇥</button>
|
||||
<button
|
||||
class="pane-btn"
|
||||
title="Split down"
|
||||
onclick={() => onSplit(leaf.id, "v")}
|
||||
aria-label="Split down"
|
||||
>⇣</button>
|
||||
<button
|
||||
class="pane-btn close"
|
||||
title="Close pane"
|
||||
onclick={() => onClose(leaf.id)}
|
||||
aria-label="Close pane"
|
||||
>×</button>
|
||||
</span>
|
||||
</div>
|
||||
<div class="xterm-wrap">
|
||||
<XtermPane
|
||||
distro={leaf.distro}
|
||||
cwd={leaf.cwd}
|
||||
onStatus={(msg, ok) => {
|
||||
status = msg;
|
||||
statusOk = ok;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.leaf {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
.pane-toolbar {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 2px 8px;
|
||||
background: #181818;
|
||||
border-bottom: 1px solid #2a2a2a;
|
||||
font-size: 11px;
|
||||
color: #aaa;
|
||||
user-select: none;
|
||||
min-height: 22px;
|
||||
}
|
||||
.pane-label {
|
||||
font-family: "Cascadia Mono", "JetBrains Mono", "Consolas", monospace;
|
||||
font-weight: 600;
|
||||
color: #ccc;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.pane-status {
|
||||
margin-left: auto;
|
||||
font-family: "Cascadia Mono", "JetBrains Mono", "Consolas", monospace;
|
||||
color: #777;
|
||||
font-size: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.pane-status.ok { color: #6c6; }
|
||||
.pane-status.err { color: #d66; }
|
||||
.pane-actions {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
}
|
||||
.pane-btn {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #888;
|
||||
font: inherit;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.pane-btn:hover {
|
||||
background: #2a2a2a;
|
||||
color: #ddd;
|
||||
}
|
||||
.pane-btn.close:hover {
|
||||
background: #5a1a1a;
|
||||
color: #fcc;
|
||||
}
|
||||
.xterm-wrap {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue