Compare commits

..

3 Commits

Author SHA1 Message Date
HarelM 2b7a092ad3 Remove comment 2026-08-21 13:58:48 +03:00
HarelM 705233241f Fix double sidebars 2026-08-21 13:47:44 +03:00
HarelM 3c1c3b6a74 Adopted changes to have a sidebar that's dragable 2026-08-21 13:02:35 +03:00
21 changed files with 324 additions and 144 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 uses: github/codeql-action/autobuild@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
# ️ Command-line programs to run using the OS shell. # ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl # 📚 https://git.io/JvXDl
+1 -1
View File
@@ -5,11 +5,11 @@
- Upgrade to MapLibre GL JS 6 and Vite 8, and update the remaining dependencies - 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` - 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 - 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..._ - _...Add new stuff here..._
### 🐞 Bug fixes ### 🐞 Bug fixes
- The map's data listener now fires on tile loads again, so source and vector layer field autocompletion is populated - The map's data listener now fires on tile loads again, so source and vector layer field autocompletion is populated
- The `maputnik` desktop binary now opens the default browser automatically on startup (opt out with `--no-browser`)
- _...Add new stuff here..._ - _...Add new stuff here..._
## 3.1.0 ## 3.1.0
+8 -3
View File
@@ -7,16 +7,21 @@ require (
github.com/fsnotify/fsnotify v1.6.0 github.com/fsnotify/fsnotify v1.6.0
github.com/gorilla/handlers v1.5.1 github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.5.3 github.com/gorilla/websocket v1.5.0
github.com/maputnik/desktop v1.0.7 github.com/maputnik/desktop v1.0.7
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/urfave/cli v1.22.12 github.com/urfave/cli v1.22.12
) )
require ( require (
github.com/GeertJohan/go.incremental v1.0.0 // indirect
github.com/akavel/rsrc v0.8.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/daaku/go.zipexe v1.0.2 // indirect github.com/daaku/go.zipexe v1.0.2 // indirect
github.com/felixge/httpsnoop v1.0.1 // indirect github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/jessevdk/go-flags v1.4.0 // indirect
github.com/nkovacs/streamquote v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
golang.org/x/sys v0.1.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.0.1 // indirect
golang.org/x/sys v0.0.0-20220908164124-27713097b956 // indirect
) )
+9 -6
View File
@@ -1,7 +1,9 @@
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg=
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
github.com/GeertJohan/go.rice v1.0.3 h1:k5viR+xGtIhF61125vCE1cmJ5957RQGXG6dmbaWZSmI= github.com/GeertJohan/go.rice v1.0.3 h1:k5viR+xGtIhF61125vCE1cmJ5957RQGXG6dmbaWZSmI=
github.com/GeertJohan/go.rice v1.0.3/go.mod h1:XVdrU4pW00M4ikZed5q56tPf1v2KwnIKeIdc9CBYNt4= github.com/GeertJohan/go.rice v1.0.3/go.mod h1:XVdrU4pW00M4ikZed5q56tPf1v2KwnIKeIdc9CBYNt4=
github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
@@ -18,14 +20,14 @@ github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/maputnik/desktop v1.0.7 h1:rdFg7emIJOT3YsZpwqSChmWtMOvu+T4h6WwVQAZP9n4= github.com/maputnik/desktop v1.0.7 h1:rdFg7emIJOT3YsZpwqSChmWtMOvu+T4h6WwVQAZP9n4=
github.com/maputnik/desktop v1.0.7/go.mod h1:wmDjHUztx9jOBz0I22589yWguAGdV/sEM57YANpN8oQ= github.com/maputnik/desktop v1.0.7/go.mod h1:wmDjHUztx9jOBz0I22589yWguAGdV/sEM57YANpN8oQ=
github.com/nkovacs/streamquote v1.0.0 h1:PmVIV08Zlx2lZK5fFZlMZ04eHcDTIFJCv/5/0twVUow=
github.com/nkovacs/streamquote v1.0.0/go.mod h1:BN+NaZ2CmdKqUuTUXUEm9j95B2TRbpOWpxbJYzzgUsc= github.com/nkovacs/streamquote v1.0.0/go.mod h1:BN+NaZ2CmdKqUuTUXUEm9j95B2TRbpOWpxbJYzzgUsc=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
@@ -39,11 +41,12 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8= github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8=
github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
golang.org/x/sys v0.0.0-20220908164124-27713097b956 h1:XeJjHH1KiLpKGb6lvMiksZ9l0fVUh+AmGcm0nOMEBOY=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+2 -26
View File
@@ -2,7 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"net"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
@@ -10,7 +9,6 @@ import (
"github.com/gorilla/handlers" "github.com/gorilla/handlers"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/maputnik/desktop/filewatch" "github.com/maputnik/desktop/filewatch"
"github.com/pkg/browser"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@@ -38,10 +36,6 @@ func main() {
Name: "static", Name: "static",
Usage: "Serve directory under /static/", Usage: "Serve directory under /static/",
}, },
&cli.BoolFlag{
Name: "no-browser",
Usage: "Do not automatically open the default browser",
},
} }
app.Action = func(c *cli.Context) error { app.Action = func(c *cli.Context) error {
@@ -77,26 +71,8 @@ func main() {
loggedRouter := handlers.LoggingHandler(os.Stdout, router) loggedRouter := handlers.LoggingHandler(os.Stdout, router)
corsRouter := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}), handlers.AllowedMethods([]string{"GET", "PUT"}), handlers.AllowedOrigins([]string{"*"}), handlers.AllowCredentials())(loggedRouter) corsRouter := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}), handlers.AllowedMethods([]string{"GET", "PUT"}), handlers.AllowedOrigins([]string{"*"}), handlers.AllowCredentials())(loggedRouter)
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", c.Int("port"))) fmt.Printf("Exposing Maputnik on http://localhost:%d\n", c.Int("port"))
if err != nil { return http.ListenAndServe(fmt.Sprintf(":%d", c.Int("port")), corsRouter)
return err
}
url := fmt.Sprintf("http://localhost:%d", c.Int("port"))
fmt.Printf("Exposing Maputnik on %s\n", url)
// Listener is already accepting connections, so this can't race http.Serve below.
// xdg-open is known to hang on some headless Linux setups, so this runs in its own
// goroutine to keep a stuck opener from stalling server startup.
if !c.Bool("no-browser") {
go func() {
if err := browser.OpenURL(url); err != nil {
fmt.Printf("Could not open browser automatically: %s\nPlease open %s manually.\n", err, url)
}
}()
}
return http.Serve(listener, corsRouter)
} }
app.Run(os.Args) app.Run(os.Args)
+18
View File
@@ -122,6 +122,8 @@ export class Assertable<T> {
// Value assertions (auto-retrying for Query targets). // Value assertions (auto-retrying for Query targets).
shouldEqual = (value: any) => this.assertValue((actual) => expect(actual).toBe(value)); shouldEqual = (value: any) => this.assertValue((actual) => expect(actual).toBe(value));
shouldBeGreaterThan = (value: number) => this.assertValue((actual) => expect(actual).toBeGreaterThan(value));
shouldInclude = (value: any) => shouldInclude = (value: any) =>
this.assertValue((actual) => { this.assertValue((actual) => {
if (typeof value === "object" && value !== null) { if (typeof value === "object" && value !== null) {
@@ -349,6 +351,15 @@ export class PlaywrightHelper {
await this.page.mouse.up(); 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) => { clickCenter: async (testId: string) => {
const { x, y } = await centerOf(this.testId(testId)); const { x, y } = await centerOf(this.testId(testId));
await this.page.mouse.move(x, y); await this.page.mouse.move(x, y);
@@ -446,6 +457,13 @@ export class PlaywrightHelper {
inputValue: (testId: string) => new Query<string>(() => this.testId(testId).first().inputValue()), 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()), elementsText: (testId: string) => new Query<string>(() => this.testId(testId).first().innerText()),
locationHash: () => new Query<string>(async () => new URL(this.page.url()).hash), locationHash: () => new Query<string>(async () => new URL(this.page.url()).hash),
+27
View File
@@ -0,0 +1,27 @@
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);
});
});
+54 -47
View File
@@ -20,7 +20,7 @@
"@mapbox/mapbox-gl-rtl-text": "^0.4.0", "@mapbox/mapbox-gl-rtl-text": "^0.4.0",
"@maplibre/maplibre-gl-geocoder": "^1.9.4", "@maplibre/maplibre-gl-geocoder": "^1.9.4",
"@maplibre/maplibre-gl-inspect": "^1.9.0", "@maplibre/maplibre-gl-inspect": "^1.9.0",
"@maplibre/maplibre-gl-style-spec": "^26.4.1", "@maplibre/maplibre-gl-style-spec": "^26.2.1",
"array-move": "^4.0.0", "array-move": "^4.0.0",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"classnames": "^2.5.1", "classnames": "^2.5.1",
@@ -30,7 +30,7 @@
"downshift": "^9.4.0", "downshift": "^9.4.0",
"events": "^3.3.0", "events": "^3.3.0",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"i18next": "^26.4.0", "i18next": "^26.3.6",
"i18next-browser-languagedetector": "^8.2.1", "i18next-browser-languagedetector": "^8.2.1",
"i18next-resources-to-backend": "^1.2.3", "i18next-resources-to-backend": "^1.2.3",
"json-stringify-pretty-compact": "^4.0.0", "json-stringify-pretty-compact": "^4.0.0",
@@ -42,7 +42,7 @@
"lodash.get": "^4.4.2", "lodash.get": "^4.4.2",
"lodash.isequal": "^4.5.0", "lodash.isequal": "^4.5.0",
"lodash.throttle": "^4.1.1", "lodash.throttle": "^4.1.1",
"maplibre-gl": "^6.5.0", "maplibre-gl": "^6.4.1",
"maputnik-design": "github:maputnik/design#172b06c", "maputnik-design": "github:maputnik/design#172b06c",
"ol": "^10.10.0", "ol": "^10.10.0",
"ol-mapbox-style": "^13.4.2", "ol-mapbox-style": "^13.4.2",
@@ -55,9 +55,10 @@
"react-collapse": "^5.1.1", "react-collapse": "^5.1.1",
"react-color": "^2.19.3", "react-color": "^2.19.3",
"react-dom": "^19.2.8", "react-dom": "^19.2.8",
"react-i18next": "^17.0.12", "react-i18next": "^17.0.11",
"react-icons": "^5.7.0", "react-icons": "^5.7.0",
"react-markdown": "^10.1.0", "react-markdown": "^10.1.0",
"react-resizable-panels": "^4.11.0",
"reconnecting-websocket": "^4.4.0", "reconnecting-websocket": "^4.4.0",
"slugify": "^1.6.9", "slugify": "^1.6.9",
"string-hash": "^1.1.3", "string-hash": "^1.1.3",
@@ -89,10 +90,10 @@
"@types/react-dom": "^19.2.4", "@types/react-dom": "^19.2.4",
"@types/string-hash": "^1.1.3", "@types/string-hash": "^1.1.3",
"@types/wicg-file-system-access": "^2023.10.7", "@types/wicg-file-system-access": "^2023.10.7",
"@vitejs/plugin-react": "^6.1.0", "@vitejs/plugin-react": "^6.0.5",
"@vitest/coverage-v8": "^4.1.11", "@vitest/coverage-v8": "^4.1.11",
"cors": "^2.8.6", "cors": "^2.8.6",
"eslint": "^10.9.0", "eslint": "^10.8.1",
"eslint-plugin-react": "^7.37.5", "eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.4", "eslint-plugin-react-refresh": "^0.5.4",
@@ -102,14 +103,14 @@
"nyc": "^18.0.0", "nyc": "^18.0.0",
"postcss": "^8.5.26", "postcss": "^8.5.26",
"react-hot-loader": "^4.13.1", "react-hot-loader": "^4.13.1",
"sass": "^1.103.1", "sass": "^1.102.0",
"stylelint": "^17.14.1", "stylelint": "^17.14.1",
"stylelint-config-recommended-scss": "^17.0.1", "stylelint-config-recommended-scss": "^17.0.1",
"stylelint-scss": "^7.2.0", "stylelint-scss": "^7.2.0",
"typescript": "^6.0.3", "typescript": "^6.0.3",
"typescript-eslint": "^8.67.0", "typescript-eslint": "^8.67.0",
"uuid": "^14.0.2", "uuid": "^14.0.2",
"vite": "^8.2.2", "vite": "^8.2.1",
"vite-plugin-istanbul": "^9.0.1", "vite-plugin-istanbul": "^9.0.1",
"vitest": "^4.1.11" "vitest": "^4.1.11"
} }
@@ -327,9 +328,9 @@
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.29.7", "version": "7.29.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz",
"integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -1706,9 +1707,9 @@
} }
}, },
"node_modules/@maplibre/maplibre-gl-style-spec": { "node_modules/@maplibre/maplibre-gl-style-spec": {
"version": "26.4.1", "version": "26.2.1",
"resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-26.4.1.tgz", "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-26.2.1.tgz",
"integrity": "sha512-I/qcIKVFHFSg1Meu/eqHrkSTjIez0gCsSaK56TNPutM3TkE61aSq6F1cZ4Kg4KiNs3cpViLtubDjfyRcQCdEJQ==", "integrity": "sha512-QFKCXkOeSzOr8jF75jm6kySOg+dUvOehPhRi68gcOYPHb7U5JloUq0dJW0Y5/fZV8ygfT0Vp2RWodvq+fyxFWA==",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@mapbox/jsonlint-lines-primitives": "^2.0.3", "@mapbox/jsonlint-lines-primitives": "^2.0.3",
@@ -1725,9 +1726,9 @@
} }
}, },
"node_modules/@maplibre/mlt": { "node_modules/@maplibre/mlt": {
"version": "1.2.0", "version": "1.1.12",
"resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.1.12.tgz",
"integrity": "sha512-g45M8gEI4sMO3X9ib4K7n3ZKFf0qQOL+NMkHCnEK51lOrYFHiEssOuZncx1+miIgi1IEE2NcbRMcq8RBkL+QHA==", "integrity": "sha512-ZeK5w2TTeHOajcLaEQs1KZXw2V9wIKo1PmThlxlsHoXsQsYlBqLJzPOd6tJHRtGTChUY3DPPmjXRArYVvAbmZw==",
"license": "(MIT OR Apache-2.0)", "license": "(MIT OR Apache-2.0)",
"dependencies": { "dependencies": {
"@mapbox/point-geometry": "^1.1.0" "@mapbox/point-geometry": "^1.1.0"
@@ -3379,9 +3380,9 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/@vitejs/plugin-react": { "node_modules/@vitejs/plugin-react": {
"version": "6.1.0", "version": "6.0.5",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.1.0.tgz", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.5.tgz",
"integrity": "sha512-qd2BzUBehkov86WFhg0JkEFEYyCLG9uPCe6qWTY/kRlss9OvJrOF2UbIWT7p+8IzZHkEu0DNGHc4HSv+JdDLsw==", "integrity": "sha512-BOVzne/NL162sMdResB25mUv+vWMF5NoAjNf09TeGlE7ZpszZWSD3winycicLJw72yeVsoCn/2kOhEuCvEShMA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -3393,7 +3394,6 @@
"peerDependencies": { "peerDependencies": {
"@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0",
"babel-plugin-react-compiler": "^1.0.0", "babel-plugin-react-compiler": "^1.0.0",
"oxc-transform-react": "^0.145.0",
"vite": "^8.0.0" "vite": "^8.0.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
@@ -3402,9 +3402,6 @@
}, },
"babel-plugin-react-compiler": { "babel-plugin-react-compiler": {
"optional": true "optional": true
},
"oxc-transform-react": {
"optional": true
} }
} }
}, },
@@ -5246,9 +5243,9 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "10.9.0", "version": "10.8.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.9.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.8.1.tgz",
"integrity": "sha512-5KeEOJZBfEVA47boFiBsf+6MmmJpffM7qEBg4pLla2e4nlKgdKlqCW0oSLOGsT8Wl5uCGJptLV1bkaiShj90Gw==", "integrity": "sha512-wqA7W2jbsC/BnV9Iv1UZpKVFkO1AdNoSmYW8NWG4HNOBbkAMvIqDZ27pI2f07dqn583NcIC44ckjAcOXDL1QbQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"workspaces": [ "workspaces": [
@@ -6702,9 +6699,9 @@
} }
}, },
"node_modules/i18next": { "node_modules/i18next": {
"version": "26.4.0", "version": "26.3.6",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-26.4.0.tgz", "resolved": "https://registry.npmjs.org/i18next/-/i18next-26.3.6.tgz",
"integrity": "sha512-rsmK5bFqsD1AetSFSIa43wtNR4WpvvH4p0tLEsTxkC7QTrfdFm06nbQ95bh8Og4wwaCnUEcm9DVYL2cgxitiQg==", "integrity": "sha512-Bu5Z2nAXgfVyM8xvW3jk9EKRIuX37PudsrBViThNFx7CR7aaYTpP01cxNB/E4c4UUzTDiAZRstEhsRfPOL/8xA==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@@ -8492,9 +8489,9 @@
"license": "BSD-2-Clause" "license": "BSD-2-Clause"
}, },
"node_modules/maplibre-gl": { "node_modules/maplibre-gl": {
"version": "6.5.0", "version": "6.4.1",
"resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-6.5.0.tgz", "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-6.4.1.tgz",
"integrity": "sha512-kVStPz9Rw/ATjWV5tQ3iCR0tY+viz16Nh3E14iZNlBj0HloMAzFaDNtFYqPGkZSFRnv56txMh3ImjR0g6oClTw==", "integrity": "sha512-KzxQKtfBu/pSz1C+yW1hNS9eyj2h2lC7ufdAi6/SEt177n3oAfDfmUmslRfJdXY7ReAFBcnvwsqmiyoDhtA9GQ==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"@mapbox/point-geometry": "^1.1.0", "@mapbox/point-geometry": "^1.1.0",
@@ -8503,7 +8500,7 @@
"@mapbox/vector-tile": "^3.0.0", "@mapbox/vector-tile": "^3.0.0",
"@maplibre/geojson-vt": "^6.1.1", "@maplibre/geojson-vt": "^6.1.1",
"@maplibre/maplibre-gl-style-spec": "^26.2.1", "@maplibre/maplibre-gl-style-spec": "^26.2.1",
"@maplibre/mlt": "^1.2.0", "@maplibre/mlt": "^1.1.12",
"@maplibre/vt-pbf": "^4.3.2", "@maplibre/vt-pbf": "^4.3.2",
"@types/geojson": "^7946.0.16", "@types/geojson": "^7946.0.16",
"earcut": "^3.2.3", "earcut": "^3.2.3",
@@ -10792,12 +10789,12 @@
} }
}, },
"node_modules/react-i18next": { "node_modules/react-i18next": {
"version": "17.0.12", "version": "17.0.11",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.0.12.tgz", "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.0.11.tgz",
"integrity": "sha512-lFWPEGkxQ6RhusdUkysFBD58VHfSSzvHBzqMgN0SvfVpdQGfwtNkStTqdy08/sJd7s807qqutgx93fRpD0DJ3Q==", "integrity": "sha512-cDtkXgxjuFTWUH6V+aQn1Ve5vDiUztCNPWW5GtSHDccsgRXO1nE6QFWCEmc1KAutrb3OUv87wFShJL5RhUwPXg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.29.7", "@babel/runtime": "^7.29.2",
"html-parse-stringify": "^4.0.1", "html-parse-stringify": "^4.0.1",
"use-sync-external-store": "^1.6.0" "use-sync-external-store": "^1.6.0"
}, },
@@ -10867,6 +10864,16 @@
"react": ">=18" "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": { "node_modules/reactcss": {
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
@@ -11320,9 +11327,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/sass": { "node_modules/sass": {
"version": "1.103.1", "version": "1.102.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.103.1.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.102.0.tgz",
"integrity": "sha512-9icZURbP51S6S0QGoyaeqk9uB06GNWxsFYWfH5RgpFgqK5FA8tJcM3AdVxrZEVJ7dz+L87nG95gBKf4VuaMHGw==", "integrity": "sha512-NSOyTnaQF7rTAEOtI2fwb386vL+akyiQLBZu8Na7hXCb+umJy0GAqlcMIaqACZ6Z1VgTBS4K9PG6B3IdjHGJsw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -12885,16 +12892,16 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "8.2.2", "version": "8.2.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.1.tgz",
"integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", "integrity": "sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"lightningcss": "^1.33.0", "lightningcss": "^1.33.0",
"picomatch": "^4.0.5", "picomatch": "^4.0.5",
"postcss": "^8.5.26", "postcss": "^8.5.25",
"rolldown": "~1.2.4", "rolldown": "~1.2.1",
"tinyglobby": "^0.2.17" "tinyglobby": "^0.2.17"
}, },
"bin": { "bin": {
@@ -12911,7 +12918,7 @@
}, },
"peerDependencies": { "peerDependencies": {
"@types/node": "^20.19.0 || >=22.12.0", "@types/node": "^20.19.0 || >=22.12.0",
"@vitejs/devtools": "^0.4.0 || ^0.5.0", "@vitejs/devtools": "^0.4.0",
"esbuild": "^0.27.0 || ^0.28.0", "esbuild": "^0.27.0 || ^0.28.0",
"jiti": ">=1.21.0", "jiti": ">=1.21.0",
"less": "^4.0.0", "less": "^4.0.0",
+9 -8
View File
@@ -38,7 +38,7 @@
"@mapbox/mapbox-gl-rtl-text": "^0.4.0", "@mapbox/mapbox-gl-rtl-text": "^0.4.0",
"@maplibre/maplibre-gl-geocoder": "^1.9.4", "@maplibre/maplibre-gl-geocoder": "^1.9.4",
"@maplibre/maplibre-gl-inspect": "^1.9.0", "@maplibre/maplibre-gl-inspect": "^1.9.0",
"@maplibre/maplibre-gl-style-spec": "^26.4.1", "@maplibre/maplibre-gl-style-spec": "^26.2.1",
"array-move": "^4.0.0", "array-move": "^4.0.0",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"classnames": "^2.5.1", "classnames": "^2.5.1",
@@ -48,7 +48,7 @@
"downshift": "^9.4.0", "downshift": "^9.4.0",
"events": "^3.3.0", "events": "^3.3.0",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"i18next": "^26.4.0", "i18next": "^26.3.6",
"i18next-browser-languagedetector": "^8.2.1", "i18next-browser-languagedetector": "^8.2.1",
"i18next-resources-to-backend": "^1.2.3", "i18next-resources-to-backend": "^1.2.3",
"json-stringify-pretty-compact": "^4.0.0", "json-stringify-pretty-compact": "^4.0.0",
@@ -60,7 +60,7 @@
"lodash.get": "^4.4.2", "lodash.get": "^4.4.2",
"lodash.isequal": "^4.5.0", "lodash.isequal": "^4.5.0",
"lodash.throttle": "^4.1.1", "lodash.throttle": "^4.1.1",
"maplibre-gl": "^6.5.0", "maplibre-gl": "^6.4.1",
"maputnik-design": "github:maputnik/design#172b06c", "maputnik-design": "github:maputnik/design#172b06c",
"ol": "^10.10.0", "ol": "^10.10.0",
"ol-mapbox-style": "^13.4.2", "ol-mapbox-style": "^13.4.2",
@@ -73,9 +73,10 @@
"react-collapse": "^5.1.1", "react-collapse": "^5.1.1",
"react-color": "^2.19.3", "react-color": "^2.19.3",
"react-dom": "^19.2.8", "react-dom": "^19.2.8",
"react-i18next": "^17.0.12", "react-i18next": "^17.0.11",
"react-icons": "^5.7.0", "react-icons": "^5.7.0",
"react-markdown": "^10.1.0", "react-markdown": "^10.1.0",
"react-resizable-panels": "^4.11.0",
"reconnecting-websocket": "^4.4.0", "reconnecting-websocket": "^4.4.0",
"slugify": "^1.6.9", "slugify": "^1.6.9",
"string-hash": "^1.1.3", "string-hash": "^1.1.3",
@@ -124,10 +125,10 @@
"@types/react-dom": "^19.2.4", "@types/react-dom": "^19.2.4",
"@types/string-hash": "^1.1.3", "@types/string-hash": "^1.1.3",
"@types/wicg-file-system-access": "^2023.10.7", "@types/wicg-file-system-access": "^2023.10.7",
"@vitejs/plugin-react": "^6.1.0", "@vitejs/plugin-react": "^6.0.5",
"@vitest/coverage-v8": "^4.1.11", "@vitest/coverage-v8": "^4.1.11",
"cors": "^2.8.6", "cors": "^2.8.6",
"eslint": "^10.9.0", "eslint": "^10.8.1",
"eslint-plugin-react": "^7.37.5", "eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.4", "eslint-plugin-react-refresh": "^0.5.4",
@@ -137,14 +138,14 @@
"nyc": "^18.0.0", "nyc": "^18.0.0",
"postcss": "^8.5.26", "postcss": "^8.5.26",
"react-hot-loader": "^4.13.1", "react-hot-loader": "^4.13.1",
"sass": "^1.103.1", "sass": "^1.102.0",
"stylelint": "^17.14.1", "stylelint": "^17.14.1",
"stylelint-config-recommended-scss": "^17.0.1", "stylelint-config-recommended-scss": "^17.0.1",
"stylelint-scss": "^7.2.0", "stylelint-scss": "^7.2.0",
"typescript": "^6.0.3", "typescript": "^6.0.3",
"typescript-eslint": "^8.67.0", "typescript-eslint": "^8.67.0",
"uuid": "^14.0.2", "uuid": "^14.0.2",
"vite": "^8.2.2", "vite": "^8.2.1",
"vite-plugin-istanbul": "^9.0.1", "vite-plugin-istanbul": "^9.0.1",
"vitest": "^4.1.11" "vitest": "^4.1.11"
} }
+112 -33
View File
@@ -1,9 +1,23 @@
import React from "react"; import React, { useEffect, useState } from "react";
import { Group, Panel, Separator, useDefaultLayout } from "react-resizable-panels";
import { ScrollContainer } from "./ScrollContainer"; import { ScrollContainer } from "./ScrollContainer";
import { type WithTranslation, withTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { IconContext } from "react-icons"; import { IconContext } from "react-icons";
type AppLayoutInternalProps = { // 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 = {
toolbar: React.ReactElement toolbar: React.ReactElement
layerList: React.ReactElement layerList: React.ReactElement
layerEditor?: React.ReactElement layerEditor?: React.ReactElement
@@ -11,43 +25,108 @@ type AppLayoutInternalProps = {
map: React.ReactElement map: React.ReactElement
bottom?: React.ReactElement bottom?: React.ReactElement
modals?: React.ReactNode modals?: React.ReactNode
} & WithTranslation; };
class AppLayoutInternal extends React.Component<AppLayoutInternalProps> { export const AppLayout: React.FC<AppLayoutProps> = (props) => {
const { t, i18n } = useTranslation();
render() { const sidebarLayout = useDefaultLayout({
document.body.dir = this.props.i18n.dir(); 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],
});
// 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"}}> return <IconContext.Provider value={{size: "14px"}}>
<div className="maputnik-layout"> <div
{this.props.toolbar} className="maputnik-layout"
style={{"--sidebar-width": `${sidebarWidth}px`} as React.CSSProperties}
>
{props.toolbar}
<div className="maputnik-layout-main"> <div className="maputnik-layout-main">
{this.props.codeEditor && <div className="maputnik-layout-code-editor"> <Group
<ScrollContainer> className="maputnik-layout-panels"
{this.props.codeEditor} 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}
</ScrollContainer> </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>
{props.bottom && <div className="maputnik-layout-bottom">
{props.bottom}
</div> </div>
} }
{!this.props.codeEditor && <> {props.modals}
<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> </div>
</IconContext.Provider>; </IconContext.Provider>;
} };
}
export const AppLayout = withTranslation()(AppLayoutInternal);
+2
View File
@@ -54,6 +54,8 @@
"Delete expression": "Ausdruck löschen", "Delete expression": "Ausdruck löschen",
"Delete filter block": "Filterblock löschen", "Delete filter block": "Filterblock löschen",
"Deuteranopia filter": "Deuteranopie-Filter", "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", "Duplicate": "Duplizieren",
"Encoding": "Kodierung", "Encoding": "Kodierung",
"Enter URL...": "URL eingeben...", "Enter URL...": "URL eingeben...",
+2
View File
@@ -54,6 +54,8 @@
"Delete expression": "Supprimer l'expression", "Delete expression": "Supprimer l'expression",
"Delete filter block": "Supprimer le bloc de filtre", "Delete filter block": "Supprimer le bloc de filtre",
"Deuteranopia filter": "Filtre Deutéranopie", "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", "Duplicate": "Dupliquer",
"Encoding": "Encodage", "Encoding": "Encodage",
"Enter URL...": "Entrez l'URL...", "Enter URL...": "Entrez l'URL...",
+2
View File
@@ -54,6 +54,8 @@
"Delete expression": "מחיקת ביטוי", "Delete expression": "מחיקת ביטוי",
"Delete filter block": "מחיקת גוש מסנן", "Delete filter block": "מחיקת גוש מסנן",
"Deuteranopia filter": "Deuteranopia filter", "Deuteranopia filter": "Deuteranopia filter",
"Drag to resize the layer list": "יש לגרור כדי לשנות את גודל רשימת השכבות",
"Drag to resize the sidebar": "יש לגרור כדי לשנות את גודל סרגל הצד",
"Duplicate": "שכפול", "Duplicate": "שכפול",
"Encoding": "קידוד", "Encoding": "קידוד",
"Enter URL...": "הכנסו כתובת", "Enter URL...": "הכנסו כתובת",
+2
View File
@@ -54,6 +54,8 @@
"Delete expression": "Elimina espressione", "Delete expression": "Elimina espressione",
"Delete filter block": "Elimina blocco filtro", "Delete filter block": "Elimina blocco filtro",
"Deuteranopia filter": "Filtro deuteranopia", "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", "Duplicate": "Duplica",
"Encoding": "Codifica", "Encoding": "Codifica",
"Enter URL...": "Inserisci URL...", "Enter URL...": "Inserisci URL...",
+2
View File
@@ -54,6 +54,8 @@
"Delete expression": "式を削除", "Delete expression": "式を削除",
"Delete filter block": "フィルタブロックを削除", "Delete filter block": "フィルタブロックを削除",
"Deuteranopia filter": "緑色盲フィルタ", "Deuteranopia filter": "緑色盲フィルタ",
"Drag to resize the layer list": "ドラッグしてレイヤーリストのサイズを変更",
"Drag to resize the sidebar": "ドラッグしてサイドバーのサイズを変更",
"Duplicate": "複製", "Duplicate": "複製",
"Encoding": "エンコーディング", "Encoding": "エンコーディング",
"Enter URL...": "URLを入力", "Enter URL...": "URLを入力",
+2
View File
@@ -54,6 +54,8 @@
"Delete expression": "표현식 삭제", "Delete expression": "표현식 삭제",
"Delete filter block": "필터 블록 삭제", "Delete filter block": "필터 블록 삭제",
"Deuteranopia filter": "녹색맹 필터", "Deuteranopia filter": "녹색맹 필터",
"Drag to resize the layer list": "드래그하여 레이어 목록 크기 조정",
"Drag to resize the sidebar": "드래그하여 사이드바 크기 조정",
"Duplicate": "복제", "Duplicate": "복제",
"Encoding": "인코딩", "Encoding": "인코딩",
"Enter URL...": "URL 입력...", "Enter URL...": "URL 입력...",
+2
View File
@@ -55,6 +55,8 @@
"Delete filter block": "Filtre bloğunu sil", "Delete filter block": "Filtre bloğunu sil",
"Deuteranopia filter": "Döteranopi filtresi", "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 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", "Duplicate": "Kopyala",
"Encoding": "Kodlama", "Encoding": "Kodlama",
"Enter URL...": "URL girin...", "Enter URL...": "URL girin...",
+2
View File
@@ -54,6 +54,8 @@
"Delete expression": "删除表达式", "Delete expression": "删除表达式",
"Delete filter block": "删除过滤器块", "Delete filter block": "删除过滤器块",
"Deuteranopia filter": "绿色盲滤镜", "Deuteranopia filter": "绿色盲滤镜",
"Drag to resize the layer list": "拖动以调整图层列表大小",
"Drag to resize the sidebar": "拖动以调整侧边栏大小",
"Duplicate": "复制", "Duplicate": "复制",
"Encoding": "编码", "Encoding": "编码",
"Enter URL...": "输入URL...", "Enter URL...": "输入URL...",
+2 -1
View File
@@ -6,7 +6,8 @@
.maputnik-map__container { .maputnik-map__container {
background: white; background: white;
display: flex; display: flex;
width: vars.$layout-map-width; width: 100%;
height: 100%;
&--error { &--error {
align-items: center; align-items: center;
+60 -12
View File
@@ -13,6 +13,9 @@
//APP LAYOUT //APP LAYOUT
.maputnik-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; font-family: vars.$font-family;
color: vars.$color-white; color: vars.$color-white;
@@ -28,31 +31,76 @@
display: flex; display: flex;
} }
&-list { // The resizable panel group filling the main area.
width: 200px; &-panels {
background-color: vars.$color-black; flex: 1;
min-width: 0;
height: 100%;
} }
&-sidebar-panels,
&-sidebar,
&-code-editor,
&-list,
&-drawer,
&-map {
height: 100%;
// scroll-container is position: absolute
position: relative;
}
&-sidebar,
&-code-editor,
&-list,
&-drawer { &-drawer {
width: 370px;
background-color: vars.$color-black; background-color: vars.$color-black;
// scroll-container is position: absolute
position: relative;
} }
&-code-editor { &-resize-handle {
width: 570px; width: 5px;
background-color: vars.$color-black; background-color: transparent;
// scroll-container is position: absolute
position: relative; 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 { &-bottom {
position: fixed; position: fixed;
bottom: 0; bottom: 0;
right: 0;
z-index: 10; z-index: 10;
width: vars.$layout-map-width; inset-inline-start: var(--sidebar-width);
inset-inline-end: 0;
background-color: vars.$color-black; background-color: vars.$color-black;
} }
} }
-1
View File
@@ -23,7 +23,6 @@ $toolbar-offset: 0;
$layout-list-width: 200px; $layout-list-width: 200px;
$layout-editor-width: 370px; $layout-editor-width: 370px;
$layout-map-width: calc(100% - #{$layout-list-width + $layout-editor-width});
// 'menu-down' from 'https://materialdesignicons.com/' // 'menu-down' from 'https://materialdesignicons.com/'
// See <https://github.com/Templarian/MaterialDesign/blob/master/LICENSE> // See <https://github.com/Templarian/MaterialDesign/blob/master/LICENSE>