mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-06-06 02:31:13 +02:00
refactor(layouts): simplify to global config + preserve windows + add UI dropdown
Simplified layout system based on user feedback: **1. Global Layout Config (Simpler)** - Moved layoutConfig from per-workspace to global state - One configuration applies to all workspaces (easier to understand) - Updated state migration v8→v9 to move config to global level - Updated WorkspaceSettings UI to edit global config - Renamed updateWorkspaceLayoutConfig → updateLayoutConfig **2. Preserve Extra Windows (Fixed Bug)** - Fixed applyPresetToLayout to keep windows beyond preset slots - When applying 4-window grid to 6 windows, windows 5-6 are preserved - Extra windows stacked vertically on right side (70/30 split) - No more window loss when applying presets **3. Layout Dropdown in TabBar (Better UX)** - Added dropdown menu next to workspace tabs - Shows all available presets with icons (Grid2X2, Columns2, Split) - Displays window requirements and availability - Disables presets that need more windows than available - One-click preset application with toast feedback - More accessible than /layout command All tests passing (457 passed). State migration handles v6→v7→v8→v9 correctly. Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
@@ -131,16 +131,16 @@ describe("findLowestAvailableWorkspaceNumber", () => {
|
||||
describe("addWindow", () => {
|
||||
// Helper to create minimal test state
|
||||
const createTestState = (layoutConfig: LayoutConfig, existingLayout: MosaicNode<string> | null = null): GrimoireState => ({
|
||||
__version: 8,
|
||||
__version: 9,
|
||||
windows: {},
|
||||
activeWorkspaceId: "test-workspace",
|
||||
layoutConfig, // Global layout config (not per-workspace)
|
||||
workspaces: {
|
||||
"test-workspace": {
|
||||
id: "test-workspace",
|
||||
number: 1,
|
||||
windowIds: [],
|
||||
layout: existingLayout,
|
||||
layoutConfig,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -76,8 +76,8 @@ export const addWindow = (
|
||||
commandString: payload.commandString,
|
||||
};
|
||||
|
||||
// Insert window using workspace layout configuration
|
||||
const newLayout = insertWindow(ws.layout, newWindowId, ws.layoutConfig);
|
||||
// Insert window using global layout configuration
|
||||
const newLayout = insertWindow(ws.layout, newWindowId, state.layoutConfig);
|
||||
|
||||
return {
|
||||
...state,
|
||||
@@ -347,30 +347,18 @@ export const updateWindow = (
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the layout configuration for a workspace.
|
||||
* Controls how new windows are inserted into the workspace layout.
|
||||
* Updates the global layout configuration.
|
||||
* Controls how new windows are inserted into all workspaces.
|
||||
*/
|
||||
export const updateWorkspaceLayoutConfig = (
|
||||
export const updateLayoutConfig = (
|
||||
state: GrimoireState,
|
||||
workspaceId: string,
|
||||
layoutConfig: Partial<GrimoireState["workspaces"][string]["layoutConfig"]>,
|
||||
layoutConfig: Partial<GrimoireState["layoutConfig"]>,
|
||||
): GrimoireState => {
|
||||
const workspace = state.workspaces[workspaceId];
|
||||
if (!workspace) {
|
||||
return state; // Workspace doesn't exist, return unchanged
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
workspaces: {
|
||||
...state.workspaces,
|
||||
[workspaceId]: {
|
||||
...workspace,
|
||||
layoutConfig: {
|
||||
...workspace.layoutConfig,
|
||||
...layoutConfig,
|
||||
},
|
||||
},
|
||||
layoutConfig: {
|
||||
...state.layoutConfig,
|
||||
...layoutConfig,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -18,14 +18,14 @@ const initialState: GrimoireState = {
|
||||
number: 1,
|
||||
windowIds: [],
|
||||
layout: null,
|
||||
layoutConfig: {
|
||||
insertionMode: "smart", // Smart auto-balancing by default
|
||||
splitPercentage: 50, // Equal split
|
||||
insertionPosition: "second", // New windows on right/bottom
|
||||
autoPreset: undefined, // No preset maintenance
|
||||
},
|
||||
},
|
||||
},
|
||||
layoutConfig: {
|
||||
insertionMode: "smart", // Smart auto-balancing by default
|
||||
splitPercentage: 50, // Equal split
|
||||
insertionPosition: "second", // New windows on right/bottom
|
||||
autoPreset: undefined, // No preset maintenance
|
||||
},
|
||||
};
|
||||
|
||||
// Custom storage with error handling and migrations
|
||||
@@ -229,14 +229,9 @@ export const useGrimoire = () => {
|
||||
[setState],
|
||||
);
|
||||
|
||||
const updateWorkspaceLayoutConfig = useCallback(
|
||||
(
|
||||
workspaceId: string,
|
||||
layoutConfig: Partial<GrimoireState["workspaces"][string]["layoutConfig"]>,
|
||||
) =>
|
||||
setState((prev) =>
|
||||
Logic.updateWorkspaceLayoutConfig(prev, workspaceId, layoutConfig),
|
||||
),
|
||||
const updateLayoutConfig = useCallback(
|
||||
(layoutConfig: Partial<GrimoireState["layoutConfig"]>) =>
|
||||
setState((prev) => Logic.updateLayoutConfig(prev, layoutConfig)),
|
||||
[setState],
|
||||
);
|
||||
|
||||
@@ -259,7 +254,7 @@ export const useGrimoire = () => {
|
||||
setActiveWorkspace,
|
||||
setActiveAccount,
|
||||
setActiveAccountRelays,
|
||||
updateWorkspaceLayoutConfig,
|
||||
updateLayoutConfig,
|
||||
applyPresetLayout,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user