feat: add layout presets system with /layout command

Phase 3 implementation:
- Created layout-presets.ts with 3 built-in presets (side-by-side, main-sidebar, grid)
- Implemented fillLayoutTemplate() for recursive template filling with window IDs
- Added collectWindowIds() for depth-first traversal of layout trees
- Created applyPresetToLayout() to reorganize existing windows

- Created layout-parser.ts for /layout command argument parsing
- Added layout command to man.ts with documentation and examples

- Built LayoutViewer component with:
  * Visual preset gallery with diagrams
  * Window count validation
  * Apply preset functionality
  * Error handling for insufficient windows
  * Command-line preset specification support

- Wired LayoutViewer into WindowRenderer with lazy loading
- Added "layout" to AppId type definition
- Exposed applyPresetLayout in useGrimoire hook

Presets allow users to quickly reorganize multiple windows into
common layouts: 50/50 splits, 70/30 main+sidebar, or 2×2 grids.

Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
Alejandro Gómez
2025-12-18 12:13:28 +01:00
parent a78b5226ce
commit 52f39a8073
8 changed files with 501 additions and 1 deletions

View File

@@ -27,6 +27,9 @@ const DebugViewer = lazy(() =>
import("./DebugViewer").then((m) => ({ default: m.DebugViewer })),
);
const ConnViewer = lazy(() => import("./ConnViewer"));
const LayoutViewer = lazy(() =>
import("./LayoutViewer").then((m) => ({ default: m.LayoutViewer })),
);
// Loading fallback component
function ViewerLoading() {
@@ -162,6 +165,14 @@ export function WindowRenderer({ window, onClose }: WindowRendererProps) {
case "conn":
content = <ConnViewer />;
break;
case "layout":
content = (
<LayoutViewer
presetId={window.props.presetId}
error={window.props.error}
/>
);
break;
default:
content = (
<div className="p-4 text-muted-foreground">