Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot] e096288ef5 chore(deps): Bump github/codeql-action/analyze from 4.37.8 to 4.37.9
Bumps [github/codeql-action/analyze](https://github.com/github/codeql-action) from 4.37.8 to 4.37.9.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28...cdf488f595d80d6e07e03d4674febd5ab45fa938)

---
updated-dependencies:
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-31 13:48:13 +00:00
18 changed files with 52 additions and 253 deletions
+1 -1
View File
@@ -67,4 +67,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
-1
View File
@@ -5,7 +5,6 @@
- Upgrade to MapLibre GL JS 6 and Vite 8, and update the remaining dependencies
- Serve the RTL text plugin from `@mapbox/mapbox-gl-rtl-text` instead of a pinned CDN URL, so its version is tracked in `package.json`
- Exported HTML now loads MapLibre GL JS as an ES module, since v6 no longer ships a UMD bundle
- The sidebar can now be resized, both as a whole and in the split between the layer list and the layer editor
- _...Add new stuff here..._
### 🐞 Bug fixes
-18
View File
@@ -122,8 +122,6 @@ export class Assertable<T> {
// Value assertions (auto-retrying for Query targets).
shouldEqual = (value: any) => this.assertValue((actual) => expect(actual).toBe(value));
shouldBeGreaterThan = (value: number) => this.assertValue((actual) => expect(actual).toBeGreaterThan(value));
shouldInclude = (value: any) =>
this.assertValue((actual) => {
if (typeof value === "object" && value !== null) {
@@ -351,15 +349,6 @@ export class PlaywrightHelper {
await this.page.mouse.up();
},
/** Presses at the centre of an element and drags it by the given offset. */
dragBy: async (testId: string, deltaX: number, deltaY = 0) => {
const { x, y } = await centerOf(this.testId(testId));
await this.page.mouse.move(x, y);
await this.page.mouse.down();
await this.page.mouse.move(x + deltaX, y + deltaY, { steps: 10 });
await this.page.mouse.up();
},
clickCenter: async (testId: string) => {
const { x, y } = await centerOf(this.testId(testId));
await this.page.mouse.move(x, y);
@@ -457,13 +446,6 @@ export class PlaywrightHelper {
inputValue: (testId: string) => new Query<string>(() => this.testId(testId).first().inputValue()),
elementWidth: (testId: string) =>
new Query<number>(async () => {
const box = await this.testId(testId).first().boundingBox();
if (!box) throw new Error(`Element "${testId}" has no bounding box`);
return box.width;
}),
elementsText: (testId: string) => new Query<string>(() => this.testId(testId).first().innerText()),
locationHash: () => new Query<string>(async () => new URL(this.page.url()).hash),
-27
View File
@@ -1,27 +0,0 @@
import { beforeEach, describe, test } from "./utils/fixtures";
import { MaputnikDriver } from "./maputnik-driver";
describe("sidebar resize", () => {
const { given, get, when, then } = new MaputnikDriver();
beforeEach(async () => {
await given.setupMockBackedResponses();
await when.setStyle("layer");
});
test("dragging the outer handle widens the sidebar", async () => {
const initialWidth = await get.elementWidth("sidebar-panel").get();
await when.dragBy("sidebar-resize-handle", 100);
await then(get.elementWidth("sidebar-panel")).shouldBeGreaterThan(initialWidth + 50);
});
test("dragging the inner handle widens the layer list", async () => {
const initialWidth = await get.elementWidth("layer-list-panel").get();
await when.dragBy("inner-resize-handle", 50);
await then(get.elementWidth("layer-list-panel")).shouldBeGreaterThan(initialWidth + 20);
});
});
-11
View File
@@ -58,7 +58,6 @@
"react-i18next": "^17.0.12",
"react-icons": "^5.7.0",
"react-markdown": "^10.1.0",
"react-resizable-panels": "^4.11.0",
"reconnecting-websocket": "^4.4.0",
"slugify": "^1.6.9",
"string-hash": "^1.1.3",
@@ -10849,16 +10848,6 @@
"react": ">=18"
}
},
"node_modules/react-resizable-panels": {
"version": "4.11.0",
"resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-4.11.0.tgz",
"integrity": "sha512-LPk/AkFDGkg7SsbOyL93ojrE6E7lhrxxDwnYNjfmnSeI6BE7Sje6dB24PXgZk8DeugdeXNk1LO+ohRqIjhxiLw==",
"license": "MIT",
"peerDependencies": {
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
}
},
"node_modules/reactcss": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
-1
View File
@@ -76,7 +76,6 @@
"react-i18next": "^17.0.12",
"react-icons": "^5.7.0",
"react-markdown": "^10.1.0",
"react-resizable-panels": "^4.11.0",
"reconnecting-websocket": "^4.4.0",
"slugify": "^1.6.9",
"string-hash": "^1.1.3",
+38 -117
View File
@@ -1,23 +1,9 @@
import React, { useEffect, useState } from "react";
import { Group, Panel, Separator, useDefaultLayout } from "react-resizable-panels";
import React from "react";
import { ScrollContainer } from "./ScrollContainer";
import { useTranslation } from "react-i18next";
import { type WithTranslation, withTranslation } from "react-i18next";
import { IconContext } from "react-icons";
// Keep these in sync with $layout-list-width/$layout-editor-width in _vars.scss
const DEFAULT_LIST_WIDTH = 200;
const DEFAULT_DRAWER_WIDTH = 370;
const DEFAULT_SIDEBAR_WIDTH = DEFAULT_LIST_WIDTH + DEFAULT_DRAWER_WIDTH;
const PANEL_STYLE: React.CSSProperties = { overflow: "hidden" };
const SIDEBAR_LAYOUT_ID = "maputnik:sidebar-layout";
const SIDEBAR_INNER_LAYOUT_ID = "maputnik:sidebar-inner-layout";
const SIDEBAR_PANEL_ID = "sidebar";
const MAP_PANEL_ID = "map";
const LIST_PANEL_ID = "list";
const DRAWER_PANEL_ID = "drawer";
type AppLayoutProps = {
type AppLayoutInternalProps = {
toolbar: React.ReactElement
layerList: React.ReactElement
layerEditor?: React.ReactElement
@@ -25,108 +11,43 @@ type AppLayoutProps = {
map: React.ReactElement
bottom?: React.ReactElement
modals?: React.ReactNode
};
} & WithTranslation;
export const AppLayout: React.FC<AppLayoutProps> = (props) => {
const { t, i18n } = useTranslation();
class AppLayoutInternal extends React.Component<AppLayoutInternalProps> {
const sidebarLayout = useDefaultLayout({
id: SIDEBAR_LAYOUT_ID,
panelIds: [SIDEBAR_PANEL_ID, MAP_PANEL_ID],
});
const innerLayout = useDefaultLayout({
id: SIDEBAR_INNER_LAYOUT_ID,
panelIds: [LIST_PANEL_ID, DRAWER_PANEL_ID],
});
render() {
document.body.dir = this.props.i18n.dir();
// The bottom panel is position: fixed, so it can't be a flex sibling of the
// map panel; it follows the sidebar through this custom property instead.
const [sidebarWidth, setSidebarWidth] = useState(DEFAULT_SIDEBAR_WIDTH);
useEffect(() => {
document.body.dir = i18n.dir();
}, [i18n, i18n.language]);
return <IconContext.Provider value={{size: "14px"}}>
<div
className="maputnik-layout"
style={{"--sidebar-width": `${sidebarWidth}px`} as React.CSSProperties}
>
{props.toolbar}
<div className="maputnik-layout-main">
<Group
className="maputnik-layout-panels"
orientation="horizontal"
id={SIDEBAR_LAYOUT_ID}
defaultLayout={sidebarLayout.defaultLayout}
onLayoutChanged={sidebarLayout.onLayoutChanged}
>
<Panel
id={SIDEBAR_PANEL_ID}
data-wd-key="sidebar-panel"
className={props.codeEditor ? "maputnik-layout-code-editor" : "maputnik-layout-sidebar"}
style={PANEL_STYLE}
defaultSize={`${DEFAULT_SIDEBAR_WIDTH}px`}
minSize="280px"
onResize={({inPixels}) => setSidebarWidth(inPixels)}
>
{props.codeEditor && <ScrollContainer>
{props.codeEditor}
return <IconContext.Provider value={{size: "14px"}}>
<div className="maputnik-layout">
{this.props.toolbar}
<div className="maputnik-layout-main">
{this.props.codeEditor && <div className="maputnik-layout-code-editor">
<ScrollContainer>
{this.props.codeEditor}
</ScrollContainer>
}
{!props.codeEditor && <Group
className="maputnik-layout-sidebar-panels"
orientation="horizontal"
id={SIDEBAR_INNER_LAYOUT_ID}
defaultLayout={innerLayout.defaultLayout}
onLayoutChanged={innerLayout.onLayoutChanged}
>
<Panel
id={LIST_PANEL_ID}
data-wd-key="layer-list-panel"
className="maputnik-layout-list"
style={PANEL_STYLE}
defaultSize={`${DEFAULT_LIST_WIDTH}px`}
minSize="100px"
>
{props.layerList}
</Panel>
<Separator
className="maputnik-layout-resize-handle"
data-wd-key="inner-resize-handle"
title={t("Drag to resize the layer list")}
aria-label={t("Drag to resize the layer list")}
/>
<Panel
id={DRAWER_PANEL_ID}
className="maputnik-layout-drawer"
style={PANEL_STYLE}
defaultSize={`${DEFAULT_DRAWER_WIDTH}px`}
minSize="150px"
>
<ScrollContainer>
{props.layerEditor}
</ScrollContainer>
</Panel>
</Group>
}
</Panel>
<Separator
className="maputnik-layout-resize-handle"
data-wd-key="sidebar-resize-handle"
title={t("Drag to resize the sidebar")}
aria-label={t("Drag to resize the sidebar")}
/>
<Panel id={MAP_PANEL_ID} className="maputnik-layout-map" style={PANEL_STYLE} minSize="200px">
{props.map}
</Panel>
</Group>
</div>
}
{!this.props.codeEditor && <>
<div className="maputnik-layout-list">
{this.props.layerList}
</div>
<div className="maputnik-layout-drawer">
<ScrollContainer>
{this.props.layerEditor}
</ScrollContainer>
</div>
</>}
{this.props.map}
</div>
{this.props.bottom && <div className="maputnik-layout-bottom">
{this.props.bottom}
</div>
}
{this.props.modals}
</div>
{props.bottom && <div className="maputnik-layout-bottom">
{props.bottom}
</div>
}
{props.modals}
</div>
</IconContext.Provider>;
};
</IconContext.Provider>;
}
}
export const AppLayout = withTranslation()(AppLayoutInternal);
-2
View File
@@ -54,8 +54,6 @@
"Delete expression": "Ausdruck löschen",
"Delete filter block": "Filterblock löschen",
"Deuteranopia filter": "Deuteranopie-Filter",
"Drag to resize the layer list": "Ziehen, um die Ebenenliste zu skalieren",
"Drag to resize the sidebar": "Ziehen, um die Seitenleiste zu skalieren",
"Duplicate": "Duplizieren",
"Encoding": "Kodierung",
"Enter URL...": "URL eingeben...",
-2
View File
@@ -54,8 +54,6 @@
"Delete expression": "Supprimer l'expression",
"Delete filter block": "Supprimer le bloc de filtre",
"Deuteranopia filter": "Filtre Deutéranopie",
"Drag to resize the layer list": "Glisser pour redimensionner la liste des calques",
"Drag to resize the sidebar": "Glisser pour redimensionner la barre latérale",
"Duplicate": "Dupliquer",
"Encoding": "Encodage",
"Enter URL...": "Entrez l'URL...",
-2
View File
@@ -54,8 +54,6 @@
"Delete expression": "מחיקת ביטוי",
"Delete filter block": "מחיקת גוש מסנן",
"Deuteranopia filter": "Deuteranopia filter",
"Drag to resize the layer list": "יש לגרור כדי לשנות את גודל רשימת השכבות",
"Drag to resize the sidebar": "יש לגרור כדי לשנות את גודל סרגל הצד",
"Duplicate": "שכפול",
"Encoding": "קידוד",
"Enter URL...": "הכנסו כתובת",
-2
View File
@@ -54,8 +54,6 @@
"Delete expression": "Elimina espressione",
"Delete filter block": "Elimina blocco filtro",
"Deuteranopia filter": "Filtro deuteranopia",
"Drag to resize the layer list": "Trascina per ridimensionare l'elenco dei livelli",
"Drag to resize the sidebar": "Trascina per ridimensionare la barra laterale",
"Duplicate": "Duplica",
"Encoding": "Codifica",
"Enter URL...": "Inserisci URL...",
-2
View File
@@ -54,8 +54,6 @@
"Delete expression": "式を削除",
"Delete filter block": "フィルタブロックを削除",
"Deuteranopia filter": "緑色盲フィルタ",
"Drag to resize the layer list": "ドラッグしてレイヤーリストのサイズを変更",
"Drag to resize the sidebar": "ドラッグしてサイドバーのサイズを変更",
"Duplicate": "複製",
"Encoding": "エンコーディング",
"Enter URL...": "URLを入力",
-2
View File
@@ -54,8 +54,6 @@
"Delete expression": "표현식 삭제",
"Delete filter block": "필터 블록 삭제",
"Deuteranopia filter": "녹색맹 필터",
"Drag to resize the layer list": "드래그하여 레이어 목록 크기 조정",
"Drag to resize the sidebar": "드래그하여 사이드바 크기 조정",
"Duplicate": "복제",
"Encoding": "인코딩",
"Enter URL...": "URL 입력...",
-2
View File
@@ -55,8 +55,6 @@
"Delete filter block": "Filtre bloğunu sil",
"Deuteranopia filter": "Döteranopi filtresi",
"Drag and drop a style JSON file here or click to browse": "Bir stil JSON dosyasını buraya sürükleyip bırakın veya göz atmak için tıklayın",
"Drag to resize the layer list": "Katman listesini yeniden boyutlandırmak için sürükleyin",
"Drag to resize the sidebar": "Kenar çubuğunu yeniden boyutlandırmak için sürükleyin",
"Duplicate": "Kopyala",
"Encoding": "Kodlama",
"Enter URL...": "URL girin...",
-2
View File
@@ -54,8 +54,6 @@
"Delete expression": "删除表达式",
"Delete filter block": "删除过滤器块",
"Deuteranopia filter": "绿色盲滤镜",
"Drag to resize the layer list": "拖动以调整图层列表大小",
"Drag to resize the sidebar": "拖动以调整侧边栏大小",
"Duplicate": "复制",
"Encoding": "编码",
"Enter URL...": "输入URL...",
+1 -2
View File
@@ -6,8 +6,7 @@
.maputnik-map__container {
background: white;
display: flex;
width: 100%;
height: 100%;
width: vars.$layout-map-width;
&--error {
align-items: center;
+11 -59
View File
@@ -13,9 +13,6 @@
//APP LAYOUT
.maputnik-layout {
// Kept up to date by AppLayout as the sidebar is resized.
--sidebar-width: #{vars.$layout-list-width + vars.$layout-editor-width};
font-family: vars.$font-family;
color: vars.$color-white;
@@ -31,76 +28,31 @@
display: flex;
}
// The resizable panel group filling the main area.
&-panels {
flex: 1;
min-width: 0;
height: 100%;
&-list {
width: 200px;
background-color: vars.$color-black;
}
&-sidebar-panels,
&-sidebar,
&-code-editor,
&-list,
&-drawer,
&-map {
height: 100%;
&-drawer {
width: 370px;
background-color: vars.$color-black;
// scroll-container is position: absolute
position: relative;
}
&-sidebar,
&-code-editor,
&-list,
&-drawer {
&-code-editor {
width: 570px;
background-color: vars.$color-black;
}
&-resize-handle {
width: 5px;
background-color: transparent;
// scroll-container is position: absolute
position: relative;
z-index: 5;
transition: background-color 0.15s ease;
&:hover,
&:active,
&:focus-visible {
background-color: rgba(vars.$color-lowgray, 0.5);
}
// The separator is keyboard resizable, so it needs a visible focus ring.
&:focus-visible {
outline: #8e8e8e auto 1px;
}
&::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 3px;
height: 30px;
border-radius: 2px;
background-color: vars.$color-lowgray;
opacity: 0;
transition: opacity 0.15s ease;
}
&:hover::after,
&:active::after,
&:focus-visible::after {
opacity: 0.7;
}
}
&-bottom {
position: fixed;
bottom: 0;
right: 0;
z-index: 10;
inset-inline-start: var(--sidebar-width);
inset-inline-end: 0;
width: vars.$layout-map-width;
background-color: vars.$color-black;
}
}
+1
View File
@@ -23,6 +23,7 @@ $toolbar-offset: 0;
$layout-list-width: 200px;
$layout-editor-width: 370px;
$layout-map-width: calc(100% - #{$layout-list-width + $layout-editor-width});
// 'menu-down' from 'https://materialdesignicons.com/'
// See <https://github.com/Templarian/MaterialDesign/blob/master/LICENSE>