From de7709039aeafe0aa477fcf7248d3f346e85ca1a Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sat, 7 Mar 2026 20:47:35 -0500 Subject: [PATCH] Persist workspace panel open/closed state per project Panel state is saved to localStorage as workspace_panels_{projectId} on every toggle and restored on mount. Each project remembers its own layout independently. Fallback guard ensures at least one panel is always open after restore. Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/views/WorkspaceView.vue | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/frontend/src/views/WorkspaceView.vue b/frontend/src/views/WorkspaceView.vue index deef333..798b1bb 100644 --- a/frontend/src/views/WorkspaceView.vue +++ b/frontend/src/views/WorkspaceView.vue @@ -37,7 +37,22 @@ function _storageKey(pid: number) { return `workspace_conv_${pid}`; } -// Panel collapse state +// Panel collapse state — persisted per project +function _panelKey(pid: number) { return `workspace_panels_${pid}`; } + +function _loadPanelState(pid: number) { + try { + const raw = localStorage.getItem(_panelKey(pid)); + if (raw) { + const saved = JSON.parse(raw); + // Ensure at least one panel is open after restore + if (!saved.tasks && !saved.chat && !saved.notes) saved.chat = true; + return saved as { tasks: boolean; chat: boolean; notes: boolean }; + } + } catch { /* ignore */ } + return { tasks: true, chat: true, notes: true }; +} + const panelOpen = ref({ tasks: true, chat: true, notes: true }); const gridColumns = computed(() => { @@ -102,11 +117,11 @@ function scrollToBottom() { watch(() => chatStore.streamingContent, scrollToBottom); function togglePanel(panel: keyof typeof panelOpen.value) { - // Ensure at least one panel stays open const open = panelOpen.value; const openCount = [open.tasks, open.chat, open.notes].filter(Boolean).length; if (open[panel] && openCount <= 1) return; panelOpen.value[panel] = !panelOpen.value[panel]; + localStorage.setItem(_panelKey(projectId.value), JSON.stringify(panelOpen.value)); } async function sendMessage() { @@ -156,6 +171,9 @@ function resetTextareaHeight() { } onMounted(async () => { + // Restore panel state + panelOpen.value = _loadPanelState(projectId.value); + // Load project info try { project.value = await apiGet(`/api/projects/${projectId.value}`);