23 Commits

Author SHA1 Message Date
vcoppe
17559913fd Merge branch 'dev' 2026-04-19 16:49:41 +02:00
vcoppe
dd9aba3adb fine tuning 2026-04-19 16:49:32 +02:00
vcoppe
55590d68a6 Merge branch 'dev' 2026-04-19 16:34:17 +02:00
vcoppe
bd40fbae74 fix routing controls on mobile 2026-04-19 16:34:06 +02:00
vcoppe
690cbc49cc avoid querying features when dragging 2026-04-19 16:31:50 +02:00
vcoppe
8e9f16c460 Merge branch 'dev' 2026-04-19 14:47:35 +02:00
vcoppe
36b16ddeef catch errors when fetching styles and add fallback one 2026-04-19 14:47:19 +02:00
vcoppe
c60b64f24f Merge branch 'dev' 2026-04-17 22:10:40 +02:00
vcoppe
16b8988fa7 fix layer filtering, must allow unknown intermediary keys 2026-04-17 22:10:30 +02:00
vcoppe
fdb6fe4e52 Merge branch 'dev' 2026-04-17 20:11:25 +02:00
Pablo Ovelleiro Corral
40f97b7c35 Fix: overlays bikerouterGravel, cyclOSMlite, mapterhornHillshade, openRailwayMap cannot be toggled in Layer settings (#329) 2026-04-17 20:07:51 +02:00
vcoppe
54b3113480 New Crowdin updates (#326)
* New translations en.json (Spanish)

* New translations merge.mdx (Spanish)

* New translations elevation.mdx (Spanish)

* New translations en.json (Chinese Traditional, Hong Kong)

* New translations en.json (Spanish)

* New translations integration.mdx (Spanish)

* New translations merge.mdx (Spanish)

* New translations integration.mdx (Spanish)

* New translations map-controls.mdx (Spanish)
2026-04-17 20:00:51 +02:00
vcoppe
0bf168e67e Merge branch 'dev' 2026-04-09 21:10:56 +02:00
vcoppe
7e9140492a fix max zoom 2026-04-09 21:10:45 +02:00
vcoppe
d762a45eb9 Merge branch 'dev' 2026-04-09 20:57:30 +02:00
vcoppe
79c0aed54f New Crowdin updates (#323)
* New translations en.json (Basque)

* New translations en.json (Dutch)

* New translations en.json (Catalan)

* New translations en.json (Romanian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Belarusian)

* New translations en.json (Czech)

* New translations en.json (Danish)

* New translations en.json (German)

* New translations en.json (Greek)

* New translations en.json (Finnish)

* New translations en.json (Hebrew)

* New translations en.json (Hungarian)

* New translations en.json (Italian)

* New translations en.json (Korean)

* New translations en.json (Lithuanian)

* New translations en.json (Norwegian)

* New translations en.json (Polish)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Swedish)

* New translations en.json (Turkish)

* New translations en.json (Ukrainian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Vietnamese)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Indonesian)

* New translations en.json (Thai)

* New translations en.json (Latvian)

* New translations en.json (Chinese Traditional, Hong Kong)

* New translations en.json (Serbian (Latin))
2026-04-09 20:57:02 +02:00
vcoppe
cb5a74de00 add esri satellite 2026-04-09 19:53:53 +02:00
vcoppe
31f25f346a New Crowdin updates (#322)
* New translations en.json (Ukrainian)

* New translations en.json (Ukrainian)

* New translations files-and-stats.mdx (Ukrainian)

* New translations getting-started.mdx (Ukrainian)

* New translations edit.mdx (Ukrainian)

* New translations view.mdx (Ukrainian)

* New translations en.json (Basque)
2026-04-09 19:33:42 +02:00
vcoppe
548ab9a459 Merge branch 'dev' 2026-04-07 22:19:15 +02:00
vcoppe
b3a11125a5 adapt temporary anchor layer 2026-04-07 22:19:03 +02:00
vcoppe
71cdc03da5 file specific routing controls layers 2026-04-07 22:15:17 +02:00
vcoppe
315c1f6a61 Merge branch 'dev' 2026-04-07 22:02:14 +02:00
vcoppe
694e73a677 reinit shadcn-svelte, fixes #318 2026-04-07 22:01:58 +02:00
53 changed files with 421 additions and 222 deletions

View File

@@ -1,17 +1,20 @@
{ {
"$schema": "https://shadcn-svelte.com/schema.json", "$schema": "https://shadcn-svelte.com/schema.json",
"style": "default", "tailwind": {
"tailwind": { "css": "src/app.css",
"css": "src/app.css", "baseColor": "neutral"
"baseColor": "slate" },
}, "aliases": {
"aliases": { "components": "$lib/components",
"components": "$lib/components", "utils": "$lib/utils",
"utils": "$lib/utils", "ui": "$lib/components/ui",
"ui": "$lib/components/ui", "hooks": "$lib/hooks",
"hooks": "$lib/hooks", "lib": "$lib"
"lib": "$lib" },
}, "typescript": true,
"typescript": true, "registry": "https://shadcn-svelte.com/registry",
"registry": "https://shadcn-svelte.com/registry" "style": "nova",
"iconLibrary": "lucide",
"menuColor": "default",
"menuAccent": "subtle"
} }

View File

@@ -14,7 +14,6 @@
"@maplibre/maplibre-gl-geocoder": "^1.9.4", "@maplibre/maplibre-gl-geocoder": "^1.9.4",
"chart.js": "^4.5.1", "chart.js": "^4.5.1",
"chartjs-plugin-zoom": "^2.2.0", "chartjs-plugin-zoom": "^2.2.0",
"clsx": "^2.1.1",
"dexie": "^4.0.11", "dexie": "^4.0.11",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"gpx": "file:../gpx", "gpx": "file:../gpx",
@@ -23,12 +22,12 @@
"mapillary-js": "^4.1.2", "mapillary-js": "^4.1.2",
"maplibre-gl": "^5.21.1", "maplibre-gl": "^5.21.1",
"sanitize-html": "^2.17.0", "sanitize-html": "^2.17.0",
"sortablejs": "^1.15.6", "sortablejs": "^1.15.6"
"tailwind-merge": "^3.3.0"
}, },
"devDependencies": { "devDependencies": {
"@fontsource-variable/inter": "^5.2.8",
"@internationalized/date": "^3.12.0", "@internationalized/date": "^3.12.0",
"@lucide/svelte": "^0.544.0", "@lucide/svelte": "^1.7.0",
"@sveltejs/adapter-static": "^3.0.8", "@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/enhanced-img": "^0.6.0", "@sveltejs/enhanced-img": "^0.6.0",
"@sveltejs/kit": "^2.21.2", "@sveltejs/kit": "^2.21.2",
@@ -45,6 +44,7 @@
"@typescript-eslint/eslint-plugin": "^8.33.1", "@typescript-eslint/eslint-plugin": "^8.33.1",
"@typescript-eslint/parser": "^8.33.1", "@typescript-eslint/parser": "^8.33.1",
"bits-ui": "^2.17.2", "bits-ui": "^2.17.2",
"clsx": "^2.1.1",
"eslint": "^9.28.0", "eslint": "^9.28.0",
"eslint-config-prettier": "^10.1.5", "eslint-config-prettier": "^10.1.5",
"eslint-plugin-svelte": "^3.9.1", "eslint-plugin-svelte": "^3.9.1",
@@ -57,15 +57,17 @@
"postcss": "^8.4.47", "postcss": "^8.4.47",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.4.0", "prettier-plugin-svelte": "^3.4.0",
"shadcn-svelte": "^1.2.7",
"svelte": "^5.33.18", "svelte": "^5.33.18",
"svelte-check": "^4.0.0", "svelte-check": "^4.0.0",
"svelte-dnd-action": "^0.9.65", "svelte-dnd-action": "^0.9.65",
"svelte-sonner": "^1.0.5", "svelte-sonner": "^1.1.0",
"tailwind-variants": "^3.1.1", "tailwind-merge": "^3.5.0",
"tailwind-variants": "^3.2.2",
"tailwindcss": "^4.1.8", "tailwindcss": "^4.1.8",
"tslib": "^2.8.1", "tslib": "^2.8.1",
"tsx": "^4.19.1", "tsx": "^4.19.1",
"tw-animate-css": "^1.3.4", "tw-animate-css": "^1.4.0",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"vaul-svelte": "^1.0.0-next.7", "vaul-svelte": "^1.0.0-next.7",
"vite": "^6.3.5" "vite": "^6.3.5"
@@ -2567,6 +2569,16 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@fontsource-variable/inter": {
"version": "5.2.8",
"resolved": "https://registry.npmjs.org/@fontsource-variable/inter/-/inter-5.2.8.tgz",
"integrity": "sha512-kOfP2D+ykbcX/P3IFnokOhVRNoTozo5/JxhAIVYLpea/UBmCQ/YWPBfWIDuBImXX/15KH+eKh4xpEUyS2sQQGQ==",
"dev": true,
"license": "OFL-1.1",
"funding": {
"url": "https://github.com/sponsors/ayuhito"
}
},
"node_modules/@humanfs/core": { "node_modules/@humanfs/core": {
"version": "0.19.1", "version": "0.19.1",
"dev": true, "dev": true,
@@ -3214,9 +3226,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@lucide/svelte": { "node_modules/@lucide/svelte": {
"version": "0.544.0", "version": "1.7.0",
"resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-0.544.0.tgz", "resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-1.7.0.tgz",
"integrity": "sha512-9f9O6uxng2pLB01sxNySHduJN3HTl5p0HDu4H26VR51vhZfiMzyOMe9Mhof3XAk4l813eTtl+/DYRvGyoRR+yw==", "integrity": "sha512-YytBKOUBGox7yWcykZnYxOkn5WpR5G1qYXLYXV/j1B79SOTTEKzB+s5yF5Rq9l9OkweDStNH2b4yTqfvhEhV8g==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"peerDependencies": { "peerDependencies": {
@@ -4726,6 +4738,9 @@
}, },
"node_modules/clsx": { "node_modules/clsx": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
@@ -4751,6 +4766,16 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/commander": {
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
"integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=20"
}
},
"node_modules/concat-map": { "node_modules/concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -6348,6 +6373,13 @@
"version": "0.2.2", "version": "0.2.2",
"license": "MIT" "license": "MIT"
}, },
"node_modules/node-fetch-native": {
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz",
"integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==",
"dev": true,
"license": "MIT"
},
"node_modules/optionator": { "node_modules/optionator": {
"version": "0.9.4", "version": "0.9.4",
"dev": true, "dev": true,
@@ -6958,6 +6990,25 @@
"version": "1.0.5", "version": "1.0.5",
"license": "MIT" "license": "MIT"
}, },
"node_modules/shadcn-svelte": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/shadcn-svelte/-/shadcn-svelte-1.2.7.tgz",
"integrity": "sha512-mWuQk4H4gtV+J2wJQ7nEPKNnB/v86AALFryZU0SSM7ChHmJJMZ1kH+qIuxYKrXm9vOOOcSWHRsWzPDB71DnjYA==",
"dev": true,
"license": "MIT",
"dependencies": {
"commander": "^14.0.0",
"node-fetch-native": "^1.6.4",
"postcss": "^8.5.5",
"tailwind-merge": "^3.0.0"
},
"bin": {
"shadcn-svelte": "dist/index.mjs"
},
"peerDependencies": {
"svelte": "^5.0.0"
}
},
"node_modules/sharp": { "node_modules/sharp": {
"version": "0.34.5", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
@@ -7235,6 +7286,8 @@
}, },
"node_modules/svelte-sonner": { "node_modules/svelte-sonner": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/svelte-sonner/-/svelte-sonner-1.1.0.tgz",
"integrity": "sha512-3lYM6ZIqWe+p9vwwWHGWP/ZdvHiUtzURsud2quIxivrX4rvpXh6i+geBGn0m3JS6KwW6W8VgbOl3xQMcDuh6gg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -7285,6 +7338,9 @@
}, },
"node_modules/tailwind-merge": { "node_modules/tailwind-merge": {
"version": "3.5.0", "version": "3.5.0",
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.5.0.tgz",
"integrity": "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==",
"dev": true,
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"type": "github", "type": "github",
@@ -7293,6 +7349,8 @@
}, },
"node_modules/tailwind-variants": { "node_modules/tailwind-variants": {
"version": "3.2.2", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-3.2.2.tgz",
"integrity": "sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -7392,6 +7450,8 @@
}, },
"node_modules/tw-animate-css": { "node_modules/tw-animate-css": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz",
"integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"funding": { "funding": {

View File

@@ -14,8 +14,9 @@
"format": "prettier --write . --config ../.prettierrc --ignore-path ../.prettierignore --ignore-path ./.gitignore" "format": "prettier --write . --config ../.prettierrc --ignore-path ../.prettierignore --ignore-path ./.gitignore"
}, },
"devDependencies": { "devDependencies": {
"@fontsource-variable/inter": "^5.2.8",
"@internationalized/date": "^3.12.0", "@internationalized/date": "^3.12.0",
"@lucide/svelte": "^0.544.0", "@lucide/svelte": "^1.7.0",
"@sveltejs/adapter-static": "^3.0.8", "@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/enhanced-img": "^0.6.0", "@sveltejs/enhanced-img": "^0.6.0",
"@sveltejs/kit": "^2.21.2", "@sveltejs/kit": "^2.21.2",
@@ -32,6 +33,7 @@
"@typescript-eslint/eslint-plugin": "^8.33.1", "@typescript-eslint/eslint-plugin": "^8.33.1",
"@typescript-eslint/parser": "^8.33.1", "@typescript-eslint/parser": "^8.33.1",
"bits-ui": "^2.17.2", "bits-ui": "^2.17.2",
"clsx": "^2.1.1",
"eslint": "^9.28.0", "eslint": "^9.28.0",
"eslint-config-prettier": "^10.1.5", "eslint-config-prettier": "^10.1.5",
"eslint-plugin-svelte": "^3.9.1", "eslint-plugin-svelte": "^3.9.1",
@@ -44,15 +46,17 @@
"postcss": "^8.4.47", "postcss": "^8.4.47",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.4.0", "prettier-plugin-svelte": "^3.4.0",
"shadcn-svelte": "^1.2.7",
"svelte": "^5.33.18", "svelte": "^5.33.18",
"svelte-check": "^4.0.0", "svelte-check": "^4.0.0",
"svelte-dnd-action": "^0.9.65", "svelte-dnd-action": "^0.9.65",
"svelte-sonner": "^1.0.5", "svelte-sonner": "^1.1.0",
"tailwind-variants": "^3.1.1", "tailwind-merge": "^3.5.0",
"tailwind-variants": "^3.2.2",
"tailwindcss": "^4.1.8", "tailwindcss": "^4.1.8",
"tslib": "^2.8.1", "tslib": "^2.8.1",
"tsx": "^4.19.1", "tsx": "^4.19.1",
"tw-animate-css": "^1.3.4", "tw-animate-css": "^1.4.0",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"vaul-svelte": "^1.0.0-next.7", "vaul-svelte": "^1.0.0-next.7",
"vite": "^6.3.5" "vite": "^6.3.5"
@@ -65,7 +69,6 @@
"@maplibre/maplibre-gl-geocoder": "^1.9.4", "@maplibre/maplibre-gl-geocoder": "^1.9.4",
"chart.js": "^4.5.1", "chart.js": "^4.5.1",
"chartjs-plugin-zoom": "^2.2.0", "chartjs-plugin-zoom": "^2.2.0",
"clsx": "^2.1.1",
"dexie": "^4.0.11", "dexie": "^4.0.11",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"gpx": "file:../gpx", "gpx": "file:../gpx",
@@ -74,7 +77,6 @@
"mapillary-js": "^4.1.2", "mapillary-js": "^4.1.2",
"maplibre-gl": "^5.21.1", "maplibre-gl": "^5.21.1",
"sanitize-html": "^2.17.0", "sanitize-html": "^2.17.0",
"sortablejs": "^1.15.6", "sortablejs": "^1.15.6"
"tailwind-merge": "^3.3.0"
} }
} }

