diff --git a/frontend/src/components/panels/Data.svelte b/frontend/src/components/panels/Data.svelte
index 400e556f..905cfca7 100644
--- a/frontend/src/components/panels/Data.svelte
+++ b/frontend/src/components/panels/Data.svelte
@@ -1,15 +1,12 @@
-
+
diff --git a/frontend/src/components/panels/Layers.svelte b/frontend/src/components/panels/Layers.svelte
index e5d91fc8..4d32b3ff 100644
--- a/frontend/src/components/panels/Layers.svelte
+++ b/frontend/src/components/panels/Layers.svelte
@@ -7,6 +7,7 @@
import Separator from "/src/components/widgets/labels/Separator.svelte";
import WidgetLayout from "/src/components/widgets/WidgetLayout.svelte";
import type { NodeGraphStore } from "/src/stores/node-graph";
+ import { layersPanelControlBarLeftLayout, layersPanelControlBarRightLayout, layersPanelBottomBarLayout } from "/src/stores/portfolio";
import type { PortfolioStore } from "/src/stores/portfolio";
import type { TooltipStore } from "/src/stores/tooltip";
import { pasteFile } from "/src/utility-functions/files";
@@ -509,11 +510,11 @@
(dragInPanel = false)}>
-
- {#if $portfolio.layersPanelControlBarLeftLayout?.length > 0 && $portfolio.layersPanelControlBarRightLayout?.length > 0}
+
+ {#if $layersPanelControlBarLeftLayout?.length > 0 && $layersPanelControlBarRightLayout?.length > 0}
{/if}
-
+
-
+
diff --git a/frontend/src/components/panels/Properties.svelte b/frontend/src/components/panels/Properties.svelte
index fee12bd7..4ae6fd75 100644
--- a/frontend/src/components/panels/Properties.svelte
+++ b/frontend/src/components/panels/Properties.svelte
@@ -1,15 +1,12 @@
-
+
diff --git a/frontend/src/components/panels/Welcome.svelte b/frontend/src/components/panels/Welcome.svelte
index a38d724e..ab1de065 100644
--- a/frontend/src/components/panels/Welcome.svelte
+++ b/frontend/src/components/panels/Welcome.svelte
@@ -5,12 +5,11 @@
import IconLabel from "/src/components/widgets/labels/IconLabel.svelte";
import TextLabel from "/src/components/widgets/labels/TextLabel.svelte";
import WidgetLayout from "/src/components/widgets/WidgetLayout.svelte";
- import type { PortfolioStore } from "/src/stores/portfolio";
+ import { welcomeScreenButtonsLayout } from "/src/stores/portfolio";
import { pasteFile } from "/src/utility-functions/files";
import type { EditorWrapper } from "/wrapper/pkg/graphite_wasm_wrapper";
const editor = getContext("editor");
- const portfolio = getContext("portfolio");
function dropFile(e: DragEvent) {
if (!e.dataTransfer) return;
@@ -29,7 +28,7 @@
-
+
diff --git a/frontend/src/stores/portfolio.ts b/frontend/src/stores/portfolio.ts
index 4944d74c..be3799c9 100644
--- a/frontend/src/stores/portfolio.ts
+++ b/frontend/src/stores/portfolio.ts
@@ -15,12 +15,6 @@ type PortfolioStoreState = {
documents: DocumentInfo[];
activeDocumentIndex: number;
panelLayout: WorkspacePanelLayout;
- welcomeScreenButtonsLayout: Layout;
- propertiesPanelLayout: Layout;
- dataPanelLayout: Layout;
- layersPanelControlBarLeftLayout: Layout;
- layersPanelControlBarRightLayout: Layout;
- layersPanelBottomBarLayout: Layout;
layerCache: SvelteMap;
layerStructure: LayerStructureEntry[];
};
@@ -29,12 +23,6 @@ const initialState: PortfolioStoreState = {
documents: [],
activeDocumentIndex: 0,
panelLayout: {},
- welcomeScreenButtonsLayout: [],
- propertiesPanelLayout: [],
- dataPanelLayout: [],
- layersPanelControlBarLeftLayout: [],
- layersPanelControlBarRightLayout: [],
- layersPanelBottomBarLayout: [],
layerCache: new SvelteMap(),
layerStructure: [],
};
@@ -46,6 +34,30 @@ const store: Writable = import.meta.hot?.data?.store || wri
if (import.meta.hot) import.meta.hot.data.store = store;
const { subscribe, update } = store;
+export const welcomeScreenButtonsLayout = makeLayoutStore("welcomeScreenButtonsLayout");
+export const propertiesPanelLayout = makeLayoutStore("propertiesPanelLayout");
+export const dataPanelLayout = makeLayoutStore("dataPanelLayout");
+export const layersPanelControlBarLeftLayout = makeLayoutStore("layersPanelControlBarLeftLayout");
+export const layersPanelControlBarRightLayout = makeLayoutStore("layersPanelControlBarRightLayout");
+export const layersPanelBottomBarLayout = makeLayoutStore("layersPanelBottomBarLayout");
+
+// Each panel layout has its own dedicated store so a layout update only re-renders that panel's consumers.
+// Putting them at module scope (not inside the component) lets them survive a Svelte remount during a
+// panel-tree restructure, since the backend's diff-based updates aren't re-sent on subscribe.
+function makeLayoutStore(name: string): Writable {
+ const persisted = import.meta.hot?.data?.[name];
+ const layoutStore: Writable = persisted || writable([]);
+ if (import.meta.hot) import.meta.hot.data[name] = layoutStore;
+ return layoutStore;
+}
+
+function patchLayoutStore(layoutStore: Writable, data: Parameters[1]) {
+ layoutStore.update((layout) => {
+ patchLayout(layout, data);
+ return layout;
+ });
+}
+
export function createPortfolioStore(subscriptions: SubscriptionsRouter, editor: EditorWrapper) {
destroyPortfolioStore();
@@ -123,53 +135,35 @@ export function createPortfolioStore(subscriptions: SubscriptionsRouter, editor:
});
});
- // All panel layouts below live in this store so panels that remount during a panel-tree change keep their contents
+ // Each panel layout uses its own store so updates only re-render that panel's consumers
subscriptions.subscribeLayoutUpdate("WelcomeScreenButtons", async (data) => {
await tick();
- update((state) => {
- patchLayout(state.welcomeScreenButtonsLayout, data);
- return state;
- });
+ patchLayoutStore(welcomeScreenButtonsLayout, data);
});
subscriptions.subscribeLayoutUpdate("PropertiesPanel", async (data) => {
await tick();
- update((state) => {
- patchLayout(state.propertiesPanelLayout, data);
- return state;
- });
+ patchLayoutStore(propertiesPanelLayout, data);
});
subscriptions.subscribeLayoutUpdate("DataPanel", async (data) => {
await tick();
- update((state) => {
- patchLayout(state.dataPanelLayout, data);
- return state;
- });
+ patchLayoutStore(dataPanelLayout, data);
});
subscriptions.subscribeLayoutUpdate("LayersPanelControlLeftBar", async (data) => {
await tick();
- update((state) => {
- patchLayout(state.layersPanelControlBarLeftLayout, data);
- return state;
- });
+ patchLayoutStore(layersPanelControlBarLeftLayout, data);
});
subscriptions.subscribeLayoutUpdate("LayersPanelControlRightBar", async (data) => {
await tick();
- update((state) => {
- patchLayout(state.layersPanelControlBarRightLayout, data);
- return state;
- });
+ patchLayoutStore(layersPanelControlBarRightLayout, data);
});
subscriptions.subscribeLayoutUpdate("LayersPanelBottomBar", async (data) => {
await tick();
- update((state) => {
- patchLayout(state.layersPanelBottomBarLayout, data);
- return state;
- });
+ patchLayoutStore(layersPanelBottomBarLayout, data);
});
subscriptions.subscribeFrontendMessage("UpdateDocumentLayerStructure", (data) => {