cleanup
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
<html lang="">
|
||||
<head>
|
||||
<title>Weather Station</title>
|
||||
<link rel="icon" href="/favicon.png">
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
@@ -23,9 +25,6 @@
|
||||
<meta name="twitter:title" content="Weather Station">
|
||||
<meta name="twitter:description" content="Local Weather & Forecasting">
|
||||
<meta name="twitter:image" content="/favicon.png">
|
||||
|
||||
<link rel="icon" href="/favicon.png">
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
101
client/package-lock.json
generated
101
client/package-lock.json
generated
@@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"@ztimson/css-utils": "^1.3.5",
|
||||
"@ztimson/utils": "^0.29.5",
|
||||
"ol-mapbox-style": "^13.4.1",
|
||||
"vue": "^3.5.38"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -589,6 +590,40 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@mapbox/jsonlint-lines-primitives": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.3.tgz",
|
||||
"integrity": "sha512-0SElaV0uMxEnxzBhhX9WTuPyUeMsAN/SS0i16tjuba4/mio63MG9khjC1a0JAiPGXAwvwm4UfHJURCN7nyudQg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 22"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/unitbezier": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-1.0.0.tgz",
|
||||
"integrity": "sha512-fqd515fjBmANKGGsQ286E2Wvj/XvDFpGzwJxq4CI6jMQue6Oy04uCKp+JWKF00xRTmk6cEu1jPJ9p3xqH8YWqQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/@maplibre/maplibre-gl-style-spec": {
|
||||
"version": "24.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.10.0.tgz",
|
||||
"integrity": "sha512-lichxSiagMEBBrqHF0trtMQH9RKh+9jUlIJl0qW0QHvt2H/tbvUWdE+ZzI2Jd0/pT7j/iavLonlPu7EQ/ixTOw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
|
||||
"@mapbox/unitbezier": "^1.0.0",
|
||||
"json-stringify-pretty-compact": "^4.0.0",
|
||||
"minimist": "^1.2.8",
|
||||
"quickselect": "^3.0.0",
|
||||
"tinyqueue": "^3.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"gl-style-format": "dist/gl-style-format.mjs",
|
||||
"gl-style-migrate": "dist/gl-style-migrate.mjs",
|
||||
"gl-style-validate": "dist/gl-style-validate.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz",
|
||||
@@ -950,7 +985,6 @@
|
||||
"version": "3.9.3",
|
||||
"resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.3.tgz",
|
||||
"integrity": "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@polka/url": {
|
||||
@@ -1274,7 +1308,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/rbush/-/rbush-4.0.0.tgz",
|
||||
"integrity": "sha512-+N+2H39P8X+Hy1I5mC6awlTX54k3FhiUmvt7HWzGJZvF+syUAAxP/stwppS8JE84YHqFgRMv6fCy31202CMFxQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vitejs/plugin-vue": {
|
||||
@@ -1558,7 +1591,6 @@
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@zarrita/storage/-/storage-0.2.0.tgz",
|
||||
"integrity": "sha512-855ZXqtnds7spnT8vNvD+MXa3QExP1m2GqShe8yt7uZXHnQLgJHgkpVwFjE1B0KDDRO0ki09hmk6OboTaIfPsQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"reference-spec-reader": "^0.2.0",
|
||||
@@ -1868,7 +1900,6 @@
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.2.tgz",
|
||||
"integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
@@ -1940,7 +1971,6 @@
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz",
|
||||
"integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
@@ -1972,7 +2002,6 @@
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/geotiff/-/geotiff-3.0.5.tgz",
|
||||
"integrity": "sha512-OWcL9S9+yDZ6iAlXMt32T1iwUApJM8UiD47xbm6ZP1h33d10fqkPs14EG/ttT5EnefpZSx3G15iDFC5FxUNUwA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@petamoriken/float16": "^3.9.3",
|
||||
@@ -2141,6 +2170,12 @@
|
||||
"node": "^22.22.2 || ^24.15.0 || >=26.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/json-stringify-pretty-compact": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz",
|
||||
"integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/json5": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||
@@ -2165,7 +2200,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz",
|
||||
"integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/lightningcss": {
|
||||
@@ -2461,6 +2495,12 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/mapbox-to-css-font": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mapbox-to-css-font/-/mapbox-to-css-font-3.2.0.tgz",
|
||||
"integrity": "sha512-kvsEfzvLik34BiFj+S19bv5d70l9qSdkUzrq99dvZ9d5POaLyB4vJMQmq3BoJ5D6lFG1GYnMM7o7cm5Jh8YEEg==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/memorystream": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
|
||||
@@ -2470,6 +2510,15 @@
|
||||
"node": ">= 0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/mrmime": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
|
||||
@@ -2572,7 +2621,6 @@
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/numcodecs/-/numcodecs-0.3.2.tgz",
|
||||
"integrity": "sha512-6YSPnmZgg0P87jnNhi3s+FVLOcIn3y+1CTIgUulA3IdASzK9fJM87sUFkpyA+be9GibGRaST2wCgkD+6U+fWKw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fflate": "^0.8.0"
|
||||
@@ -2603,7 +2651,6 @@
|
||||
"version": "10.9.0",
|
||||
"resolved": "https://registry.npmjs.org/ol/-/ol-10.9.0.tgz",
|
||||
"integrity": "sha512-svbbgVQUmEHaKpLQ8kRySojs59Brvgl2zYIrqG9eQNXGfsbi55rQasZIDpwpQzDL6OlzrUb0H4hQaiX9wDoGmA==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@types/rbush": "4.0.0",
|
||||
@@ -2618,6 +2665,22 @@
|
||||
"url": "https://opencollective.com/openlayers"
|
||||
}
|
||||
},
|
||||
"node_modules/ol-mapbox-style": {
|
||||
"version": "13.4.1",
|
||||
"resolved": "https://registry.npmjs.org/ol-mapbox-style/-/ol-mapbox-style-13.4.1.tgz",
|
||||
"integrity": "sha512-da4FKZUXoXMzK5ADeRHAXzd3bTeiKg/Y9LBOTB6qNTP62MQm93y6ISrIXzOS9atfGgQMEHJ2pCgP272IMeZCXA==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@maplibre/maplibre-gl-style-spec": "^24.4.1",
|
||||
"mapbox-to-css-font": "^3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ahocevar"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ol": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/open": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz",
|
||||
@@ -2643,14 +2706,12 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
||||
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
|
||||
"dev": true,
|
||||
"license": "(MIT AND Zlib)"
|
||||
},
|
||||
"node_modules/parse-headers": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.6.tgz",
|
||||
"integrity": "sha512-Tz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/path-browserify": {
|
||||
@@ -2681,7 +2742,6 @@
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.1.tgz",
|
||||
"integrity": "sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"resolve-protobuf-schema": "^2.1.0"
|
||||
@@ -2776,14 +2836,12 @@
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.1.tgz",
|
||||
"integrity": "sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/quick-lru": {
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.2.tgz",
|
||||
"integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -2796,14 +2854,12 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz",
|
||||
"integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/rbush": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rbush/-/rbush-4.0.1.tgz",
|
||||
"integrity": "sha512-IP0UpfeWQujYC8Jg162rMNc01Rf0gWMMAb2Uxus/Q0qOFw4lCcq6ZnQEZwUoJqWyUGJ9th7JjwI4yIWo+uvoAQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"quickselect": "^3.0.0"
|
||||
@@ -2842,14 +2898,12 @@
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/reference-spec-reader/-/reference-spec-reader-0.2.0.tgz",
|
||||
"integrity": "sha512-q0mfCi5yZSSHXpCyxjgQeaORq3tvDsxDyzaadA/5+AbAUwRyRuuTh0aRQuE/vAOt/qzzxidJ5iDeu1cLHaNBlQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/resolve-protobuf-schema": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz",
|
||||
"integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"protocol-buffers-schema": "^3.3.1"
|
||||
@@ -3417,6 +3471,12 @@
|
||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyqueue": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz",
|
||||
"integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/totalist": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
|
||||
@@ -3476,7 +3536,6 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unzipit/-/unzipit-2.0.0.tgz",
|
||||
"integrity": "sha512-DVeVIWUZCAQPNzm5sB0hpsG1GygTTdBnzNtYYEpInkttx5evkyqRgZi6rTczoySqp8hO5jHVKzrH0f23X8FZLg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@@ -3779,7 +3838,6 @@
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz",
|
||||
"integrity": "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/which": {
|
||||
@@ -3819,7 +3877,6 @@
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.10.2.tgz",
|
||||
"integrity": "sha512-RqM+2o1RYs6T8+3DzDSoTRAUfrvaejbVHcp3+thnAtDKo8LskR+HomLajEy5UjTz24rpka7AxVBRR3g2wTUkJA==",
|
||||
"dev": true,
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
@@ -3833,7 +3890,6 @@
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/zarrita/-/zarrita-0.7.3.tgz",
|
||||
"integrity": "sha512-wChTQ1Ox75INoQCzKAfLWAfB70JJ4KjdW8Sz5x4ZWrFB4Dw+YZdnxHTL0xSdsrB9EmKSeK7fS1Y+I2ibhfGbkw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@zarrita/storage": "^0.2.0",
|
||||
@@ -3844,7 +3900,6 @@
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.2.0.tgz",
|
||||
"integrity": "sha512-oyPnDa1X5c13+Y7mA/FDMNJrn4S8UNBe0KCqtDmor40Re7ALrPN6npFwyYVRRh+PqozZQdeg23QtbcamZnG5rA==",
|
||||
"dev": true,
|
||||
"license": "MIT AND BSD-3-Clause"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"@ztimson/css-utils": "^1.3.5",
|
||||
"@ztimson/utils": "^0.29.5",
|
||||
"ol-mapbox-style": "^13.4.1",
|
||||
"vue": "^3.5.38"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -24,9 +25,9 @@
|
||||
"typescript": "~6.0.0",
|
||||
"vite": "^8.0.16",
|
||||
"vite-plugin-vue-devtools": "^8.1.2",
|
||||
"vue": "^3.5.38",
|
||||
"vue-chartjs": "^5.3.3",
|
||||
"vue-tsc": "^3.3.5",
|
||||
"vue": "^3.5.38"
|
||||
"vue-tsc": "^3.3.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^22.18.0 || >=24.12.0"
|
||||
|
||||
370
client/public/dark-theme.json
Normal file
370
client/public/dark-theme.json
Normal file
@@ -0,0 +1,370 @@
|
||||
{
|
||||
"version": 8,
|
||||
"name": "Smooth Dark",
|
||||
"sources": {
|
||||
"osm": {
|
||||
"type": "vector",
|
||||
"tiles": ["https://tiles.zakscode.com/data/osm/{z}/{x}/{y}.pbf"],
|
||||
"maxzoom": 14
|
||||
}
|
||||
},
|
||||
"glyphs": "http://localhost:8080/fonts/{fontstack}/{range}.pbf",
|
||||
"layers": [
|
||||
{
|
||||
"id": "background",
|
||||
"type": "background",
|
||||
"paint": { "background-color": "#2b2b2e" }
|
||||
},
|
||||
{
|
||||
"id": "water",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "water",
|
||||
"paint": { "fill-color": "#1e2832" }
|
||||
},
|
||||
{
|
||||
"id": "landcover-grass",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "landcover",
|
||||
"filter": ["==", "class", "grass"],
|
||||
"paint": { "fill-color": "#2a3028", "fill-opacity": 0.6 }
|
||||
},
|
||||
{
|
||||
"id": "landcover-wood",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "landcover",
|
||||
"filter": ["==", "class", "wood"],
|
||||
"paint": { "fill-color": "#262e24", "fill-opacity": 0.5 }
|
||||
},
|
||||
{
|
||||
"id": "landuse-park",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "landuse",
|
||||
"filter": ["==", "class", "park"],
|
||||
"paint": { "fill-color": "#283028", "fill-opacity": 0.7 }
|
||||
},
|
||||
{
|
||||
"id": "landuse-cemetery",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "landuse",
|
||||
"filter": ["==", "class", "cemetery"],
|
||||
"paint": { "fill-color": "#2c2e2a", "fill-opacity": 0.7 }
|
||||
},
|
||||
{
|
||||
"id": "landuse-hospital",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "landuse",
|
||||
"filter": ["==", "class", "hospital"],
|
||||
"paint": { "fill-color": "#322828", "fill-opacity": 0.6 }
|
||||
},
|
||||
{
|
||||
"id": "landuse-school",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "landuse",
|
||||
"filter": ["==", "class", "school"],
|
||||
"paint": { "fill-color": "#302c28", "fill-opacity": 0.6 }
|
||||
},
|
||||
{
|
||||
"id": "building",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "building",
|
||||
"minzoom": 13,
|
||||
"paint": {
|
||||
"fill-color": "#333336",
|
||||
"fill-opacity": { "stops": [[13, 0.3], [16, 0.6]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "boundary-country",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "boundary",
|
||||
"filter": ["==", "admin_level", 2],
|
||||
"paint": {
|
||||
"line-color": "#4a4448",
|
||||
"line-width": { "stops": [[2, 0.5], [6, 1.5], [10, 2.5]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "boundary-state",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "boundary",
|
||||
"filter": ["==", "admin_level", 4],
|
||||
"minzoom": 4,
|
||||
"paint": {
|
||||
"line-color": "#3e3a3c",
|
||||
"line-width": { "stops": [[4, 0.3], [8, 1]] },
|
||||
"line-dasharray": [3, 2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "waterway",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "waterway",
|
||||
"paint": {
|
||||
"line-color": "#1e2832",
|
||||
"line-width": { "stops": [[8, 0.5], [14, 2]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "tunnel",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["==", "brunnel", "tunnel"], ["in", "class", "motorway", "trunk", "primary", "secondary", "tertiary"]],
|
||||
"paint": {
|
||||
"line-color": "#2e2e30",
|
||||
"line-width": { "stops": [[8, 0.5], [14, 4], [18, 10]] },
|
||||
"line-dasharray": [3, 3]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "road-motorway",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["==", "class", "motorway"], ["!=", "brunnel", "tunnel"]],
|
||||
"paint": {
|
||||
"line-color": "#4a4240",
|
||||
"line-width": { "stops": [[5, 0.5], [10, 2], [14, 5], [18, 12]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "road-trunk",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["==", "class", "trunk"], ["!=", "brunnel", "tunnel"]],
|
||||
"paint": {
|
||||
"line-color": "#443e3c",
|
||||
"line-width": { "stops": [[6, 0.4], [10, 1.5], [14, 4], [18, 10]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "road-primary",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["==", "class", "primary"], ["!=", "brunnel", "tunnel"]],
|
||||
"paint": {
|
||||
"line-color": "#3e3a38",
|
||||
"line-width": { "stops": [[7, 0.3], [10, 1], [14, 3.5], [18, 9]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "road-secondary",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["==", "class", "secondary"], ["!=", "brunnel", "tunnel"]],
|
||||
"paint": {
|
||||
"line-color": "#383636",
|
||||
"line-width": { "stops": [[8, 0.3], [12, 1], [14, 3], [18, 7]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "road-tertiary",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["==", "class", "tertiary"], ["!=", "brunnel", "tunnel"]],
|
||||
"paint": {
|
||||
"line-color": "#353334",
|
||||
"line-width": { "stops": [[9, 0.2], [14, 2], [18, 5]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "road-minor",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["in", "class", "minor", "service"], ["!=", "brunnel", "tunnel"]],
|
||||
"minzoom": 12,
|
||||
"paint": {
|
||||
"line-color": "#333234",
|
||||
"line-width": { "stops": [[12, 0.3], [16, 2], [18, 4]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "road-path",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["==", "class", "path"],
|
||||
"minzoom": 14,
|
||||
"paint": {
|
||||
"line-color": "#3a3638",
|
||||
"line-width": 1,
|
||||
"line-dasharray": [4, 2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rail",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["==", "class", "rail"],
|
||||
"minzoom": 10,
|
||||
"paint": {
|
||||
"line-color": "#3c3a3e",
|
||||
"line-width": { "stops": [[10, 0.5], [14, 1.5]] },
|
||||
"line-dasharray": [5, 5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "bridge",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["==", "brunnel", "bridge"], ["in", "class", "motorway", "trunk", "primary", "secondary", "tertiary"]],
|
||||
"paint": {
|
||||
"line-color": "#403c3a",
|
||||
"line-width": { "stops": [[8, 0.5], [14, 4], [18, 10]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "aero-runway",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "aeroway",
|
||||
"filter": ["==", "class", "runway"],
|
||||
"minzoom": 11,
|
||||
"paint": {
|
||||
"line-color": "#3a383c",
|
||||
"line-width": { "stops": [[11, 2], [16, 12]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "aero-taxiway",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "aeroway",
|
||||
"filter": ["==", "class", "taxiway"],
|
||||
"minzoom": 12,
|
||||
"paint": {
|
||||
"line-color": "#3a383c",
|
||||
"line-width": { "stops": [[12, 0.5], [16, 4]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "label-water",
|
||||
"type": "symbol",
|
||||
"source": "osm",
|
||||
"source-layer": "water_name",
|
||||
"layout": {
|
||||
"text-field": "{name}",
|
||||
"text-font": ["Noto Sans Regular"],
|
||||
"text-size": { "stops": [[3, 10], [8, 14]] },
|
||||
"text-letter-spacing": 0.1
|
||||
},
|
||||
"paint": {
|
||||
"text-color": "#4a6068",
|
||||
"text-halo-color": "#2b2b2e",
|
||||
"text-halo-width": 1.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "label-road",
|
||||
"type": "symbol",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation_name",
|
||||
"minzoom": 13,
|
||||
"layout": {
|
||||
"text-field": "{name}",
|
||||
"text-font": ["Noto Sans Regular"],
|
||||
"text-size": { "stops": [[13, 10], [16, 13]] },
|
||||
"symbol-placement": "line",
|
||||
"text-rotation-alignment": "map"
|
||||
},
|
||||
"paint": {
|
||||
"text-color": "#6a6268",
|
||||
"text-halo-color": "#2b2b2e",
|
||||
"text-halo-width": 1.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "label-place-city",
|
||||
"type": "symbol",
|
||||
"source": "osm",
|
||||
"source-layer": "place",
|
||||
"filter": ["==", "class", "city"],
|
||||
"layout": {
|
||||
"text-field": "{name}",
|
||||
"text-font": ["Noto Sans Regular"],
|
||||
"text-size": { "stops": [[4, 11], [8, 16], [12, 20]] },
|
||||
"text-anchor": "center"
|
||||
},
|
||||
"paint": {
|
||||
"text-color": "#a0969a",
|
||||
"text-halo-color": "#2b2b2e",
|
||||
"text-halo-width": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "label-place-town",
|
||||
"type": "symbol",
|
||||
"source": "osm",
|
||||
"source-layer": "place",
|
||||
"filter": ["==", "class", "town"],
|
||||
"minzoom": 7,
|
||||
"layout": {
|
||||
"text-field": "{name}",
|
||||
"text-font": ["Noto Sans Regular"],
|
||||
"text-size": { "stops": [[7, 10], [12, 15]] },
|
||||
"text-anchor": "center"
|
||||
},
|
||||
"paint": {
|
||||
"text-color": "#8a8088",
|
||||
"text-halo-color": "#2b2b2e",
|
||||
"text-halo-width": 1.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "label-place-village",
|
||||
"type": "symbol",
|
||||
"source": "osm",
|
||||
"source-layer": "place",
|
||||
"filter": ["==", "class", "village"],
|
||||
"minzoom": 10,
|
||||
"layout": {
|
||||
"text-field": "{name}",
|
||||
"text-font": ["Noto Sans Regular"],
|
||||
"text-size": { "stops": [[10, 9], [14, 13]] },
|
||||
"text-anchor": "center"
|
||||
},
|
||||
"paint": {
|
||||
"text-color": "#787078",
|
||||
"text-halo-color": "#2b2b2e",
|
||||
"text-halo-width": 1.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "label-country",
|
||||
"type": "symbol",
|
||||
"source": "osm",
|
||||
"source-layer": "place",
|
||||
"filter": ["==", "class", "country"],
|
||||
"layout": {
|
||||
"text-field": "{name}",
|
||||
"text-font": ["Noto Sans Regular"],
|
||||
"text-size": { "stops": [[2, 10], [5, 16]] },
|
||||
"text-transform": "uppercase",
|
||||
"text-letter-spacing": 0.15
|
||||
},
|
||||
"paint": {
|
||||
"text-color": "#908690",
|
||||
"text-halo-color": "#2b2b2e",
|
||||
"text-halo-width": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
370
client/public/light-theme.json
Normal file
370
client/public/light-theme.json
Normal file
@@ -0,0 +1,370 @@
|
||||
{
|
||||
"version": 8,
|
||||
"name": "Smooth Light",
|
||||
"sources": {
|
||||
"osm": {
|
||||
"type": "vector",
|
||||
"tiles": ["https://tiles.zakscode.com/data/osm/{z}/{x}/{y}.pbf"],
|
||||
"maxzoom": 14
|
||||
}
|
||||
},
|
||||
"glyphs": "http://localhost:8080/fonts/{fontstack}/{range}.pbf",
|
||||
"layers": [
|
||||
{
|
||||
"id": "background",
|
||||
"type": "background",
|
||||
"paint": { "background-color": "#f2efe9" }
|
||||
},
|
||||
{
|
||||
"id": "water",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "water",
|
||||
"paint": { "fill-color": "#c8d7d5" }
|
||||
},
|
||||
{
|
||||
"id": "landcover-grass",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "landcover",
|
||||
"filter": ["==", "class", "grass"],
|
||||
"paint": { "fill-color": "#e0e8d8", "fill-opacity": 0.6 }
|
||||
},
|
||||
{
|
||||
"id": "landcover-wood",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "landcover",
|
||||
"filter": ["==", "class", "wood"],
|
||||
"paint": { "fill-color": "#d4dfc4", "fill-opacity": 0.5 }
|
||||
},
|
||||
{
|
||||
"id": "landuse-park",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "landuse",
|
||||
"filter": ["==", "class", "park"],
|
||||
"paint": { "fill-color": "#dce8d0", "fill-opacity": 0.7 }
|
||||
},
|
||||
{
|
||||
"id": "landuse-cemetery",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "landuse",
|
||||
"filter": ["==", "class", "cemetery"],
|
||||
"paint": { "fill-color": "#e0e4dd", "fill-opacity": 0.7 }
|
||||
},
|
||||
{
|
||||
"id": "landuse-hospital",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "landuse",
|
||||
"filter": ["==", "class", "hospital"],
|
||||
"paint": { "fill-color": "#f0e4e4", "fill-opacity": 0.6 }
|
||||
},
|
||||
{
|
||||
"id": "landuse-school",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "landuse",
|
||||
"filter": ["==", "class", "school"],
|
||||
"paint": { "fill-color": "#eae0d8", "fill-opacity": 0.6 }
|
||||
},
|
||||
{
|
||||
"id": "building",
|
||||
"type": "fill",
|
||||
"source": "osm",
|
||||
"source-layer": "building",
|
||||
"minzoom": 13,
|
||||
"paint": {
|
||||
"fill-color": "#dfdbd7",
|
||||
"fill-opacity": { "stops": [[13, 0.3], [16, 0.6]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "boundary-country",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "boundary",
|
||||
"filter": ["==", "admin_level", 2],
|
||||
"paint": {
|
||||
"line-color": "#c4b8aa",
|
||||
"line-width": { "stops": [[2, 0.5], [6, 1.5], [10, 2.5]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "boundary-state",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "boundary",
|
||||
"filter": ["==", "admin_level", 4],
|
||||
"minzoom": 4,
|
||||
"paint": {
|
||||
"line-color": "#d0c8bc",
|
||||
"line-width": { "stops": [[4, 0.3], [8, 1]] },
|
||||
"line-dasharray": [3, 2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "waterway",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "waterway",
|
||||
"paint": {
|
||||
"line-color": "#c8d7d5",
|
||||
"line-width": { "stops": [[8, 0.5], [14, 2]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "tunnel",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["==", "brunnel", "tunnel"], ["in", "class", "motorway", "trunk", "primary", "secondary", "tertiary"]],
|
||||
"paint": {
|
||||
"line-color": "#e8e4e0",
|
||||
"line-width": { "stops": [[8, 0.5], [14, 4], [18, 10]] },
|
||||
"line-dasharray": [3, 3]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "road-motorway",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["==", "class", "motorway"], ["!=", "brunnel", "tunnel"]],
|
||||
"paint": {
|
||||
"line-color": "#e0d0b8",
|
||||
"line-width": { "stops": [[5, 0.5], [10, 2], [14, 5], [18, 12]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "road-trunk",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["==", "class", "trunk"], ["!=", "brunnel", "tunnel"]],
|
||||
"paint": {
|
||||
"line-color": "#e4d8c4",
|
||||
"line-width": { "stops": [[6, 0.4], [10, 1.5], [14, 4], [18, 10]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "road-primary",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["==", "class", "primary"], ["!=", "brunnel", "tunnel"]],
|
||||
"paint": {
|
||||
"line-color": "#e8dfd4",
|
||||
"line-width": { "stops": [[7, 0.3], [10, 1], [14, 3.5], [18, 9]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "road-secondary",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["==", "class", "secondary"], ["!=", "brunnel", "tunnel"]],
|
||||
"paint": {
|
||||
"line-color": "#ece6dc",
|
||||
"line-width": { "stops": [[8, 0.3], [12, 1], [14, 3], [18, 7]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "road-tertiary",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["==", "class", "tertiary"], ["!=", "brunnel", "tunnel"]],
|
||||
"paint": {
|
||||
"line-color": "#f0ebe4",
|
||||
"line-width": { "stops": [[9, 0.2], [14, 2], [18, 5]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "road-minor",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["in", "class", "minor", "service"], ["!=", "brunnel", "tunnel"]],
|
||||
"minzoom": 12,
|
||||
"paint": {
|
||||
"line-color": "#f0ebe4",
|
||||
"line-width": { "stops": [[12, 0.3], [16, 2], [18, 4]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "road-path",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["==", "class", "path"],
|
||||
"minzoom": 14,
|
||||
"paint": {
|
||||
"line-color": "#d8d0c4",
|
||||
"line-width": 1,
|
||||
"line-dasharray": [4, 2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rail",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["==", "class", "rail"],
|
||||
"minzoom": 10,
|
||||
"paint": {
|
||||
"line-color": "#d0ccc4",
|
||||
"line-width": { "stops": [[10, 0.5], [14, 1.5]] },
|
||||
"line-dasharray": [5, 5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "bridge",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation",
|
||||
"filter": ["all", ["==", "brunnel", "bridge"], ["in", "class", "motorway", "trunk", "primary", "secondary", "tertiary"]],
|
||||
"paint": {
|
||||
"line-color": "#e0d8cc",
|
||||
"line-width": { "stops": [[8, 0.5], [14, 4], [18, 10]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "aero-runway",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "aeroway",
|
||||
"filter": ["==", "class", "runway"],
|
||||
"minzoom": 11,
|
||||
"paint": {
|
||||
"line-color": "#d8d4cc",
|
||||
"line-width": { "stops": [[11, 2], [16, 12]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "aero-taxiway",
|
||||
"type": "line",
|
||||
"source": "osm",
|
||||
"source-layer": "aeroway",
|
||||
"filter": ["==", "class", "taxiway"],
|
||||
"minzoom": 12,
|
||||
"paint": {
|
||||
"line-color": "#d8d4cc",
|
||||
"line-width": { "stops": [[12, 0.5], [16, 4]] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "label-water",
|
||||
"type": "symbol",
|
||||
"source": "osm",
|
||||
"source-layer": "water_name",
|
||||
"layout": {
|
||||
"text-field": "{name}",
|
||||
"text-font": ["Noto Sans Regular"],
|
||||
"text-size": { "stops": [[3, 10], [8, 14]] },
|
||||
"text-letter-spacing": 0.1
|
||||
},
|
||||
"paint": {
|
||||
"text-color": "#8aacaa",
|
||||
"text-halo-color": "#f2efe9",
|
||||
"text-halo-width": 1.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "label-road",
|
||||
"type": "symbol",
|
||||
"source": "osm",
|
||||
"source-layer": "transportation_name",
|
||||
"minzoom": 13,
|
||||
"layout": {
|
||||
"text-field": "{name}",
|
||||
"text-font": ["Noto Sans Regular"],
|
||||
"text-size": { "stops": [[13, 10], [16, 13]] },
|
||||
"symbol-placement": "line",
|
||||
"text-rotation-alignment": "map"
|
||||
},
|
||||
"paint": {
|
||||
"text-color": "#9c9284",
|
||||
"text-halo-color": "#f2efe9",
|
||||
"text-halo-width": 1.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "label-place-city",
|
||||
"type": "symbol",
|
||||
"source": "osm",
|
||||
"source-layer": "place",
|
||||
"filter": ["==", "class", "city"],
|
||||
"layout": {
|
||||
"text-field": "{name}",
|
||||
"text-font": ["Noto Sans Regular"],
|
||||
"text-size": { "stops": [[4, 11], [8, 16], [12, 20]] },
|
||||
"text-anchor": "center"
|
||||
},
|
||||
"paint": {
|
||||
"text-color": "#6b6156",
|
||||
"text-halo-color": "#f2efe9",
|
||||
"text-halo-width": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "label-place-town",
|
||||
"type": "symbol",
|
||||
"source": "osm",
|
||||
"source-layer": "place",
|
||||
"filter": ["==", "class", "town"],
|
||||
"minzoom": 7,
|
||||
"layout": {
|
||||
"text-field": "{name}",
|
||||
"text-font": ["Noto Sans Regular"],
|
||||
"text-size": { "stops": [[7, 10], [12, 15]] },
|
||||
"text-anchor": "center"
|
||||
},
|
||||
"paint": {
|
||||
"text-color": "#7a7068",
|
||||
"text-halo-color": "#f2efe9",
|
||||
"text-halo-width": 1.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "label-place-village",
|
||||
"type": "symbol",
|
||||
"source": "osm",
|
||||
"source-layer": "place",
|
||||
"filter": ["==", "class", "village"],
|
||||
"minzoom": 10,
|
||||
"layout": {
|
||||
"text-field": "{name}",
|
||||
"text-font": ["Noto Sans Regular"],
|
||||
"text-size": { "stops": [[10, 9], [14, 13]] },
|
||||
"text-anchor": "center"
|
||||
},
|
||||
"paint": {
|
||||
"text-color": "#8a8078",
|
||||
"text-halo-color": "#f2efe9",
|
||||
"text-halo-width": 1.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "label-country",
|
||||
"type": "symbol",
|
||||
"source": "osm",
|
||||
"source-layer": "place",
|
||||
"filter": ["==", "class", "country"],
|
||||
"layout": {
|
||||
"text-field": "{name}",
|
||||
"text-font": ["Noto Sans Regular"],
|
||||
"text-size": { "stops": [[2, 10], [5, 16]] },
|
||||
"text-transform": "uppercase",
|
||||
"text-letter-spacing": 0.15
|
||||
},
|
||||
"paint": {
|
||||
"text-color": "#8a7e72",
|
||||
"text-halo-color": "#f2efe9",
|
||||
"text-halo-width": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
||||
|
Before Width: | Height: | Size: 276 B |
@@ -108,47 +108,75 @@ onMounted(async () => {
|
||||
<div class="stat" @click="openGraph?.('heat_index')">
|
||||
<span class="stat-label">Feels Like</span>
|
||||
<div v-if="!data" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading/></div>
|
||||
<span v-else class="stat-value">{{ ~~(data.heat_index) }}<span class="fg-muted">°C</span></span>
|
||||
<span v-else class="stat-value">
|
||||
<template v-if="data.heat_index == null">—</template>
|
||||
<template v-else>{{ ~~(data.heat_index) }}<span class="fg-muted">°C</span></template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="stat" @click="openGraph?.('humidity')">
|
||||
<span class="stat-label">Humidity</span>
|
||||
<div v-if="!data" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading/></div>
|
||||
<span v-else class="stat-value">{{ Math.round(data.humidity) }}%</span>
|
||||
<span v-else class="stat-value">
|
||||
<template v-if="data.humidity == null">—</template>
|
||||
<template v-else>{{ Math.round(data.humidity) }}<span class="fg-muted">%</span></template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="stat" @click="openGraph?.('precipitation_chance')">
|
||||
<span class="stat-label">Rain</span>
|
||||
<div v-if="!data" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading /></div>
|
||||
<span v-else class="stat-value">
|
||||
<template v-if="data.raining == null">—</template>
|
||||
<template v-else-if="data.raining">Raining</template>
|
||||
<template v-else>{{data.precipitation_chance}}<span class="fg-muted">%</span></template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="stat" @click="openGraph?.('clouds')">
|
||||
<span class="stat-label">Cloud Cover</span>
|
||||
<div v-if="!data" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading/></div>
|
||||
<span v-else class="stat-value">{{ Math.round(data.clouds) }}%</span>
|
||||
</div>
|
||||
<div class="stat" @click="openGraph?.('pressure_hpa')">
|
||||
<span class="stat-label">Pressure</span>
|
||||
<div v-if="!data" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading/></div>
|
||||
<span v-else class="stat-value">{{ data.pressure_hpa?.toFixed(1) }} <span class="fg-muted">hPa</span></span>
|
||||
<span v-else class="stat-value">
|
||||
<template v-if="data.clouds == null">—</template>
|
||||
<template v-else>{{ Math.round(data.clouds) }}<span class="fg-muted">%</span></template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="stat" @click="openGraph?.('pressure_slp')">
|
||||
<span class="stat-label">Sea Level</span>
|
||||
<div v-if="!data" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading/></div>
|
||||
<span v-else class="stat-value">{{ data.pressure_slp?.toFixed(1) }} <span class="fg-muted">({{ getPressureTrend(data.pressure_trend) }})</span></span>
|
||||
<span v-else class="stat-value">
|
||||
<template v-if="data.pressure_slp == null">—</template>
|
||||
<template v-else>{{ data.pressure_slp?.toFixed(1) }} <span class="fg-muted">({{ getPressureTrend(data.pressure_trend) }})</span></template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="stat" @click="openGraph?.('vapor_pressure_deficit')">
|
||||
<span class="stat-label">VPD KPA</span>
|
||||
<div v-if="!data" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading/></div>
|
||||
<span v-else class="stat-value">{{ data.vapor_pressure_deficit?.toFixed(2) }} <span class="fg-muted">kPa</span></span>
|
||||
<span v-else class="stat-value">
|
||||
<template v-if="data.vapor_pressure_deficit == null">—</template>
|
||||
<template v-else>{{ data.vapor_pressure_deficit?.toFixed(2) }} <span class="fg-muted">kPa</span></template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="stat" @click="openGraph?.('air_quality')">
|
||||
<span class="stat-label">Air Quality</span>
|
||||
<div v-if="!data" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading/></div>
|
||||
<span v-else class="stat-value">{{ data.air_quality }} <span class="fg-muted">/ 500</span></span>
|
||||
<span v-else class="stat-value">
|
||||
<template v-if="data.air_quality == null">—</template>
|
||||
<template v-else>{{ data.air_quality }} <span class="fg-muted">/ 500</span></template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="stat" @click="openGraph?.('air_quality_ohms')">
|
||||
<span class="stat-label">Gas Resistance</span>
|
||||
<div v-if="!data" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading/></div>
|
||||
<span v-else class="stat-value">{{ data.air_quality_ohms }} <span class="fg-muted">Ω</span></span>
|
||||
<span v-else class="stat-value">
|
||||
<template v-if="data.air_quality_ohms == null">—</template>
|
||||
<template v-else>{{ data.air_quality_ohms }} <span class="fg-muted">Ω</span></template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="stat" @click="openGraph?.('visibility')">
|
||||
<span class="stat-label">Visibility</span>
|
||||
<div v-if="!data" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading/></div>
|
||||
<span v-else class="stat-value">{{ data.visibility?.toFixed(1) }} <span class="fg-muted">km</span></span>
|
||||
<span v-else class="stat-value">
|
||||
<template v-if="data.visibility == null">—</template>
|
||||
<template v-else>{{ data.visibility?.toFixed(1) }} <span class="fg-muted">km</span></template>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -73,9 +73,9 @@ onMounted(async () => {
|
||||
<span>↑{{ ~~(d.temperature_max) + '°' || '—' }}</span>
|
||||
<span class="day-low">↓{{ ~~(d.temperature_min) + '°' || '—' }}</span>
|
||||
</div>
|
||||
<div class="day-humid">🌡️ {{ ~~(d.humidity) || 0 }}%</div>
|
||||
<div class="day-wind">🍃 {{ ~~(d.wind_gusts as any) || 0 }} Kph ({{dir(d.wind_dir as any)}})</div>
|
||||
<div class="day-rain">🌧️ {{ d.precipitation_chance || 0 }}% ({{ (d.precipitation as any || 0).toFixed(1) }}mm)</div>
|
||||
<div class="day-humid align-x">🌡️ {{ ~~(d.humidity) || 0 }}%</div>
|
||||
<div class="day-wind align-x">🍃 {{ ~~(d.wind_gusts as any) || 0 }} Kph ({{dir(d.wind_dir as any)}})</div>
|
||||
<div class="day-rain align-x">🌧️ {{ d.precipitation_chance || 0 }}% ({{ (d.precipitation as any || 0).toFixed(1) }}mm)</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="strip">
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { AirTrafficLayer } from '@/services/adsb.ts'
|
||||
import { AISLayer } from '@/services/ais.ts'
|
||||
import {api} from '@/services/api.ts';
|
||||
import {RangeLayer} from '@/services/range.ts';
|
||||
import VectorTileLayer from 'ol/layer/VectorTile';
|
||||
import VectorTileSource from 'ol/source/VectorTile';
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { api } from '@/services/api.ts'
|
||||
import { RangeLayer } from '@/services/range.ts'
|
||||
import VectorTileLayer from 'ol/layer/VectorTile'
|
||||
import { onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import Map from 'ol/Map'
|
||||
import View from 'ol/View'
|
||||
import TileLayer from 'ol/layer/Tile'
|
||||
@@ -18,27 +17,23 @@ import CircleGeom from 'ol/geom/Circle'
|
||||
import { defaults as defaultInteractions } from 'ol/interaction'
|
||||
import { fromLonLat, toLonLat } from 'ol/proj'
|
||||
import { Style, Fill, Stroke, Circle as CircleStyle } from 'ol/style'
|
||||
import { applyStyle } from 'ol-mapbox-style'
|
||||
import 'ol/ol.css'
|
||||
|
||||
const current = ref({latitude: 0, longitude: 0});
|
||||
const props = defineProps<{ dark: boolean }>()
|
||||
const mapEl = ref<HTMLDivElement>()
|
||||
const current = ref({ latitude: 0, longitude: 0 })
|
||||
const props = defineProps<{ dark: boolean }>()
|
||||
const mapEl = ref<HTMLDivElement>()
|
||||
const showOverlays = ref(false)
|
||||
const atActive = ref(true)
|
||||
|
||||
const NM = 1852
|
||||
|
||||
const radarFrames = ref<{ path: string; time: number }[]>([])
|
||||
const radarFrameIndex = ref(0)
|
||||
const radarPath = computed(() => radarFrames.value[radarFrameIndex.value]?.path ?? '')
|
||||
const nowcastStartIndex = ref(0)
|
||||
|
||||
const showWind = ref(false)
|
||||
const windSrc = ref('')
|
||||
|
||||
const OVERLAYS = [
|
||||
{ id: 'rain', label: 'Rain', icon: '🌧️', url: () => `https://tilecache.rainviewer.com${radarPath.value}/256/{z}/{x}/{y}/2/1_1.png` },
|
||||
{ id: 'wind', label: 'Wind', icon: '💨', url: () => '' },
|
||||
{ id: 'rain', label: 'Rain', icon: '🌧️' },
|
||||
{ id: 'wind', label: 'Wind', icon: '💨' },
|
||||
]
|
||||
|
||||
const activeOverlays = ref<Set<string>>(new Set(['rain']))
|
||||
@@ -56,43 +51,65 @@ function buildWindSrc(lat: number, lon: number, zoom: number) {
|
||||
}
|
||||
|
||||
function syncWindSrc() {
|
||||
const view = map.getView()
|
||||
const view = map.getView()
|
||||
const center: any = toLonLat(view.getCenter()!)
|
||||
windSrc.value = buildWindSrc(center[1], center[0], view.getZoom() ?? 8)
|
||||
}
|
||||
|
||||
async function fetchRadarFrames() {
|
||||
const res = await fetch('https://api.rainviewer.com/public/weather-maps.json')
|
||||
const data = await res.json()
|
||||
const past = data.radar.past ?? []
|
||||
const nowcast = data.radar.nowcast ?? []
|
||||
radarFrames.value = [...past, ...nowcast]
|
||||
nowcastStartIndex.value = past.length
|
||||
function showWindOverlay() {
|
||||
syncWindSrc()
|
||||
showWind.value = true
|
||||
map.getInteractions().forEach(i => i.setActive(false))
|
||||
}
|
||||
|
||||
function buildRainSource(url: string): XYZ {
|
||||
return new XYZ({
|
||||
url,
|
||||
attributions: '',
|
||||
maxZoom: 7,
|
||||
tileLoadFunction: (tile: any, src: string) => {
|
||||
const img = tile.getImage()
|
||||
img.onerror = () => tile.setState(3)
|
||||
img.src = src
|
||||
},
|
||||
})
|
||||
function hideWindOverlay() {
|
||||
showWind.value = false
|
||||
map.getInteractions().forEach(i => i.setActive(true))
|
||||
}
|
||||
|
||||
function seekRadar(index: number) {
|
||||
radarFrameIndex.value = index
|
||||
const layer = overlayLayers['rain']
|
||||
if (layer) {
|
||||
layer.setSource(buildRainSource(OVERLAYS.find(o => o.id === 'rain')!.url()))
|
||||
async function fetchRadarUrl(): Promise<string | null> {
|
||||
try {
|
||||
const res = await fetch('https://api.rainviewer.com/public/weather-maps.json')
|
||||
const data = await res.json()
|
||||
const past = data.radar?.past ?? []
|
||||
const latest = past[past.length - 1]
|
||||
if (!latest) return null
|
||||
return `https://tilecache.rainviewer.com${latest.path}/256/{z}/{x}/{y}/2/1_1.png`
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function buildRainLayer(url: string): TileLayer<XYZ> {
|
||||
return new TileLayer({
|
||||
source: new XYZ({
|
||||
url,
|
||||
maxZoom: 7,
|
||||
tileLoadFunction: (tile: any, src: string) => {
|
||||
const img = tile.getImage()
|
||||
img.onerror = () => tile.setState(3)
|
||||
img.src = src
|
||||
},
|
||||
}),
|
||||
opacity: 0.2,
|
||||
zIndex: 5,
|
||||
})
|
||||
}
|
||||
|
||||
async function refreshRain() {
|
||||
const url = await fetchRadarUrl()
|
||||
if (!url) return
|
||||
|
||||
if (overlayLayers['rain']) map.removeLayer(overlayLayers['rain'])
|
||||
if (!activeOverlays.value.has('rain')) return
|
||||
|
||||
const layer = buildRainLayer(url)
|
||||
overlayLayers['rain'] = layer
|
||||
map.addLayer(layer)
|
||||
}
|
||||
|
||||
function toggleAT() {
|
||||
if(atActive.value) {
|
||||
if (atActive.value) {
|
||||
aisLayer.hide()
|
||||
airTraffic.hide()
|
||||
range.hide()
|
||||
@@ -108,58 +125,42 @@ function toggleOverlay(id: string) {
|
||||
if (id === 'wind') {
|
||||
if (activeOverlays.value.has('wind')) {
|
||||
activeOverlays.value.delete('wind')
|
||||
showWind.value = false
|
||||
hideWindOverlay()
|
||||
} else {
|
||||
activeOverlays.value.add('wind')
|
||||
syncWindSrc()
|
||||
showWind.value = true
|
||||
showWindOverlay()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (activeOverlays.value.has(id)) {
|
||||
activeOverlays.value.delete(id)
|
||||
const layer = overlayLayers[id]
|
||||
if (layer) { map.removeLayer(layer); delete overlayLayers[id] }
|
||||
} else {
|
||||
activeOverlays.value.add(id)
|
||||
const layer = buildOverlayLayer(id)
|
||||
overlayLayers[id] = layer
|
||||
map.addLayer(layer)
|
||||
if (id === 'rain') {
|
||||
if (activeOverlays.value.has('rain')) {
|
||||
activeOverlays.value.delete('rain')
|
||||
if (overlayLayers['rain']) { map.removeLayer(overlayLayers['rain']); delete overlayLayers['rain'] }
|
||||
} else {
|
||||
activeOverlays.value.add('rain')
|
||||
refreshRain()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function buildBaseLayer(dark: boolean) {
|
||||
return new VectorTileLayer({
|
||||
source: new VectorTileSource({
|
||||
url: dark
|
||||
? 'https://tiles.zakscode.com/data/osm/{z}/{x}/{y}.pbf'
|
||||
: 'https://tiles.zakscode.com/styles/light/512/{z}/{x}/{y}.png',
|
||||
// ? 'https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}.png'
|
||||
// : 'https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}.png',
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
function buildOverlayLayer(id: string): TileLayer<XYZ> {
|
||||
const def = OVERLAYS.find(o => o.id === id)!
|
||||
return new TileLayer({
|
||||
source: buildRainSource(def.url()),
|
||||
opacity: 0.2,
|
||||
zIndex: 5,
|
||||
})
|
||||
const layer = new VectorTileLayer({ declutter: true })
|
||||
applyStyle(layer, dark ? '/dark-theme.json' : '/light-theme.json')
|
||||
return layer
|
||||
}
|
||||
|
||||
function buildStationLayer(lat: number, lon: number, dark: boolean): VectorLayer<VectorSource> {
|
||||
const center = fromLonLat([lon, lat])
|
||||
const source = new VectorSource()
|
||||
const center = fromLonLat([lon, lat])
|
||||
const source = new VectorSource()
|
||||
const ringStroke = dark ? 'rgba(255,255,255,0.5)' : 'rgba(0,0,0,0.35)'
|
||||
|
||||
for (const nm of [50, 100, 150, 200]) {
|
||||
const ring = new Feature(new CircleGeom(center, nm * NM))
|
||||
ring.setStyle(new Style({
|
||||
stroke: new Stroke({ color: ringStroke, width: 1, lineDash: [6, 4] }),
|
||||
fill: new Fill({ color: 'transparent' }),
|
||||
fill: new Fill({ color: 'transparent' }),
|
||||
}))
|
||||
source.addFeature(ring)
|
||||
}
|
||||
@@ -168,7 +169,7 @@ function buildStationLayer(lat: number, lon: number, dark: boolean): VectorLayer
|
||||
dot.setStyle(new Style({
|
||||
image: new CircleStyle({
|
||||
radius: 7,
|
||||
fill: new Fill({ color: dark ? '#ffffff' : '#000000' }),
|
||||
fill: new Fill({ color: dark ? '#ffffff' : '#000000' }),
|
||||
stroke: new Stroke({ color: dark ? '#000000' : '#ffffff', width: 2 }),
|
||||
}),
|
||||
}))
|
||||
@@ -178,48 +179,29 @@ function buildStationLayer(lat: number, lon: number, dark: boolean): VectorLayer
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
fetchRadarFrames().then(() => {
|
||||
radarFrameIndex.value = nowcastStartIndex.value - 1
|
||||
});
|
||||
|
||||
const position = await api.position();
|
||||
|
||||
const position = await api.position()
|
||||
const lat = position?.latitude || 0
|
||||
const lon = position?.longitude || 0
|
||||
|
||||
stationLayer = buildStationLayer(lat, lon, props.dark)
|
||||
|
||||
map = new Map({
|
||||
target: mapEl.value!,
|
||||
layers: [buildBaseLayer(props.dark), stationLayer],
|
||||
target: mapEl.value!,
|
||||
layers: [buildBaseLayer(props.dark), stationLayer],
|
||||
interactions: defaultInteractions({ altShiftDragRotate: false, pinchRotate: false }),
|
||||
view: new View({ center: fromLonLat([lon, lat]), zoom: 8, maxZoom: 13 }),
|
||||
view: new View({ center: fromLonLat([lon, lat]), zoom: 8, maxZoom: 13 }),
|
||||
controls: [],
|
||||
})
|
||||
|
||||
aisLayer = new AISLayer(map);
|
||||
aisLayer.show();
|
||||
aisLayer = new AISLayer(map)
|
||||
aisLayer.show()
|
||||
airTraffic = new AirTrafficLayer(map)
|
||||
airTraffic.show()
|
||||
range = new RangeLayer(map);
|
||||
range.show();
|
||||
range = new RangeLayer(map)
|
||||
range.show()
|
||||
|
||||
for (const id of activeOverlays.value) {
|
||||
if (id === 'wind') continue
|
||||
const layer = buildOverlayLayer(id)
|
||||
overlayLayers[id] = layer
|
||||
map.addLayer(layer)
|
||||
}
|
||||
|
||||
map.on('moveend', () => {
|
||||
if (showWind.value) syncWindSrc()
|
||||
})
|
||||
|
||||
radarInterval = setInterval(async () => {
|
||||
await fetchRadarFrames()
|
||||
radarFrameIndex.value = nowcastStartIndex.value - 1
|
||||
seekRadar(radarFrameIndex.value)
|
||||
}, 5 * 60 * 1000)
|
||||
refreshRain()
|
||||
radarInterval = setInterval(refreshRain, 5 * 60 * 1000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@@ -332,80 +314,12 @@ watch(() => props.dark, dark => {
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.radar-timeline {
|
||||
position: absolute;
|
||||
bottom: 72px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
background: var(--surface);
|
||||
border-radius: 16px;
|
||||
padding: 8px 16px;
|
||||
box-shadow: 0 2px 12px rgba(0,0,0,0.2);
|
||||
backdrop-filter: blur(8px);
|
||||
width: min(600px, calc(100vw - 32px));
|
||||
}
|
||||
|
||||
.slider-wrap {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.slider-ticks {
|
||||
position: relative;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.tick {
|
||||
position: absolute;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
|
||||
&__line {
|
||||
width: 1px;
|
||||
height: 5px;
|
||||
background: var(--border);
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: 9px;
|
||||
color: var(--text-muted, #888);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&.nowcast &__line { background: #6ab4ff; }
|
||||
&.nowcast &__label { color: #6ab4ff; }
|
||||
}
|
||||
|
||||
input[type='range'] {
|
||||
width: 100%;
|
||||
accent-color: var(--accent);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.timeline-label {
|
||||
font-size: 12px;
|
||||
color: var(--text);
|
||||
min-width: 42px;
|
||||
text-align: right;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.desktop { display: flex; }
|
||||
.mobile { display: none; }
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.desktop { display: none; }
|
||||
.mobile { display: flex; }
|
||||
.radar-timeline { bottom: 10px; }
|
||||
.overlay-toggles { bottom: 10px; }
|
||||
.layers-menu { bottom: 10px; }
|
||||
}
|
||||
@@ -415,7 +329,6 @@ input[type='range'] {
|
||||
<div class="map-wrap">
|
||||
<div ref="mapEl" class="map-el" />
|
||||
|
||||
<!-- Windy animated wind iframe -->
|
||||
<iframe
|
||||
v-if="showWind"
|
||||
class="wind-iframe"
|
||||
@@ -424,7 +337,6 @@ input[type='range'] {
|
||||
allowfullscreen
|
||||
/>
|
||||
|
||||
<!-- Desktop toggles -->
|
||||
<div class="overlay-toggles desktop">
|
||||
<button class="overlay-btn" :class="{ active: atActive }" @click="toggleAT">
|
||||
✈️ Traffic
|
||||
@@ -439,7 +351,6 @@ input[type='range'] {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Mobile layers button + dropdown -->
|
||||
<div class="layers-menu mobile">
|
||||
<button class="layers-btn" @click="showOverlays = !showOverlays">
|
||||
⚙️ Layers
|
||||
|
||||
@@ -65,7 +65,11 @@ const {current: d} = useWeather();
|
||||
<div class="stat" @click="openGraph?.('precipitation_chance')">
|
||||
<span class="stat-label">Rain</span>
|
||||
<div v-if="!d" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading /></div>
|
||||
<span v-else class="stat-value">{{ d.raining == null ? '—' : d.raining ? 'Raining' : d.precipitation_chance + '%' }}</span>
|
||||
<span v-else class="stat-value">
|
||||
<template v-if="d.raining == null">—</template>
|
||||
<template v-else-if="d.raining">Raining</template>
|
||||
<template v-else>{{d.precipitation_chance}}<span class="fg-muted">%</span></template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="stat" @click="openGraph?.('lightning_rate')">
|
||||
<span class="stat-label">Lightning</span>
|
||||
@@ -82,6 +86,11 @@ const {current: d} = useWeather();
|
||||
<div class="divider" />
|
||||
|
||||
<div class="stat-grid">
|
||||
<div class="stat" @click="openGraph?.('pressure_hpa')">
|
||||
<span class="stat-label">Pressure</span>
|
||||
<div v-if="!d" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading /></div>
|
||||
<span v-else class="stat-value">{{ d.pressure_hpa?.toFixed(1) ?? '—' }} <span class="fg-muted">hpa</span></span>
|
||||
</div>
|
||||
<div class="stat" @click="openGraph?.('pressure_hpa')">
|
||||
<span class="stat-label">Pressure (SLP)</span>
|
||||
<div v-if="!d" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading /></div>
|
||||
@@ -92,11 +101,6 @@ const {current: d} = useWeather();
|
||||
<div v-if="!d" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading /></div>
|
||||
<span v-else class="stat-value">{{ d.precipitation?.toFixed(1) ?? '—' }} <span v-if="d.precipitation != null" class="fg-muted">mm</span></span>
|
||||
</div>
|
||||
<div class="stat" @click="openGraph?.('accumulation')">
|
||||
<span class="stat-label">Accumulation</span>
|
||||
<div v-if="!d" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading /></div>
|
||||
<span v-else class="stat-value">{{ d.accumulation?.toFixed(1) ?? '—' }} <span v-if="d.accumulation != null" class="fg-muted">cm</span></span>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-label">Dew Point</span>
|
||||
<div v-if="!d" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading /></div>
|
||||
@@ -107,6 +111,11 @@ const {current: d} = useWeather();
|
||||
<div v-if="!d" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading /></div>
|
||||
<span v-else class="stat-value">{{ d.frost_risk ?? '—' }}</span>
|
||||
</div>
|
||||
<div class="stat" @click="openGraph?.('accumulation')">
|
||||
<span class="stat-label">Accumulation</span>
|
||||
<div v-if="!d" class="w-100 pos-rel br-2 overflow-hidden" style="height: 1.75em"><Loading /></div>
|
||||
<span v-else class="stat-value">{{ d.accumulation?.toFixed(1) ?? '—' }} <span v-if="d.accumulation != null" class="fg-muted">cm</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -167,7 +167,10 @@ canvas { width: 100%; height: 180px; }
|
||||
<div class="card">
|
||||
<div class="card-title">🫨 Seismic</div>
|
||||
<div v-if="!d" class="p-2">
|
||||
<div class="w-100 pos-rel br-2 overflow-hidden" style="height: 200px">
|
||||
<div class="w-100 pos-rel br-2 overflow-hidden mb-2" style="height: 30px">
|
||||
<Loading />
|
||||
</div>
|
||||
<div class="w-100 pos-rel br-2 overflow-hidden" style="height: 150px">
|
||||
<Loading />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user