View File

@@ -1,76 +1,93 @@
@import 'tailwindcss'; @import 'tailwindcss';
@import 'tw-animate-css'; @import 'tw-animate-css';
@import "shadcn-svelte/tailwind.css";
@import "@fontsource-variable/inter";
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
:root { :root {
--background: hsl(0 0% 100%) /* <- Wrap in HSL */; --background: oklch(1 0 0);
--foreground: hsl(240 10% 3.9%); --foreground: oklch(0.145 0 0);
--muted: hsl(240 4.8% 95.9%); --muted: oklch(0.97 0 0);
--muted-foreground: hsl(240 3.8% 46.1%); --muted-foreground: oklch(0.556 0 0);
--popover: hsl(0 0% 100%); --popover: oklch(1 0 0);
--popover-foreground: hsl(240 10% 3.9%); --popover-foreground: oklch(0.145 0 0);
--card: hsl(0 0% 100%); --card: oklch(1 0 0);
--card-foreground: hsl(240 10% 3.9%); --card-foreground: oklch(0.145 0 0);
--border: hsl(240 5.9% 90%); --border: oklch(0.922 0 0);
--input: hsl(240 5.9% 90%); --input: oklch(0.922 0 0);
--primary: hsl(240 5.9% 10%); --primary: oklch(0.205 0 0);
--primary-foreground: hsl(0 0% 98%); --primary-foreground: oklch(0.985 0 0);
--secondary: hsl(240 4.8% 95.9%); --secondary: oklch(0.97 0 0);
--secondary-foreground: hsl(240 5.9% 10%); --secondary-foreground: oklch(0.205 0 0);
--accent: hsl(240 4.8% 95.9%); --accent: oklch(0.97 0 0);
--accent-foreground: hsl(240 5.9% 10%); --accent-foreground: oklch(0.205 0 0);
--destructive: hsl(0 72.2% 50.6%); --destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: hsl(0 0% 98%); --destructive-foreground: hsl(0 0% 98%);
--ring: hsl(240 10% 3.9%); --ring: oklch(0.708 0 0);
--sidebar: hsl(0 0% 98%); --sidebar: oklch(0.985 0 0);
--sidebar-foreground: hsl(240 5.3% 26.1%); --sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: hsl(240 5.9% 10%); --sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: hsl(0 0% 98%); --sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: hsl(240 4.8% 95.9%); --sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: hsl(240 5.9% 10%); --sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: hsl(220 13% 91%); --sidebar-border: oklch(0.922 0 0);
--sidebar-ring: hsl(217.2 91.2% 59.8%); --sidebar-ring: oklch(0.708 0 0);
--support: rgb(220 15 130); --support: rgb(220 15 130);
--link: rgb(0 110 180); --link: rgb(0 110 180);
--selection: hsl(240 4.8% 93%); --selection: hsl(240 4.8% 93%);
--radius: 0.5rem; --radius: 0.5rem;
--chart-1: oklch(0.87 0 0);
--chart-2: oklch(0.556 0 0);
--chart-3: oklch(0.439 0 0);
--chart-4: oklch(0.371 0 0);
--chart-5: oklch(0.269 0 0);
} }
.dark { .dark {
--background: hsl(240 10% 3.9%); --background: oklch(0.145 0 0);
--foreground: hsl(0 0% 98%); --foreground: oklch(0.985 0 0);
--muted: hsl(240 3.7% 15.9%); --muted: oklch(0.269 0 0);
--muted-foreground: hsl(240 5% 64.9%); --muted-foreground: oklch(0.708 0 0);
--popover: hsl(240 10% 3.9%); --popover: oklch(0.205 0 0);
--popover-foreground: hsl(0 0% 98%); --popover-foreground: oklch(0.985 0 0);
--card: hsl(240 10% 3.9%); --card: oklch(0.205 0 0);
--card-foreground: hsl(0 0% 98%); --card-foreground: oklch(0.985 0 0);
--border: hsl(240 3.7% 15.9%); --border: oklch(1 0 0 / 10%);
--input: hsl(240 3.7% 15.9%); --input: oklch(1 0 0 / 15%);
--primary: hsl(0 0% 98%); --primary: oklch(0.922 0 0);
--primary-foreground: hsl(240 5.9% 10%); --primary-foreground: oklch(0.205 0 0);
--secondary: hsl(240 3.7% 15.9%); --secondary: oklch(0.269 0 0);
--secondary-foreground: hsl(0 0% 98%); --secondary-foreground: oklch(0.985 0 0);
--accent: hsl(240 3.7% 15.9%); --accent: oklch(0.269 0 0);
--accent-foreground: hsl(0 0% 98%); --accent-foreground: oklch(0.985 0 0);
--destructive: hsl(0 62.8% 30.6%); --destructive: oklch(0.704 0.191 22.216);
--destructive-foreground: hsl(0 0% 98%); --destructive-foreground: hsl(0 0% 98%);
--ring: hsl(240 4.9% 83.9%); --ring: oklch(0.556 0 0);
--sidebar: hsl(240 5.9% 10%); --sidebar: oklch(0.205 0 0);
--sidebar-foreground: hsl(240 4.8% 95.9%); --sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: hsl(224.3 76.3% 48%); --sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: hsl(0 0% 100%); --sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: hsl(240 3.7% 15.9%); --sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: hsl(240 4.8% 95.9%); --sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: hsl(240 3.7% 15.9%); --sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: hsl(217.2 91.2% 59.8%); --sidebar-ring: oklch(0.556 0 0);
--support: rgb(255 110 190); --support: rgb(255 110 190);
--link: rgb(80 190 255); --link: rgb(80 190 255);
--selection: hsl(240 3.7% 22%); --selection: hsl(240 3.7% 22%);
--chart-1: oklch(0.87 0 0);
--chart-2: oklch(0.556 0 0);
--chart-3: oklch(0.439 0 0);
--chart-4: oklch(0.371 0 0);
--chart-5: oklch(0.269 0 0);
} }
@theme inline { @theme inline {
@@ -113,14 +130,35 @@
--color-link: var(--link); --color-link: var(--link);
--breakpoint-xs: 540px; --breakpoint-xs: 540px;
--font-sans: 'Inter Variable', sans-serif;
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--radius-2xl: calc(var(--radius) * 1.8);
--radius-3xl: calc(var(--radius) * 2.2);
--radius-4xl: calc(var(--radius) * 2.6);
} }
@layer base { @layer base {
* { * {
@apply border-border; @apply border-border outline-ring/50;
} }
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground;
} }
html {
@apply font-sans;
}
} }

