From 4afd99aedf2ddcd800866e6e0ac33731195e8680 Mon Sep 17 00:00:00 2001 From: Brandon Keepers Date: Sat, 28 Feb 2026 16:58:33 -0500 Subject: [PATCH 01/15] Use @neaps/react --- package-lock.json | 1487 +++++++++++++---- package.json | 1 + website/astro.config.mjs | 33 +- website/package.json | 17 +- website/src/components/TideHeight.tsx | 56 - website/src/components/api/ApiEndpoint.astro | 10 +- website/src/components/layout/Header.astro | 4 +- .../src/components/tides/NearbyStations.tsx | 68 + website/src/components/tides/StationMap.tsx | 170 -- .../src/components/tides/StationSearch.tsx | 90 - website/src/components/tides/StationsMap.tsx | 270 --- .../components/tides/StationsMapIsland.tsx | 49 + website/src/components/tides/TideGraph.tsx | 196 --- website/src/components/tides/TideStation.tsx | 65 - .../components/tides/TideStationIsland.tsx | 40 + website/src/components/tides/Today.tsx | 176 -- website/src/pages/about.astro | 51 +- website/src/pages/bathymetry/index.astro | 50 +- website/src/pages/index.astro | 14 +- website/src/pages/license.astro | 68 +- website/src/pages/tides/database.astro | 42 +- website/src/pages/tides/harmonics.astro | 24 +- website/src/pages/tides/index.astro | 10 +- website/src/pages/tides/neaps.astro | 18 +- .../src/pages/tides/stations/[...id].astro | 63 +- website/src/pages/tides/stations/index.astro | 16 +- website/src/styles/global.css | 163 +- website/src/utils/tides.ts | 20 - website/src/utils/useNeapsAPI.ts | 53 - website/tailwind.config.mjs | 50 - 30 files changed, 1651 insertions(+), 1723 deletions(-) delete mode 100644 website/src/components/TideHeight.tsx create mode 100644 website/src/components/tides/NearbyStations.tsx delete mode 100644 website/src/components/tides/StationMap.tsx delete mode 100644 website/src/components/tides/StationSearch.tsx delete mode 100644 website/src/components/tides/StationsMap.tsx create mode 100644 website/src/components/tides/StationsMapIsland.tsx delete mode 100644 website/src/components/tides/TideGraph.tsx delete mode 100644 website/src/components/tides/TideStation.tsx create mode 100644 website/src/components/tides/TideStationIsland.tsx delete mode 100644 website/src/components/tides/Today.tsx delete mode 100644 website/src/utils/tides.ts delete mode 100644 website/src/utils/useNeapsAPI.ts delete mode 100644 website/tailwind.config.mjs diff --git a/package-lock.json b/package-lock.json index cbf234e..c8d6c22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ ], "dependencies": { "@neaps/api": "^0.4.0", + "@neaps/react": "https://pkg.pr.new/openwatersio/neaps/@neaps/react@4ef1d35", "@neaps/tide-database": "^0.6.20260220", "@neaps/tide-predictor": "^0.8.0", "neaps": "^0.6.0" @@ -219,21 +220,6 @@ "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0" } }, - "node_modules/@astrojs/tailwind": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@astrojs/tailwind/-/tailwind-6.0.2.tgz", - "integrity": "sha512-j3mhLNeugZq6A8dMNXVarUa8K6X9AW+QHU9u3lKNrPLMHhOQ0S7VeWhHwEeJFpEK1BTKEUY1U78VQv2gN6hNGg==", - "license": "MIT", - "dependencies": { - "autoprefixer": "^10.4.21", - "postcss": "^8.5.3", - "postcss-load-config": "^4.0.2" - }, - "peerDependencies": { - "astro": "^3.0.0 || ^4.0.0 || ^5.0.0", - "tailwindcss": "^3.0.24" - } - }, "node_modules/@astrojs/telemetry": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.0.tgz", @@ -1756,30 +1742,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@js-temporal/polyfill": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@js-temporal/polyfill/-/polyfill-0.5.1.tgz", - "integrity": "sha512-hloP58zRVCRSpgDxmqCWJNlizAlUgJFqG2ypq79DCvyv9tHjRYMDOcPFjzfl/A1/YxDvRCZz8wvZvmapQnKwFQ==", - "license": "ISC", - "dependencies": { - "jsbi": "^4.3.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@jsdevtools/ono": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", "license": "MIT" }, - "node_modules/@kurkle/color": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", - "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", - "license": "MIT" - }, "node_modules/@mapbox/geojson-rewind": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", @@ -1835,9 +1803,9 @@ } }, "node_modules/@mapbox/point-geometry": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", - "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-1.1.0.tgz", + "integrity": "sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ==", "license": "ISC" }, "node_modules/@mapbox/tiny-sdf": { @@ -1853,12 +1821,14 @@ "license": "BSD-2-Clause" }, "node_modules/@mapbox/vector-tile": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", - "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-2.0.4.tgz", + "integrity": "sha512-AkOLcbgGTdXScosBWwmmD7cDlvOjkg/DetGva26pIRiZPdeJYjYKarIlb4uxVzi6bwHO6EWH82eZ5Nuv4T5DUg==", "license": "BSD-3-Clause", "dependencies": { - "@mapbox/point-geometry": "~0.1.0" + "@mapbox/point-geometry": "~1.1.0", + "@types/geojson": "^7946.0.16", + "pbf": "^4.0.1" } }, "node_modules/@mapbox/whoots-js": { @@ -1870,17 +1840,23 @@ "node": ">=6.0.0" } }, + "node_modules/@maplibre/geojson-vt": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-5.0.4.tgz", + "integrity": "sha512-KGg9sma45S+stfH9vPCJk1J0lSDLWZgCT9Y8u8qWZJyjFlP8MNP1WGTxIMYJZjDvVT3PDn05kN1C95Sut1HpgQ==", + "license": "ISC" + }, "node_modules/@maplibre/maplibre-gl-style-spec": { - "version": "20.4.0", - "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.4.0.tgz", - "integrity": "sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw==", + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.5.0.tgz", + "integrity": "sha512-55sPMCtWAZY7r7ftU2at1SsBJfhJyIE5X16Tbl+uFcnTuiCxEuh6839iq/hgjLM8zUEjXdRu2V30bfsYCNB1Qg==", "license": "ISC", "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", "@mapbox/unitbezier": "^0.0.1", "json-stringify-pretty-compact": "^4.0.0", "minimist": "^1.2.8", - "quickselect": "^2.0.0", + "quickselect": "^3.0.0", "rw": "^1.3.3", "tinyqueue": "^3.0.0" }, @@ -1890,11 +1866,29 @@ "gl-style-validate": "dist/gl-style-validate.mjs" } }, - "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/quickselect": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==", - "license": "ISC" + "node_modules/@maplibre/mlt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.1.6.tgz", + "integrity": "sha512-rgtY3x65lrrfXycLf6/T22ZnjTg5WgIOsptOIoCaMZy4O4UAKTyZlYY0h6v8le721pTptF94U65yMDQkug+URw==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@mapbox/point-geometry": "^1.1.0" + } + }, + "node_modules/@maplibre/vt-pbf": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@maplibre/vt-pbf/-/vt-pbf-4.3.0.tgz", + "integrity": "sha512-jIvp8F5hQCcreqOOpEt42TJMUlsrEcpf/kI1T2v85YrQRV6PPXUcEXUg5karKtH6oh47XJZ4kHu56pUkOuqA7w==", + "license": "MIT", + "dependencies": { + "@mapbox/point-geometry": "^1.1.0", + "@mapbox/vector-tile": "^2.0.4", + "@maplibre/geojson-vt": "^5.0.4", + "@types/geojson": "^7946.0.16", + "@types/supercluster": "^7.1.3", + "pbf": "^4.0.1", + "supercluster": "^8.0.1" + } }, "node_modules/@neaps/api": { "version": "0.4.0", @@ -1912,6 +1906,41 @@ "neaps-server": "bin/server.js" } }, + "node_modules/@neaps/react": { + "version": "0.1.0", + "resolved": "https://pkg.pr.new/openwatersio/neaps/@neaps/react@4ef1d35", + "integrity": "sha512-9nmu5DZLxI/3oybNe5nWzt9c/6mZvPgQ+PR6ra3dNLJS8C7iUYEGCr3mMMwScDt5tNVL2qh18t1CpIQVAGdVXQ==", + "license": "MIT", + "dependencies": { + "@tanstack/react-query": "^5.64.0", + "@visx/axis": "^4.0.1-alpha.0", + "@visx/curve": "^4.0.1-alpha.0", + "@visx/event": "^4.0.1-alpha.0", + "@visx/gradient": "^4.0.1-alpha.0", + "@visx/group": "^4.0.1-alpha.0", + "@visx/scale": "^4.0.1-alpha.0", + "@visx/shape": "^4.0.1-alpha.0", + "@visx/tooltip": "^4.0.1-alpha.0", + "astronomy-engine": "^2.1.19", + "coordinate-format": "^1.0.0", + "d3-array": "^3.2.1", + "date-fns": "^3.6.0" + }, + "peerDependencies": { + "maplibre-gl": ">=4", + "react": ">=18", + "react-dom": ">=18", + "react-map-gl": ">=7" + }, + "peerDependenciesMeta": { + "maplibre-gl": { + "optional": true + }, + "react-map-gl": { + "optional": true + } + } + }, "node_modules/@neaps/tide-database": { "version": "0.6.20260220", "resolved": "https://registry.npmjs.org/@neaps/tide-database/-/tide-database-0.6.20260220.tgz", @@ -2413,6 +2442,264 @@ "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", "license": "MIT" }, + "node_modules/@tailwindcss/node": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz", + "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.31.1", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.1" + } + }, + "node_modules/@tailwindcss/node/node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/@tailwindcss/node/node_modules/tailwindcss": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", + "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", + "license": "MIT" + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz", + "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.2.1", + "@tailwindcss/oxide-darwin-arm64": "4.2.1", + "@tailwindcss/oxide-darwin-x64": "4.2.1", + "@tailwindcss/oxide-freebsd-x64": "4.2.1", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", + "@tailwindcss/oxide-linux-x64-musl": "4.2.1", + "@tailwindcss/oxide-wasm32-wasi": "4.2.1", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz", + "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz", + "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz", + "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz", + "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz", + "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz", + "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz", + "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz", + "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz", + "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz", + "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.8.1", + "@emnapi/runtime": "^1.8.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.1", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz", + "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz", + "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, "node_modules/@tailwindcss/typography": { "version": "0.5.19", "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.19.tgz", @@ -2438,6 +2725,52 @@ "node": ">=4" } }, + "node_modules/@tailwindcss/vite": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.1.tgz", + "integrity": "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.2.1", + "@tailwindcss/oxide": "4.2.1", + "tailwindcss": "4.2.1" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@tailwindcss/vite/node_modules/tailwindcss": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", + "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", + "license": "MIT" + }, + "node_modules/@tanstack/query-core": { + "version": "5.90.20", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.20.tgz", + "integrity": "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.90.21", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.21.tgz", + "integrity": "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.90.20" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -2504,9 +2837,87 @@ "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "license": "MIT", "dependencies": { - "@types/node": "*" + "@types/node": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.3.tgz", + "integrity": "sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==", + "license": "MIT" + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz", + "integrity": "sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", + "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" } }, + "node_modules/@types/d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.0.tgz", + "integrity": "sha512-/myT3I7EwlukNOX2xVdMzb8FRgNzRMpsZddwst9Ld/VFe6LyJyRp0s32l/V9XoUzk+Gqu56F/oGk6507+8BxrA==", + "license": "MIT" + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -2552,15 +2963,6 @@ "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, - "node_modules/@types/geojson-vt": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/@types/geojson-vt/-/geojson-vt-3.2.5.tgz", - "integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==", - "license": "MIT", - "dependencies": { - "@types/geojson": "*" - } - }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -2583,23 +2985,12 @@ "license": "MIT", "peer": true }, - "node_modules/@types/mapbox__point-geometry": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz", - "integrity": "sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==", + "node_modules/@types/lodash": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", "license": "MIT" }, - "node_modules/@types/mapbox__vector-tile": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.4.tgz", - "integrity": "sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==", - "license": "MIT", - "dependencies": { - "@types/geojson": "*", - "@types/mapbox__point-geometry": "*", - "@types/pbf": "*" - } - }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -2649,12 +3040,6 @@ "undici-types": "~7.16.0" } }, - "node_modules/@types/pbf": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", - "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==", - "license": "MIT" - }, "node_modules/@types/prop-types": { "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", @@ -2961,6 +3346,191 @@ "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==", "license": "MIT" }, + "node_modules/@visx/axis": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/axis/-/axis-4.0.1-alpha.0.tgz", + "integrity": "sha512-XzRsZ5vt6QAFsYeFSQAQtmrSafjLUVNfdygOT8auPbborsgXKSVryCMyf6afWITMrmpOg2FlkaNx2H/VvW9PKg==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@visx/group": "4.0.1-alpha.0", + "@visx/point": "4.0.1-alpha.0", + "@visx/scale": "4.0.1-alpha.0", + "@visx/shape": "4.0.1-alpha.0", + "@visx/text": "4.0.1-alpha.0", + "classnames": "^2.3.1" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/bounds": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/bounds/-/bounds-4.0.1-alpha.0.tgz", + "integrity": "sha512-YcFN3lAZfqocPaOVUmeGebinqfBUo+YPcBHzsQt1jaEvkcVBUhDRS6mai4tm6jUGvwW9nEAzqTQ1L343lqitYw==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@types/react-dom": "*" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0", + "react-dom": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/curve": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/curve/-/curve-4.0.1-alpha.0.tgz", + "integrity": "sha512-jRu61Uz274pV1zyioXmboyrLutYbnKsgjj4njSGCnhdXj5GkZvZbg+ThDb6oOzoAnJOBRLz4rzPlWvNJOzuVMg==", + "license": "MIT", + "dependencies": { + "@visx/vendor": "4.0.0-alpha.0" + } + }, + "node_modules/@visx/event": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/event/-/event-4.0.1-alpha.0.tgz", + "integrity": "sha512-EQqCMSv/s8NbFjo+hz3FKsvvYfP+2QslsFJ/24/O5l/W+7UC6J6aAvO0ujVwrTwdYbuQ+vhxKi1xdPdKR/qj1g==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@visx/point": "4.0.1-alpha.0" + } + }, + "node_modules/@visx/gradient": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/gradient/-/gradient-4.0.1-alpha.0.tgz", + "integrity": "sha512-HxkxLdThV/gPaulw+t7/ESo7AtqIBq9IlHIkHi7lQqXe0Yl+x8rpM3KYlYqEZjtihD9CeEaVJjBbdY7fQb54IA==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/group": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/group/-/group-4.0.1-alpha.0.tgz", + "integrity": "sha512-V19l7iQ7jccBv8kao/EByuI6o4xtxzzLV9nqVI1hRvmdzTVsuLpqlwzYCZUXJaTVvUWf8s4D2SQFjGkj/Nw+0w==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "classnames": "^2.3.1" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/point": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/point/-/point-4.0.1-alpha.0.tgz", + "integrity": "sha512-ijTfr/Nx09f03vIj9nyTr3z4Xth4Y75427UaogJh6dnIRLMEFHQOwNu791sbfiNj0a+ZXuaE32h0vKrFe4/8Qg==", + "license": "MIT" + }, + "node_modules/@visx/scale": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/scale/-/scale-4.0.1-alpha.0.tgz", + "integrity": "sha512-nzjeE87vFSAXGWFiiNfBpNLAf0Q8Qmf6syvKLjqNi4kGZkdhbUll3E/59YsgWXmjM8+llPLWzGsP+JPvo5eq1A==", + "license": "MIT", + "dependencies": { + "@visx/vendor": "4.0.0-alpha.0" + } + }, + "node_modules/@visx/shape": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/shape/-/shape-4.0.1-alpha.0.tgz", + "integrity": "sha512-62QeiVNmPlterQGwhkEDcbq7M0MqY0lBsK5QKXtM9ZoPZWkuGV3aykA3+Xu20B2FAvyJq4LqJzBc7Sxr+EAdbA==", + "license": "MIT", + "dependencies": { + "@types/lodash": "^4.17.13", + "@types/react": "*", + "@visx/curve": "4.0.1-alpha.0", + "@visx/group": "4.0.1-alpha.0", + "@visx/scale": "4.0.1-alpha.0", + "@visx/vendor": "4.0.0-alpha.0", + "classnames": "^2.3.1", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/text": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/text/-/text-4.0.1-alpha.0.tgz", + "integrity": "sha512-wVLXR6DtaeU6TetPGsM3p6I/gCr48RFv1CZQ9+q21Q5G6CUDoObOpsIp+OR0yTlqkP3OSJYTmhsVdiU3LKkBxA==", + "license": "MIT", + "dependencies": { + "@types/lodash": "^4.17.13", + "@types/react": "*", + "classnames": "^2.3.1", + "lodash": "^4.17.21", + "reduce-css-calc": "^1.3.0" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/tooltip": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/tooltip/-/tooltip-4.0.1-alpha.0.tgz", + "integrity": "sha512-N7SAGDHyxFonpsRMTTSbN6O5bh2CAjrX0TpAtpAuLVP6Q2pN3Y0jSGGhs6rZsyPYP6AnveeoV9jjXZAayTjsbA==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@visx/bounds": "4.0.1-alpha.0", + "classnames": "^2.3.1", + "react-use-measure": "^2.0.4" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0", + "react-dom": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/vendor": { + "version": "4.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/vendor/-/vendor-4.0.0-alpha.0.tgz", + "integrity": "sha512-6I+MuqXBcv9jnlcVowHoHKSdk9gXTWkHLKyqBwRWg7LY6A3Ei8SHfubpqGV5rBUSppxMq2RszPJUS6w+H0YgmQ==", + "license": "MIT and ISC", + "dependencies": { + "@types/d3-array": "3.0.3", + "@types/d3-color": "3.1.0", + "@types/d3-delaunay": "6.0.1", + "@types/d3-format": "3.0.1", + "@types/d3-geo": "3.1.0", + "@types/d3-interpolate": "3.0.1", + "@types/d3-path": "3.1.1", + "@types/d3-scale": "4.0.2", + "@types/d3-shape": "3.1.7", + "@types/d3-time": "3.0.0", + "@types/d3-time-format": "2.1.0", + "d3-array": "3.2.1", + "d3-color": "3.1.0", + "d3-delaunay": "6.0.2", + "d3-format": "3.1.0", + "d3-geo": "3.1.0", + "d3-interpolate": "3.0.1", + "d3-path": "3.1.0", + "d3-scale": "4.0.2", + "d3-shape": "3.2.0", + "d3-time": "3.1.0", + "d3-time-format": "4.1.0", + "internmap": "2.0.3" + } + }, + "node_modules/@visx/vendor/node_modules/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-gUY/qeHq/yNqqoCKNq4vtpFLdoCdvyNpWoC/KNjhGbhDuQpAM9sIQQKkXSNpXa9h5KySs/gzm7R88WkUutgwWQ==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", @@ -3568,48 +4138,18 @@ } } }, + "node_modules/astronomy-engine": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/astronomy-engine/-/astronomy-engine-2.1.19.tgz", + "integrity": "sha512-8yWKNf7UeNbH458h3sAJ6ZgAjE5jTXp/mNNRFoC20j2SHwZIjAQeEsBB2Q3uCFRaTCCJRv33K2XhkhZQMXoX6w==", + "license": "MIT" + }, "node_modules/async-sema": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/async-sema/-/async-sema-3.1.1.tgz", "integrity": "sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==", "license": "MIT" }, - "node_modules/autoprefixer": { - "version": "10.4.23", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz", - "integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001760", - "fraction.js": "^5.3.4", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -4078,29 +4618,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chart.js": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", - "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@kurkle/color": "^0.3.0" - }, - "engines": { - "pnpm": ">=8" - } - }, - "node_modules/chartjs-adapter-date-fns": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-3.0.0.tgz", - "integrity": "sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==", - "license": "MIT", - "peerDependencies": { - "chart.js": ">=2.8.0", - "date-fns": ">=2.0.0" - } - }, "node_modules/cheerio": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", @@ -4182,6 +4699,12 @@ "node": ">=8" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, "node_modules/cli-boxes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", @@ -4679,12 +5202,138 @@ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", + "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/date-fns": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", "license": "MIT", - "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/kossnocorp" @@ -4726,6 +5375,15 @@ "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", "license": "MIT" }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -5000,6 +5658,19 @@ "once": "^1.4.0" } }, + "node_modules/enhanced-resolve": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", + "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/entities": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", @@ -5494,19 +6165,6 @@ "node": ">= 0.6" } }, - "node_modules/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -5548,12 +6206,6 @@ "node": ">=6.9.0" } }, - "node_modules/geojson-vt": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz", - "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==", - "license": "ISC" - }, "node_modules/geokdbush": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/geokdbush/-/geokdbush-2.0.1.tgz", @@ -5705,20 +6357,6 @@ "node": ">= 6" } }, - "node_modules/global-prefix": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz", - "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==", - "license": "MIT", - "dependencies": { - "ini": "^4.1.3", - "kind-of": "^6.0.3", - "which": "^4.0.0" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/globals": { "version": "15.15.0", "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", @@ -6086,30 +6724,10 @@ "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" + }, + "engines": { + "node": ">=0.10.0" + } }, "node_modules/import-meta-resolve": { "version": "4.2.0", @@ -6127,13 +6745,13 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, - "node_modules/ini": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", - "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", "license": "ISC", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=12" } }, "node_modules/ipaddr.js": { @@ -6301,15 +6919,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "license": "ISC", - "engines": { - "node": ">=16" - } - }, "node_modules/isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", @@ -6339,7 +6948,6 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "license": "MIT", - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -6362,12 +6970,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbi": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-4.3.2.tgz", - "integrity": "sha512-9fqMSQbhJykSeii05nxKl4m6Eqn2P6rOlYiS+C5Dr/HPIU/7yZxu5qzbs40tgaFORiw2Amd0mirjxatXYMkIew==", - "license": "Apache-2.0" - }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -6416,15 +7018,6 @@ "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==", "license": "ISC" }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/kleur": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", @@ -6440,6 +7033,255 @@ "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", "license": "MIT" }, + "node_modules/lightningcss": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", + "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.31.1", + "lightningcss-darwin-arm64": "1.31.1", + "lightningcss-darwin-x64": "1.31.1", + "lightningcss-freebsd-x64": "1.31.1", + "lightningcss-linux-arm-gnueabihf": "1.31.1", + "lightningcss-linux-arm64-gnu": "1.31.1", + "lightningcss-linux-arm64-musl": "1.31.1", + "lightningcss-linux-x64-gnu": "1.31.1", + "lightningcss-linux-x64-musl": "1.31.1", + "lightningcss-win32-arm64-msvc": "1.31.1", + "lightningcss-win32-x64-msvc": "1.31.1" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", + "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", + "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", + "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", + "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", + "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", + "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", + "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", + "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", + "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", + "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", + "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -6779,38 +7621,33 @@ } }, "node_modules/maplibre-gl": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.7.1.tgz", - "integrity": "sha512-lgL7XpIwsgICiL82ITplfS7IGwrB1OJIw/pCvprDp2dhmSSEBgmPzYRvwYYYvJGJD7fxUv1Tvpih4nZ6VrLuaA==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.19.0.tgz", + "integrity": "sha512-REhYUN8gNP3HlcIZS6QU2uy8iovl31cXsrNDkCcqWSQbCkcpdYLczqDz5PVIwNH42UQNyvukjes/RoHPDrOUmQ==", "license": "BSD-3-Clause", - "peer": true, "dependencies": { "@mapbox/geojson-rewind": "^0.5.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2", - "@mapbox/point-geometry": "^0.1.0", - "@mapbox/tiny-sdf": "^2.0.6", + "@mapbox/point-geometry": "^1.1.0", + "@mapbox/tiny-sdf": "^2.0.7", "@mapbox/unitbezier": "^0.0.1", - "@mapbox/vector-tile": "^1.3.1", + "@mapbox/vector-tile": "^2.0.4", "@mapbox/whoots-js": "^3.1.0", - "@maplibre/maplibre-gl-style-spec": "^20.3.1", - "@types/geojson": "^7946.0.14", - "@types/geojson-vt": "3.2.5", - "@types/mapbox__point-geometry": "^0.1.4", - "@types/mapbox__vector-tile": "^1.3.4", - "@types/pbf": "^3.0.5", + "@maplibre/geojson-vt": "^5.0.4", + "@maplibre/maplibre-gl-style-spec": "^24.4.1", + "@maplibre/mlt": "^1.1.6", + "@maplibre/vt-pbf": "^4.2.1", + "@types/geojson": "^7946.0.16", "@types/supercluster": "^7.1.3", - "earcut": "^3.0.0", - "geojson-vt": "^4.0.2", - "gl-matrix": "^3.4.3", - "global-prefix": "^4.0.0", + "earcut": "^3.0.2", + "gl-matrix": "^3.4.4", "kdbush": "^4.0.2", "murmurhash-js": "^1.0.0", - "pbf": "^3.3.0", - "potpack": "^2.0.0", + "pbf": "^4.0.1", + "potpack": "^2.1.0", "quickselect": "^3.0.0", "supercluster": "^8.0.1", - "tinyqueue": "^3.0.0", - "vt-pbf": "^3.1.3" + "tinyqueue": "^3.0.0" }, "engines": { "node": ">=16.14.0", @@ -6830,6 +7667,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/math-expression-evaluator": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.4.0.tgz", + "integrity": "sha512-4vRUvPyxdO8cWULGTh9dZWL2tZK6LDBvj+OGHBER7poH9Qdt7kXEoj20wiz4lQUbUXQZFjPbe5mVDo9nutizCw==", + "license": "MIT" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -8350,12 +9193,11 @@ "license": "MIT" }, "node_modules/pbf": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", - "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.1.tgz", + "integrity": "sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA==", "license": "BSD-3-Clause", "dependencies": { - "ieee754": "^1.1.12", "resolve-protobuf-schema": "^2.1.0" }, "bin": { @@ -8881,16 +9723,6 @@ "node": ">=0.10.0" } }, - "node_modules/react-chartjs-2": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.3.1.tgz", - "integrity": "sha512-h5IPXKg9EXpjoBzUfyWJvllMjG2mQ4EiuHQFhms/AjUm0XSZHhyRy2xVmLXHKrtcdrPO4mnGqRtYoD0vp95A0A==", - "license": "MIT", - "peerDependencies": { - "chart.js": "^4.1.1", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -8938,6 +9770,21 @@ "node": ">=0.10.0" } }, + "node_modules/react-use-measure": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz", + "integrity": "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.13", + "react-dom": ">=16.13" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -8974,6 +9821,32 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/reduce-css-calc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "integrity": "sha512-0dVfwYVOlf/LBA2ec4OwQ6p3X9mYxn/wOl2xTcLwjnPYrkgEfPx3VI4eGCH3rQLlPISG5v9I9bkZosKsNRTRKA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^0.4.2", + "math-expression-evaluator": "^1.2.14", + "reduce-function-call": "^1.0.1" + } + }, + "node_modules/reduce-css-calc/node_modules/balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha512-STw03mQKnGUYtoNjmowo4F2cRmIIxYEGiMsjjwla/u5P1lxadj/05WkNaFjNiKTgJkj8KiXbgAiRTmcQRwQNtg==", + "license": "MIT" + }, + "node_modules/reduce-function-call": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz", + "integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/regex": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", @@ -9307,6 +10180,12 @@ "dev": true, "license": "MIT" }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" + }, "node_modules/rollup": { "version": "4.57.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.0.tgz", @@ -10098,7 +10977,6 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", "license": "MIT", - "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -10203,6 +11081,19 @@ "node": ">=8.10.0" } }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/tar": { "version": "7.5.7", "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", @@ -11636,17 +12527,6 @@ "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", "license": "MIT" }, - "node_modules/vt-pbf": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", - "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", - "license": "MIT", - "dependencies": { - "@mapbox/point-geometry": "0.1.0", - "@mapbox/vector-tile": "^1.3.1", - "pbf": "^3.2.1" - } - }, "node_modules/web-namespaces": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", @@ -11707,21 +12587,6 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, "node_modules/which-pm-runs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", @@ -12043,39 +12908,63 @@ "dependencies": { "@astrojs/check": "^0.9.6", "@astrojs/react": "^4.4.2", - "@astrojs/tailwind": "^6.0.2", "@astrojs/vercel": "^9.0.4", "@iconify-json/mdi": "^1.2.3", - "@js-temporal/polyfill": "^0.5.1", "@neaps/api": "*", + "@neaps/react": "*", "@neaps/tide-predictor": "*", "@tailwindcss/typography": "^0.5.19", + "@tailwindcss/vite": "^4.2.1", + "@tanstack/react-query": "^5.90.21", "astro": "^5.17.1", "astro-icon": "^1.1.5", - "chart.js": "^4.4.0", - "chartjs-adapter-date-fns": "^3.0.0", "clsx": "^2.1.1", "coordinate-format": "^1.0.0", - "date-fns": "^3.0.0", - "maplibre-gl": "^4.7.0", + "maplibre-gl": "^5.19.0", "neaps": "*", "react": "^18.3.1", - "react-chartjs-2": "^5.2.0", "react-dom": "^18.3.1", "react-map-gl": "^8.1.0", "tailwind-merge": "^2.5.0", - "tailwindcss": "^3.4.1", + "tailwindcss": "^4.2.1", "typescript": "^5.6.0" }, "devDependencies": { - "@types/react": "^18.3.0", - "@types/react-dom": "^18.3.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", "husky": "^9.1.7", "lint-staged": "^16.2.7", "prettier": "^3.8.1", "prettier-plugin-astro": "^0.14.1", "prettier-plugin-tailwindcss": "^0.7.2" } + }, + "website/node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "website/node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "website/node_modules/tailwindcss": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", + "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", + "license": "MIT" } } } diff --git a/package.json b/package.json index ef919ed..e8e08f2 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "@neaps/api": "^0.4.0", + "@neaps/react": "https://pkg.pr.new/openwatersio/neaps/@neaps/react@4ef1d35", "@neaps/tide-database": "^0.6.20260220", "@neaps/tide-predictor": "^0.8.0", "neaps": "^0.6.0" diff --git a/website/astro.config.mjs b/website/astro.config.mjs index 8186772..2b50c65 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -1,5 +1,5 @@ import { defineConfig } from "astro/config"; -import tailwind from "@astrojs/tailwind"; +import tailwindcss from "@tailwindcss/vite"; import react from "@astrojs/react"; import vercel from "@astrojs/vercel"; @@ -8,16 +8,31 @@ import icon from "astro-icon"; // https://astro.build/config export default defineConfig({ site: "https://openwaters.io", - integrations: [ - tailwind({ - applyBaseStyles: false, - }), - react(), - icon(), - ], + integrations: [react(), icon()], vite: { + plugins: [tailwindcss()], + resolve: { + // Deduplicate React to ensure a single instance across the file: symlink boundary. + dedupe: ["react", "react-dom", "react/jsx-runtime"], + }, ssr: { - noExternal: ["maplibre-gl"], + // Process these through Vite's bundler for SSR (instead of externalizing to Node) + // so that resolve.dedupe applies to React, and browser-only packages don't fail. + // Includes @neaps/react and all its dependencies (which live in the neaps workspace + // and have ESM extensionless imports that Node.js can't resolve natively). + noExternal: [ + "@neaps/react", + // @neaps/react dependencies (and their transitive deps that use ESM + // extensionless imports, which Node.js can't resolve natively) + /^@visx\//, + "@tanstack/react-query", + "astronomy-engine", + "d3-array", + "date-fns", + // map dependencies + "maplibre-gl", + "react-map-gl", + ], }, }, adapter: vercel({}), diff --git a/website/package.json b/website/package.json index 9b0cb3d..1eb7efe 100644 --- a/website/package.json +++ b/website/package.json @@ -14,33 +14,30 @@ "dependencies": { "@astrojs/check": "^0.9.6", "@astrojs/react": "^4.4.2", - "@astrojs/tailwind": "^6.0.2", "@astrojs/vercel": "^9.0.4", "@iconify-json/mdi": "^1.2.3", - "@js-temporal/polyfill": "^0.5.1", "@neaps/api": "*", + "@neaps/react": "*", "@neaps/tide-predictor": "*", "@tailwindcss/typography": "^0.5.19", + "@tailwindcss/vite": "^4.2.1", + "@tanstack/react-query": "^5.90.21", "astro": "^5.17.1", "astro-icon": "^1.1.5", - "chart.js": "^4.4.0", - "chartjs-adapter-date-fns": "^3.0.0", "clsx": "^2.1.1", "coordinate-format": "^1.0.0", - "date-fns": "^3.0.0", - "maplibre-gl": "^4.7.0", + "maplibre-gl": "^5.19.0", "neaps": "*", "react": "^18.3.1", - "react-chartjs-2": "^5.2.0", "react-dom": "^18.3.1", "react-map-gl": "^8.1.0", "tailwind-merge": "^2.5.0", - "tailwindcss": "^3.4.1", + "tailwindcss": "^4.2.1", "typescript": "^5.6.0" }, "devDependencies": { - "@types/react": "^18.3.0", - "@types/react-dom": "^18.3.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", "husky": "^9.1.7", "lint-staged": "^16.2.7", "prettier": "^3.8.1", diff --git a/website/src/components/TideHeight.tsx b/website/src/components/TideHeight.tsx deleted file mode 100644 index f52b077..0000000 --- a/website/src/components/TideHeight.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { imperial } from "../utils/units"; - -const FEET_PER_METER = 3.28084; -const MILES_PER_METER = 0.000621371; - -interface DistanceProps { - meters: number; - precision?: number; -} - -export function Distance({ meters, precision }: DistanceProps) { - let value: number; - let unit: string; - - if (imperial) { - const miles = meters * MILES_PER_METER; - if (miles >= 0.1) { - value = miles; - unit = "mi"; - } else { - value = meters * FEET_PER_METER; - unit = "ft"; - } - } else { - if (meters >= 1000) { - value = meters / 1000; - unit = "km"; - } else { - value = meters; - unit = "m"; - } - } - - return ( - - {value.toFixed(precision ?? (value >= 5 ? 0 : 1))} - {unit} - - ); -} - -export function TideHeight({ - value, - precision = 1, -}: { - value: number; - precision?: number; -}) { - const unit = imperial ? "ft" : "m"; - return ( - - {value.toFixed(precision)} - {unit} - - ); -} diff --git a/website/src/components/api/ApiEndpoint.astro b/website/src/components/api/ApiEndpoint.astro index d5c43c3..123f052 100644 --- a/website/src/components/api/ApiEndpoint.astro +++ b/website/src/components/api/ApiEndpoint.astro @@ -36,7 +36,7 @@ const exampleResponse = > {endpoint.method} - {API_HOST}{endpoint.path} @@ -61,12 +61,12 @@ const exampleResponse = Description - + {endpoint.parameters.map((param) => ( {param.name} - + {param.in} @@ -82,7 +82,7 @@ const exampleResponse = )} - {param.description} + {param.description} ))} @@ -97,7 +97,7 @@ const exampleResponse = exampleResponse && (

