feat: Remember panel state per workspace (Vibe Kanban) (#2064)
* I've successfully implemented workspace-specific panel state persistence. Here's a summary of the changes:
## Summary
### Changes Made
1. **`frontend/src/stores/useUiPreferencesStore.ts`**
- Added `WorkspacePanelState` type to track `rightMainPanelMode` and `isLeftMainPanelVisible` per workspace
- Added `workspacePanelStates: Record<string, WorkspacePanelState>` to store state keyed by workspace ID
- Updated `toggleLeftMainPanel`, `toggleRightMainPanelMode`, `setRightMainPanelMode`, and `setLeftMainPanelVisible` to accept an optional `workspaceId` parameter
- Added `getWorkspacePanelState` and `setWorkspacePanelState` actions
- Added `useWorkspacePanelState(workspaceId)` hook for easy consumption
- Updated `partialize` to persist `workspacePanelStates` to localStorage
2. **`frontend/src/components/ui-new/containers/WorkspacesLayout.tsx`**
- Changed from using `useUiPreferencesStore` directly to using `useWorkspacePanelState(workspaceId)` hook
- Panel state is now workspace-specific
3. **`frontend/src/components/ui-new/actions/useActionVisibility.ts`**
- Updated to use `useWorkspacePanelState` for visibility context
4. **`frontend/src/components/ui-new/actions/index.ts`**
- Updated `ToggleLeftMainPanel`, `ToggleChangesMode`, `ToggleLogsMode`, `TogglePreviewMode`, and `ToggleDevServer` actions to pass `currentWorkspaceId` when toggling panel modes
### Scope
**Workspace-specific:**
- `rightMainPanelMode` - Which panel (Preview/Changes/Logs) is open
- `isLeftMainPanelVisible` - Whether the chat panel is visible
**Stays global:**
- `isLeftSidebarVisible` - Workspace list sidebar (navigation element)
- `isRightSidebarVisible` - Git/Settings sidebar (global actions)
- Panel sizes (already work correctly)
### Testing
Verified the feature works:
1. Opened Preview panel in Workspace A
2. Navigated to Workspace B → Preview panel is closed (default state)
3. Navigated back to Workspace A → Preview panel is still open ✓
* Cleanup script changes for workspace c8b73e59-ac41-4c0f-be78-7b6499d514f9
* The refactoring is complete. Let me provide a summary of the changes:
## Summary
Refactored `useUiPreferencesStore.ts` to remove duplicate code paths for workspace-specific panel state:
### Changes Made
1. **`frontend/src/stores/useUiPreferencesStore.ts`**
- Removed legacy global state (`isLeftMainPanelVisible`, `rightMainPanelMode`) from State type and initialization
- Simplified 4 panel state actions by removing `else` branches for legacy behavior:
- `toggleLeftMainPanel` - now early-returns if no workspaceId
- `toggleRightMainPanelMode` - simplified to single set() call
- `setRightMainPanelMode` - simplified to single set() call
- `setLeftMainPanelVisible` - simplified
- Removed `resetForCreateMode` action (was only setting legacy state)
- Removed unused `useIsRightMainPanelVisible` hook
2. **`frontend/src/contexts/WorkspaceContext.tsx`**
- Removed the `useEffect` that called `resetForCreateMode()` on create mode
- Removed unused `useUiPreferencesStore` import
3. **`frontend/src/contexts/LogsPanelContext.tsx`**
- Updated to use `useWorkspacePanelState` with workspace ID from context
4. **`frontend/src/components/ui-new/containers/SessionChatBoxContainer.tsx`**
- Updated to use `useWorkspacePanelState` with workspace ID
### Impact
- **~50 lines removed** from the codebase
- **Cleaner code** - no more `if (workspaceId) ... else ...` branching in every action
- **Same behavior** - all callers were already passing workspaceId
* Cleanup script changes for workspace c8b73e59-ac41-4c0f-be78-7b6499d514f9
This commit is contained in:
committed by
GitHub
parent
1e8783331c
commit
e1b0ef70a4
@@ -478,17 +478,18 @@ export const Actions = {
|
||||
|
||||
ToggleLeftMainPanel: {
|
||||
id: 'toggle-left-main-panel',
|
||||
label: () =>
|
||||
useUiPreferencesStore.getState().isLeftMainPanelVisible
|
||||
? 'Hide Chat Panel'
|
||||
: 'Show Chat Panel',
|
||||
label: 'Toggle Chat Panel',
|
||||
icon: ChatsTeardropIcon,
|
||||
requiresTarget: false,
|
||||
isActive: (ctx) => ctx.isLeftMainPanelVisible,
|
||||
isEnabled: (ctx) =>
|
||||
!(ctx.isLeftMainPanelVisible && ctx.rightMainPanelMode === null),
|
||||
execute: () => {
|
||||
useUiPreferencesStore.getState().toggleLeftMainPanel();
|
||||
getLabel: (ctx) =>
|
||||
ctx.isLeftMainPanelVisible ? 'Hide Chat Panel' : 'Show Chat Panel',
|
||||
execute: (ctx) => {
|
||||
useUiPreferencesStore
|
||||
.getState()
|
||||
.toggleLeftMainPanel(ctx.currentWorkspaceId ?? undefined);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -508,60 +509,69 @@ export const Actions = {
|
||||
|
||||
ToggleChangesMode: {
|
||||
id: 'toggle-changes-mode',
|
||||
label: () =>
|
||||
useUiPreferencesStore.getState().rightMainPanelMode ===
|
||||
RIGHT_MAIN_PANEL_MODES.CHANGES
|
||||
? 'Hide Changes Panel'
|
||||
: 'Show Changes Panel',
|
||||
label: 'Toggle Changes Panel',
|
||||
icon: GitDiffIcon,
|
||||
requiresTarget: false,
|
||||
isVisible: (ctx) => !ctx.isCreateMode,
|
||||
isActive: (ctx) =>
|
||||
ctx.rightMainPanelMode === RIGHT_MAIN_PANEL_MODES.CHANGES,
|
||||
isEnabled: (ctx) => !ctx.isCreateMode,
|
||||
execute: () => {
|
||||
getLabel: (ctx) =>
|
||||
ctx.rightMainPanelMode === RIGHT_MAIN_PANEL_MODES.CHANGES
|
||||
? 'Hide Changes Panel'
|
||||
: 'Show Changes Panel',
|
||||
execute: (ctx) => {
|
||||
useUiPreferencesStore
|
||||
.getState()
|
||||
.toggleRightMainPanelMode(RIGHT_MAIN_PANEL_MODES.CHANGES);
|
||||
.toggleRightMainPanelMode(
|
||||
RIGHT_MAIN_PANEL_MODES.CHANGES,
|
||||
ctx.currentWorkspaceId ?? undefined
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
ToggleLogsMode: {
|
||||
id: 'toggle-logs-mode',
|
||||
label: () =>
|
||||
useUiPreferencesStore.getState().rightMainPanelMode ===
|
||||
RIGHT_MAIN_PANEL_MODES.LOGS
|
||||
? 'Hide Logs Panel'
|
||||
: 'Show Logs Panel',
|
||||
label: 'Toggle Logs Panel',
|
||||
icon: TerminalIcon,
|
||||
requiresTarget: false,
|
||||
isVisible: (ctx) => !ctx.isCreateMode,
|
||||
isActive: (ctx) => ctx.rightMainPanelMode === RIGHT_MAIN_PANEL_MODES.LOGS,
|
||||
isEnabled: (ctx) => !ctx.isCreateMode,
|
||||
execute: () => {
|
||||
getLabel: (ctx) =>
|
||||
ctx.rightMainPanelMode === RIGHT_MAIN_PANEL_MODES.LOGS
|
||||
? 'Hide Logs Panel'
|
||||
: 'Show Logs Panel',
|
||||
execute: (ctx) => {
|
||||
useUiPreferencesStore
|
||||
.getState()
|
||||
.toggleRightMainPanelMode(RIGHT_MAIN_PANEL_MODES.LOGS);
|
||||
.toggleRightMainPanelMode(
|
||||
RIGHT_MAIN_PANEL_MODES.LOGS,
|
||||
ctx.currentWorkspaceId ?? undefined
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
TogglePreviewMode: {
|
||||
id: 'toggle-preview-mode',
|
||||
label: () =>
|
||||
useUiPreferencesStore.getState().rightMainPanelMode ===
|
||||
RIGHT_MAIN_PANEL_MODES.PREVIEW
|
||||
? 'Hide Preview Panel'
|
||||
: 'Show Preview Panel',
|
||||
label: 'Toggle Preview Panel',
|
||||
icon: DesktopIcon,
|
||||
requiresTarget: false,
|
||||
isVisible: (ctx) => !ctx.isCreateMode,
|
||||
isActive: (ctx) =>
|
||||
ctx.rightMainPanelMode === RIGHT_MAIN_PANEL_MODES.PREVIEW,
|
||||
isEnabled: (ctx) => !ctx.isCreateMode,
|
||||
execute: () => {
|
||||
getLabel: (ctx) =>
|
||||
ctx.rightMainPanelMode === RIGHT_MAIN_PANEL_MODES.PREVIEW
|
||||
? 'Hide Preview Panel'
|
||||
: 'Show Preview Panel',
|
||||
execute: (ctx) => {
|
||||
useUiPreferencesStore
|
||||
.getState()
|
||||
.toggleRightMainPanelMode(RIGHT_MAIN_PANEL_MODES.PREVIEW);
|
||||
.toggleRightMainPanelMode(
|
||||
RIGHT_MAIN_PANEL_MODES.PREVIEW,
|
||||
ctx.currentWorkspaceId ?? undefined
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -707,7 +717,10 @@ export const Actions = {
|
||||
// Auto-open preview mode when starting dev server
|
||||
useUiPreferencesStore
|
||||
.getState()
|
||||
.setRightMainPanelMode(RIGHT_MAIN_PANEL_MODES.PREVIEW);
|
||||
.setRightMainPanelMode(
|
||||
RIGHT_MAIN_PANEL_MODES.PREVIEW,
|
||||
ctx.currentWorkspaceId ?? undefined
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useUiPreferencesStore } from '@/stores/useUiPreferencesStore';
|
||||
import {
|
||||
useUiPreferencesStore,
|
||||
useWorkspacePanelState,
|
||||
} from '@/stores/useUiPreferencesStore';
|
||||
import { useDiffViewStore, useDiffViewMode } from '@/stores/useDiffViewStore';
|
||||
import { useWorkspaceContext } from '@/contexts/WorkspaceContext';
|
||||
import { useUserSystem } from '@/components/ConfigProvider';
|
||||
@@ -22,8 +25,11 @@ import type { CommandBarPage } from './pages';
|
||||
* action visibility and state conditions.
|
||||
*/
|
||||
export function useActionVisibilityContext(): ActionVisibilityContext {
|
||||
const layout = useUiPreferencesStore();
|
||||
const { workspace, workspaceId, isCreateMode, repos } = useWorkspaceContext();
|
||||
// Use workspace-specific panel state (pass undefined when in create mode)
|
||||
const panelState = useWorkspacePanelState(
|
||||
isCreateMode ? undefined : workspaceId
|
||||
);
|
||||
const diffPaths = useDiffViewStore((s) => s.diffPaths);
|
||||
const diffViewMode = useDiffViewMode();
|
||||
const expanded = useUiPreferencesStore((s) => s.expanded);
|
||||
@@ -61,10 +67,10 @@ export function useActionVisibilityContext(): ActionVisibilityContext {
|
||||
false;
|
||||
|
||||
return {
|
||||
rightMainPanelMode: layout.rightMainPanelMode,
|
||||
isLeftSidebarVisible: layout.isLeftSidebarVisible,
|
||||
isLeftMainPanelVisible: layout.isLeftMainPanelVisible,
|
||||
isRightSidebarVisible: layout.isRightSidebarVisible,
|
||||
rightMainPanelMode: panelState.rightMainPanelMode,
|
||||
isLeftSidebarVisible: panelState.isLeftSidebarVisible,
|
||||
isLeftMainPanelVisible: panelState.isLeftMainPanelVisible,
|
||||
isRightSidebarVisible: panelState.isRightSidebarVisible,
|
||||
isCreateMode,
|
||||
hasWorkspace: !!workspace,
|
||||
workspaceArchived: workspace?.archived ?? false,
|
||||
@@ -81,10 +87,10 @@ export function useActionVisibilityContext(): ActionVisibilityContext {
|
||||
isAttemptRunning: isAttemptRunningVisible,
|
||||
};
|
||||
}, [
|
||||
layout.rightMainPanelMode,
|
||||
layout.isLeftSidebarVisible,
|
||||
layout.isLeftMainPanelVisible,
|
||||
layout.isRightSidebarVisible,
|
||||
panelState.rightMainPanelMode,
|
||||
panelState.isLeftSidebarVisible,
|
||||
panelState.isLeftMainPanelVisible,
|
||||
panelState.isRightSidebarVisible,
|
||||
isCreateMode,
|
||||
workspace,
|
||||
repos,
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
type ExecutionStatus,
|
||||
} from '../primitives/SessionChatBox';
|
||||
import {
|
||||
useUiPreferencesStore,
|
||||
useWorkspacePanelState,
|
||||
RIGHT_MAIN_PANEL_MODES,
|
||||
} from '@/stores/useUiPreferencesStore';
|
||||
import { Actions, type ActionDefinition } from '../actions';
|
||||
@@ -102,7 +102,8 @@ export function SessionChatBoxContainer({
|
||||
|
||||
const { executeAction } = useActions();
|
||||
const actionCtx = useActionVisibilityContext();
|
||||
const { rightMainPanelMode, setRightMainPanelMode } = useUiPreferencesStore();
|
||||
const { rightMainPanelMode, setRightMainPanelMode } =
|
||||
useWorkspacePanelState(workspaceId);
|
||||
|
||||
const handleViewCode = useCallback(() => {
|
||||
setRightMainPanelMode(
|
||||
|
||||
@@ -20,7 +20,7 @@ import { useUserSystem } from '@/components/ConfigProvider';
|
||||
import {
|
||||
PERSIST_KEYS,
|
||||
usePaneSize,
|
||||
useUiPreferencesStore,
|
||||
useWorkspacePanelState,
|
||||
RIGHT_MAIN_PANEL_MODES,
|
||||
} from '@/stores/useUiPreferencesStore';
|
||||
|
||||
@@ -60,6 +60,7 @@ function ModeProvider({
|
||||
|
||||
export function WorkspacesLayout() {
|
||||
const {
|
||||
workspaceId,
|
||||
workspace: selectedWorkspace,
|
||||
isLoading,
|
||||
isCreateMode,
|
||||
@@ -72,6 +73,7 @@ export function WorkspacesLayout() {
|
||||
startNewSession,
|
||||
} = useWorkspaceContext();
|
||||
|
||||
// Use workspace-specific panel state (pass undefined when in create mode)
|
||||
const {
|
||||
isLeftSidebarVisible,
|
||||
isLeftMainPanelVisible,
|
||||
@@ -79,7 +81,7 @@ export function WorkspacesLayout() {
|
||||
rightMainPanelMode,
|
||||
setLeftSidebarVisible,
|
||||
setLeftMainPanelVisible,
|
||||
} = useUiPreferencesStore();
|
||||
} = useWorkspacePanelState(isCreateMode ? undefined : workspaceId);
|
||||
|
||||
const {
|
||||
config,
|
||||
|
||||
@@ -9,9 +9,10 @@ import {
|
||||
} from 'react';
|
||||
import type { LogsPanelContent } from '@/components/ui-new/containers/LogsContentContainer';
|
||||
import {
|
||||
useUiPreferencesStore,
|
||||
useWorkspacePanelState,
|
||||
RIGHT_MAIN_PANEL_MODES,
|
||||
} from '@/stores/useUiPreferencesStore';
|
||||
import { useWorkspaceContext } from '@/contexts/WorkspaceContext';
|
||||
|
||||
interface LogsPanelContextValue {
|
||||
logsPanelContent: LogsPanelContent | null;
|
||||
@@ -50,7 +51,10 @@ interface LogsPanelProviderProps {
|
||||
}
|
||||
|
||||
export function LogsPanelProvider({ children }: LogsPanelProviderProps) {
|
||||
const { rightMainPanelMode, setRightMainPanelMode } = useUiPreferencesStore();
|
||||
const { workspaceId, isCreateMode } = useWorkspaceContext();
|
||||
const { rightMainPanelMode, setRightMainPanelMode } = useWorkspacePanelState(
|
||||
isCreateMode ? undefined : workspaceId
|
||||
);
|
||||
|
||||
const [logsPanelContent, setLogsPanelContent] =
|
||||
useState<LogsPanelContent | null>(null);
|
||||
|
||||
@@ -22,7 +22,6 @@ import {
|
||||
} from '@/hooks/useGitHubComments';
|
||||
import { useDiffStream } from '@/hooks/useDiffStream';
|
||||
import { attemptsApi } from '@/lib/api';
|
||||
import { useUiPreferencesStore } from '@/stores/useUiPreferencesStore';
|
||||
import { useDiffViewStore } from '@/stores/useDiffViewStore';
|
||||
import type {
|
||||
Workspace as ApiWorkspace,
|
||||
@@ -91,13 +90,6 @@ export function WorkspaceProvider({ children }: WorkspaceProviderProps) {
|
||||
// Derive isCreateMode from URL path instead of prop to allow provider to persist across route changes
|
||||
const isCreateMode = location.pathname === '/workspaces/create';
|
||||
|
||||
// Reset UI state when entering create mode
|
||||
useEffect(() => {
|
||||
if (isCreateMode) {
|
||||
useUiPreferencesStore.getState().resetForCreateMode();
|
||||
}
|
||||
}, [isCreateMode]);
|
||||
|
||||
// Fetch workspaces for sidebar display
|
||||
const {
|
||||
workspaces: activeWorkspaces,
|
||||
|
||||
@@ -20,6 +20,17 @@ export type ContextBarPosition =
|
||||
| 'bottom-left'
|
||||
| 'bottom-right';
|
||||
|
||||
// Workspace-specific panel state
|
||||
export type WorkspacePanelState = {
|
||||
rightMainPanelMode: RightMainPanelMode | null;
|
||||
isLeftMainPanelVisible: boolean;
|
||||
};
|
||||
|
||||
const DEFAULT_WORKSPACE_PANEL_STATE: WorkspacePanelState = {
|
||||
rightMainPanelMode: null,
|
||||
isLeftMainPanelVisible: true,
|
||||
};
|
||||
|
||||
// Centralized persist keys for type safety
|
||||
export const PERSIST_KEYS = {
|
||||
// Sidebar sections
|
||||
@@ -76,13 +87,14 @@ type State = {
|
||||
paneSizes: Record<string, number | string>;
|
||||
collapsedPaths: Record<string, string[]>;
|
||||
|
||||
// Layout state
|
||||
// Global layout state (applies across all workspaces)
|
||||
isLeftSidebarVisible: boolean;
|
||||
isLeftMainPanelVisible: boolean;
|
||||
isRightSidebarVisible: boolean;
|
||||
rightMainPanelMode: RightMainPanelMode | null;
|
||||
previewRefreshKey: number;
|
||||
|
||||
// Workspace-specific panel state
|
||||
workspacePanelStates: Record<string, WorkspacePanelState>;
|
||||
|
||||
// UI preferences actions
|
||||
setRepoAction: (repoId: string, action: RepoAction) => void;
|
||||
setExpanded: (key: string, value: boolean) => void;
|
||||
@@ -94,14 +106,26 @@ type State = {
|
||||
|
||||
// Layout actions
|
||||
toggleLeftSidebar: () => void;
|
||||
toggleLeftMainPanel: () => void;
|
||||
toggleLeftMainPanel: (workspaceId?: string) => void;
|
||||
toggleRightSidebar: () => void;
|
||||
toggleRightMainPanelMode: (mode: RightMainPanelMode) => void;
|
||||
setRightMainPanelMode: (mode: RightMainPanelMode | null) => void;
|
||||
toggleRightMainPanelMode: (
|
||||
mode: RightMainPanelMode,
|
||||
workspaceId?: string
|
||||
) => void;
|
||||
setRightMainPanelMode: (
|
||||
mode: RightMainPanelMode | null,
|
||||
workspaceId?: string
|
||||
) => void;
|
||||
setLeftSidebarVisible: (value: boolean) => void;
|
||||
setLeftMainPanelVisible: (value: boolean) => void;
|
||||
setLeftMainPanelVisible: (value: boolean, workspaceId?: string) => void;
|
||||
triggerPreviewRefresh: () => void;
|
||||
resetForCreateMode: () => void;
|
||||
|
||||
// Workspace-specific panel state actions
|
||||
getWorkspacePanelState: (workspaceId: string) => WorkspacePanelState;
|
||||
setWorkspacePanelState: (
|
||||
workspaceId: string,
|
||||
state: Partial<WorkspacePanelState>
|
||||
) => void;
|
||||
};
|
||||
|
||||
export const useUiPreferencesStore = create<State>()(
|
||||
@@ -114,13 +138,14 @@ export const useUiPreferencesStore = create<State>()(
|
||||
paneSizes: {},
|
||||
collapsedPaths: {},
|
||||
|
||||
// Layout state
|
||||
// Global layout state
|
||||
isLeftSidebarVisible: true,
|
||||
isLeftMainPanelVisible: true,
|
||||
isRightSidebarVisible: true,
|
||||
rightMainPanelMode: null,
|
||||
previewRefreshKey: 0,
|
||||
|
||||
// Workspace-specific panel state
|
||||
workspacePanelStates: {},
|
||||
|
||||
// UI preferences actions
|
||||
setRepoAction: (repoId, action) =>
|
||||
set((s) => ({ repoActions: { ...s.repoActions, [repoId]: action } })),
|
||||
@@ -151,59 +176,123 @@ export const useUiPreferencesStore = create<State>()(
|
||||
toggleLeftSidebar: () =>
|
||||
set((s) => ({ isLeftSidebarVisible: !s.isLeftSidebarVisible })),
|
||||
|
||||
toggleLeftMainPanel: () => {
|
||||
const { isLeftMainPanelVisible, rightMainPanelMode } = get();
|
||||
if (isLeftMainPanelVisible && rightMainPanelMode === null) return;
|
||||
set({ isLeftMainPanelVisible: !isLeftMainPanelVisible });
|
||||
toggleLeftMainPanel: (workspaceId) => {
|
||||
if (!workspaceId) return;
|
||||
const state = get();
|
||||
const wsState =
|
||||
state.workspacePanelStates[workspaceId] ??
|
||||
DEFAULT_WORKSPACE_PANEL_STATE;
|
||||
if (
|
||||
wsState.isLeftMainPanelVisible &&
|
||||
wsState.rightMainPanelMode === null
|
||||
)
|
||||
return;
|
||||
set({
|
||||
workspacePanelStates: {
|
||||
...state.workspacePanelStates,
|
||||
[workspaceId]: {
|
||||
...wsState,
|
||||
isLeftMainPanelVisible: !wsState.isLeftMainPanelVisible,
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
toggleRightSidebar: () =>
|
||||
set((s) => ({ isRightSidebarVisible: !s.isRightSidebarVisible })),
|
||||
|
||||
toggleRightMainPanelMode: (mode) => {
|
||||
const { rightMainPanelMode } = get();
|
||||
const isCurrentlyActive = rightMainPanelMode === mode;
|
||||
toggleRightMainPanelMode: (mode, workspaceId) => {
|
||||
if (!workspaceId) return;
|
||||
const state = get();
|
||||
const wsState =
|
||||
state.workspacePanelStates[workspaceId] ??
|
||||
DEFAULT_WORKSPACE_PANEL_STATE;
|
||||
const isCurrentlyActive = wsState.rightMainPanelMode === mode;
|
||||
|
||||
if (isCurrentlyActive) {
|
||||
set({
|
||||
rightMainPanelMode: null,
|
||||
isLeftSidebarVisible: true,
|
||||
});
|
||||
} else {
|
||||
set({
|
||||
rightMainPanelMode: mode,
|
||||
isLeftSidebarVisible: isWideScreen()
|
||||
? get().isLeftSidebarVisible
|
||||
set({
|
||||
workspacePanelStates: {
|
||||
...state.workspacePanelStates,
|
||||
[workspaceId]: {
|
||||
...wsState,
|
||||
rightMainPanelMode: isCurrentlyActive ? null : mode,
|
||||
},
|
||||
},
|
||||
isLeftSidebarVisible: isCurrentlyActive
|
||||
? true
|
||||
: isWideScreen()
|
||||
? state.isLeftSidebarVisible
|
||||
: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setRightMainPanelMode: (mode) => {
|
||||
if (mode !== null) {
|
||||
set({
|
||||
rightMainPanelMode: mode,
|
||||
setRightMainPanelMode: (mode, workspaceId) => {
|
||||
if (!workspaceId) return;
|
||||
const state = get();
|
||||
const wsState =
|
||||
state.workspacePanelStates[workspaceId] ??
|
||||
DEFAULT_WORKSPACE_PANEL_STATE;
|
||||
set({
|
||||
workspacePanelStates: {
|
||||
...state.workspacePanelStates,
|
||||
[workspaceId]: {
|
||||
...wsState,
|
||||
rightMainPanelMode: mode,
|
||||
},
|
||||
},
|
||||
...(mode !== null && {
|
||||
isLeftSidebarVisible: isWideScreen()
|
||||
? get().isLeftSidebarVisible
|
||||
? state.isLeftSidebarVisible
|
||||
: false,
|
||||
});
|
||||
} else {
|
||||
set({ rightMainPanelMode: null });
|
||||
}
|
||||
}),
|
||||
});
|
||||
},
|
||||
|
||||
setLeftSidebarVisible: (value) => set({ isLeftSidebarVisible: value }),
|
||||
|
||||
setLeftMainPanelVisible: (value) =>
|
||||
set({ isLeftMainPanelVisible: value }),
|
||||
setLeftMainPanelVisible: (value, workspaceId) => {
|
||||
if (!workspaceId) return;
|
||||
const state = get();
|
||||
const wsState =
|
||||
state.workspacePanelStates[workspaceId] ??
|
||||
DEFAULT_WORKSPACE_PANEL_STATE;
|
||||
set({
|
||||
workspacePanelStates: {
|
||||
...state.workspacePanelStates,
|
||||
[workspaceId]: {
|
||||
...wsState,
|
||||
isLeftMainPanelVisible: value,
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
triggerPreviewRefresh: () =>
|
||||
set((s) => ({ previewRefreshKey: s.previewRefreshKey + 1 })),
|
||||
|
||||
resetForCreateMode: () =>
|
||||
// Workspace-specific panel state actions
|
||||
getWorkspacePanelState: (workspaceId) => {
|
||||
const state = get();
|
||||
return (
|
||||
state.workspacePanelStates[workspaceId] ??
|
||||
DEFAULT_WORKSPACE_PANEL_STATE
|
||||
);
|
||||
},
|
||||
|
||||
setWorkspacePanelState: (workspaceId, panelState) => {
|
||||
const state = get();
|
||||
const currentWsState =
|
||||
state.workspacePanelStates[workspaceId] ??
|
||||
DEFAULT_WORKSPACE_PANEL_STATE;
|
||||
set({
|
||||
rightMainPanelMode: null,
|
||||
}),
|
||||
workspacePanelStates: {
|
||||
...state.workspacePanelStates,
|
||||
[workspaceId]: {
|
||||
...currentWsState,
|
||||
...panelState,
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: 'ui-preferences',
|
||||
@@ -214,10 +303,11 @@ export const useUiPreferencesStore = create<State>()(
|
||||
contextBarPosition: state.contextBarPosition,
|
||||
paneSizes: state.paneSizes,
|
||||
collapsedPaths: state.collapsedPaths,
|
||||
// Layout (only persist panel visibility, not mode states)
|
||||
// Global layout (persist sidebar visibility)
|
||||
isLeftSidebarVisible: state.isLeftSidebarVisible,
|
||||
isLeftMainPanelVisible: state.isLeftMainPanelVisible,
|
||||
isRightSidebarVisible: state.isRightSidebarVisible,
|
||||
// Workspace-specific panel state (persisted)
|
||||
workspacePanelStates: state.workspacePanelStates,
|
||||
}),
|
||||
}
|
||||
)
|
||||
@@ -301,6 +391,70 @@ export function usePersistedCollapsedPaths(
|
||||
return [pathSet, setPathSet];
|
||||
}
|
||||
|
||||
// Layout convenience hooks
|
||||
export const useIsRightMainPanelVisible = () =>
|
||||
useUiPreferencesStore((s) => s.rightMainPanelMode !== null);
|
||||
// Hook for workspace-specific panel state
|
||||
export function useWorkspacePanelState(workspaceId: string | undefined) {
|
||||
// Get workspace-specific state (falls back to defaults when no workspaceId)
|
||||
const workspacePanelStates = useUiPreferencesStore(
|
||||
(s) => s.workspacePanelStates
|
||||
);
|
||||
const wsState = workspaceId
|
||||
? (workspacePanelStates[workspaceId] ?? DEFAULT_WORKSPACE_PANEL_STATE)
|
||||
: DEFAULT_WORKSPACE_PANEL_STATE;
|
||||
|
||||
// Global state (sidebars are global)
|
||||
const isLeftSidebarVisible = useUiPreferencesStore(
|
||||
(s) => s.isLeftSidebarVisible
|
||||
);
|
||||
const isRightSidebarVisible = useUiPreferencesStore(
|
||||
(s) => s.isRightSidebarVisible
|
||||
);
|
||||
|
||||
// Actions from store
|
||||
const toggleRightMainPanelMode = useUiPreferencesStore(
|
||||
(s) => s.toggleRightMainPanelMode
|
||||
);
|
||||
const setRightMainPanelMode = useUiPreferencesStore(
|
||||
(s) => s.setRightMainPanelMode
|
||||
);
|
||||
const setLeftMainPanelVisible = useUiPreferencesStore(
|
||||
(s) => s.setLeftMainPanelVisible
|
||||
);
|
||||
const setLeftSidebarVisible = useUiPreferencesStore(
|
||||
(s) => s.setLeftSidebarVisible
|
||||
);
|
||||
|
||||
// Memoized callbacks that include workspaceId
|
||||
const toggleRightMainPanelModeForWorkspace = useCallback(
|
||||
(mode: RightMainPanelMode) => toggleRightMainPanelMode(mode, workspaceId),
|
||||
[toggleRightMainPanelMode, workspaceId]
|
||||
);
|
||||
|
||||
const setRightMainPanelModeForWorkspace = useCallback(
|
||||
(mode: RightMainPanelMode | null) =>
|
||||
setRightMainPanelMode(mode, workspaceId),
|
||||
[setRightMainPanelMode, workspaceId]
|
||||
);
|
||||
|
||||
const setLeftMainPanelVisibleForWorkspace = useCallback(
|
||||
(value: boolean) => setLeftMainPanelVisible(value, workspaceId),
|
||||
[setLeftMainPanelVisible, workspaceId]
|
||||
);
|
||||
|
||||
return {
|
||||
// Workspace-specific state
|
||||
rightMainPanelMode: wsState.rightMainPanelMode,
|
||||
isLeftMainPanelVisible: wsState.isLeftMainPanelVisible,
|
||||
|
||||
// Global state (sidebars)
|
||||
isLeftSidebarVisible,
|
||||
isRightSidebarVisible,
|
||||
|
||||
// Workspace-specific actions
|
||||
toggleRightMainPanelMode: toggleRightMainPanelModeForWorkspace,
|
||||
setRightMainPanelMode: setRightMainPanelModeForWorkspace,
|
||||
setLeftMainPanelVisible: setLeftMainPanelVisibleForWorkspace,
|
||||
|
||||
// Global actions
|
||||
setLeftSidebarVisible,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user