Apply the workspace redesign to the sidebar and pane canvas - #59
Closed
BunsDev wants to merge 9 commits into
Closed
Conversation
The canvas could only stack panes vertically: layoutRects split purely on height, insertBelow always appended below, and no operation could move a pane once placed. Panes now tile in both directions and can be dragged onto another pane's edge to re-tile. Pane tree: - Splits carry an `orientation`. "column" is the default by omission, so layouts persisted before this change still load as the vertical stacks they were. - layoutRects is axis-generic, and minimumSize sums along a split's own axis while taking the max across it. The old minimumHeight only ever summed heights, so it could not describe side-by-side minimums. - insertRelative places a pane above/below/left/right; moveLeaf prunes the pane from its old slot before re-inserting, so the branch it leaves collapses rather than keeping an empty slot. Impossible moves return the original root by identity so callers can detect a no-op cheaply. Interaction: - Pointer events, not HTML5 drag-and-drop: panes host live xterm canvases, where a native drag image reads as a rendering glitch, and owning the gesture lets the drop target be a region of a pane rather than the whole element. - Nearest edge wins, giving four triangular drop zones meeting at the centre. Escape cancels; a lone pane never starts a drag. - Dividers are orientation-aware for pointer drags (clientX vs clientY) and keys (left/right on a row, up/down on a column). ARIA reports the separator's own orientation, the opposite of its drag axis. The drop highlight is position:fixed, since client rects are already viewport-space - no positioned ancestor required and no pane's overflow can clip it. It animates between targets so the gesture reads as continuous, and holds still under prefers-reduced-motion. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The pane tree is imported dynamically, so its exports are untyped and `.map((leaf) => ...)` callbacks tripped TS7006 under tsconfig.test.json. Local `vitest run` never surfaced this - only `pnpm typecheck` does, which is why CI caught it and the local run did not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two passes of the Psyche workspace redesign, covering the token layer, the session row, the pane frame, focus sets and the focus-mode minimap. Tokens. The default theme now states the spec's neutral ramp (#0B0B0D -> #1E1E24) and reserves violet for one job: marking where keyboard input goes. Selection became a neutral raised fill and status a worded chip, so the three signals that used to share one accent are finally distinct. The theme picker, vibrancy toggle and opacity slider keep working. Session row. 44px, border-box. The leading glyph reports the lane's git state rather than duplicating the pane kind, which moves to the meta line beside the branch. Rows carry focus-set membership swatches -- squares, so they cannot be read as status dots -- and the focused pane's row gets a violet bar layered over the neutral selection fill. Pane frame. A 32px six-track header whose buttons never clip, with a span cycle (tiled -> full column -> full row) and a maximise/restore control. Panes degrade on their own width through container queries instead of the window's. Span, focus mode and set scoping are all derived layouts: none of them edits the tiled tree, so leaving a mode restores exactly the tiling you had, and a pane opened or closed mid-mode lands in the tiling underneath. Focus sets. Multi-select from the + menu, a pick bar that exists only while picking, and a colour-coded subset that scopes the canvas. Clicking a member scopes to its set; the project header returns to all panes. Also fixes a latent bug: focusing a pane on pointerdown re-rendered the canvas and detached the click target before pointerup, so the first click on any pane-header button was swallowed. The close button had been special-cased for this; the guard now covers every header button. The pane header's retry button had already been dropped in this checkout by concurrent work. That removal and its matching test update overlap the header rewrite, so they are unavoidably part of this commit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
native/ holds the macOS Tauri app and the iOS app, and 51 files under it are tracked -- but the blanket `native/` rule meant git pruned the whole directory during a worktree scan. Two consequences: `git add native/...` refused tracked files unless forced, and `git add -A` silently skipped every change in the desktop and iOS apps. Anyone committing here had to know to reach for -f, and anyone who did not simply lost the change. Replaced with rules for what is actually generated: cargo's target dir, SwiftPM's .build, the Xcode derived-data path, and Tauri's generated capability schemas, plus the usual Xcode user-state directories. The tauri package's node_modules was already covered by the global rule. Verified no tracked file became ignored, the 4.6G target tree and the 82M .build tree are still ignored, and `git add` now works unforced. This surfaces two files the blanket rule had been hiding, both left untracked pending a call on them: the tauri package's pnpm-lock.yaml, and web/editor.bundle.js -- whose two siblings, sessions.bundle.js and panes.bundle.js, are both tracked. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
native/macos/psyche-build-tauri is a pnpm workspace member and there is no shared-workspace-lockfile override, so the root pnpm-lock.yaml is the one pnpm reads -- it already carries an importer entry pinning every dependency of the desktop app. The lockfile sitting inside the member is a leftover from running `pnpm install` in that directory. Nothing consumes it, nothing keeps it in step with the root, and tracking it would offer a second and silently drifting answer to which versions the desktop app builds against. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
index.html loads three bundles -- editor, sessions, panes -- but only two were tracked. The odd one out was invisible to git, which is how it came to be deleted from a working tree while index.html still had a script tag pointing at it, leaving the app unable to load its editor with nothing in `git status` to say why. The blanket `native/` ignore is what hid the gap: the file could never have shown up as untracked while that rule stood, so the inconsistency had no way to surface. With that rule gone, tracking it restores the invariant that everything index.html references is in the repo. esbuild's output is deterministic here -- two consecutive `pnpm build:web` runs produce byte-identical bundles -- so this does not add diff churn. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The three web bundles are build output that lives in the repo, so nothing stopped a commit landing with an edited source and a stale bundle beside it -- the app would load last build's code and the diff would look right. Rebuilds each bundle and compares bytes. The esbuild flags come from parsing package.json's build:web rather than being restated here, so changing the build cannot leave the check validating a command that no longer runs; the rebuild simply follows it. Output goes to a temp dir, never over the tracked bundle. Also asserts every script index.html references exists on disk. That is the failure the blanket `native/` ignore allowed: a referenced bundle was deleted from a working tree with nothing in `git status` to show for it, leaving the app unable to load its editor. Verified by breaking it three ways -- a bundle edited in place, a source edited without rebuilding, and a referenced bundle deleted -- and confirming each fails with a message naming the file and the fix. Equal-length drift is the usual shape, so the message reports the first differing byte rather than just the size. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Applies the Workspace Redesign to the macOS Tauri web UI by updating theme tokens and restyling the sidebar session rows and pane canvas, while also extending the pane-tree model to support 2D tiling (row/column splits), derived layouts (span / focus-set scoping), and new interactions (drag-to-reposition, focus-mode minimap, focus sets).
Changes:
- Updates theme tokens and CSS to implement redesigned session row anatomy, pane header layout, container-query tiers, focus-set pick UI, drag/drop affordances, and minimap styling.
- Extends the pane tree to support split orientation, relative insertion/moves, derived layouts (
spanLayout,retainThreads), and 2D layout math. - Adds/updates Vitest coverage around pane tree 2D tiling, span/focus modes, focus sets, and introduces a committed-bundle freshness check; fixes
.gitignoreto tracknative/sources while ignoring generated outputs.
Reviewed changes
Copilot reviewed 12 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| native/macos/psyche-build-tauri/web/styles.css | Redesign tokens + sidebar/pane-canvas styling, container queries, drag indicator, focus sets UI, minimap styles. |
| native/macos/psyche-build-tauri/web/panes/pane-tree.mjs | Adds split orientation + 2D layout, move/retain/span derived layout helpers, updated canFit/layout math. |
| native/macos/psyche-build-tauri/web/panes/pane-entry.js | Re-exports new pane-tree APIs for the browser bundle. |
| native/macos/psyche-build-tauri/web/panes.bundle.js | Rebuilt minified bundle for updated pane-tree exports/logic. |
| native/macos/psyche-build-tauri/web/main.js | Wires new pane header controls, 2D tiling drag-to-reposition, focus sets, focus-mode minimap, status rendering changes. |
| native/macos/psyche-build-tauri/web/index.html | Adds “Focus set — pick panes” menu item. |
| docs/superpowers/specs/2026-08-10-native-session-persistence-design.md | New design/spec doc for native session persistence (not implemented in this PR). |
| docs/superpowers/plans/2026-08-10-native-session-persistence.md | New implementation plan doc for native session persistence. |
| .gitignore | Stops blanket-ignoring native/; ignores only generated build outputs + nested lockfile. |
| tests/tauriWebBundles.test.ts | Adds a byte-level bundle freshness test that rebuilds bundles using build:web flags. |
| tests/tauriPhysicalPanes.test.ts | Updates tests for new pane minimums and new span/maximize/focus-set derived-root behavior. |
| tests/tauriPaneTree.test.ts | Adds coverage for orientation, relative insertion, move, retainThreads, and spanLayout. |
| tests/tauriCovenSessionSiderail.test.ts | Updates siderail rendering harness/tests for git-state glyphs, focus sets, and timed close confirm. |
| tests/tauriCovenLaunch.test.ts | Updates retry control expectations (moved from header button to context menu). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+1278
to
+1280
| .terminal-pane-header { cursor: grab; } | ||
| body.is-pane-dragging { cursor: grabbing; user-select: none; } | ||
| body.is-pane-dragging .terminal-pane-header { cursor: grabbing; } |
Comment on lines
+1407
to
+1417
| .pane-minimap { | ||
| width: 78px; | ||
| min-height: 0; | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 6px; | ||
| overflow-y: auto; | ||
| padding: 8px 6px 4px 0; | ||
| scrollbar-width: none; | ||
| } | ||
| .pane-minimap::-webkit-scrollbar { display: none; } |
Member
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the Psyche Workspace Redesign in the macOS Tauri app, over the 2D pane tiling already on this branch.
The design ships as an interactive prototype plus ten spec boards covering the audit, tokens, component anatomy, the status matrix, the keyboard model and the responsive rules. This lands the sidebar and pane-canvas half of it.
The redesign
Tokens. The default theme now states the spec's neutral ramp (
#0B0B0D → #1E1E24) and reserves violet for one job: marking where keyboard input goes. Selection became a neutral raised fill and status a worded chip, so the three signals that used to share one accent are finally distinct. The theme picker, vibrancy toggle and opacity slider keep working — the other five themes just restate their own ramp.Session row. 44px, border-box. The leading glyph reports the lane's git state rather than duplicating the pane kind, which moves to the meta line beside the branch. Rows carry focus-set membership swatches — squares, so they can't be read as status dots — and the focused pane's row gets a violet bar layered over the neutral selection fill.
Pane frame. A 32px six-track header whose buttons never clip, with a span cycle (tiled → full column → full row) and a maximise/restore control. Panes degrade on their own width through container queries rather than the window's, dropping the meta line below 460px and the status word below 300px.
Focus sets. Multi-select from the
+menu, a pick bar that exists only while picking, and a colour-coded subset that scopes the canvas. Clicking a member scopes to its set; the project header returns to all panes. Inside a set,×removes from the set rather than hiding the pane.Focus mode + minimap. Maximise draws one pane and a 78px rail keeps the rest reachable. Esc restores the tiling.
Span, focus mode and set scoping are all derived layouts —
spanLayout()andretainThreads()build them from the tiled tree without touching it. Leaving a mode restores exactly the tiling you had, and a pane opened or closed mid-mode lands in the tiling underneath.Bugs found along the way
The first click on any pane-header button was swallowed. Focusing a pane on pointerdown re-rendered the canvas, which detaches and re-appends the panes — so the click target left the document before pointerup and no click fired. The close button had been special-cased for this; the guard now covers every header button. Caught in the browser, not in tests.
native/was gitignored while 51 files under it were tracked.git addrefused those files unless forced, andgit add -Asilently skipped every change to the desktop and iOS apps. Replaced with rules for what is actually generated (cargo'starget, SwiftPM's.build, the Xcode derived-data path, Tauri's generated schemas). That ignore is also howeditor.bundle.jscame to be deleted from a working tree whileindex.htmlstill had a script tag pointing at it — the app couldn't load its editor andgit statushad nothing to say about it. It's now tracked alongside its two siblings, with a test that fails if any bundle drifts from its sources.Verification
appStoreConnect,releaseWorkflow), which fail identically on a clean tree. Typecheck clean.spanLayout/retainThreadsunit tests, span/maximise/set-scoping through the derived-root path, the container-query tiers, the row anatomy, the timed close confirm, and the bundle freshness check.19px 698px 7px 22px 22px 22px), meta hiding at 363px, all buttons still visible at the 200px floor, span producing a full-height column, pick mode → create → scoped canvas → project header restoring all panes, and focus mode with a working minimap.Notes for review
9748976.🤖 Generated with Claude Code