mirror of
https://github.com/maputnik/editor.git
synced 2026-02-09 06:00:09 +00:00
merge main
This commit is contained in:
46
.eslintrc
46
.eslintrc
@@ -1,46 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2020": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:react/jsx-runtime",
|
||||
"plugin:react-hooks/recommended",
|
||||
],
|
||||
"ignorePatterns": [
|
||||
"dist"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"settings": {
|
||||
"react": { "version": "16.4" }
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint",
|
||||
"react-refresh"],
|
||||
"rules": {
|
||||
"react-refresh/only-export-components": [
|
||||
"warn",
|
||||
{ "allowConstantExport": true }
|
||||
],
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{ "argsIgnorePattern": "^_" }
|
||||
],
|
||||
"no-unused-vars": "off",
|
||||
"react/prop-types": ["off"],
|
||||
// Disable no-undef. It's covered by @typescript-eslint
|
||||
"no-undef": "off",
|
||||
"indent": ["error", 2],
|
||||
"no-var": ["error"]
|
||||
},
|
||||
"globals": {
|
||||
"global": "readonly"
|
||||
}
|
||||
}
|
||||
13
.github/dependabot.yml
vendored
13
.github/dependabot.yml
vendored
@@ -1,14 +1,17 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
- package-ecosystem: "npm" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "daily"
|
||||
open-pull-requests-limit: 2
|
||||
open-pull-requests-limit: 20
|
||||
versioning-strategy: increase
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
open-pull-requests-limit: 2
|
||||
versioning-strategy: increase
|
||||
|
||||
26
.github/workflows/auto-merge-dependabot.yml
vendored
Normal file
26
.github/workflows/auto-merge-dependabot.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: Automerge Dependabot
|
||||
|
||||
on: pull_request
|
||||
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
dependabot:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.actor == 'dependabot[bot]' }}
|
||||
steps:
|
||||
- name: Dependabot metadata
|
||||
id: metadata
|
||||
uses: dependabot/fetch-metadata@v2.2.0
|
||||
with:
|
||||
github-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
- name: Approve Dependabot PRs
|
||||
run: gh pr review --approve "$PR_URL"
|
||||
env:
|
||||
PR_URL: ${{github.event.pull_request.html_url}}
|
||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
- name: Enable auto-merge for Dependabot PRs
|
||||
run: gh pr merge --auto --squash "$PR_URL"
|
||||
env:
|
||||
PR_URL: ${{github.event.pull_request.html_url}}
|
||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -107,7 +107,7 @@ jobs:
|
||||
start: npm run start
|
||||
browser: ${{ matrix.browser }}
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
files: ${{ github.workspace }}/.nyc_output/out.json
|
||||
verbose: true
|
||||
|
||||
2
.github/workflows/create-bump-version-pr.yml
vendored
2
.github/workflows/create-bump-version-pr.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
./build/bump-version-changelog.js ${{ inputs.version }}
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
commit-message: Bump version to ${{ inputs.version }}
|
||||
branch: bump-version-to-${{ inputs.version }}
|
||||
|
||||
2
.github/workflows/deploy.yml
vendored
2
.github/workflows/deploy.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
run: npm run build
|
||||
|
||||
- name: Upload to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: dist
|
||||
|
||||
@@ -6,9 +6,15 @@
|
||||
- Add scheme type options for vector/raster tile
|
||||
- Add `tileSize` field for raster and raster-dem tile sources
|
||||
- Update Protomaps Light gallery style to v4
|
||||
- Add support to edit local files on the file system if supported by the browser
|
||||
- Upgrade to MapLibre LG JS v5
|
||||
- Upgrade Vite 6 and Cypress 14 ([#970](https://github.com/maplibre/maputnik/pull/970))
|
||||
- Upgrade OpenLayers from v6 to v10
|
||||
- _...Add new stuff here..._
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- Fix incorrect handing of network error response (#944)
|
||||
- _...Add new stuff here..._
|
||||
|
||||
## 2.1.1
|
||||
|
||||
@@ -20,14 +20,14 @@ const changelog = fs.readFileSync(changelogPath, 'utf8');
|
||||
*/
|
||||
const regex = /^## (\d+\.\d+\.\d+.*?)\n(.+?)(?=\n^## \d+\.\d+\.\d+.*?\n)/gms;
|
||||
|
||||
let releaseNotes = [];
|
||||
const releaseNotes = [];
|
||||
let match;
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
while (match = regex.exec(changelog)) {
|
||||
releaseNotes.push({
|
||||
'version': match[1],
|
||||
'changelog': match[2].trim(),
|
||||
});
|
||||
releaseNotes.push({
|
||||
'version': match[1],
|
||||
'changelog': match[2].trim(),
|
||||
});
|
||||
}
|
||||
|
||||
const latest = releaseNotes[0];
|
||||
@@ -44,5 +44,4 @@ const templatedReleaseNotes = `${header}
|
||||
|
||||
${latest.changelog}`;
|
||||
|
||||
// eslint-disable-next-line eol-last
|
||||
process.stdout.write(templatedReleaseNotes.trimEnd());
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MaputnikDriver } from "./maputnik-driver";
|
||||
|
||||
describe("accessibility", () => {
|
||||
let { beforeAndAfter, get, when, then } = new MaputnikDriver();
|
||||
const { beforeAndAfter, get, when, then } = new MaputnikDriver();
|
||||
beforeAndAfter();
|
||||
|
||||
describe("skip links", () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MaputnikDriver } from "./maputnik-driver";
|
||||
|
||||
describe("history", () => {
|
||||
let { beforeAndAfter, when, get, then } = new MaputnikDriver();
|
||||
const { beforeAndAfter, when, get, then } = new MaputnikDriver();
|
||||
beforeAndAfter();
|
||||
|
||||
let undoKeyCombo: string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MaputnikDriver } from "./maputnik-driver";
|
||||
|
||||
describe("i18n", () => {
|
||||
let { beforeAndAfter, get, when, then } = new MaputnikDriver();
|
||||
const { beforeAndAfter, get, when, then } = new MaputnikDriver();
|
||||
beforeAndAfter();
|
||||
|
||||
describe("language detector", () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MaputnikDriver } from "./maputnik-driver";
|
||||
|
||||
describe("keyboard", () => {
|
||||
let { beforeAndAfter, given, when, get, then } = new MaputnikDriver();
|
||||
const { beforeAndAfter, given, when, get, then } = new MaputnikDriver();
|
||||
beforeAndAfter();
|
||||
describe("shortcuts", () => {
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { v1 as uuid } from "uuid";
|
||||
import { MaputnikDriver } from "./maputnik-driver";
|
||||
|
||||
describe("layers", () => {
|
||||
let { beforeAndAfter, get, when, then } = new MaputnikDriver();
|
||||
const { beforeAndAfter, get, when, then } = new MaputnikDriver();
|
||||
beforeAndAfter();
|
||||
beforeEach(() => {
|
||||
when.setStyle("both");
|
||||
@@ -101,7 +101,7 @@ describe("layers", () => {
|
||||
});
|
||||
describe("background", () => {
|
||||
it("add", () => {
|
||||
let id = when.modal.fillLayers({
|
||||
const id = when.modal.fillLayers({
|
||||
type: "background",
|
||||
});
|
||||
then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||
@@ -117,7 +117,7 @@ describe("layers", () => {
|
||||
describe("modify", () => {
|
||||
function createBackground() {
|
||||
// Setup
|
||||
let id = uuid();
|
||||
const id = uuid();
|
||||
|
||||
when.selectWithin("add-layer.layer-type", "background");
|
||||
when.setValue("add-layer.layer-id.input", "background:" + id);
|
||||
@@ -139,11 +139,11 @@ describe("layers", () => {
|
||||
describe("layer", () => {
|
||||
it("expand/collapse");
|
||||
it("id", () => {
|
||||
let bgId = createBackground();
|
||||
const bgId = createBackground();
|
||||
|
||||
when.click("layer-list-item:background:" + bgId);
|
||||
|
||||
let id = uuid();
|
||||
const id = uuid();
|
||||
when.setValue("layer-editor.layer-id.input", "foobar:" + id);
|
||||
when.click("min-zoom");
|
||||
|
||||
@@ -219,7 +219,7 @@ describe("layers", () => {
|
||||
|
||||
describe("comments", () => {
|
||||
let bgId: string;
|
||||
let comment = "42";
|
||||
const comment = "42";
|
||||
|
||||
beforeEach(() => {
|
||||
bgId = createBackground();
|
||||
@@ -320,11 +320,11 @@ describe("layers", () => {
|
||||
|
||||
// TODO
|
||||
it.skip("parse error", () => {
|
||||
let bgId = createBackground();
|
||||
const bgId = createBackground();
|
||||
|
||||
when.click("layer-list-item:background:" + bgId);
|
||||
|
||||
let errorSelector = ".CodeMirror-lint-marker-error";
|
||||
const errorSelector = ".CodeMirror-lint-marker-error";
|
||||
then(get.elementByTestId(errorSelector)).shouldNotExist();
|
||||
|
||||
when.click(".CodeMirror");
|
||||
@@ -339,7 +339,7 @@ describe("layers", () => {
|
||||
|
||||
describe("fill", () => {
|
||||
it("add", () => {
|
||||
let id = when.modal.fillLayers({
|
||||
const id = when.modal.fillLayers({
|
||||
type: "fill",
|
||||
layer: "example",
|
||||
});
|
||||
@@ -361,7 +361,7 @@ describe("layers", () => {
|
||||
|
||||
describe("line", () => {
|
||||
it("add", () => {
|
||||
let id = when.modal.fillLayers({
|
||||
const id = when.modal.fillLayers({
|
||||
type: "line",
|
||||
layer: "example",
|
||||
});
|
||||
@@ -385,7 +385,7 @@ describe("layers", () => {
|
||||
|
||||
describe("symbol", () => {
|
||||
it("add", () => {
|
||||
let id = when.modal.fillLayers({
|
||||
const id = when.modal.fillLayers({
|
||||
type: "symbol",
|
||||
layer: "example",
|
||||
});
|
||||
@@ -404,7 +404,7 @@ describe("layers", () => {
|
||||
|
||||
describe("raster", () => {
|
||||
it("add", () => {
|
||||
let id = when.modal.fillLayers({
|
||||
const id = when.modal.fillLayers({
|
||||
type: "raster",
|
||||
layer: "raster",
|
||||
});
|
||||
@@ -423,7 +423,7 @@ describe("layers", () => {
|
||||
|
||||
describe("circle", () => {
|
||||
it("add", () => {
|
||||
let id = when.modal.fillLayers({
|
||||
const id = when.modal.fillLayers({
|
||||
type: "circle",
|
||||
layer: "example",
|
||||
});
|
||||
@@ -442,7 +442,7 @@ describe("layers", () => {
|
||||
|
||||
describe("fill extrusion", () => {
|
||||
it("add", () => {
|
||||
let id = when.modal.fillLayers({
|
||||
const id = when.modal.fillLayers({
|
||||
type: "fill-extrusion",
|
||||
layer: "example",
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { MaputnikDriver } from "./maputnik-driver";
|
||||
|
||||
describe("map", () => {
|
||||
let { beforeAndAfter, get, when, then } = new MaputnikDriver();
|
||||
const { beforeAndAfter, get, when, then } = new MaputnikDriver();
|
||||
beforeAndAfter();
|
||||
describe("zoom level", () => {
|
||||
it("via url", () => {
|
||||
let zoomLevel = 12.37;
|
||||
const zoomLevel = 12.37;
|
||||
when.setStyle("geojson", zoomLevel);
|
||||
then(get.elementByTestId("maplibre:ctrl-zoom")).shouldBeVisible();
|
||||
then(get.elementByTestId("maplibre:ctrl-zoom")).shouldContainText(
|
||||
@@ -14,7 +14,7 @@ describe("map", () => {
|
||||
});
|
||||
|
||||
it("via map controls", () => {
|
||||
let zoomLevel = 12.37;
|
||||
const zoomLevel = 12.37;
|
||||
when.setStyle("geojson", zoomLevel);
|
||||
then(get.elementByTestId("maplibre:ctrl-zoom")).shouldBeVisible();
|
||||
when.clickZoomIn();
|
||||
|
||||
@@ -8,8 +8,8 @@ export default class ModalDriver {
|
||||
fillLayers: (opts: { type: string; layer?: string; id?: string }) => {
|
||||
// Having logic in test code is an anti pattern.
|
||||
// This should be splitted to multiple single responsibility functions
|
||||
let type = opts.type;
|
||||
let layer = opts.layer;
|
||||
const type = opts.type;
|
||||
const layer = opts.layer;
|
||||
let id;
|
||||
if (opts.id) {
|
||||
id = opts.id;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MaputnikDriver } from "./maputnik-driver";
|
||||
|
||||
describe("modals", () => {
|
||||
let { beforeAndAfter, when, get, then } = new MaputnikDriver();
|
||||
const { beforeAndAfter, when, get, then } = new MaputnikDriver();
|
||||
beforeAndAfter();
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -25,7 +25,7 @@ describe("modals", () => {
|
||||
|
||||
describe("when click open url", () => {
|
||||
beforeEach(() => {
|
||||
let styleFileUrl = get.exampleFileUrl();
|
||||
const styleFileUrl = get.exampleFileUrl();
|
||||
|
||||
when.setValue("modal:open.url.input", styleFileUrl);
|
||||
when.click("modal:open.url.button");
|
||||
@@ -70,7 +70,7 @@ describe("modals", () => {
|
||||
it("public source");
|
||||
|
||||
it("add new source", () => {
|
||||
let sourceId = "n1z2v3r";
|
||||
const sourceId = "n1z2v3r";
|
||||
when.setValue("modal:sources.add.source_id", sourceId);
|
||||
when.select("modal:sources.add.source_type", "tile_vector");
|
||||
when.select("modal:sources.add.scheme_type", "tms");
|
||||
@@ -84,7 +84,7 @@ describe("modals", () => {
|
||||
});
|
||||
|
||||
it("add new raster source", () => {
|
||||
let sourceId = "rastertest";
|
||||
const sourceId = "rastertest";
|
||||
when.setValue("modal:sources.add.source_id", sourceId);
|
||||
when.select("modal:sources.add.source_type", "tile_raster");
|
||||
when.select("modal:sources.add.scheme_type", "xyz");
|
||||
@@ -159,7 +159,7 @@ describe("modals", () => {
|
||||
});
|
||||
});
|
||||
it("glyphs url", () => {
|
||||
let glyphsUrl = "http://example.com/{fontstack}/{range}.pbf";
|
||||
const glyphsUrl = "http://example.com/{fontstack}/{range}.pbf";
|
||||
when.setValue("modal:settings.glyphs", glyphsUrl);
|
||||
when.click("modal:settings.name");
|
||||
then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||
@@ -168,7 +168,7 @@ describe("modals", () => {
|
||||
});
|
||||
|
||||
it("maptiler access token", () => {
|
||||
let apiKey = "testing123";
|
||||
const apiKey = "testing123";
|
||||
when.setValue(
|
||||
"modal:settings.maputnik:openmaptiles_access_token",
|
||||
apiKey
|
||||
@@ -182,7 +182,7 @@ describe("modals", () => {
|
||||
});
|
||||
|
||||
it("thunderforest access token", () => {
|
||||
let apiKey = "testing123";
|
||||
const apiKey = "testing123";
|
||||
when.setValue(
|
||||
"modal:settings.maputnik:thunderforest_access_token",
|
||||
apiKey
|
||||
@@ -194,7 +194,7 @@ describe("modals", () => {
|
||||
});
|
||||
|
||||
it("stadia access token", () => {
|
||||
let apiKey = "testing123";
|
||||
const apiKey = "testing123";
|
||||
when.setValue(
|
||||
"modal:settings.maputnik:stadia_access_token",
|
||||
apiKey
|
||||
|
||||
61
eslint.config.js
Normal file
61
eslint.config.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import eslint from '@eslint/js';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import reactPlugin from 'eslint-plugin-react';
|
||||
import reactHooksPlugin from 'eslint-plugin-react-hooks';
|
||||
import reactRefreshPlugin from 'eslint-plugin-react-refresh';
|
||||
|
||||
export default tseslint.config({
|
||||
extends: [
|
||||
eslint.configs.recommended,
|
||||
tseslint.configs.recommended,
|
||||
],
|
||||
files: ['**/*.{js,jsx,ts,tsx}'],
|
||||
ignores: [
|
||||
"dist/**/*",
|
||||
],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2024,
|
||||
sourceType: 'module',
|
||||
globals: {
|
||||
global: 'readonly'
|
||||
}
|
||||
},
|
||||
settings: {
|
||||
react: { version: '18.2' }
|
||||
},
|
||||
plugins: {
|
||||
'react': reactPlugin,
|
||||
'react-hooks': reactHooksPlugin,
|
||||
'react-refresh': reactRefreshPlugin
|
||||
},
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true }
|
||||
],
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'warn',
|
||||
{
|
||||
varsIgnorePattern: '^_',
|
||||
caughtErrors: 'all',
|
||||
caughtErrorsIgnorePattern: '^_',
|
||||
argsIgnorePattern: '^_'
|
||||
}
|
||||
],
|
||||
'no-unused-vars': 'off',
|
||||
'react/prop-types': 'off',
|
||||
'no-undef': 'off',
|
||||
'indent': ['error', 2],
|
||||
'no-var': 'error',
|
||||
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
'@typescript-eslint/no-empty-object-type': 'off',
|
||||
|
||||
},
|
||||
linterOptions: {
|
||||
reportUnusedDisableDirectives: true,
|
||||
noInlineConfig: false
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -10,7 +10,7 @@ export default {
|
||||
keySeparator: false,
|
||||
namespaceSeparator: false,
|
||||
|
||||
defaultValue: (locale, ns, key) => {
|
||||
defaultValue: (_locale, _ns, _key) => {
|
||||
// The default value is a string that indicates that the string is not translated.
|
||||
return '__STRING_NOT_TRANSLATED__';
|
||||
}
|
||||
|
||||
6451
package-lock.json
generated
6451
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
81
package.json
81
package.json
@@ -9,7 +9,7 @@
|
||||
"build": "tsc && vite build --base=/maputnik/",
|
||||
"build-desktop": "tsc && vite build --base=/ && cd desktop && make",
|
||||
"i18n:refresh": "i18next 'src/**/*.{ts,tsx,js,jsx}'",
|
||||
"lint": "eslint ./src ./cypress --ext ts,tsx,js,jsx --report-unused-disable-directives --max-warnings 0",
|
||||
"lint": "eslint",
|
||||
"test": "cypress run",
|
||||
"cy:open": "cypress open",
|
||||
"lint-css": "stylelint \"src/styles/*.scss\"",
|
||||
@@ -23,25 +23,22 @@
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/maplibre/maputnik#readme",
|
||||
"dependencies": {
|
||||
"@mapbox/mapbox-gl-rtl-text": "^0.2.3",
|
||||
"@maplibre/maplibre-gl-geocoder": "^1.6.0",
|
||||
"@maplibre/maplibre-gl-inspect": "^1.6.3",
|
||||
"@maplibre/maplibre-gl-style-spec": "^20.3.1",
|
||||
"@mapbox/mapbox-gl-rtl-text": "^0.3.0",
|
||||
"@maplibre/maplibre-gl-geocoder": "^1.7.1",
|
||||
"@maplibre/maplibre-gl-inspect": "^1.7.1",
|
||||
"@maplibre/maplibre-gl-style-spec": "^23.1.0",
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@mdi/react": "^1.6.1",
|
||||
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
||||
"@typescript-eslint/parser": "^7.3.1",
|
||||
"array-move": "^4.0.0",
|
||||
"buffer": "^6.0.3",
|
||||
"classnames": "^2.5.1",
|
||||
"codemirror": "^5.65.2",
|
||||
"color": "^4.2.3",
|
||||
"cypress-plugin-tab": "^1.0.5",
|
||||
"detect-browser": "^5.3.0",
|
||||
"events": "^3.3.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"i18next": "^23.12.2",
|
||||
"i18next-browser-languagedetector": "^8.0.0",
|
||||
"i18next": "^24.2.1",
|
||||
"i18next-browser-languagedetector": "^8.0.2",
|
||||
"i18next-resources-to-backend": "^1.2.1",
|
||||
"json-stringify-pretty-compact": "^4.0.0",
|
||||
"json-to-ast": "^2.1.0",
|
||||
@@ -53,10 +50,10 @@
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"maplibre-gl": "^5.0.0",
|
||||
"maplibre-gl": "^5.0.1",
|
||||
"maputnik-design": "github:maputnik/design#172b06c",
|
||||
"ol": "^6.14.1",
|
||||
"ol-mapbox-style": "^7.1.1",
|
||||
"ol": "^10.3.1",
|
||||
"ol-mapbox-style": "^12.4.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.2.0",
|
||||
"react-accessible-accordion": "^5.0.0",
|
||||
@@ -68,15 +65,14 @@
|
||||
"react-color": "^2.19.3",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-file-reader-input": "^2.0.0",
|
||||
"react-i18next": "^15.0.1",
|
||||
"react-i18next": "^15.4.0",
|
||||
"react-icon-base": "^2.1.2",
|
||||
"react-icons": "^5.0.1",
|
||||
"react-icons": "^5.4.0",
|
||||
"react-sortable-hoc": "^2.0.0",
|
||||
"reconnecting-websocket": "^4.4.0",
|
||||
"sass": "^1.72.0",
|
||||
"slugify": "^1.6.6",
|
||||
"string-hash": "^1.1.3",
|
||||
"url": "^0.11.3"
|
||||
"url": "^0.11.4"
|
||||
},
|
||||
"jshintConfig": {
|
||||
"esversion": 6
|
||||
@@ -96,12 +92,13 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/code-coverage": "^3.12.30",
|
||||
"@cypress/code-coverage": "^3.13.10",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
||||
"@rollup/plugin-replace": "^5.0.5",
|
||||
"@shellygo/cypress-test-utils": "^2.1.9",
|
||||
"@rollup/plugin-replace": "^6.0.2",
|
||||
"@shellygo/cypress-test-utils": "^4.1.11",
|
||||
"@types/codemirror": "^5.60.15",
|
||||
"@types/color": "^3.0.6",
|
||||
"@types/color": "^4.2.0",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/geojson": "^7946.0.14",
|
||||
@@ -112,38 +109,40 @@
|
||||
"@types/lodash.get": "^4.4.9",
|
||||
"@types/lodash.isequal": "^4.5.8",
|
||||
"@types/lodash.throttle": "^4.1.9",
|
||||
"@types/mocha": "^10.0.6",
|
||||
"@types/randomcolor": "^0.5.9",
|
||||
"@types/react": "^18.2.67",
|
||||
"@types/react-aria-menubutton": "^6.2.14",
|
||||
"@types/react-aria-modal": "^4.0.10",
|
||||
"@types/react-autocomplete": "^1.8.10",
|
||||
"@types/react-aria-modal": "^5.0.0",
|
||||
"@types/react-autocomplete": "^1.8.11",
|
||||
"@types/react-collapse": "^5.0.4",
|
||||
"@types/react-color": "^3.0.12",
|
||||
"@types/react-color": "^3.0.13",
|
||||
"@types/react-dom": "^18.2.22",
|
||||
"@types/react-file-reader-input": "^2.0.4",
|
||||
"@types/react-icon-base": "^2.1.6",
|
||||
"@types/string-hash": "^1.1.3",
|
||||
"@types/uuid": "^9.0.8",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"@types/wicg-file-system-access": "^2023.10.5",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"cors": "^2.8.5",
|
||||
"cypress": "^13.13.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-react": "^7.34.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.6",
|
||||
"i18next-parser": "^9.0.1",
|
||||
"cypress": "^14.0.0",
|
||||
"cypress-plugin-tab": "^1.0.5",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"eslint-plugin-react-hooks": "^5.1.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.18",
|
||||
"i18next-parser": "^9.1.0",
|
||||
"istanbul": "^0.4.5",
|
||||
"istanbul-lib-coverage": "^3.2.2",
|
||||
"mocha": "^10.3.0",
|
||||
"postcss": "^8.4.38",
|
||||
"react-hot-loader": "^4.13.1",
|
||||
"stylelint": "^16.2.1",
|
||||
"stylelint-config-recommended-scss": "^14.0.0",
|
||||
"stylelint-scss": "^6.2.1",
|
||||
"typescript": "^5.4.3",
|
||||
"uuid": "^9.0.1",
|
||||
"vite": "^5.4.6",
|
||||
"vite-plugin-istanbul": "^6.0.0"
|
||||
"sass": "^1.83.4",
|
||||
"stylelint": "^16.13.2",
|
||||
"stylelint-config-recommended-scss": "^14.1.0",
|
||||
"stylelint-scss": "^6.10.1",
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.21.0",
|
||||
"uuid": "^11.0.5",
|
||||
"vite": "^6.0.11",
|
||||
"vite-plugin-istanbul": "^6.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@ type AppState = {
|
||||
export: boolean
|
||||
debug: boolean
|
||||
}
|
||||
fileHandle: FileSystemFileHandle | null
|
||||
}
|
||||
|
||||
export default class App extends React.Component<any, AppState> {
|
||||
@@ -284,6 +285,7 @@ export default class App extends React.Component<any, AppState> {
|
||||
openlayersDebugOptions: {
|
||||
debugToolbox: false,
|
||||
},
|
||||
fileHandle: null,
|
||||
}
|
||||
|
||||
this.layerWatcher = new LayerWatcher({
|
||||
@@ -611,7 +613,8 @@ export default class App extends React.Component<any, AppState> {
|
||||
}
|
||||
}
|
||||
|
||||
openStyle = (styleObj: StyleSpecification & {id: string}) => {
|
||||
openStyle = (styleObj: StyleSpecification & {id: string}, fileHandle: FileSystemFileHandle | null) => {
|
||||
this.setState({fileHandle: fileHandle});
|
||||
styleObj = this.setDefaultValues(styleObj)
|
||||
this.onStyleChanged(styleObj)
|
||||
}
|
||||
@@ -847,6 +850,10 @@ export default class App extends React.Component<any, AppState> {
|
||||
this.setModal(modalName, !this.state.isOpen[modalName]);
|
||||
}
|
||||
|
||||
onSetFileHandle(fileHandle: FileSystemFileHandle | null) {
|
||||
this.setState({fileHandle: fileHandle});
|
||||
}
|
||||
|
||||
onChangeOpenlayersDebug = (key: keyof AppState["openlayersDebugOptions"], value: boolean) => {
|
||||
this.setState({
|
||||
openlayersDebugOptions: {
|
||||
@@ -949,11 +956,14 @@ export default class App extends React.Component<any, AppState> {
|
||||
onStyleChanged={this.onStyleChanged}
|
||||
isOpen={this.state.isOpen.export}
|
||||
onOpenToggle={this.toggleModal.bind(this, 'export')}
|
||||
fileHandle={this.state.fileHandle}
|
||||
onSetFileHandle={this.onSetFileHandle}
|
||||
/>
|
||||
<ModalOpen
|
||||
isOpen={this.state.isOpen.open}
|
||||
onStyleOpen={this.openStyle}
|
||||
onOpenToggle={this.toggleModal.bind(this, 'open')}
|
||||
fileHandle={this.state.fileHandle}
|
||||
/>
|
||||
<ModalSources
|
||||
mapStyle={this.state.mapStyle}
|
||||
|
||||
@@ -2,7 +2,15 @@ import React from 'react'
|
||||
import classnames from 'classnames'
|
||||
import {detect} from 'detect-browser';
|
||||
|
||||
import {MdFileDownload, MdOpenInBrowser, MdSettings, MdLayers, MdHelpOutline, MdFindInPage, MdLanguage} from 'react-icons/md'
|
||||
import {
|
||||
MdOpenInBrowser,
|
||||
MdSettings,
|
||||
MdLayers,
|
||||
MdHelpOutline,
|
||||
MdFindInPage,
|
||||
MdLanguage,
|
||||
MdSave
|
||||
} from 'react-icons/md'
|
||||
import pkgJson from '../../package.json'
|
||||
//@ts-ignore
|
||||
import maputnikLogo from 'maputnik-design/logos/logo-color.svg?inline'
|
||||
@@ -216,8 +224,8 @@ class AppToolbarInternal extends React.Component<AppToolbarInternalProps> {
|
||||
<IconText>{t("Open")}</IconText>
|
||||
</ToolbarAction>
|
||||
<ToolbarAction wdKey="nav:export" onClick={this.props.onToggleModal.bind(this, 'export')}>
|
||||
<MdFileDownload />
|
||||
<IconText>{t("Export")}</IconText>
|
||||
<MdSave />
|
||||
<IconText>{t("Save")}</IconText>
|
||||
</ToolbarAction>
|
||||
<ToolbarAction wdKey="nav:sources" onClick={this.props.onToggleModal.bind(this, 'sources')}>
|
||||
<MdLayers />
|
||||
|
||||
@@ -15,7 +15,7 @@ function validate(url: string, t: TFunction): JSX.Element | undefined {
|
||||
const urlObj = new URL(url);
|
||||
return urlObj.protocol;
|
||||
}
|
||||
catch (err) {
|
||||
catch (_err) {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -318,14 +318,7 @@ class LayerListContainerInternal extends React.Component<LayerListContainerInter
|
||||
}
|
||||
}
|
||||
|
||||
// The next two lines have react-refresh/only-export-components disabled because they are
|
||||
// internal components that are not intended to be used outside of this file.
|
||||
// For some reason, the linter is not recognizing these components correctly.
|
||||
// When these components are migrated to functional components, the HOCs will no longer be needed
|
||||
// and the comments can be removed.
|
||||
// eslint-disable-next-line react-refresh/only-export-components
|
||||
const LayerListContainer = withTranslation()(LayerListContainerInternal);
|
||||
// eslint-disable-next-line react-refresh/only-export-components
|
||||
const LayerListContainerSortable = SortableContainer((props: LayerListContainerProps) => <LayerListContainer {...props} />)
|
||||
|
||||
type LayerListProps = LayerListContainerProps & {
|
||||
|
||||
@@ -103,7 +103,7 @@ class MapMaplibreGlInternal extends React.Component<MapMaplibreGlInternalProps,
|
||||
let should = false;
|
||||
try {
|
||||
should = JSON.stringify(this.props) !== JSON.stringify(nextProps) || JSON.stringify(this.state) !== JSON.stringify(nextState);
|
||||
} catch(e) {
|
||||
} catch(_e) {
|
||||
// no biggie, carry on
|
||||
}
|
||||
return should;
|
||||
@@ -161,7 +161,7 @@ class MapMaplibreGlInternal extends React.Component<MapMaplibreGlInternalProps,
|
||||
map.showCollisionBoxes = mapOpts.showCollisionBoxes!;
|
||||
map.showOverdrawInspector = mapOpts.showOverdrawInspector!;
|
||||
|
||||
let geocoder = this.initGeocoder(map);
|
||||
const geocoder = this.initGeocoder(map);
|
||||
|
||||
const zoomControl = new ZoomControl();
|
||||
map.addControl(zoomControl, 'top-right');
|
||||
|
||||
@@ -85,10 +85,11 @@ class MapOpenLayersInternal extends React.Component<MapOpenLayersInternalProps,
|
||||
componentDidMount() {
|
||||
this.overlay = new Overlay({
|
||||
element: this.popupContainer!,
|
||||
autoPan: true,
|
||||
autoPanAnimation: {
|
||||
duration: 250
|
||||
}
|
||||
autoPan: {
|
||||
animation: {
|
||||
duration: 250
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
|
||||
@@ -4,8 +4,8 @@ import {saveAs} from 'file-saver'
|
||||
import {version} from 'maplibre-gl/package.json'
|
||||
import {format} from '@maplibre/maplibre-gl-style-spec'
|
||||
import type {StyleSpecification} from 'maplibre-gl'
|
||||
import {MdFileDownload} from 'react-icons/md'
|
||||
import { WithTranslation, withTranslation } from 'react-i18next';
|
||||
import {MdMap, MdSave} from 'react-icons/md'
|
||||
import {WithTranslation, withTranslation} from 'react-i18next';
|
||||
|
||||
import FieldString from './FieldString'
|
||||
import InputButton from './InputButton'
|
||||
@@ -15,6 +15,7 @@ import fieldSpecAdditional from '../libs/field-spec-additional'
|
||||
|
||||
|
||||
const MAPLIBRE_GL_VERSION = version;
|
||||
const showSaveFilePickerAvailable = typeof window.showSaveFilePicker === "function";
|
||||
|
||||
|
||||
type ModalExportInternalProps = {
|
||||
@@ -22,12 +23,14 @@ type ModalExportInternalProps = {
|
||||
onStyleChanged(...args: unknown[]): unknown
|
||||
isOpen: boolean
|
||||
onOpenToggle(...args: unknown[]): unknown
|
||||
onSetFileHandle(fileHandle: FileSystemFileHandle | null): unknown
|
||||
fileHandle: FileSystemFileHandle | null
|
||||
} & WithTranslation;
|
||||
|
||||
|
||||
class ModalExportInternal extends React.Component<ModalExportInternalProps> {
|
||||
|
||||
tokenizedStyle () {
|
||||
tokenizedStyle() {
|
||||
return format(
|
||||
style.stripAccessTokens(
|
||||
style.replaceAccessTokens(this.props.mapStyle)
|
||||
@@ -35,8 +38,8 @@ class ModalExportInternal extends React.Component<ModalExportInternalProps> {
|
||||
);
|
||||
}
|
||||
|
||||
exportName () {
|
||||
if(this.props.mapStyle.name) {
|
||||
exportName() {
|
||||
if (this.props.mapStyle.name) {
|
||||
return Slugify(this.props.mapStyle.name, {
|
||||
replacement: '_',
|
||||
remove: /[*\-+~.()'"!:]/g,
|
||||
@@ -47,7 +50,7 @@ class ModalExportInternal extends React.Component<ModalExportInternalProps> {
|
||||
}
|
||||
}
|
||||
|
||||
downloadHtml() {
|
||||
createHtml() {
|
||||
const tokenStyle = this.tokenizedStyle();
|
||||
const htmlTitle = this.props.mapStyle.name || this.props.t("Map");
|
||||
const html = `<!DOCTYPE html>
|
||||
@@ -81,11 +84,58 @@ class ModalExportInternal extends React.Component<ModalExportInternalProps> {
|
||||
saveAs(blob, exportName + ".html");
|
||||
}
|
||||
|
||||
downloadStyle() {
|
||||
async saveStyle() {
|
||||
const tokenStyle = this.tokenizedStyle();
|
||||
const blob = new Blob([tokenStyle], {type: "application/json;charset=utf-8"});
|
||||
const exportName = this.exportName();
|
||||
saveAs(blob, exportName + ".json");
|
||||
|
||||
// it is not guaranteed that the File System Access API is available on all
|
||||
// browsers. If the function is not available, a fallback behavior is used.
|
||||
if (!showSaveFilePickerAvailable) {
|
||||
const blob = new Blob([tokenStyle], {type: "application/json;charset=utf-8"});
|
||||
const exportName = this.exportName();
|
||||
saveAs(blob, exportName + ".json");
|
||||
return;
|
||||
}
|
||||
|
||||
let fileHandle = this.props.fileHandle;
|
||||
if (fileHandle == null) {
|
||||
fileHandle = await this.createFileHandle();
|
||||
this.props.onSetFileHandle(fileHandle)
|
||||
if (fileHandle == null) return;
|
||||
}
|
||||
|
||||
const writable = await fileHandle.createWritable();
|
||||
await writable.write(tokenStyle);
|
||||
await writable.close();
|
||||
this.props.onOpenToggle();
|
||||
}
|
||||
|
||||
async saveStyleAs() {
|
||||
const tokenStyle = this.tokenizedStyle();
|
||||
|
||||
const fileHandle = await this.createFileHandle();
|
||||
this.props.onSetFileHandle(fileHandle)
|
||||
if (fileHandle == null) return;
|
||||
|
||||
const writable = await fileHandle.createWritable();
|
||||
await writable.write(tokenStyle);
|
||||
await writable.close();
|
||||
this.props.onOpenToggle();
|
||||
}
|
||||
|
||||
async createFileHandle(): Promise<FileSystemFileHandle | null> {
|
||||
const pickerOpts: SaveFilePickerOptions = {
|
||||
types: [
|
||||
{
|
||||
description: "json",
|
||||
accept: {"application/json": [".json"]},
|
||||
},
|
||||
],
|
||||
suggestedName: this.exportName(),
|
||||
};
|
||||
|
||||
const fileHandle = await window.showSaveFilePicker(pickerOpts) as FileSystemFileHandle;
|
||||
this.props.onSetFileHandle(fileHandle)
|
||||
return fileHandle;
|
||||
}
|
||||
|
||||
changeMetadataProperty(property: string, value: any) {
|
||||
@@ -107,14 +157,14 @@ class ModalExportInternal extends React.Component<ModalExportInternalProps> {
|
||||
data-wd-key="modal:export"
|
||||
isOpen={this.props.isOpen}
|
||||
onOpenToggle={this.props.onOpenToggle}
|
||||
title={t('Export Style')}
|
||||
title={t('Save Style')}
|
||||
className="maputnik-export-modal"
|
||||
>
|
||||
|
||||
<section className="maputnik-modal-section">
|
||||
<h1>{t("Download Style")}</h1>
|
||||
<h1>{t("Save Style")}</h1>
|
||||
<p>
|
||||
{t("Download a JSON style to your computer.")}
|
||||
{t("Save the JSON style to your computer.")}
|
||||
</p>
|
||||
|
||||
<div>
|
||||
@@ -139,18 +189,20 @@ class ModalExportInternal extends React.Component<ModalExportInternalProps> {
|
||||
</div>
|
||||
|
||||
<div className="maputnik-modal-export-buttons">
|
||||
<InputButton
|
||||
onClick={this.downloadStyle.bind(this)}
|
||||
>
|
||||
<MdFileDownload />
|
||||
{t("Download Style")}
|
||||
<InputButton onClick={this.saveStyle.bind(this)}>
|
||||
<MdSave/>
|
||||
{t("Save")}
|
||||
</InputButton>
|
||||
{showSaveFilePickerAvailable && (
|
||||
<InputButton onClick={this.saveStyleAs.bind(this)}>
|
||||
<MdSave/>
|
||||
{t("Save as")}
|
||||
</InputButton>
|
||||
)}
|
||||
|
||||
<InputButton
|
||||
onClick={this.downloadHtml.bind(this)}
|
||||
>
|
||||
<MdFileDownload />
|
||||
{t("Download HTML")}
|
||||
<InputButton onClick={this.createHtml.bind(this)}>
|
||||
<MdMap/>
|
||||
{t("Create HTML")}
|
||||
</InputButton>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -47,6 +47,7 @@ type ModalOpenInternalProps = {
|
||||
isOpen: boolean
|
||||
onOpenToggle(...args: unknown[]): unknown
|
||||
onStyleOpen(...args: unknown[]): unknown
|
||||
fileHandle: FileSystemFileHandle | null
|
||||
} & WithTranslation;
|
||||
|
||||
type ModalOpenState = {
|
||||
@@ -135,10 +136,44 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
|
||||
this.onStyleSelect(this.state.styleUrl);
|
||||
}
|
||||
|
||||
onUpload = (_: any, files: Result[]) => {
|
||||
onOpenFile = async () => {
|
||||
this.clearError();
|
||||
|
||||
const pickerOpts: OpenFilePickerOptions = {
|
||||
types: [
|
||||
{
|
||||
description: "json",
|
||||
accept: { "application/json": [".json"] },
|
||||
},
|
||||
],
|
||||
multiple: false,
|
||||
};
|
||||
|
||||
const [fileHandle] = await window.showOpenFilePicker(pickerOpts) as Array<FileSystemFileHandle>;
|
||||
const file = await fileHandle.getFile();
|
||||
const content = await file.text();
|
||||
|
||||
let mapStyle;
|
||||
try {
|
||||
mapStyle = JSON.parse(content)
|
||||
} catch (err) {
|
||||
this.setState({
|
||||
error: (err as Error).toString()
|
||||
});
|
||||
return;
|
||||
}
|
||||
mapStyle = style.ensureStyleValidity(mapStyle)
|
||||
|
||||
this.props.onStyleOpen(mapStyle, fileHandle);
|
||||
this.onOpenToggle();
|
||||
return file;
|
||||
}
|
||||
|
||||
// it is not guaranteed that the File System Access API is available on all
|
||||
// browsers. If the function is not available, a fallback behavior is used.
|
||||
onFileChanged = async (_: any, files: Result[]) => {
|
||||
const [, file] = files[0];
|
||||
const reader = new FileReader();
|
||||
|
||||
this.clearError();
|
||||
|
||||
reader.readAsText(file, "UTF-8");
|
||||
@@ -196,7 +231,7 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
return (
|
||||
<div>
|
||||
<Modal
|
||||
data-wd-key="modal:open"
|
||||
@@ -206,11 +241,20 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
|
||||
>
|
||||
{errorElement}
|
||||
<section className="maputnik-modal-section">
|
||||
<h1>{t("Upload Style")}</h1>
|
||||
<p>{t("Upload a JSON style from your computer.")}</p>
|
||||
<FileReaderInput onChange={this.onUpload} tabIndex={-1} aria-label={t("Style file")}>
|
||||
<InputButton className="maputnik-upload-button"><MdFileUpload /> {t("Upload")}</InputButton>
|
||||
</FileReaderInput>
|
||||
<h1>{t("Open local Style")}</h1>
|
||||
<p>{t("Open a local JSON style from your computer.")}</p>
|
||||
<div>
|
||||
{typeof window.showOpenFilePicker === "function" ? (
|
||||
<InputButton
|
||||
className="maputnik-big-button"
|
||||
onClick={this.onOpenFile}><MdFileUpload/> {t("Open Style")}
|
||||
</InputButton>
|
||||
) : (
|
||||
<FileReaderInput onChange={this.onFileChanged} tabIndex={-1} aria-label={t("Open Style")}>
|
||||
<InputButton className="maputnik-upload-button"><MdFileUpload /> {t("Open Style")}</InputButton>
|
||||
</FileReaderInput>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="maputnik-modal-section">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-ignore - this is a fork of jsonlint
|
||||
// @ts-expect-error - this is a fork of jsonlint
|
||||
import jsonlint from 'jsonlint';
|
||||
import CodeMirror, { MarkerRange } from 'codemirror';
|
||||
import jsonToAst from 'json-to-ast';
|
||||
@@ -33,7 +33,7 @@ CodeMirror.registerHelper("lint", "json", (text: string) => {
|
||||
try {
|
||||
jsonlint.parse(text);
|
||||
}
|
||||
catch(e) {
|
||||
catch(_e) {
|
||||
// Do nothing we catch the error above
|
||||
}
|
||||
return found;
|
||||
@@ -55,7 +55,7 @@ CodeMirror.registerHelper("lint", "mgl", (text: string, opts: any, doc: any) =>
|
||||
try {
|
||||
parser.parse(text);
|
||||
}
|
||||
catch (e) {
|
||||
catch (_e) {
|
||||
// ignore errors
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,17 @@ function loadJSON(url: string, defaultValue: any, cb: (...args: any[]) => void)
|
||||
mode: 'cors',
|
||||
credentials: "same-origin"
|
||||
})
|
||||
.then(function(response) {
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to load metadata for ' + url);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(function(body) {
|
||||
.then((body) => {
|
||||
cb(body)
|
||||
})
|
||||
.catch(function() {
|
||||
console.warn('Can not metadata for ' + url)
|
||||
.catch(() => {
|
||||
console.warn('Can not load metadata for ' + url + ', using default value ' + defaultValue);
|
||||
cb(defaultValue)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @ts-ignore
|
||||
import style from './style'
|
||||
|
||||
export function initialStyleUrl() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Internationalization
|
||||
|
||||
The process of internationlization is pretty straight forward for Maputnik.
|
||||
The process of internationalization is pretty straight forward for Maputnik.
|
||||
|
||||
## Add a new language
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"Map view": "Kartenansicht",
|
||||
"Maputnik on GitHub": "Maputnik auf GitHub",
|
||||
"Open": "Öffnen",
|
||||
"Export": "Exportieren",
|
||||
"Save": "Speichern",
|
||||
"Data Sources": "Datenquellen",
|
||||
"Style Settings": "Stileinstellungen",
|
||||
"View": "Ansicht",
|
||||
@@ -81,17 +81,14 @@
|
||||
"Close modal": "Modale Fenster schließen",
|
||||
"Debug": "Debug",
|
||||
"Options": "Optionen",
|
||||
"<0>Open in OSM</0> — Opens the current view on openstreetmap.org": "<0>In OSM öffnen</0> — Öffnet die aktuelle Ansicht auf openstreetmap.org",
|
||||
"Export Style": "Stil exportieren",
|
||||
"Download Style": "Stil herunterladen",
|
||||
"Download a JSON style to your computer.": "Lade einen JSON-Stil auf deinen Computer herunter.",
|
||||
"Download HTML": "HTML herunterladen",
|
||||
"Save Style": "Stil Speichern",
|
||||
"Save the JSON style to your computer.": "Speichere den JSON Stil auf deinem Computer.",
|
||||
"Save as": "Speichern unter",
|
||||
"Create HTML": "HTML erstellen",
|
||||
"Cancel": "Abbrechen",
|
||||
"Open Style": "Stil öffnen",
|
||||
"Upload Style": "Stil hochladen",
|
||||
"Upload a JSON style from your computer.": "Lade einen JSON-Stil von deinem Computer hoch.",
|
||||
"Style file": "Stildatei",
|
||||
"Upload": "Hochladen",
|
||||
"Open local Style": "Lokalen Stil öffnen",
|
||||
"Open a local JSON style from your computer.": "Öffne einen lokalen JSON Stil von deinem Computer.",
|
||||
"Load from URL": "Von URL laden",
|
||||
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "Von einer URL laden. Beachte, dass die URL <1>CORS aktiviert</1> haben muss.",
|
||||
"Style URL": "Stil-URL",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"Map view": "Vue de la carte",
|
||||
"Maputnik on GitHub": "Maputnik sur GitHub",
|
||||
"Open": "Ouvrir",
|
||||
"Export": "Exporter",
|
||||
"Save": "Enregistrer",
|
||||
"Data Sources": "Sources de données",
|
||||
"Style Settings": "Paramètres du style",
|
||||
"View": "Vue",
|
||||
@@ -81,17 +81,14 @@
|
||||
"Close modal": "Fermer la fenêtre modale",
|
||||
"Debug": "Déboguer",
|
||||
"Options": "Options",
|
||||
"<0>Open in OSM</0> — Opens the current view on openstreetmap.org": "<0>Ouvrir dans OSM</0> — Ouvre la vue actuelle sur openstreetmap.org",
|
||||
"Export Style": "Exporter le style",
|
||||
"Download Style": "Télécharger le style",
|
||||
"Download a JSON style to your computer.": "Téléchargez un style JSON sur votre ordinateur.",
|
||||
"Download HTML": "Télécharger HTML",
|
||||
"Save Style": "Enregistrer le style",
|
||||
"Save the JSON style to your computer.": "Enregistrer le style JSON sur votre ordinateur.",
|
||||
"Save as": "Enregistrer sous",
|
||||
"Create HTML": "Créer le HTML",
|
||||
"Cancel": "Annuler",
|
||||
"Open Style": "Ouvrir le style",
|
||||
"Upload Style": "Transférer un style",
|
||||
"Upload a JSON style from your computer.": "Transférer un style JSON depuis votre ordinateur.",
|
||||
"Style file": "Fichier de style",
|
||||
"Upload": "Transférer",
|
||||
"Open local Style": "Ouvrir un style local",
|
||||
"Open a local JSON style from your computer.": "Ouvrir un style JSON local depuis votre ordinateur.",
|
||||
"Load from URL": "Charger depuis une URL",
|
||||
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "Charger depuis une URL. Notez que l'URL doit avoir les <1>CORS activés</1>.",
|
||||
"Style URL": "URL du style",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"Map view": "תצוגת מפה",
|
||||
"Maputnik on GitHub": "מפוטניק בגיטהב",
|
||||
"Open": "פתיחה",
|
||||
"Export": "ייצוא",
|
||||
"Save": "שמור",
|
||||
"Data Sources": "מקורות מידע",
|
||||
"Style Settings": "הגדרות הסטייל",
|
||||
"View": "תצוגה",
|
||||
@@ -81,16 +81,14 @@
|
||||
"Close modal": "סגירת חלונית",
|
||||
"Debug": "דיבאג",
|
||||
"Options": "אפשרויות",
|
||||
"Export Style": "ייצוא של הסטייל",
|
||||
"Download Style": "הורדה של הסטייל",
|
||||
"Download a JSON style to your computer.": "הורדה של הסטייל למחשב",
|
||||
"Download HTML": "הורדה כ-HTML",
|
||||
"Save Style": "שמירת הסטייל",
|
||||
"Save the JSON style to your computer.": "שמירת הסטייל JSON במחשב שלך.",
|
||||
"Save as": "שמירה בשם",
|
||||
"Create HTML": "צור HTML",
|
||||
"Cancel": "ביטול",
|
||||
"Open Style": "פתיחת סטייל",
|
||||
"Upload Style": "העלאה של סטייל",
|
||||
"Upload a JSON style from your computer.": "העלאה של סטייל מהמחשב",
|
||||
"Style file": "קובץ סטייל",
|
||||
"Upload": "העלאה",
|
||||
"Open local Style": "פתיחת סטייל מקומי",
|
||||
"Open a local JSON style from your computer.": "פתיחת סטייל JSON מקומי מהמחשב שלך.",
|
||||
"Load from URL": "פתיחה מתוך כתובת",
|
||||
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "פתיחה מכתובת, שימו לב: הכתובת צריכה לתמוך ב- CORS",
|
||||
"Style URL": "כתוסת סטייל",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"Map view": "地図画面",
|
||||
"Maputnik on GitHub": "GitHubのMaputnik",
|
||||
"Open": "開く",
|
||||
"Export": "エクスポート",
|
||||
"Save": "保存",
|
||||
"Data Sources": "データソース",
|
||||
"Style Settings": "スタイル設定",
|
||||
"View": "表示",
|
||||
@@ -81,16 +81,14 @@
|
||||
"Close modal": "モーダルを閉じる",
|
||||
"Debug": "デバッグ",
|
||||
"Options": "設定",
|
||||
"Export Style": "スタイルをエクスポート",
|
||||
"Download Style": "スタイルをダウンロード",
|
||||
"Download a JSON style to your computer.": "パソコンにJSONスタイルをダウンロードします。",
|
||||
"Download HTML": "HTMLをダウンロード",
|
||||
"Save Style": "スタイルを保存",
|
||||
"Save the JSON style to your computer.": "JSONスタイルをコンピュータに保存します。",
|
||||
"Save as": "名前を付けて保存",
|
||||
"Create HTML": "HTMLを作成",
|
||||
"Cancel": "キャンセル",
|
||||
"Open Style": "スタイルを開く",
|
||||
"Upload Style": "スタイルをアップロードする",
|
||||
"Upload a JSON style from your computer.": "JSONスタイルをパソコンからアップロードする",
|
||||
"Style file": "スタイルファイル",
|
||||
"Upload": "アップロード",
|
||||
"Open local Style": "ローカルスタイルを開く",
|
||||
"Open a local JSON style from your computer.": "コンピュータからローカルJSONスタイルを開きます。",
|
||||
"Load from URL": "URLから読み込む",
|
||||
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "URLから読み込む。注意: URLは <1>CORSを有効にする</1> 必要があります。",
|
||||
"Style URL": "スタイルURL",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"Map view": "地图视图",
|
||||
"Maputnik on GitHub": "GitHub上的Maputnik",
|
||||
"Open": "打开",
|
||||
"Export": "导出",
|
||||
"Save": "保存",
|
||||
"Data Sources": "数据源",
|
||||
"Style Settings": "样式设置",
|
||||
"View": "视图",
|
||||
@@ -81,16 +81,14 @@
|
||||
"Close modal": "关闭模态框",
|
||||
"Debug": "调试",
|
||||
"Options": "选项",
|
||||
"Export Style": "导出样式",
|
||||
"Download Style": "下载样式",
|
||||
"Download a JSON style to your computer.": "将JSON样式下载到您的电脑。",
|
||||
"Download HTML": "下载HTML",
|
||||
"Save Style": "保存样式",
|
||||
"Save the JSON style to your computer.": "将JSON样式保存到您的计算机。",
|
||||
"Save as": "另存为",
|
||||
"Create HTML": "创建HTML",
|
||||
"Cancel": "取消",
|
||||
"Open Style": "打开样式",
|
||||
"Upload Style": "上传样式",
|
||||
"Upload a JSON style from your computer.": "从您的电脑上传JSON样式。",
|
||||
"Style file": "样式文件",
|
||||
"Upload": "上传",
|
||||
"Open local Style": "打开本地样式",
|
||||
"Open a local JSON style from your computer.": "从您的计算机打开本地JSON样式。",
|
||||
"Load from URL": "从URL加载",
|
||||
"Load from a URL. Note that the URL must have <1>CORS enabled</1>.": "从URL加载。注意:URL必须启用 <1>CORS</1>。",
|
||||
"Style URL": "样式URL",
|
||||
|
||||
@@ -104,7 +104,6 @@
|
||||
|
||||
select {
|
||||
margin: 0 6px;
|
||||
border-width: 0;
|
||||
display: inline;
|
||||
width: auto;
|
||||
border: solid 1px $color-midgray;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"types": ["geojson"],
|
||||
"types": ["geojson", "@types/wicg-file-system-access"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
@@ -22,12 +22,13 @@
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src", "cypress/e2e"],
|
||||
"exclude": ["dist"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }],
|
||||
// TODO: Remove when issue is resolved https://github.com/cypress-io/cypress/issues/27448
|
||||
"ts-node": {
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node"
|
||||
"moduleResolution": "Node",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export default defineConfig({
|
||||
values: {
|
||||
"_token_stack:": "",
|
||||
},
|
||||
}) as any,
|
||||
}),
|
||||
react(),
|
||||
istanbul({
|
||||
cypress: true,
|
||||
|
||||
Reference in New Issue
Block a user