Skip to content

Commit 7642906

Browse files
authored
feat: open the Style panel only when explicitly requested (#1775)
* feat: open the Style panel only when explicitly requested Selecting a layer no longer pops the Style panel open over the map, which made the workspace jump around during ordinary layer picking. The panel now expands only from the new "Open Style panel" item in a layer's menu. * Address review feedback - Gate the Style panel's open-request effect on `autoCollapse`, so a request made while the notebook or a story-map presentation owns the workspace can no longer force the panel open over them. The `autoCollapse` effect acts only on transitions, so such an expand would have stuck until the notebook was closed and reopened. - Hide the "Open Style panel" menu item when the Style panel is hidden (Settings → "Show Style panel"). The panel is not mounted then, so the request was dropped rather than queued and the item did nothing.
1 parent 1578884 commit 7642906

5 files changed

Lines changed: 48 additions & 19 deletions

File tree

apps/geolibre-desktop/src/components/layout/DesktopShell.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,10 @@ export function DesktopShell({
866866
useNetcdfIdentify(mapControllerRef, mapReadyGeneration);
867867
const [layerPanelWidth, setLayerPanelWidth] = useState(initialSidePanelWidth);
868868
const [stylePanelWidth, setStylePanelWidth] = useState(initialSidePanelWidth);
869+
const [stylePanelOpenRequest, setStylePanelOpenRequest] = useState(0);
870+
const openStylePanel = useCallback(() => {
871+
setStylePanelOpenRequest((request) => request + 1);
872+
}, []);
869873
const [notebookPanelWidth, setNotebookPanelWidth] = useState(DEFAULT_NOTEBOOK_PANEL_WIDTH);
870874
// Opening the notebook (Processing → Jupyter Notebook) splits the workspace
871875
// 50/50 between the map and the notebook: we size the notebook to half of the
@@ -2245,6 +2249,9 @@ export function DesktopShell({
22452249
onOpenRasterStylePanel={() =>
22462250
openRasterLayerPanel(createAppAPI(mapControllerRef))
22472251
}
2252+
onOpenStylePanel={
2253+
layoutOptions.stylePanelVisible ? openStylePanel : undefined
2254+
}
22482255
onOpenRasterSubset={setRasterSubsetLayer}
22492256
collapsed={collapsed}
22502257
onCollapsedChange={onCollapsedChange}
@@ -2268,6 +2275,7 @@ export function DesktopShell({
22682275
onOpenRasterStylePanel={() =>
22692276
openRasterLayerPanel(createAppAPI(mapControllerRef))
22702277
}
2278+
onOpenStylePanel={layoutOptions.stylePanelVisible ? openStylePanel : undefined}
22712279
onOpenRasterSubset={setRasterSubsetLayer}
22722280
autoCollapse={
22732281
storymapPresenting ||
@@ -2493,6 +2501,7 @@ export function DesktopShell({
24932501
<StylePanel
24942502
mapControllerRef={mapControllerRef}
24952503
onResizeStart={startStylePanelResize}
2504+
openRequest={stylePanelOpenRequest}
24962505
collapsed={collapsed}
24972506
onCollapsedChange={onCollapsedChange}
24982507
// Controlled mode ignores autoCollapse for collapsing (the
@@ -2513,6 +2522,7 @@ export function DesktopShell({
25132522
<StylePanel
25142523
mapControllerRef={mapControllerRef}
25152524
onResizeStart={startStylePanelResize}
2525+
openRequest={stylePanelOpenRequest}
25162526
autoCollapse={
25172527
notebookOpen ||
25182528
storymapPresenting ||

apps/geolibre-desktop/src/components/panels/LayerPanel.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,13 @@ interface LayerPanelProps {
243243
onMaterializeDuckDBLayer: (layer: GeoLibreLayer) => void;
244244
/** Open the floating Add Raster Layer panel for advanced raster styling. */
245245
onOpenRasterStylePanel: () => void;
246+
/**
247+
* Select the target layer and expand the built-in Style panel. Left undefined
248+
* when that panel is hidden (Settings → "Show Style panel"), which also hides
249+
* the menu item — the panel is not mounted then, so the request would be
250+
* dropped rather than queued.
251+
*/
252+
onOpenStylePanel?: () => void;
246253
/**
247254
* Open the floating Extract Subset panel for a COG/WMS/XYZ layer, letting the
248255
* user draw a bounding box and export a clipped GeoTIFF.
@@ -608,6 +615,7 @@ export function LayerPanel({
608615
onCancelGeometryEdit,
609616
onMaterializeDuckDBLayer,
610617
onOpenRasterStylePanel,
618+
onOpenStylePanel,
611619
onOpenRasterSubset,
612620
autoCollapse = false,
613621
collapsed: controlledCollapsed,
@@ -3364,6 +3372,17 @@ export function LayerPanel({
33643372
action item below has no such focus target, so each
33653373
lets Radix dismiss the menu on select rather than
33663374
leaving it pinned open. */}
3375+
{onOpenStylePanel && (
3376+
<DropdownMenuItem
3377+
onSelect={() => {
3378+
selectLayer(layer.id);
3379+
onOpenStylePanel();
3380+
}}
3381+
>
3382+
<Palette className="me-2 h-3.5 w-3.5" />
3383+
{t("layers.openStylePanel")}
3384+
</DropdownMenuItem>
3385+
)}
33673386
<DropdownMenuItem
33683387
onSelect={() => {
33693388
addLayerGroup(undefined, moveIds);

apps/geolibre-desktop/src/components/panels/StylePanel.tsx

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ function labelOverrideInvalid(
173173
interface StylePanelProps {
174174
mapControllerRef: RefObject<MapController | null>;
175175
onResizeStart: (event: ReactPointerEvent<HTMLDivElement>) => void;
176+
/** Incremented when another part of the UI explicitly requests this panel. */
177+
openRequest?: number;
176178
/**
177179
* When this flips to `true` the panel collapses to its thin rail (it is not
178180
* unmounted). Used to clear room when the notebook opens beside the map; the
@@ -984,6 +986,7 @@ function RasterStyleSlider({
984986
export function StylePanel({
985987
mapControllerRef,
986988
onResizeStart,
989+
openRequest = 0,
987990
autoCollapse = false,
988991
collapsed: controlledCollapsed,
989992
onCollapsedChange,
@@ -998,8 +1001,8 @@ export function StylePanel({
9981001
const updateLayer = useAppStore((s) => s.updateLayer);
9991002
const moveLayer = useAppStore((s) => s.moveLayer);
10001003
const projectName = useAppStore((s) => s.projectName);
1001-
// Style starts on its rail on every platform. Selecting a real layer below
1002-
// expands it; selecting the special Background row does not.
1004+
// Style starts on its rail on every platform and remains there until the
1005+
// user explicitly expands it.
10031006
const [internalCollapsed, setInternalCollapsed] = useState(true);
10041007
// In the shared right-sidebar mode the parent owns collapse (controlled);
10051008
// otherwise the panel manages it locally. `setIsCollapsed` routes to whichever
@@ -1013,23 +1016,19 @@ export function StylePanel({
10131016
},
10141017
[isControlled, onCollapsedChange],
10151018
);
1016-
// Selecting a real layer expands the panel from its rail. Skipped while
1017-
// `autoCollapse` holds it closed (the notebook or a story-map presentation
1018-
// owns the workspace), so a selection made there cannot pop Style back open
1019-
// over them and defeat the auto-collapse below.
1020-
const previousSelectedLayerId = useRef(selectedLayerId);
1019+
// An explicit request (Layers → "Open Style panel") expands the panel from its
1020+
// rail. Skipped while `autoCollapse` holds it closed (the notebook or a
1021+
// story-map presentation owns the workspace), so a request made there cannot
1022+
// pop Style back open over them: the `autoCollapse` effect below acts only on
1023+
// transitions, so an expand that slipped through would stick until the
1024+
// notebook was closed and reopened. The request is still consumed so it does
1025+
// not fire later.
1026+
const previousOpenRequest = useRef(openRequest);
10211027
useEffect(() => {
1022-
const previous = previousSelectedLayerId.current;
1023-
previousSelectedLayerId.current = selectedLayerId;
1024-
if (
1025-
!autoCollapse &&
1026-
selectedLayerId &&
1027-
selectedLayerId !== previous &&
1028-
layers.some((candidate) => candidate.id === selectedLayerId)
1029-
) {
1030-
setIsCollapsed(false);
1031-
}
1032-
}, [autoCollapse, layers, selectedLayerId, setIsCollapsed]);
1028+
if (openRequest === previousOpenRequest.current) return;
1029+
previousOpenRequest.current = openRequest;
1030+
if (!autoCollapse) setIsCollapsed(false);
1031+
}, [autoCollapse, openRequest, setIsCollapsed]);
10331032
// Collapse to the rail when `autoCollapse` flips on (e.g. the notebook opens),
10341033
// and restore the prior expand/collapse state when it flips back off (notebook
10351034
// closes). Both act only on the transition so the user can still toggle the

apps/geolibre-desktop/src/i18n/locales/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4892,6 +4892,7 @@
48924892
"bindWindowCumulative": "Everything up to the current step (cumulative)",
48934893
"bindCancel": "Cancel",
48944894
"bindConfirm": "Bind",
4895+
"openStylePanel": "Open Style panel",
48954896
"openRasterStylePanel": "Edit raster style…",
48964897
"exportRasterSuccess": "Raster exported.",
48974898
"exportRasterError": "Could not export this raster.",

docs/tutorials/first-map.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ See [Adding Data](../user-guide/adding-data.md) for every supported source.
2121

2222
## 3. Style the layer
2323

24-
1. Select the `countries` layer in the Layers panel. The [Style panel](../user-guide/styling.md) opens on the right.
24+
1. Select the `countries` layer in the Layers panel, then expand the [Style panel](../user-guide/styling.md) on the right if it is collapsed.
2525
2. Adjust the **Fill color**, **Outline color**, and **Fill opacity** to taste.
2626
3. To make a choropleth, set **Style type** to **Graduated**, pick a numeric field (for example a population or GDP column), choose a **Colormap**, and click **Apply style type**.
2727

0 commit comments

Comments
 (0)