From 485bac89e55a4c16f8b37ef45d07a1c94f4f1f80 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Fri, 1 May 2026 19:55:50 -0700 Subject: [PATCH] Fix regression with the color picker in the Properties panel being broken --- frontend/src/components/panels/Data.svelte | 7 +- frontend/src/components/panels/Layers.svelte | 9 +-- .../src/components/panels/Properties.svelte | 7 +- frontend/src/components/panels/Welcome.svelte | 5 +- frontend/src/stores/portfolio.ts | 68 +++++++++---------- 5 files changed, 42 insertions(+), 54 deletions(-) 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) => {