mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-07-17 17:21:48 +00:00
Shift showSidePanel to URL as source of truth
This commit is contained in:
@@ -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.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.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.
|
* [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 `<Chart>` child component. Run E2E and visual tests to verify no rendering regressions occurred.
|
* [ ] **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 `<Chart>` child component. Run E2E and visual tests to verify no rendering regressions occurred.
|
||||||
|
|
||||||
#### Phase 4: Structural Page Nesting
|
#### Phase 4: Structural Page Nesting
|
||||||
|
|||||||
20
src/app.tsx
20
src/app.tsx
@@ -86,8 +86,6 @@ export function App() {
|
|||||||
|
|
||||||
/** Error to display. */
|
/** Error to display. */
|
||||||
const [error, setError] = useState<string>();
|
const [error, setError] = useState<string>();
|
||||||
/** Whether the side panel is shown. */
|
|
||||||
const [showSidePanel, setShowSidePanel] = useState(false);
|
|
||||||
|
|
||||||
/** Whether to show the error popup. */
|
/** Whether to show the error popup. */
|
||||||
const [showErrorPopup, setShowErrorPopup] = useState(false);
|
const [showErrorPopup, setShowErrorPopup] = useState(false);
|
||||||
@@ -122,6 +120,8 @@ export function App() {
|
|||||||
const showWikiTreeMenus = args.showWikiTreeMenus;
|
const showWikiTreeMenus = args.showWikiTreeMenus;
|
||||||
/** Freeze animations after initial chart render. */
|
/** Freeze animations after initial chart render. */
|
||||||
const freezeAnimation = args.freezeAnimation;
|
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. */
|
/** The currently selected individual. Fallback to default individual from loaded data if not specified. */
|
||||||
const updatedSelection = useMemo(() => {
|
const updatedSelection = useMemo(() => {
|
||||||
return data ? getSelection(data.chartData, args.selection) : undefined;
|
return data ? getSelection(data.chartData, args.selection) : undefined;
|
||||||
@@ -161,10 +161,12 @@ export function App() {
|
|||||||
|
|
||||||
function onToggleSidePanel() {
|
function onToggleSidePanel() {
|
||||||
const newShowSidePanel = !showSidePanel;
|
const newShowSidePanel = !showSidePanel;
|
||||||
setShowSidePanel(newShowSidePanel);
|
updateUrl(
|
||||||
updateUrl({
|
{
|
||||||
sidePanel: newShowSidePanel ? 'true' : 'false',
|
sidePanel: newShowSidePanel ? 'true' : 'false',
|
||||||
});
|
},
|
||||||
|
{replace: true},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets error message after data load failure. */
|
/** Sets error message after data load failure. */
|
||||||
@@ -368,7 +370,6 @@ export function App() {
|
|||||||
args.selection,
|
args.selection,
|
||||||
);
|
);
|
||||||
updateChartWithConfig(args.config, data);
|
updateChartWithConfig(args.config, data);
|
||||||
setShowSidePanel(args.showSidePanel);
|
|
||||||
setState(AppState.SHOWING_CHART);
|
setState(AppState.SHOWING_CHART);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (!isMountedRef.current || fetchIdRef.current !== currentFetchId) {
|
if (!isMountedRef.current || fetchIdRef.current !== currentFetchId) {
|
||||||
@@ -446,8 +447,9 @@ export function App() {
|
|||||||
|
|
||||||
function updateUrl(
|
function updateUrl(
|
||||||
args: Record<string, string | (string | null)[] | null | undefined>,
|
args: Record<string, string | (string | null)[] | null | undefined>,
|
||||||
|
options?: {replace?: boolean},
|
||||||
) {
|
) {
|
||||||
navigate(getUrlForArgs(location, args));
|
navigate(getUrlForArgs(location, args), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -587,7 +589,7 @@ export function App() {
|
|||||||
onConfigChange={(config) => {
|
onConfigChange={(config) => {
|
||||||
setConfig(config);
|
setConfig(config);
|
||||||
updateChartWithConfig(config, data);
|
updateChartWithConfig(config, data);
|
||||||
updateUrl(configToArgs(config));
|
updateUrl(configToArgs(config), {replace: true});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<SidebarPusher>{renderChart(selection)}</SidebarPusher>
|
<SidebarPusher>{renderChart(selection)}</SidebarPusher>
|
||||||
|
|||||||
Reference in New Issue
Block a user