View File

@@ -35,6 +35,28 @@ export const basemaps: { [key: string]: string | StyleSpecification } = {
maptilerTopo: `https://api.maptiler.com/maps/topo-v4/style.json?key=${maptilerKeyPlaceHolder}`, maptilerTopo: `https://api.maptiler.com/maps/topo-v4/style.json?key=${maptilerKeyPlaceHolder}`,
maptilerOutdoors: `https://api.maptiler.com/maps/outdoor-v4/style.json?key=${maptilerKeyPlaceHolder}`, maptilerOutdoors: `https://api.maptiler.com/maps/outdoor-v4/style.json?key=${maptilerKeyPlaceHolder}`,
maptilerSatellite: `https://api.maptiler.com/maps/hybrid-v4/style.json?key=${maptilerKeyPlaceHolder}`, maptilerSatellite: `https://api.maptiler.com/maps/hybrid-v4/style.json?key=${maptilerKeyPlaceHolder}`,
esriSatellite: {
version: 8,
sources: {
esriSatellite: {
type: 'raster',
tiles: [
'https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/WMTS/tile/1.0.0/World_Imagery/default/default028mm/{z}/{y}/{x}.jpg',
],
tileSize: 256,
maxzoom: 19,
attribution:
'© <a href="https://www.esri.com/" target="_blank">Esri</a>, Vantor, Earthstar Geographics, and the GIS User Community',
},
},
layers: [
{
id: 'esriSatellite',
type: 'raster',
source: 'esriSatellite',
},
],
},
openStreetMap: { openStreetMap: {
version: 8, version: 8,
sources: { sources: {
@@ -781,6 +803,7 @@ export const basemapTree: LayerTreeType = {
maptilerTopo: true, maptilerTopo: true,
maptilerOutdoors: true, maptilerOutdoors: true,
maptilerSatellite: true, maptilerSatellite: true,
esriSatellite: true,
openStreetMap: true, openStreetMap: true,
openTopoMap: true, openTopoMap: true,
openHikingMap: true, openHikingMap: true,
@@ -1006,6 +1029,7 @@ export const defaultBasemapTree: LayerTreeType = {
maptilerTopo: true, maptilerTopo: true,
maptilerOutdoors: true, maptilerOutdoors: true,
maptilerSatellite: true, maptilerSatellite: true,
esriSatellite: false,
openStreetMap: true, openStreetMap: true,
openTopoMap: true, openTopoMap: true,
openHikingMap: true, openHikingMap: true,

View File

@@ -14,12 +14,12 @@
} = $props(); } = $props();
</script> </script>
<div class="text-sm bg-secondary rounded border flex flex-row items-center p-2 {className}"> <div class="text-[13px] bg-secondary rounded border flex flex-row items-center p-2 {className}">
<CircleQuestionMark size="16" class="w-4 mr-2 shrink-0 grow-0" /> <CircleQuestionMark size="16" class="w-4 mr-2 shrink-0 grow-0" />
<div> <div>
{@render children()} {@render children()}
{#if link} {#if link}
<a href={link} target="_blank" class="text-sm text-link hover:underline"> <a href={link} target="_blank" class="text-[13px] text-link hover:underline">
{i18n._('menu.more')} {i18n._('menu.more')}
</a> </a>
{/if} {/if}

View File

@@ -142,6 +142,7 @@ export class MapLayerEventManager {
} }
private _handleMouseMove(e: maplibregl.MapMouseEvent) { private _handleMouseMove(e: maplibregl.MapMouseEvent) {
if (e.originalEvent.buttons > 0) return;
const featuresByLayer = this._getRenderedFeaturesByLayer(e); const featuresByLayer = this._getRenderedFeaturesByLayer(e);
Object.keys(this._listeners).forEach((layerId) => { Object.keys(this._listeners).forEach((layerId) => {
const features = featuresByLayer[layerId] || []; const features = featuresByLayer[layerId] || [];

View File

@@ -81,8 +81,13 @@ export class StyleManager {
let basemap = get(currentBasemap); let basemap = get(currentBasemap);
const basemapInfo = basemaps[basemap] ?? custom[basemap]?.value ?? basemaps[defaultBasemap]; const basemapInfo = basemaps[basemap] ?? custom[basemap]?.value ?? basemaps[defaultBasemap];
const basemapStyle = await this.get(basemapInfo);
let basemapStyle = basemaps.openStreetMap as maplibregl.StyleSpecification;
try {
basemapStyle = await this.get(basemapInfo);
} catch (e) {
console.error(e.message);
}
this.merge(style, basemapStyle); this.merge(style, basemapStyle);
if (this._maptilerKey !== '') { if (this._maptilerKey !== '') {
@@ -109,45 +114,52 @@ export class StyleManager {
if (!layers[overlay]) { if (!layers[overlay]) {
if (this._pastOverlays.has(overlay)) { if (this._pastOverlays.has(overlay)) {
const overlayInfo = custom[overlay]?.value ?? overlays[overlay]; const overlayInfo = custom[overlay]?.value ?? overlays[overlay];
const overlayStyle = await this.get(overlayInfo); try {
for (let layer of overlayStyle.layers ?? []) { const overlayStyle = await this.get(overlayInfo);
if (map_.getLayer(layer.id)) { for (let layer of overlayStyle.layers ?? []) {
map_.removeLayer(layer.id); if (map_.getLayer(layer.id)) {
map_.removeLayer(layer.id);
}
} }
} catch (e) {
// Should not happen
} }
this._pastOverlays.delete(overlay); this._pastOverlays.delete(overlay);
} }
} else { } else {
const overlayInfo = custom[overlay]?.value ?? overlays[overlay]; const overlayInfo = custom[overlay]?.value ?? overlays[overlay];
const overlayStyle = await this.get(overlayInfo); try {
const opacity = overlayOpacities[overlay]; const overlayStyle = await this.get(overlayInfo);
const opacity = overlayOpacities[overlay];
for (let sourceId in overlayStyle.sources) { for (let sourceId in overlayStyle.sources) {
if (!map_.getSource(sourceId)) { if (!map_.getSource(sourceId)) {
map_.addSource(sourceId, overlayStyle.sources[sourceId]); map_.addSource(sourceId, overlayStyle.sources[sourceId]);
}
}
for (let layer of overlayStyle.layers ?? []) {
if (!map_.getLayer(layer.id)) {
if (opacity !== undefined) {
if (layer.type === 'raster') {
if (!layer.paint) {
layer.paint = {};
}
layer.paint['raster-opacity'] = opacity;
} else if (layer.type === 'hillshade') {
if (!layer.paint) {
layer.paint = {};
}
layer.paint['hillshade-exaggeration'] = opacity / 2;
}
} }
map_.addLayer(layer, ANCHOR_LAYER_KEY.overlays);
} }
}
this._pastOverlays.add(overlay); for (let layer of overlayStyle.layers ?? []) {
if (!map_.getLayer(layer.id)) {
if (opacity !== undefined) {
if (layer.type === 'raster') {
if (!layer.paint) {
layer.paint = {};
}
layer.paint['raster-opacity'] = opacity;
} else if (layer.type === 'hillshade') {
if (!layer.paint) {
layer.paint = {};
}
layer.paint['hillshade-exaggeration'] = opacity / 2;
}
}
map_.addLayer(layer, ANCHOR_LAYER_KEY.overlays);
}
}
this._pastOverlays.add(overlay);
} catch (e) {
console.error(e.message);
}
} }
} }
} catch (e) {} } catch (e) {}
@@ -181,6 +193,9 @@ export class StyleManager {
styleUrl = styleUrl.replace(maptilerKeyPlaceHolder, this._maptilerKey); styleUrl = styleUrl.replace(maptilerKeyPlaceHolder, this._maptilerKey);
} }
const response = await fetch(styleUrl, { cache: 'force-cache' }); const response = await fetch(styleUrl, { cache: 'force-cache' });
if (!response.ok) {
throw new Error(`HTTP error fetching style "${styleInfo}": ${response.status}`);
}
const style = await response.json(); const style = await response.json();
return style; return style;
} else { } else {

View File

@@ -57,8 +57,10 @@ export class RoutingControls {
updateControlsBinded: () => void = this.updateControls.bind(this); updateControlsBinded: () => void = this.updateControls.bind(this);
appendAnchorBinded: (e: MapMouseEvent) => void = this.appendAnchor.bind(this); appendAnchorBinded: (e: MapMouseEvent) => void = this.appendAnchor.bind(this);
addIntermediateAnchorBinded: (e: MapMouseEvent) => void = this.addIntermediateAnchor.bind(this);
draggedAnchorIndex: number | null = null; draggedAnchorIndex: number | null = null;
lastDraggedAnchorEventTime: number = 0;
draggingStartingPosition: maplibregl.Point = new maplibregl.Point(0, 0); draggingStartingPosition: maplibregl.Point = new maplibregl.Point(0, 0);
onMouseEnterBinded: () => void = this.onMouseEnter.bind(this); onMouseEnterBinded: () => void = this.onMouseEnter.bind(this);
onMouseLeaveBinded: () => void = this.onMouseLeave.bind(this); onMouseLeaveBinded: () => void = this.onMouseLeave.bind(this);
@@ -85,7 +87,7 @@ export class RoutingControls {
this.file = file; this.file = file;
for (let zoom = MIN_ANCHOR_ZOOM; zoom <= MAX_ANCHOR_ZOOM; zoom++) { for (let zoom = MIN_ANCHOR_ZOOM; zoom <= MAX_ANCHOR_ZOOM; zoom++) {
this.layers.set(zoom, { this.layers.set(zoom, {
id: `routing-controls-${zoom}`, id: `routing-controls-${this.fileId}-${zoom}`,
anchors: [], anchors: [],
}); });
} }
@@ -133,6 +135,7 @@ export class RoutingControls {
map_.on('style.load', this.updateControlsBinded); map_.on('style.load', this.updateControlsBinded);
map_.on('click', this.appendAnchorBinded); map_.on('click', this.appendAnchorBinded);
layerEventManager.on('mousemove', this.fileId, this.showTemporaryAnchorBinded); layerEventManager.on('mousemove', this.fileId, this.showTemporaryAnchorBinded);
layerEventManager.on('click', this.fileId, this.addIntermediateAnchorBinded);
this.fileUnsubscribe = this.file.subscribe(this.updateControlsBinded); this.fileUnsubscribe = this.file.subscribe(this.updateControlsBinded);
} }
@@ -237,6 +240,7 @@ export class RoutingControls {
map_?.off('style.load', this.updateControlsBinded); map_?.off('style.load', this.updateControlsBinded);
map_?.off('click', this.appendAnchorBinded); map_?.off('click', this.appendAnchorBinded);
layerEventManager?.off('mousemove', this.fileId, this.showTemporaryAnchorBinded); layerEventManager?.off('mousemove', this.fileId, this.showTemporaryAnchorBinded);
layerEventManager?.off('click', this.fileId, this.addIntermediateAnchorBinded);
map_?.off('mousemove', this.updateTemporaryAnchorBinded); map_?.off('mousemove', this.updateTemporaryAnchorBinded);
this.layers.forEach((layer) => { this.layers.forEach((layer) => {
@@ -521,12 +525,19 @@ export class RoutingControls {
if (get(streetViewEnabled) && get(streetViewSource) === 'google') { if (get(streetViewEnabled) && get(streetViewSource) === 'google') {
return; return;
} }
if (
this.draggedAnchorIndex !== null ||
Date.now() - this.lastDraggedAnchorEventTime < 100
) {
// Exit if anchor is being dragged
return;
}
if ( if (
e.target.queryRenderedFeatures(e.point, { e.target.queryRenderedFeatures(e.point, {
layers: [...this.layers.values()].map((layer) => layer.id), layers: [this.fileId, ...[...this.layers.values()].map((layer) => layer.id)],
}).length }).length
) { ) {
// Clicked on routing control, ignoring // Clicked on routing control or layer, ignoring
return; return;
} }
this.appendAnchorWithCoordinates({ this.appendAnchorWithCoordinates({
@@ -598,6 +609,15 @@ export class RoutingControls {
await this.routeBetweenAnchors([lastAnchor, newAnchor], [lastAnchorPoint, newAnchorPoint]); await this.routeBetweenAnchors([lastAnchor, newAnchor], [lastAnchorPoint, newAnchorPoint]);
} }
addIntermediateAnchor(e: maplibregl.MapMouseEvent) {
e.preventDefault();
if (this.temporaryAnchor !== null) {
this.turnIntoPermanentAnchor();
return;
}
}
getNeighbouringAnchors(anchor: Anchor): [Anchor | null, Anchor | null] { getNeighbouringAnchors(anchor: Anchor): [Anchor | null, Anchor | null] {
let previousAnchor: Anchor | null = null; let previousAnchor: Anchor | null = null;
let nextAnchor: Anchor | null = null; let nextAnchor: Anchor | null = null;
@@ -818,8 +838,11 @@ export class RoutingControls {
onClick(e: MapLayerMouseEvent) { onClick(e: MapLayerMouseEvent) {
e.preventDefault(); e.preventDefault();
if (this.temporaryAnchor !== null) { if (
this.turnIntoPermanentAnchor(); this.draggedAnchorIndex !== null ||
Date.now() - this.lastDraggedAnchorEventTime < 100
) {
// Exit if anchor is being dragged
return; return;
} }
@@ -908,6 +931,8 @@ export class RoutingControls {
lat: e.lngLat.lat, lat: e.lngLat.lat,
lon: e.lngLat.lng, lon: e.lngLat.lng,
}); });
this.lastDraggedAnchorEventTime = Date.now();
} }
onMouseUp(e: MapLayerMouseEvent | MapLayerTouchEvent) { onMouseUp(e: MapLayerMouseEvent | MapLayerTouchEvent) {
@@ -946,6 +971,7 @@ export class RoutingControls {
} }
this.draggedAnchorIndex = null; this.draggedAnchorIndex = null;
this.lastDraggedAnchorEventTime = Date.now();
} }
showTemporaryAnchor(e: MapLayerMouseEvent) { showTemporaryAnchor(e: MapLayerMouseEvent) {
@@ -1073,7 +1099,9 @@ export class RoutingControls {
if (!this.temporaryAnchor) { if (!this.temporaryAnchor) {
return; return;
} }
let source = get(map)?.getSource('routing-controls-0') as GeoJSONSource | undefined; let source = get(map)?.getSource(`routing-controls-${this.fileId}-0`) as
| GeoJSONSource
| undefined;
if (source) { if (source) {
if (this.temporaryAnchor) { if (this.temporaryAnchor) {
source.updateData({ source.updateData({
@@ -1088,7 +1116,9 @@ export class RoutingControls {
return; return;
} }
const map_ = get(map); const map_ = get(map);
let source = map_?.getSource('routing-controls-0') as GeoJSONSource | undefined; let source = map_?.getSource(`routing-controls-${this.fileId}-0`) as
| GeoJSONSource
| undefined;
if (source) { if (source) {
if (this.temporaryAnchor) { if (this.temporaryAnchor) {
source.updateData({ source.updateData({

View File

@@ -31,13 +31,13 @@ get along, so we shut typescript up by casting `value` to `never`.
data-slot="slider-track" data-slot="slider-track"
data-orientation={orientation} data-orientation={orientation}
class={cn( class={cn(
"h-1.5 bg-muted rounded-full data-horizontal:h-1 data-horizontal:w-full data-vertical:h-full data-vertical:w-1 bg-muted relative grow overflow-hidden data-horizontal:w-full data-vertical:h-full" "bg-muted rounded-full data-horizontal:h-1.5 data-horizontal:w-full data-vertical:h-full data-vertical:w-1 bg-muted relative grow overflow-hidden data-horizontal:w-full data-vertical:h-full"
)} )}
> >
<SliderPrimitive.Range <SliderPrimitive.Range
data-slot="slider-range" data-slot="slider-range"
class={cn( class={cn(
"h-full bg-black absolute select-none data-horizontal:h-full data-vertical:w-full" "bg-primary absolute select-none data-horizontal:h-full data-vertical:w-full"
)} )}
/> />
</span> </span>

View File

@@ -13,8 +13,8 @@ Puede usar **gpx.studio** para crear mapas que muestren sus archivos GPX e integ
Todo lo que necesita es: Todo lo que necesita es:
1. GPX files hosted on your server or on Google Drive, or accessible via a public URL; 1. Archivos GPX alojados en su servidor o en Google Drive, o accesibles a través de una URL pública;
2. _Optional:_ a <a href="https://cloud.maptiler.com/auth/widget?next=https://cloud.maptiler.com/maps/" target="_blank">MapTiler key</a> to load MapTiler maps. 2. _Opcional:_ una <a href="https://cloud.maptiler.com/auth/widget?next=https://cloud.maptiler.com/maps/" target="_blank">Tecla MapTiler</a> para cargar mapas MapTiler.
Luego puede jugar con el configurador de abajo para personalizar su mapa y generar el código HTML correspondiente. Luego puede jugar con el configurador de abajo para personalizar su mapa y generar el código HTML correspondiente.

View File

@@ -69,4 +69,4 @@ Pueden activarse en la [configuración de capas del mapa](./menu/settings).
En estos ajustes, también puede administrar la opacidad de las capas superpuestas. En estos ajustes, también puede administrar la opacidad de las capas superpuestas.
For advanced users, it is possible to add custom basemaps and overlays by providing <a href="https://en.wikipedia.org/wiki/Web_Map_Tile_Service" target="_blank">WMTS</a>, <a href="https://en.wikipedia.org/wiki/Web_Map_Service" target="_blank">WMS</a>, or <a href="https://maplibre.org/maplibre-style-spec/" target="_blank">MapLibre style JSON</a> URLs. Para los usuarios avanzados, es posible añadir mapas base y superposiciones personalizadas proporcionando <a href="https://en.wikipedia.org/wiki/Web_Map_Tile_Service" target="_blank">WMTS</a>, <a href="https://en.wikipedia.org/wiki/Web_Map_Service" target="_blank">WMS</a> o URLs <a href="https://docs.mapbox.com/help/glossary/style/" target="_blank">JSON estilo Mapbox</a>.

View File

@@ -10,7 +10,7 @@ title: Desnivel
# <MountainSnow size="24" class="inline-block" style="margin-bottom: 5px" /> { title } # <MountainSnow size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
Le permite añadir datos de desnivel a trazas y [puntos de interés](../gpx), o reemplazar los datos existentes. Esta herramienta permite añadir datos de elevación a los rastros y [puntos de interés](../gpx), o reemplazar los datos existentes.
<div class="flex flex-row justify-center"> <div class="flex flex-row justify-center">
<Elevation class="text-foreground p-3 border rounded-md shadow-lg" /> <Elevation class="text-foreground p-3 border rounded-md shadow-lg" />
@@ -18,7 +18,7 @@ Le permite añadir datos de desnivel a trazas y [puntos de interés](../gpx), o
<DocsNote> <DocsNote>
Elevation data is provided by <a href="https://maptiler.com" target="_blank">MapTiler</a>. Los datos de notificación son proporcionados por <a href="https://maptiler.com" target="_blank">MapTiler</a>.
You can learn more about its origin and accuracy in the <a href="https://docs.maptiler.com/guides/map-tiling-hosting/data-hosting/rgb-terrain-by-maptiler/" target="_blank">documentation</a>. Puedes aprender más sobre su origen y precisión en la <a href="https://docs.maptiler.com/guides/map-tiling-hosting/data-hosting/rgb-terrain-by-maptiler/" target="_blank">documentación</a>.
</DocsNote> </DocsNote>

View File

@@ -18,8 +18,8 @@ Para usar esta herramienta, necesita [seleccionar](../files-and-stats) múltiple
<DocsNote> <DocsNote>
Selected items are merged in the order they appear in the files list. Los elementos seleccionados se combinan en el orden en que aparecen en la lista de archivos.
Reorder items by drag-and-drop if needed. Si es necesario, puede reordenar los elementos arrastrando y soltando.
</DocsNote> </DocsNote>

View File

@@ -1,5 +1,5 @@
--- ---
title: Files and statistics title: Файли та статистика
--- ---
<script lang="ts"> <script lang="ts">
@@ -19,41 +19,41 @@ title: Files and statistics
# { title } # { title }
## File list ## Список файлів
Once you have [opened](./menu/file) files, they will be shown as tabs in the file list located at the bottom of the map. Після того як ви [відкриєте](./menu/file) файли, вони будуть показуватися у вигляді вкладок у списку файлів, розташованому внизу карти.
You can reorder them by dragging and dropping the tabs. Ви можете змінити їх порядок, перетягуючи вкладки.
And when many files are open, you can scroll through the list of tabs to navigate between them. А коли відкрито багато файлів, ви можете прокручувати список вкладок, щоб переходити між ними.
<DocsNote> <DocsNote>
When using a mouse, you need to hold <kbd>Shift</kbd> to scroll horizontally. Під час роботи з мишею для горизонтальної прокрутки потрібно утримувати клавіші <kbd>Shift</kbd>.
</DocsNote> </DocsNote>
### File selection ### Вибір файлу
By clicking on a tab, you can switch between the files to inspect their statistics, and apply [edit actions](./menu/edit) and [tools](./toolbar) to them. Натиснувши на вкладку, ви можете перемикатися між файлами, щоб переглянути їхні статистичні дані, а також застосовувати до них [дії редагування](./menu/edit) та [інструменти](./toolbar).
By holding the <kbd>Ctrl/Cmd</kbd> key, you can add files to the selection or remove them, and by holding <kbd>Shift</kbd>, you can select a range of files. Утримуючи клавішу <kbd>Ctrl/Cmd</kbd>, ви можете додавати файли до виділення або видаляти їх, а утримуючи клавішу <kbd>Shift</kbd>, ви можете виділити діапазон файлів.
Most of the [edit actions](./menu/edit) and [tools](./toolbar) can be applied to multiple files at once. Більшість [операцій редагування](./menu/edit) та [інструментів](./toolbar) можна застосовувати одразу до декількох файлів.
<DocsNote> <DocsNote>
You can also navigate through the files using the arrow keys on your keyboard, and use <kbd>Shift</kbd> to add files to the selection. Ви також можете переходити між файлами за допомогою клавіш зі стрілками на клавіатурі, а також натискати <kbd>Shift</kbd>, щоб додати файли до виділення.
</DocsNote> </DocsNote>
### Edit actions ### Редагувати дії
By right-clicking on a file tab, you can access the same actions as in the [edit menu](./menu/edit). Клацнувши правою кнопкою миші на вкладці файлу, ви отримаєте доступ до тих самих дій, що й у [меню редагування](./menu/edit).
### Tree layout ### Структура дерева
As mentioned in the [view options section](./menu/view), you can switch to a tree layout for the files list. Як зазначено в [розділі налаштувань перегляду](./menu/view), ви можете перейти до деревоподібного показу списку файлів.
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map. Ця схема ідеально підходить для роботи з великою кількістю відкритих файлів, оскільки вони розміщуються у вигляді вертикального списку в правій частині екрана.
In addition, the file tree view enables you to inspect the [tracks, segments, and points of interest](./gpx) contained inside the files through collapsible sections. Крім того, у дереві файлів можна переглядати [треки, сегменти та цікаві місця](./gpx), що містяться у файлах, за допомогою розгортальних розділів.
You can also apply [edit actions](./menu/edit) and [tools](./toolbar) to internal file items. Ви також можете застосовувати [дії редагування](./menu/edit) та [інструменти](./toolbar) до елементів внутрішніх файлів.
Furthermore, you can drag and drop the inner items to reorder them, or move them in the hierarchy or even to another file. Furthermore, you can drag and drop the inner items to reorder them, or move them in the hierarchy or even to another file.
<DocsNote> <DocsNote>

View File

@@ -21,7 +21,7 @@ Before we dive into the details of each section, let's have a quick overview of
At the top of the interface, you will find the [main menu](./menu). At the top of the interface, you will find the [main menu](./menu).
This is where you can access common actions such as opening, closing, and exporting files, undoing and redoing actions, and adjusting the application settings. This is where you can access common actions such as opening, closing, and exporting files, undoing and redoing actions, and adjusting the application settings.
## Files and statistics ## Файли та статистика
At the bottom of the interface, you will find the list of files currently open in the application. At the bottom of the interface, you will find the list of files currently open in the application.
You can click on a file to select it and display its statistics below the list. You can click on a file to select it and display its statistics below the list.

View File

@@ -1,5 +1,5 @@
--- ---
title: Edit actions title: Редагувати дії
--- ---
<script lang="ts"> <script lang="ts">

View File

@@ -18,7 +18,7 @@ Hide the elevation profile to make room for the map, or show it to inspect the c
### <ListTree size="16" class="inline-block" style="margin-bottom: 2px" /> File tree ### <ListTree size="16" class="inline-block" style="margin-bottom: 2px" /> File tree
Toggle the tree layout for the [file list](../files-and-stats). Toggle the tree layout for the [file list](../files-and-stats).
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map. Ця схема ідеально підходить для роботи з великою кількістю відкритих файлів, оскільки вони розміщуються у вигляді вертикального списку в правій частині екрана.
In addition, the file tree view enables you to inspect the [tracks, segments, and points of interest](../gpx) contained inside the files through collapsible sections. In addition, the file tree view enables you to inspect the [tracks, segments, and points of interest](../gpx) contained inside the files through collapsible sections.
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Switch to previous basemap ### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Switch to previous basemap

View File

@@ -162,38 +162,33 @@ function getLayerValidator(allowed: Record<string, any>, fallback: string) {
function filterLayerTree(t: LayerTreeType, allowed: LayerTreeType | undefined): LayerTreeType { function filterLayerTree(t: LayerTreeType, allowed: LayerTreeType | undefined): LayerTreeType {
const filtered: LayerTreeType = {}; const filtered: LayerTreeType = {};
const values = Object.values(t); if (allowed) {
if (values.length == 0) return filtered; Object.entries(allowed).forEach(([key, value]) => {
if (typeof values[0] === 'boolean') { if (Object.hasOwn(t, key)) {
if (allowed) { if (typeof value === 'boolean') {
Object.keys(allowed).forEach((key) => {
if (Object.hasOwn(t, key)) {
filtered[key] = t[key]; filtered[key] = t[key];
} else { } else if (typeof value === 'object') {
filtered[key] = allowed[key]; filtered[key] = filterLayerTree(
typeof t[key] === 'object' ? t[key] : {},
value
);
} }
}); } else {
}
Object.entries(t).forEach(([key, value]) => {
if (
!Object.hasOwn(filtered, key) &&
(key.startsWith('custom-') || key.startsWith('extension-'))
) {
filtered[key] = value; filtered[key] = value;
} }
}); });
} else {
Object.entries(t).forEach(([key, value]) => {
if (typeof value === 'object') {
filtered[key] = filterLayerTree(
value,
typeof allowed === 'object' && typeof allowed[key] === 'object'
? allowed[key]
: undefined
);
}
});
} }
Object.entries(t).forEach(([key, value]) => {
if (!Object.hasOwn(filtered, key)) {
if (typeof value === 'boolean') {
if (key.startsWith('custom-') || key.startsWith('extension-')) {
filtered[key] = value;
}
} else if (typeof value === 'object') {
filtered[key] = filterLayerTree(value, undefined);
}
}
});
return filtered; return filtered;
} }

View File

@@ -1,4 +1,4 @@
import { type ClassValue, clsx } from 'clsx'; import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
import { base } from '$app/paths'; import { base } from '$app/paths';
import { languages } from '$lib/languages'; import { languages } from '$lib/languages';
@@ -18,9 +18,7 @@ export type WithoutChild<T> = T extends { child?: any } ? Omit<T, 'child'> : T;
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, 'children'> : T; export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, 'children'> : T;
export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>; export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };
ref?: U | null;
};
export function getClosestLinePoint( export function getClosestLinePoint(
points: TrackPoint[], points: TrackPoint[],

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -2,10 +2,10 @@
"metadata": { "metadata": {
"home_title": "el editor online de archivos GPX", "home_title": "el editor online de archivos GPX",
"app_title": "app", "app_title": "app",
"embed_title": " editor online de archivos GPX", "embed_title": "Editor online de archivos GPX",
"help_title": "ayuda", "help_title": "ayuda",
"404_title": "página no encontrada", "404_title": "página no encontrada",
"description": "Mira, edita y crea archivos GPX online con planificación avanzada de rutas y herramientas de procesamiento de archivos, bonitos mapas y visualizaciones detalladas de datos." "description": "Visualiza, edita y crea archivos GPX online con planificación avanzada de rutas y herramientas de procesamiento de archivos, bonitos mapas y visualizaciones detalladas de datos."
}, },
"menu": { "menu": {
"new": "Nuevo", "new": "Nuevo",
@@ -234,7 +234,7 @@
}, },
"elevation": { "elevation": {
"button": "Solicitar datos de desnivel", "button": "Solicitar datos de desnivel",
"help": "Requesting elevation data will erase the existing elevation data, if any, and replace it with data from MapTiler.", "help": "La solicitud de datos de desnivel borrará los datos de desnivel existentes, si los hay, y los reemplazará con datos de Mapbox.",
"help_no_selection": "Seleccione un elemento del archivo para solicitar datos de desnivel." "help_no_selection": "Seleccione un elemento del archivo para solicitar datos de desnivel."
}, },
"waypoint": { "waypoint": {
@@ -276,7 +276,7 @@
"new": "Nueva capa personalizada", "new": "Nueva capa personalizada",
"edit": "Editar capa personalizada", "edit": "Editar capa personalizada",
"urls": "URL(s)", "urls": "URL(s)",
"url_placeholder": "WMTS, WMS or MapLibre style JSON", "url_placeholder": "WMTS, WMS o JSON estilo Mapbox",
"max_zoom": "Zoom máximo", "max_zoom": "Zoom máximo",
"layer_type": "Tipo de capa", "layer_type": "Tipo de capa",
"basemap": "Mapa base", "basemap": "Mapa base",
@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",
@@ -493,7 +494,7 @@
"email": "Email", "email": "Email",
"contribute": "Contribuir", "contribute": "Contribuir",
"supported_by": "con el apoyo de", "supported_by": "con el apoyo de",
"features": "Features", "features": "Características",
"route_planning": "Planificación de ruta", "route_planning": "Planificación de ruta",
"route_planning_description": "Una interfaz intuitiva para crear itinerarios adaptados a cada deporte, basada en datos de OpenStreetMap.", "route_planning_description": "Una interfaz intuitiva para crear itinerarios adaptados a cada deporte, basada en datos de OpenStreetMap.",
"file_processing": "Procesamiento avanzado de archivo", "file_processing": "Procesamiento avanzado de archivo",
@@ -502,15 +503,15 @@
"maps_description": "Una gran colección de mapas base, capas y puntos de interés para ayudarle a crear su próxima aventura al aire libre o visualizar su último logro.", "maps_description": "Una gran colección de mapas base, capas y puntos de interés para ayudarle a crear su próxima aventura al aire libre o visualizar su último logro.",
"data_visualization": "Visualización de datos", "data_visualization": "Visualización de datos",
"data_visualization_description": "Un perfil de elevación interactivo con estadísticas detalladas para analizar actividades registradas y futuros objetivos.", "data_visualization_description": "Un perfil de elevación interactivo con estadísticas detalladas para analizar actividades registradas y futuros objetivos.",
"philosophy": "Philosophy", "philosophy": "Filosofía",
"foss": "Free, ad-free and open source", "foss": "Gratis, sin anuncios y código abierto",
"foss_description": "The website is free to use, without ads, and the source code is publicly available on GitHub.", "foss_description": "El sitio web es de uso gratuito, sin anuncios, y el código fuente está disponible públicamente en GitHub.",
"privacy": "Privacy-friendly", "privacy": "Respetuosa con la privacidad",
"privacy_description": "Tus archivos GPX nunca abandonan tu navegador. Sin seguimiento, sin recopilación de datos.", "privacy_description": "Tus archivos GPX nunca abandonan tu navegador. Sin seguimiento, sin recopilación de datos.",
"community": "Made possible by the community", "community": "Posible gracias a la comunidad",
"community_description": "gpx.studio tiene una comunidad asombrosa que ha cubierto sus costes a través de donaciones durante años, mientras ha dado forma al proyecto a través de sugerencias de características, informes de fallos y traducciones a muchos idiomas.", "community_description": "gpx.studio tiene una comunidad asombrosa que ha cubierto sus costes a través de donaciones durante años, mientras ha dado forma al proyecto a través de sugerencias de características, informes de fallos y traducciones a muchos idiomas.",
"support_button": "Apoya a gpx.studio en Open Collective", "support_button": "Apoya a gpx.studio en Open Collective",
"translate_button": "Help translate the website on Crowdin" "translate_button": "Ayuda a traducir el sitio web en Crowdin"
}, },
"docs": { "docs": {
"translate": "Mejorar la traducción en Crowdin", "translate": "Mejorar la traducción en Crowdin",
@@ -535,7 +536,7 @@
}, },
"embedding": { "embedding": {
"title": "Crear su propio mapa", "title": "Crear su propio mapa",
"maptiler_key": "MapTiler key (optional, only required for MapTiler maps)", "maptiler_key": "Clave MapTiler (opcional, sólo se requiere para mapas MapTiler)",
"file_urls": "URLs de archivo (separados por comas)", "file_urls": "URLs de archivo (separados por comas)",
"drive_ids": "IDs de archivo de Google Drive (separados por comas)", "drive_ids": "IDs de archivo de Google Drive (separados por comas)",
"basemap": "Mapa base", "basemap": "Mapa base",

View File

@@ -4,7 +4,7 @@
"app_title": "aplikazioa", "app_title": "aplikazioa",
"embed_title": "lineako GPX fitxategi editorea", "embed_title": "lineako GPX fitxategi editorea",
"help_title": "laguntza", "help_title": "laguntza",
"404_title": "Ez da orrialdea aurkitu", "404_title": "ez da orrialdea aurkitu",
"description": "Ikusi, editatu eta sortu GPX fitxategiak bideak bilatzeko aukera aurreratuarekin eta fitxategiak prozesatzeko tresnekin, mapa ederrekin eta datuak ikusteko xehetasun handiarekin." "description": "Ikusi, editatu eta sortu GPX fitxategiak bideak bilatzeko aukera aurreratuarekin eta fitxategiak prozesatzeko tresnekin, mapa ederrekin eta datuak ikusteko xehetasun handiarekin."
}, },
"menu": { "menu": {
@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "Túraútvonal jelzések", "openHikingMap": "Túraútvonal jelzések",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "오픈스트리트맵", "openStreetMap": "오픈스트리트맵",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Buiten", "maptilerOutdoors": "MapTiler Buiten",
"maptilerSatellite": "MapTiler satelliet", "maptilerSatellite": "MapTiler satelliet",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -28,7 +28,7 @@
"undo": "Скасувати", "undo": "Скасувати",
"redo": "Повторити", "redo": "Повторити",
"delete": "Видалити", "delete": "Видалити",
"delete_all": "Delete all", "delete_all": "Видалити все",
"select_all": "Вибрати все", "select_all": "Вибрати все",
"view": "Вигляд", "view": "Вигляд",
"elevation_profile": "Профіль рельєфу", "elevation_profile": "Профіль рельєфу",
@@ -63,7 +63,7 @@
"ctrl": "Ctrl", "ctrl": "Ctrl",
"click": "Клац", "click": "Клац",
"drag": "Перетягти", "drag": "Перетягти",
"right_click_drag": "Right-click drag", "right_click_drag": "Перетягування правою кнопкою миші",
"metadata": { "metadata": {
"button": "Інформація...", "button": "Інформація...",
"name": "Назва", "name": "Назва",
@@ -81,7 +81,7 @@
"center": "Центр", "center": "Центр",
"open_in": "Відкрити в", "open_in": "Відкрити в",
"copy_coordinates": "Копіювати координати", "copy_coordinates": "Копіювати координати",
"edit_osm": "Edit in OpenStreetMap" "edit_osm": "Редагувати в OpenStreetMap"
}, },
"toolbar": { "toolbar": {
"routing": { "routing": {
@@ -191,8 +191,8 @@
"from": "Початкова точка знаходиться занадто далеко від найближчої дороги", "from": "Початкова точка знаходиться занадто далеко від найближчої дороги",
"via": "Проміжна точка знаходиться занадто далеко від найближчої дороги", "via": "Проміжна точка знаходиться занадто далеко від найближчої дороги",
"to": "Кінцева точка знаходиться занадто далеко від найближчої дороги", "to": "Кінцева точка знаходиться занадто далеко від найближчої дороги",
"distance": "The end point is too far from the start point", "distance": "Кінцева точка знаходиться занадто далеко від початкової точки",
"connection": "No connection found between the points", "connection": "Зв'язку між точками не виявлено",
"timeout": "Розрахунок маршруту є занадто довгий, спробуйте додати ближчі точки" "timeout": "Розрахунок маршруту є занадто довгий, спробуйте додати ближчі точки"
} }
}, },
@@ -234,7 +234,7 @@
}, },
"elevation": { "elevation": {
"button": "Запит даних висот", "button": "Запит даних висот",
"help": "Requesting elevation data will erase the existing elevation data, if any, and replace it with data from MapTiler.", "help": "Запит даних про висоту призведе до видалення наявних даних про висоту (якщо такі є) та їх заміни даними з MapTiler.",
"help_no_selection": "Виберіть елемент файлу, щоб запросити дані про висоту." "help_no_selection": "Виберіть елемент файлу, щоб запросити дані про висоту."
}, },
"waypoint": { "waypoint": {
@@ -276,7 +276,7 @@
"new": "Новий користувацький шар", "new": "Новий користувацький шар",
"edit": "Редагувати користувацький шар", "edit": "Редагувати користувацький шар",
"urls": "URL-адреса(и)", "urls": "URL-адреса(и)",
"url_placeholder": "WMTS, WMS or MapLibre style JSON", "url_placeholder": "JSON у форматі WMTS, WMS або MapLibre",
"max_zoom": "Максимальний зум", "max_zoom": "Максимальний зум",
"layer_type": "Тип шару", "layer_type": "Тип шару",
"basemap": "Базова карта", "basemap": "Базова карта",
@@ -285,7 +285,7 @@
"update": "Оновити шар" "update": "Оновити шар"
}, },
"opacity": "Непрозорість накладання", "opacity": "Непрозорість накладання",
"terrain": "Terrain source", "terrain": "Джерело інформації про місцевість",
"label": { "label": {
"basemaps": "Базові карти", "basemaps": "Базові карти",
"overlays": "Накладання", "overlays": "Накладання",
@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",
@@ -331,7 +332,7 @@
"usgs": "USGS", "usgs": "USGS",
"bikerouterGravel": "bikerouter.de Gravel", "bikerouterGravel": "bikerouter.de Gravel",
"cyclOSMlite": "CyclOSM Lite", "cyclOSMlite": "CyclOSM Lite",
"mapterhornHillshade": "Mapterhorn Hillshade", "mapterhornHillshade": "Рельєфна карта Маптерхорна",
"openRailwayMap": "OpenRailwayMap", "openRailwayMap": "OpenRailwayMap",
"swisstopoSlope": "swisstopo Slope", "swisstopoSlope": "swisstopo Slope",
"swisstopoHiking": "swisstopo Hiking", "swisstopoHiking": "swisstopo Hiking",
@@ -361,7 +362,7 @@
"water": "Вода", "water": "Вода",
"shower": "Душ", "shower": "Душ",
"shelter": "Укриття", "shelter": "Укриття",
"cemetery": "Cemetery", "cemetery": "Кладовище",
"motorized": "Автомобілі та Мотоцикли", "motorized": "Автомобілі та Мотоцикли",
"fuel-station": "Паливна станція", "fuel-station": "Паливна станція",
"parking": "Парковка", "parking": "Парковка",
@@ -493,7 +494,7 @@
"email": "Електронна пошта", "email": "Електронна пошта",
"contribute": "Зробити внесок", "contribute": "Зробити внесок",
"supported_by": "за підтримки", "supported_by": "за підтримки",
"features": "Features", "features": "Об'єкти",
"route_planning": "Планування маршруту", "route_planning": "Планування маршруту",
"route_planning_description": "Інтуїтивно зрозумілий інтерфейс для створення маршрутів, адаптованих під кожен вид спорту, на основі даних OpenStreetMap.", "route_planning_description": "Інтуїтивно зрозумілий інтерфейс для створення маршрутів, адаптованих під кожен вид спорту, на основі даних OpenStreetMap.",
"file_processing": "Розширена обробка файлу", "file_processing": "Розширена обробка файлу",
@@ -502,15 +503,15 @@
"maps_description": "Велика колекція базових карт, шарів та точок інтересу, щоб допомогти вам спланувати наступну outdoor-пригоду або візуалізувати своє останнє досягнення.", "maps_description": "Велика колекція базових карт, шарів та точок інтересу, щоб допомогти вам спланувати наступну outdoor-пригоду або візуалізувати своє останнє досягнення.",
"data_visualization": "Візуалізація даних", "data_visualization": "Візуалізація даних",
"data_visualization_description": "Інтерактивний профіль висот з детальною статистикою для аналізу записаних активностей та майбутніх цілей.", "data_visualization_description": "Інтерактивний профіль висот з детальною статистикою для аналізу записаних активностей та майбутніх цілей.",
"philosophy": "Philosophy", "philosophy": "Філософія",
"foss": "Free, ad-free and open source", "foss": "Безкоштовно, без реклами та з відкритим кодом",
"foss_description": "The website is free to use, without ads, and the source code is publicly available on GitHub.", "foss_description": "Користування вебсайт є безкоштовним, він не містить реклами, а його вихідний код оприлюднено на GitHub.",
"privacy": "Privacy-friendly", "privacy": "З повагою до конфіденційності",
"privacy_description": "Your GPX files never leave your browser. No tracking, no data collection.", "privacy_description": "Ваші файли GPX ніколи не залишають меж вашого браузера. Жодного відстеження, жодного збору даних.",
"community": "Made possible by the community", "community": "Завдяки підтримці спільноти",
"community_description": "gpx.studio has an amazing community that has covered its costs through donations for years, while shaping the project through feature suggestions, bug reports, and translations into many languages.", "community_description": "gpx.studio має чудову спільноту, яка вже багато років покриває витрати проєкту коштом пожертв, а також сприяє його розвитку, пропонуючи нові функції, повідомляючи про помилки та перекладаючи сайт на багато мов.",
"support_button": "Support gpx.studio on Open Collective", "support_button": "Підтримайте gpx.studio на Open Collective",
"translate_button": "Help translate the website on Crowdin" "translate_button": "Допоможіть перекласти вебсайт на Crowdin"
}, },
"docs": { "docs": {
"translate": "Покращити переклад на Crowdin", "translate": "Покращити переклад на Crowdin",
@@ -535,7 +536,7 @@
}, },
"embedding": { "embedding": {
"title": "Створити власну карту", "title": "Створити власну карту",
"maptiler_key": "MapTiler key (optional, only required for MapTiler maps)", "maptiler_key": "Ключ MapTiler (не обов’язково, потрібен лише для карт MapTiler)",
"file_urls": "URL-адреси файлів (розділені комами)", "file_urls": "URL-адреси файлів (розділені комами)",
"drive_ids": "Ідентифікатори файлів Google Drive (розділені комами)", "drive_ids": "Ідентифікатори файлів Google Drive (розділені комами)",
"basemap": "Базова карта", "basemap": "Базова карта",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -16,9 +16,9 @@
"duplicate": "Duplicate", "duplicate": "Duplicate",
"copy": "Copy", "copy": "Copy",
"paste": "Paste", "paste": "Paste",
"cut": "Cut", "cut": "剪下",
"export": "Export...", "export": "匯出……",
"export_all": "Export all...", "export_all": "匯出所有……",
"export_options": "Export options", "export_options": "Export options",
"support_message": "The tool is free to use, but not free to run. Please consider supporting the website if you use it frequently. Thank you!", "support_message": "The tool is free to use, but not free to run. Please consider supporting the website if you use it frequently. Thank you!",
"support_button": "Help keep the website free", "support_button": "Help keep the website free",
@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",

View File

@@ -307,6 +307,7 @@
"maptilerTopo": "MapTiler Topo", "maptilerTopo": "MapTiler Topo",
"maptilerOutdoors": "MapTiler Outdoors", "maptilerOutdoors": "MapTiler Outdoors",
"maptilerSatellite": "MapTiler Satellite", "maptilerSatellite": "MapTiler Satellite",
"esriSatellite": "Esri Satellite",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",