From 11502aa8e73a2941aa0cfed198fb457b1ba62c35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemek=20Wi=C4=99ch?= Date: Thu, 11 Jun 2026 17:00:33 +0200 Subject: [PATCH] Shift `showSidePanel` to URL as source of truth --- docs/APP_REFACTORING_DESIGN.md | 2 +- src/app.tsx | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/docs/APP_REFACTORING_DESIGN.md b/docs/APP_REFACTORING_DESIGN.md index 4646299..0b27668 100644 --- a/docs/APP_REFACTORING_DESIGN.md +++ b/docs/APP_REFACTORING_DESIGN.md @@ -96,7 +96,7 @@ We will gradually eliminate React state variables in `src/app.tsx` and derive th * [x] **Step 3.1c:** Shift `showWikiTreeMenus` to URL as SSOT. Derive it directly from search parameters on render and remove its React state variable. * [x] **Step 3.1d:** Shift `freezeAnimation` to URL as SSOT. Derive it directly from search parameters on render and remove its React state variable. * [x] **Step 3.2:** Extract `selection` and `detailIndi` state. Parse them directly from URL params (`indi`, `gen`, and `detail`); update display selectors. Remove React states. Ensure that chart selection changes (`onSelection` callback) explicitly clear or update the `detail` query parameter to match the new selection to avoid getting stuck on the old details viewport. Also update the detail-only selection handler (`onDetailSelection`) to update the `detail` query parameter in the URL. -* [ ] **Step 3.3:** Extract `showSidePanel` state. Derive state directly from `?sidePanel=` parameter. Remove React state. Enhance URL args helpers to allow generating path/query target objects with replaced values, and ensure layout settings (`sidePanel`) and configuration changes use `replace: true` to prevent polluting the browser history stack. +* [x] **Step 3.3:** Extract `showSidePanel` state. Derive state directly from `?sidePanel=` parameter. Remove React state. Enhance URL args helpers to allow generating path/query target objects with replaced values, and ensure layout settings (`sidePanel`) and configuration changes use `replace: true` to prevent polluting the browser history stack. * [ ] **Step 3.4:** Extract `config` state. Parse display settings on render using `argsToConfig` helper. Remove state. In `ViewPage`, run `updateChartWithConfig(config, data)` synchronously during the render pass (e.g. in the `useMemo` that derives query parameters/config) to update the in-memory chart data before it is rendered by the `` child component. Run E2E and visual tests to verify no rendering regressions occurred. #### Phase 4: Structural Page Nesting diff --git a/src/app.tsx b/src/app.tsx index 023ed31..2b11796 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -86,8 +86,6 @@ export function App() { /** Error to display. */ const [error, setError] = useState(); - /** Whether the side panel is shown. */ - const [showSidePanel, setShowSidePanel] = useState(false); /** Whether to show the error popup. */ const [showErrorPopup, setShowErrorPopup] = useState(false); @@ -122,6 +120,8 @@ export function App() { const showWikiTreeMenus = args.showWikiTreeMenus; /** Freeze animations after initial chart render. */ const freezeAnimation = args.freezeAnimation; + /** Whether the side panel is shown. */ + const showSidePanel = args.showSidePanel; /** The currently selected individual. Fallback to default individual from loaded data if not specified. */ const updatedSelection = useMemo(() => { return data ? getSelection(data.chartData, args.selection) : undefined; @@ -161,10 +161,12 @@ export function App() { function onToggleSidePanel() { const newShowSidePanel = !showSidePanel; - setShowSidePanel(newShowSidePanel); - updateUrl({ - sidePanel: newShowSidePanel ? 'true' : 'false', - }); + updateUrl( + { + sidePanel: newShowSidePanel ? 'true' : 'false', + }, + {replace: true}, + ); } /** Sets error message after data load failure. */ @@ -368,7 +370,6 @@ export function App() { args.selection, ); updateChartWithConfig(args.config, data); - setShowSidePanel(args.showSidePanel); setState(AppState.SHOWING_CHART); } catch (error: unknown) { if (!isMountedRef.current || fetchIdRef.current !== currentFetchId) { @@ -446,8 +447,9 @@ export function App() { function updateUrl( args: Record, + options?: {replace?: boolean}, ) { - navigate(getUrlForArgs(location, args)); + navigate(getUrlForArgs(location, args), options); } /** @@ -587,7 +589,7 @@ export function App() { onConfigChange={(config) => { setConfig(config); updateChartWithConfig(config, data); - updateUrl(configToArgs(config)); + updateUrl(configToArgs(config), {replace: true}); }} /> {renderChart(selection)}