Example Response

-
+
               {JSON.stringify(exampleResponse, null, 2)}
             
diff --git a/website/src/components/layout/Header.astro b/website/src/components/layout/Header.astro index f293cac..968b2ea 100644 --- a/website/src/components/layout/Header.astro +++ b/website/src/components/layout/Header.astro @@ -15,7 +15,7 @@ const currentPath = Astro.url.pathname;
+ + +
+ + ); +} diff --git a/website/src/components/tides/StationMap.tsx b/website/src/components/tides/StationMap.tsx deleted file mode 100644 index 8ac900b..0000000 --- a/website/src/components/tides/StationMap.tsx +++ /dev/null @@ -1,170 +0,0 @@ -import { useEffect, useMemo, useRef, useState } from "react"; -import maplibregl from "maplibre-gl"; -import "maplibre-gl/dist/maplibre-gl.css"; -import type { Station } from "@neaps/tide-database"; -import { useNeapsAPI } from "../../utils/useNeapsAPI"; -import { Distance } from "../TideHeight"; - -interface Props { - station: Station; -} - -interface NearbyStation { - id: string; - name: string; - latitude: number; - longitude: number; - distance?: number; -} - -export function StationMap({ station }: Props) { - const mapContainer = useRef(null); - const map = useRef(null); - const markers = useRef>(new Map()); - const { data: nearbyStationsData } = useNeapsAPI( - "/tides/stations", - { latitude: station.latitude, longitude: station.longitude, maxResults: 5 }, - ); - const nearbyStations = nearbyStationsData ?? []; - const [hoveredStationId, setHoveredStationId] = useState(null); - - useEffect(() => { - if (!mapContainer.current) return; - - map.current = new maplibregl.Map({ - container: mapContainer.current, - style: "https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json", - center: [station.longitude, station.latitude], - zoom: 11, - attributionControl: false, - }); - - // Add a circle source to show the current station area - map.current.on("load", () => { - if (!map.current) return; - - // Add marker for current station - const currentPopup = new maplibregl.Popup({ - closeButton: false, - closeOnClick: false, - offset: 15, - }).setHTML( - `${station.name}
Current Station`, - ); - - const currentMarker = new maplibregl.Marker({ color: "#0ea5e9" }) - .setLngLat([station.longitude, station.latitude]) - .addTo(map.current); - - const currentMarkerElement = currentMarker.getElement(); - currentMarkerElement.style.cursor = "pointer"; - - currentMarkerElement.addEventListener("mouseenter", () => { - currentPopup - .setLngLat([station.longitude, station.latitude]) - .addTo(map.current!); - }); - currentMarkerElement.addEventListener("mouseleave", () => { - currentPopup.remove(); - }); - }); - - // Add markers for nearby stations - nearbyStations.forEach((nearby) => { - if (map.current) { - const popup = new maplibregl.Popup({ - closeButton: false, - closeOnClick: false, - offset: 15, - }).setHTML( - `${nearby.name}
Distance: ${(nearby.distance || 0).toFixed(1)} km`, - ); - - const marker = new maplibregl.Marker({ color: "#075985" }) - .setLngLat([nearby.longitude, nearby.latitude]) - .addTo(map.current); - - // Store marker reference - markers.current.set(nearby.id, marker); - - const markerElement = marker.getElement(); - markerElement.style.cursor = "pointer"; - - // Show popup on hover - markerElement.addEventListener("mouseenter", () => { - popup - .setLngLat([nearby.longitude, nearby.latitude]) - .addTo(map.current!); - }); - markerElement.addEventListener("mouseleave", () => { - popup.remove(); - }); - - // Navigate on click - markerElement.addEventListener("click", () => { - window.location.href = `/tides/stations/${nearby.id}`; - }); - } - }); - - return () => { - markers.current.clear(); - map.current?.remove(); - }; - }, [station, nearbyStations]); - - // Handle map panning when hovering list items - useEffect(() => { - if (hoveredStationId) { - const hoveredStation = nearbyStations.find( - (s) => s.id === hoveredStationId, - ); - if (hoveredStation && map.current) { - map.current.panTo([hoveredStation.longitude, hoveredStation.latitude], { - duration: 500, - }); - } - } else if (map.current) { - map.current.panTo([station.longitude, station.latitude], { - duration: 500, - }); - } - }, [hoveredStationId, nearbyStations, station]); - - return ( -
- - ); -} diff --git a/website/src/components/tides/StationSearch.tsx b/website/src/components/tides/StationSearch.tsx deleted file mode 100644 index 6783f68..0000000 --- a/website/src/components/tides/StationSearch.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { useState, useCallback } from "react"; -import { fetchNeapsAPI } from "../../utils/useNeapsAPI"; - -interface Station { - id: string; - name: string; - country?: string; - region?: string; -} - -interface StationSearchProps { - onFocus?: () => void; -} - -export function StationSearch({ onFocus }: StationSearchProps = {}) { - const [searchQuery, setSearchQuery] = useState(""); - const [results, setResults] = useState([]); - const [showResults, setShowResults] = useState(false); - - const handleSearch = useCallback((query: string) => { - setSearchQuery(query); - - if (query.trim().length === 0) { - setResults([]); - setShowResults(false); - return; - } - - fetchNeapsAPI("/tides/stations", { query }) - .then((data) => { - setResults(data.slice(0, 10)); - setShowResults(true); - }) - .catch((error) => { - console.error("Failed to search stations:", error); - setResults([]); - }); - }, []); - - const handleSelectResult = useCallback((stationId: string) => { - window.location.href = `/tides/stations/${stationId}`; - }, []); - - return ( -
- handleSearch(e.target.value)} - onFocus={() => { - onFocus?.(); - searchQuery && setShowResults(true); - }} - className="card card-glass w-full rounded-full px-5 py-3 text-base placeholder-navy-400 shadow-md transition-all duration-300 ease-in-out focus:bg-white focus:outline-none focus:ring-2 focus:ring-ocean-500" - /> - - {showResults && ( -
-
    - {results.map((result) => ( -
  • - -
  • - ))} - {results.length === 0 && searchQuery.trim() !== "" && ( -
  • - No stations found -
  • - )} -
-
- )} -
- ); -} diff --git a/website/src/components/tides/StationsMap.tsx b/website/src/components/tides/StationsMap.tsx deleted file mode 100644 index 7cd3224..0000000 --- a/website/src/components/tides/StationsMap.tsx +++ /dev/null @@ -1,270 +0,0 @@ -import { useState, useCallback, useRef } from "react"; -import { - Map, - Source, - Layer, - Popup, - GeolocateControl, - type MapMouseEvent, - NavigationControl, -} from "react-map-gl/maplibre"; -import "maplibre-gl/dist/maplibre-gl.css"; -import type { GeoJSONSource } from "maplibre-gl"; -import { StationSearch } from "./StationSearch"; -import { BottomDrawer } from "../ui/BottomDrawer"; -import { useNeapsAPI } from "../../utils/useNeapsAPI"; - -interface Station { - id: string; - name: string; - type?: string; - longitude: number; - latitude: number; -} - -interface StationFeature { - type: "Feature"; - properties: { - id: string; - name: string; - type: string; - }; - geometry: { - type: "Point"; - coordinates: [number, number]; - }; -} - -// Component for the cluster layer -function ClusterLayer() { - return ( - <> - - - - ); -} - -// Component for individual station markers -function StationPointsLayer() { - return ( - - ); -} - -// Component for station popup -interface StationPopupProps { - longitude: number; - latitude: number; - name: string; - onClose: () => void; -} - -function StationPopup({ - longitude, - latitude, - name, - onClose, -}: StationPopupProps) { - return ( - -
{name}
-
- ); -} - -export function StationsMap({ children }: { children?: React.ReactNode }) { - const mapRef = useRef(null); - const sidebarRef = useRef(null); - - const { data: stations } = useNeapsAPI("/tides/stations"); - const [hoveredPopup, setHoveredPopup] = useState<{ - name: string; - longitude: number; - latitude: number; - } | null>(null); - const [cursor, setCursor] = useState("auto"); - - // Create GeoJSON features from stations - const features: StationFeature[] = (stations || []).map((station) => ({ - type: "Feature" as const, - properties: { - id: station.id, - name: station.name, - type: station.type || "reference", - }, - geometry: { - type: "Point" as const, - coordinates: [station.longitude, station.latitude], - }, - })); - - const geojsonData = { - type: "FeatureCollection" as const, - features, - }; - - const handleClick = async (event: MapMouseEvent) => { - const feature = event.features?.[0]; - if (!feature) return; - - // Handle cluster click - zoom in - if (feature.properties.cluster_id !== undefined) { - const geojsonSource: GeoJSONSource = mapRef.current.getSource("stations"); - const zoom = await geojsonSource.getClusterExpansionZoom( - feature.properties.cluster_id, - ); - - mapRef.current.easeTo({ - center: - "coordinates" in feature.geometry ? feature.geometry.coordinates : [], - zoom: zoom + 2, - duration: 300, - }); - } - - // Handle station click - navigate - if (feature.properties?.id) { - window.location.href = `/tides/stations/${feature.properties.id}`; - } - }; - - const handleMouseMove = useCallback((e: MapMouseEvent) => { - if (!e.features || e.features.length === 0) { - setCursor("auto"); - setHoveredPopup(null); - return; - } - - const feature = e.features[0]; - - // Only show popup for individual stations, not clusters - if (feature.properties?.cluster_id === undefined) { - setCursor("pointer"); - if (feature.geometry.type === "Point") { - setHoveredPopup({ - name: feature.properties?.name || "Station", - longitude: feature.geometry.coordinates[0], - latitude: feature.geometry.coordinates[1], - }); - } - } else { - setCursor("pointer"); - setHoveredPopup(null); - } - }, []); - - const handleMouseLeave = useCallback((e: MapMouseEvent) => { - setCursor("auto"); - setHoveredPopup(null); - }, []); - - return ( - - {/* Desktop sidebar */} -
- - {children} -
- - {/* Mobile bottom sheet */} - - - {children} - - - - - - - - - - {hoveredPopup && ( - setHoveredPopup(null)} /> - )} -
- ); -} diff --git a/website/src/components/tides/StationsMapIsland.tsx b/website/src/components/tides/StationsMapIsland.tsx new file mode 100644 index 0000000..20cb4ef --- /dev/null +++ b/website/src/components/tides/StationsMapIsland.tsx @@ -0,0 +1,49 @@ +import { type ReactNode, useCallback } from "react"; +import { NeapsProvider, StationsMap, StationSearch } from "@neaps/react"; +import "@neaps/react/styles.css"; +import { API_HOST } from "../../utils/constants"; +import { preferredUnits } from "../../utils/units"; +import { BottomDrawer } from "../ui/BottomDrawer"; + +const MAP_STYLE = + "https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json"; + +interface Props { + children?: ReactNode; +} + +export function StationsMapIsland({ children }: Props) { + const handleStationSelect = useCallback((station: { id: string }) => { + window.location.href = `/tides/stations/${station.id}`; + }, []); + + return ( + + {/* Inline height so h-full on StationsMap resolves; calc subtracts the fixed header */} +
+ + {/* Desktop sidebar */} +
+ + {children} +
+ + {/* Mobile bottom drawer */} + + + {children} + +
+
+
+ ); +} diff --git a/website/src/components/tides/TideGraph.tsx b/website/src/components/tides/TideGraph.tsx deleted file mode 100644 index e60602f..0000000 --- a/website/src/components/tides/TideGraph.tsx +++ /dev/null @@ -1,196 +0,0 @@ -import { useMemo } from "react"; -import { - Chart as ChartJS, - CategoryScale, - LinearScale, - PointElement, - LineElement, - Title, - Tooltip, - Legend, - Filler, - TimeScale, -} from "chart.js"; -import { Line } from "react-chartjs-2"; -import "chartjs-adapter-date-fns"; -import type { Station } from "@neaps/tide-database"; -import type { ExtremesResponse, TimelineResponse } from "../../utils/tides"; - -ChartJS.register( - CategoryScale, - LinearScale, - PointElement, - LineElement, - Title, - Tooltip, - Legend, - Filler, - TimeScale, -); - -interface Props { - station: Station; - extremesData: ExtremesResponse | null; - timelineData: TimelineResponse | null; -} - -export function TideGraph({ station, extremesData, timelineData }: Props) { - const units = timelineData?.units || extremesData?.units || "meters"; - - const timelinePoints = useMemo(() => { - if (!timelineData) return []; - return timelineData.timeline.map((p) => ({ - time: new Date(p.time), - level: p.level, - })); - }, [timelineData]); - - const extremePoints = useMemo(() => { - if (!extremesData) return []; - return extremesData.extremes.map((p) => ({ - time: new Date(p.time), - level: p.level, - label: p.label, - })); - }, [extremesData]); - - const datum = - timelineData?.datum || extremesData?.datum || station.chart_datum; - - const minLevel = - timelinePoints.length > 0 - ? Math.min(...timelinePoints.map((d) => d.level)) - : 0; - const maxLevel = - timelinePoints.length > 0 - ? Math.max(...timelinePoints.map((d) => d.level)) - : 2; - const padding = (maxLevel - minLevel) * 0.1 || 0.5; - - const pointDateStyle = Intl.DateTimeFormat(undefined, { - timeZone: station.timezone, - dateStyle: "medium", - timeStyle: "short", - }); - const axisDateStyle = Intl.DateTimeFormat(undefined, { - timeZone: station.timezone, - weekday: "short", - month: "short", - day: "numeric", - }); - - const currentTime = new Date(); - const chartData = { - datasets: [ - { - label: "High/Low", - data: extremePoints.map((d) => ({ x: d.time, y: d.level })), - borderColor: "transparent", - backgroundColor: "#0284c7", - borderWidth: 0, - fill: false, - pointRadius: 5, - pointHoverRadius: 7, - pointStyle: "circle" as const, - showLine: false, - }, - { - label: "Water Level", - data: timelinePoints.map((d) => ({ x: d.time, y: d.level })), - borderColor: "#0ea5e9", - backgroundColor: "rgba(14, 165, 233, 0.1)", - borderWidth: 2, - fill: true, - tension: 0.4, - pointRadius: 0, - pointHoverRadius: 5, - pointHoverBackgroundColor: "#0ea5e9", - }, - { - label: "Current Time", - data: [ - { x: currentTime, y: Math.min(0, minLevel - padding) }, - { x: currentTime, y: maxLevel + padding }, - ], - borderColor: "rgba(249, 115, 22, 0.5)", - borderWidth: 2, - pointRadius: 0, - fill: false, - }, - ], - }; - - const unitsLabel = units === "feet" ? "ft" : "m"; - - const chartOptions = { - responsive: true, - interaction: { - mode: "index" as const, - intersect: false, - }, - plugins: { - legend: { - display: false, - }, - tooltip: { - displayColors: false, - filter: (item: any) => item.dataset.label !== "Current Time", - callbacks: { - title: (context: any) => { - if (context.length === 0) return ""; - return pointDateStyle.format(new Date(context[0].parsed.x)); - }, - label: (context: any) => { - const value = `${(context.parsed.y ?? 0).toFixed(2)} ${unitsLabel}`; - if (context.dataset.label === "High/Low") { - const extreme = extremePoints[context.dataIndex]; - return extreme?.label ? `${extreme.label}: ${value}` : value; - } - return value; - }, - }, - }, - }, - scales: { - x: { - type: "time" as const, - time: { - unit: "day" as const, - }, - ticks: { - callback: function (value: any) { - return axisDateStyle.format(new Date(value)); - }, - }, - }, - y: { - ticks: { - stepSize: maxLevel - minLevel > 3 ? 1 : 0.5, - callback: function (value: any) { - return `${value} ${unitsLabel}`; - }, - }, - title: { - display: true, - text: datum, - }, - }, - }, - }; - - return ( -
-
- {timelinePoints.length > 0 ? ( -
- -
- ) : ( -
-

Loading tide data...

-
- )} -
-
- ); -} diff --git a/website/src/components/tides/TideStation.tsx b/website/src/components/tides/TideStation.tsx deleted file mode 100644 index 488682a..0000000 --- a/website/src/components/tides/TideStation.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { useMemo } from "react"; -import type { Station } from "@neaps/tide-database"; -import { Temporal } from "@js-temporal/polyfill"; -import { useNeapsAPI } from "../../utils/useNeapsAPI"; -import type { ExtremesResponse, TimelineResponse } from "../../utils/tides"; -import { preferredUnits } from "../../utils/units"; -import Today from "./Today"; -import { TideGraph } from "./TideGraph"; - -interface Props { - station: Station; -} - -export function TideStation({ station }: Props) { - // Compute a single date range that covers both components: - // - Today needs extremes from -6.5h to +18.5h - // - TideGraph needs data from now to +3 days - // Combined: -6.5h to +3 days - const { startDate, endDate } = useMemo(() => { - const start = Temporal.Now.zonedDateTimeISO(station.timezone).subtract({ - hours: 6, - minutes: 30, - }); - const end = Temporal.Now.zonedDateTimeISO(station.timezone).add({ - days: 3, - }); - return { - startDate: start.toInstant().toString(), - endDate: end.toInstant().toString(), - }; - }, [station.timezone]); - - const { data: extremesData, loading } = useNeapsAPI( - `/tides/stations/${station.id}/extremes`, - { start: startDate, end: endDate, units: preferredUnits }, - ); - - const { data: timelineData } = useNeapsAPI( - `/tides/stations/${station.id}/timeline`, - { start: startDate, end: endDate, units: preferredUnits }, - ); - - if (loading) { - return ( -
-

Loading tide data...

-
- ); - } - - return ( -
- - -
- ); -} diff --git a/website/src/components/tides/TideStationIsland.tsx b/website/src/components/tides/TideStationIsland.tsx new file mode 100644 index 0000000..51d98e0 --- /dev/null +++ b/website/src/components/tides/TideStationIsland.tsx @@ -0,0 +1,40 @@ +import { Component, type ReactNode } from "react"; +import { NeapsProvider, TideStation } from "@neaps/react"; +import "@neaps/react/styles.css"; +import { API_HOST } from "../../utils/constants"; +import { preferredUnits } from "../../utils/units"; + +class ErrorBoundary extends Component< + { children: ReactNode }, + { error: Error | null } +> { + state = { error: null }; + static getDerivedStateFromError(error: Error) { + return { error }; + } + render() { + if (this.state.error) { + return ( +
+ Error loading tide station:{" "} + {(this.state.error as Error).message} +
+ ); + } + return this.props.children; + } +} + +interface Props { + id: string; +} + +export function TideStationIsland({ id }: Props) { + return ( + + + + + + ); +} diff --git a/website/src/components/tides/Today.tsx b/website/src/components/tides/Today.tsx deleted file mode 100644 index 865b3c0..0000000 --- a/website/src/components/tides/Today.tsx +++ /dev/null @@ -1,176 +0,0 @@ -import { useMemo } from "react"; -import { DateTime } from "../DateTime"; -import { TideHeight } from "../TideHeight"; -import type { Station } from "@neaps/tide-database"; -import { Temporal } from "@js-temporal/polyfill"; -import { cn } from "../../utils/cn"; -import type { ExtremesResponse, TimelineResponse } from "../../utils/tides"; - -// Format timezone name with UTC offset (e.g., "America/New_York" → "New York (UTC-5)") -function formatTimezoneWithOffset(timeZone: string) { - // Get the UTC offset for this timezone - const zoned = Temporal.Now.zonedDateTimeISO(timeZone); - const offset = zoned.offset; - - // Format offset as +/-HH:MM - const sign = offset.startsWith("-") ? "-" : "+"; - const formatted = - sign + - offset - .slice(1) - .split(":") - .filter((n) => n && n !== "00") - .join(":"); - - return `${timeZone.replace("_", " ")} (UTC${formatted})`; -} - -export type TodayProps = { - station: Station; - extremesData: ExtremesResponse | null; - timelineData: TimelineResponse | null; - now?: Temporal.Instant; -}; - -export default function Today({ - station, - extremesData, - timelineData, - now = Temporal.Now.instant(), -}: TodayProps) { - const start = useMemo(() => { - return Temporal.Now.zonedDateTimeISO(station.timezone).subtract({ - hours: 6, - minutes: 30, - }); - }, [station.timezone]); - - const end = useMemo(() => start.add({ hours: 25 }), [start]); - - // Filter extremes to the ~25h window for today's display - const extremes = useMemo(() => { - if (!extremesData?.extremes) return []; - const startMs = start.toInstant().epochMilliseconds; - const endMs = end.toInstant().epochMilliseconds; - return extremesData.extremes.filter((e) => { - const t = new Date(e.time).valueOf(); - return t >= startMs && t <= endMs; - }); - }, [extremesData, start, end]); - - const datum = extremesData?.datum || station.chart_datum; - - const nextTide = extremes.find( - (extreme) => new Date(extreme.time).valueOf() > now.epochMilliseconds, - ); - - // Find the closest timeline point to now for current water level - const nowLevel = useMemo(() => { - if (!timelineData?.timeline?.length) return undefined; - const nowMs = now.epochMilliseconds; - let closest = timelineData.timeline[0]; - let closestDiff = Math.abs(new Date(closest.time).valueOf() - nowMs); - for (const point of timelineData.timeline) { - const diff = Math.abs(new Date(point.time).valueOf() - nowMs); - if (diff < closestDiff) { - closest = point; - closestDiff = diff; - } - } - return closest.level; - }, [timelineData, now]); - - return ( -
-
-
-

Today's Tides

-
- -
-
- -
-
- {formatTimezoneWithOffset(station.timezone)} -
-
- {nextTide?.high ? ( - - ↑ - - ) : ( - - ↓ - - )} - {nowLevel != null && } -
-
{datum}
-
- {extremes.length > 0 ? ( -
- - - - - - - - - - {extremes.map((extreme) => ( - - - - - - ))} - -
- Time - - Type - - Height -
- - {extreme.label} - -
-
- ) : ( -
-

No tide data available

-
- )} -
-
- ); -} diff --git a/website/src/pages/about.astro b/website/src/pages/about.astro index 05730cb..d9c0f5d 100644 --- a/website/src/pages/about.astro +++ b/website/src/pages/about.astro @@ -14,7 +14,7 @@ import { CONTACT_EMAIL } from "../utils/constants";

About Open Waters

-

Hi there!

+

Hi there!

I'm Brandon, and I started Open Water Software as a home for various @@ -24,7 +24,7 @@ import { CONTACT_EMAIL } from "../utils/constants"; the sea.

-

"Open" as in "The Ocean"

+

"Open" as in "The Ocean"

The ocean is a commons. We all depend on it, and we are all @@ -41,9 +41,9 @@ import { CONTACT_EMAIL } from "../utils/constants";

-

+

If you want to learn more or talk about ways to contribute, get in touch.

@@ -56,10 +56,10 @@ import { CONTACT_EMAIL } from "../utils/constants";

-

Our Projects

+

Our Projects

-
+

Tide Predictions

Accurate tide predictions powered by our Neaps engine, with @@ -68,13 +68,13 @@ import { CONTACT_EMAIL } from "../utils/constants";

Learn more about tides →
-
+

Crowd Depth

Help improve nautical charts by sharing depth data from your @@ -83,13 +83,13 @@ import { CONTACT_EMAIL } from "../utils/constants";

Learn more about bathymetry →
-
+

Developer API

Access our marine data programmatically through well-documented @@ -97,14 +97,14 @@ import { CONTACT_EMAIL } from "../utils/constants";

View API documentation →
-

Get Involved

+

Get Involved

We welcome contributions from anyone interested in marine software and @@ -130,30 +130,3 @@ import { CONTACT_EMAIL } from "../utils/constants";

- - diff --git a/website/src/pages/bathymetry/index.astro b/website/src/pages/bathymetry/index.astro index a6333d6..069fc62 100644 --- a/website/src/pages/bathymetry/index.astro +++ b/website/src/pages/bathymetry/index.astro @@ -10,7 +10,7 @@ import { Icon } from "astro-icon/components"; description="Collect and share depth data from your marine vessel to contribute to crowd-sourced bathymetry programs." > -
+

Crowd Depth

@@ -30,26 +30,26 @@ import { Icon } from "astro-icon/components";

What is Crowd Depth?

-

+

Crowd Depth is an initiative to collect and share depth soundings from recreational and commercial vessels to improve nautical charts and bathymetric data. By crowdsourcing depth measurements, we can:

-