diff --git a/package.json b/package.json index ff926b7..be16b11 100644 --- a/package.json +++ b/package.json @@ -34,10 +34,12 @@ "jotai-cache": "latest", "jotai-effect": "latest", "lucide-react": "latest", + "mapbox-gl": "^3.6.0", "moment": "latest", "next": "latest", "react": "latest", "react-dom": "latest", + "react-map-gl": "^7.1.7", "tailwind-merge": "latest", "tailwindcss-animate": "latest" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3145d70..561123a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: lucide-react: specifier: latest version: 0.419.0(react@18.3.1) + mapbox-gl: + specifier: ^3.6.0 + version: 3.6.0 moment: specifier: latest version: 2.30.1 @@ -56,6 +59,9 @@ importers: react-dom: specifier: latest version: 18.3.1(react@18.3.1) + react-map-gl: + specifier: ^7.1.7 + version: 7.1.7(mapbox-gl@3.6.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) tailwind-merge: specifier: latest version: 2.4.0 @@ -319,6 +325,33 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@mapbox/jsonlint-lines-primitives@2.0.2': + resolution: {integrity: sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==} + engines: {node: '>= 0.6'} + + '@mapbox/mapbox-gl-supported@3.0.0': + resolution: {integrity: sha512-2XghOwu16ZwPJLOFVuIOaLbN0iKMn867evzXFyf0P22dqugezfJwLmdanAgU25ITvz1TvOfVP4jsDImlDJzcWg==} + + '@mapbox/point-geometry@0.1.0': + resolution: {integrity: sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==} + + '@mapbox/tiny-sdf@2.0.6': + resolution: {integrity: sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==} + + '@mapbox/unitbezier@0.0.1': + resolution: {integrity: sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==} + + '@mapbox/vector-tile@1.3.1': + resolution: {integrity: sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==} + + '@mapbox/whoots-js@3.1.0': + resolution: {integrity: sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==} + engines: {node: '>=6.0.0'} + + '@maplibre/maplibre-gl-style-spec@19.3.3': + resolution: {integrity: sha512-cOZZOVhDSulgK0meTsTkmNXb1ahVvmTmWmfx9gRBwc6hq98wS9JP35ESIoNq3xqEan+UN+gn8187Z6E4NKhLsw==} + hasBin: true + '@next/env@13.5.6': resolution: {integrity: sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw==} @@ -842,18 +875,33 @@ packages: '@types/conventional-commits-parser@5.0.0': resolution: {integrity: sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ==} + '@types/geojson@7946.0.14': + resolution: {integrity: sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==} + '@types/http-cache-semantics@4.0.4': resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/mapbox-gl@3.4.0': + resolution: {integrity: sha512-tbn++Mm94H1kE7W6FF0oVC9rMXHVzDDNUbS7KfBMRF8NV/8csFi+67ytKcZJ4LsrpsJ+8MC6Os6ZinEDCsrunw==} + + '@types/mapbox__point-geometry@0.1.4': + resolution: {integrity: sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==} + + '@types/mapbox__vector-tile@1.3.4': + resolution: {integrity: sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==} + '@types/node@22.0.2': resolution: {integrity: sha512-yPL6DyFwY5PiMVEwymNeqUTKsDczQBJ/5T7W/46RwLU/VH+AA8aT5TZkvBviLKLbbm0hlfftEkGrNzfRk/fofQ==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/pbf@3.0.5': + resolution: {integrity: sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==} + '@types/prop-types@15.7.12': resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} @@ -1052,6 +1100,10 @@ packages: aria-query@5.1.3: resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} + arr-union@3.1.0: + resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} + engines: {node: '>=0.10.0'} + array-buffer-byte-length@1.0.1: resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} engines: {node: '>= 0.4'} @@ -1101,6 +1153,10 @@ packages: resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} engines: {node: '>=0.8'} + assign-symbols@1.0.0: + resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} + engines: {node: '>=0.10.0'} + ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} @@ -1214,6 +1270,12 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} + bytewise-core@1.2.3: + resolution: {integrity: sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA==} + + bytewise@1.1.0: + resolution: {integrity: sha512-rHuuseJ9iQ0na6UDhnrRVDh8YnWVlU6xM3VH6q/+yHDeUH2zIhUzP+2/h3LIrhLDBtTqzWpE3p3tP/boefskKQ==} + cacheable-lookup@7.0.0: resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} engines: {node: '>=14.16'} @@ -1263,6 +1325,9 @@ packages: chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + cheap-ruler@4.0.0: + resolution: {integrity: sha512-0BJa8f4t141BYKQyn9NSQt1PguFQXMXwZiA5shfoaBYHAb2fFk2RAX+tiWMoQU+Agtzt3mdt0JtuyshAXqZ+Vw==} + check-more-types@2.24.0: resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} engines: {node: '>= 0.8.0'} @@ -1481,6 +1546,9 @@ packages: resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} engines: {node: '>=12'} + csscolorparser@1.0.3: + resolution: {integrity: sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==} + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -1636,6 +1704,9 @@ packages: resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==} engines: {node: '>=10'} + earcut@3.0.0: + resolution: {integrity: sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -1885,6 +1956,14 @@ packages: resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==} engines: {node: '>=4'} + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + + extend-shallow@3.0.2: + resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} + engines: {node: '>=0.10.0'} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -1924,6 +2003,9 @@ packages: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -2006,6 +2088,9 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + geojson-vt@4.0.2: + resolution: {integrity: sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -2045,6 +2130,10 @@ packages: resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==} engines: {node: '>= 14'} + get-value@2.0.6: + resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} + engines: {node: '>=0.10.0'} + getos@3.2.1: resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} @@ -2067,6 +2156,9 @@ packages: git-url-parse@14.0.0: resolution: {integrity: sha512-NnLweV+2A4nCvn4U/m2AoYu0pPKlsmhK9cknG7IMwsjFY1S2jxM+mAhsDxyxfCIGfGaD+dozsyX4b6vkYc83yQ==} + gl-matrix@3.4.3: + resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -2129,6 +2221,9 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + grid-index@1.1.0: + resolution: {integrity: sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==} + handlebars@4.7.8: resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} engines: {node: '>=0.4.7'} @@ -2322,6 +2417,14 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} hasBin: true + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + + is-extendable@1.0.1: + resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} + engines: {node: '>=0.10.0'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2407,6 +2510,10 @@ packages: resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} engines: {node: '>=12'} + is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -2482,6 +2589,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isobject@3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + isstream@0.1.2: resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} @@ -2561,6 +2672,9 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-stringify-pretty-compact@3.0.0: + resolution: {integrity: sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==} + json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} @@ -2583,6 +2697,9 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} + kdbush@4.0.2: + resolution: {integrity: sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -2736,6 +2853,9 @@ packages: resolution: {integrity: sha512-fSErXALFNsnowREYZ49XCdOHF8wOPWuFOGQrAhP7x5J/BqQv+B02cNsTykGpDgRVx43EKg++6ANmTaGTtW+hUA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + mapbox-gl@3.6.0: + resolution: {integrity: sha512-xjYHHIJDh6haYcKY+/9jh1eywwYfIOWCgT5Fowj4JriZexx/oOtg2S7BQDMZtpFyg9IN4VLCysmUWxY0pFNRWA==} + meow@12.1.1: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} @@ -2802,6 +2922,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + murmurhash-js@1.0.0: + resolution: {integrity: sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==} + mute-stream@1.0.0: resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -3062,6 +3185,10 @@ packages: resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} engines: {node: '>=12'} + pbf@3.3.0: + resolution: {integrity: sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==} + hasBin: true + pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} @@ -3137,6 +3264,9 @@ packages: resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==} engines: {node: ^10 || ^12 || >=14} + potpack@2.0.0: + resolution: {integrity: sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -3212,6 +3342,9 @@ packages: proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + protocol-buffers-schema@3.6.0: + resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==} + protocols@2.0.1: resolution: {integrity: sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==} @@ -3253,6 +3386,9 @@ packages: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} + quickselect@3.0.0: + resolution: {integrity: sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==} + rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -3265,6 +3401,19 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-map-gl@7.1.7: + resolution: {integrity: sha512-mwjc0obkBJOXCcoXQr3VoLqmqwo9vS4bXfbGsdxXzEgVCv/PM0v+1QggL7W0d/ccIy+VCjbXNlGij+PENz6VNg==} + peerDependencies: + mapbox-gl: '>=1.13.0' + maplibre-gl: '>=1.13.0' + react: '>=16.3.0' + react-dom: '>=16.3.0' + peerDependenciesMeta: + mapbox-gl: + optional: true + maplibre-gl: + optional: true + react-remove-scroll-bar@2.3.6: resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} engines: {node: '>=10'} @@ -3371,6 +3520,9 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve-protobuf-schema@2.1.0: + resolution: {integrity: sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==} + resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -3418,6 +3570,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} @@ -3456,6 +3611,10 @@ packages: engines: {node: '>=10'} hasBin: true + serialize-to-js@3.1.2: + resolution: {integrity: sha512-owllqNuDDEimQat7EPG0tH7JjO090xKNzUtYz6X+Sk2BXDnOCilDdNLwjWeFywG9xkJul1ULvtUQa9O4pUaY0w==} + engines: {node: '>=4.0.0'} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -3464,6 +3623,10 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} + set-value@2.0.1: + resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} + engines: {node: '>=0.10.0'} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -3524,6 +3687,18 @@ packages: resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + sort-asc@0.2.0: + resolution: {integrity: sha512-umMGhjPeHAI6YjABoSTrFp2zaBtXBej1a0yKkuMUyjjqu6FJsTF+JYwCswWDg+zJfk/5npWUUbd33HH/WLzpaA==} + engines: {node: '>=0.10.0'} + + sort-desc@0.2.0: + resolution: {integrity: sha512-NqZqyvL4VPW+RAxxXnB8gvE1kyikh8+pR+T+CXLksVRN9eiQqkQlPwqWYU0mF9Jm7UnctShlxLyAt1CaBOTL1w==} + engines: {node: '>=0.10.0'} + + sort-object@3.0.3: + resolution: {integrity: sha512-nK7WOY8jik6zaG9CRwZTaD5O7ETWDLZYMM12pqY8htll+7dYeqGfEUPcUBHOpSJg2vJOrvFIY2Dl5cX2ih1hAQ==} + engines: {node: '>=0.10.0'} + source-map-js@1.2.0: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} @@ -3544,6 +3719,10 @@ packages: spdx-license-ids@3.0.18: resolution: {integrity: sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==} + split-string@3.1.0: + resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} + engines: {node: '>=0.10.0'} + split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -3651,6 +3830,9 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + supercluster@8.0.1: + resolution: {integrity: sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==} + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -3704,6 +3886,9 @@ packages: through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + tinyqueue@3.0.0: + resolution: {integrity: sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==} + tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -3738,6 +3923,9 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + tweakpane@4.0.4: + resolution: {integrity: sha512-RkWD54zDlEbnN01wQPk0ANHGbdCvlJx/E8A1QxhTfCbX+ROWos1Ws2MnhOm39aUGMOh+36TjUwpDmLfmwTr1Fg==} + tweetnacl@0.14.5: resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} @@ -3796,6 +3984,12 @@ packages: engines: {node: '>=14.17'} hasBin: true + typewise-core@1.2.0: + resolution: {integrity: sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg==} + + typewise@1.0.3: + resolution: {integrity: sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ==} + uglify-js@3.18.0: resolution: {integrity: sha512-SyVVbcNBCk0dzr9XL/R/ySrmYf0s372K6/hFklzgcp2lBFyXtw4I7BOdDjlLhE1aVqaI/SHWXWmYdlZxuyF38A==} engines: {node: '>=0.8.0'} @@ -3811,6 +4005,10 @@ packages: resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} engines: {node: '>=18'} + union-value@1.0.1: + resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} + engines: {node: '>=0.10.0'} + unique-string@3.0.0: resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==} engines: {node: '>=12'} @@ -3884,6 +4082,9 @@ packages: resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} engines: {'0': node >=0.6.0} + vt-pbf@3.1.3: + resolution: {integrity: sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==} + wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} @@ -4233,6 +4434,31 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 + '@mapbox/jsonlint-lines-primitives@2.0.2': {} + + '@mapbox/mapbox-gl-supported@3.0.0': {} + + '@mapbox/point-geometry@0.1.0': {} + + '@mapbox/tiny-sdf@2.0.6': {} + + '@mapbox/unitbezier@0.0.1': {} + + '@mapbox/vector-tile@1.3.1': + dependencies: + '@mapbox/point-geometry': 0.1.0 + + '@mapbox/whoots-js@3.1.0': {} + + '@maplibre/maplibre-gl-style-spec@19.3.3': + dependencies: + '@mapbox/jsonlint-lines-primitives': 2.0.2 + '@mapbox/unitbezier': 0.0.1 + json-stringify-pretty-compact: 3.0.0 + minimist: 1.2.8 + rw: 1.3.3 + sort-object: 3.0.3 + '@next/env@13.5.6': {} '@next/env@14.2.5': {} @@ -4722,16 +4948,32 @@ snapshots: dependencies: '@types/node': 22.0.2 + '@types/geojson@7946.0.14': {} + '@types/http-cache-semantics@4.0.4': {} '@types/json5@0.0.29': {} + '@types/mapbox-gl@3.4.0': + dependencies: + '@types/geojson': 7946.0.14 + + '@types/mapbox__point-geometry@0.1.4': {} + + '@types/mapbox__vector-tile@1.3.4': + dependencies: + '@types/geojson': 7946.0.14 + '@types/mapbox__point-geometry': 0.1.4 + '@types/pbf': 3.0.5 + '@types/node@22.0.2': dependencies: undici-types: 6.11.1 '@types/normalize-package-data@2.4.4': {} + '@types/pbf@3.0.5': {} + '@types/prop-types@15.7.12': {} '@types/react-dom@18.3.0': @@ -4960,6 +5202,8 @@ snapshots: dependencies: deep-equal: 2.2.3 + arr-union@3.1.0: {} + array-buffer-byte-length@1.0.1: dependencies: call-bind: 1.0.7 @@ -5042,6 +5286,8 @@ snapshots: assert-plus@1.0.0: {} + assign-symbols@1.0.0: {} + ast-types-flow@0.0.8: {} ast-types@0.13.4: @@ -5156,6 +5402,15 @@ snapshots: dependencies: streamsearch: 1.1.0 + bytewise-core@1.2.3: + dependencies: + typewise-core: 1.2.0 + + bytewise@1.1.0: + dependencies: + bytewise-core: 1.2.3 + typewise: 1.0.3 + cacheable-lookup@7.0.0: {} cacheable-request@10.2.14: @@ -5203,6 +5458,8 @@ snapshots: chardet@0.7.0: {} + cheap-ruler@4.0.0: {} + check-more-types@2.24.0: {} chokidar@3.6.0: @@ -5430,6 +5687,8 @@ snapshots: dependencies: type-fest: 1.4.0 + csscolorparser@1.0.3: {} + cssesc@3.0.0: {} csstype@3.1.3: {} @@ -5619,6 +5878,8 @@ snapshots: dependencies: is-obj: 2.0.0 + earcut@3.0.0: {} + eastasianwidth@0.2.0: {} ecc-jsbn@0.1.2: @@ -6047,6 +6308,15 @@ snapshots: dependencies: pify: 2.3.0 + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + + extend-shallow@3.0.2: + dependencies: + assign-symbols: 1.0.0 + is-extendable: 1.0.1 + extend@3.0.2: {} external-editor@3.1.0: @@ -6094,6 +6364,8 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 3.3.3 + fflate@0.8.2: {} + figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 @@ -6184,6 +6456,8 @@ snapshots: functions-have-names@1.2.3: {} + geojson-vt@4.0.2: {} + get-caller-file@2.0.5: {} get-east-asian-width@1.2.0: {} @@ -6225,6 +6499,8 @@ snapshots: transitivePeerDependencies: - supports-color + get-value@2.0.6: {} + getos@3.2.1: dependencies: async: 3.2.5 @@ -6253,6 +6529,8 @@ snapshots: dependencies: git-up: 7.0.0 + gl-matrix@3.4.3: {} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -6346,6 +6624,8 @@ snapshots: graphemer@1.4.0: {} + grid-index@1.1.0: {} + handlebars@4.7.8: dependencies: minimist: 1.2.8 @@ -6531,6 +6811,12 @@ snapshots: is-docker@3.0.0: {} + is-extendable@0.1.1: {} + + is-extendable@1.0.1: + dependencies: + is-plain-object: 2.0.4 + is-extglob@2.1.1: {} is-finalizationregistry@1.0.2: @@ -6591,6 +6877,10 @@ snapshots: is-path-inside@4.0.0: {} + is-plain-object@2.0.4: + dependencies: + isobject: 3.0.1 + is-regex@1.1.4: dependencies: call-bind: 1.0.7 @@ -6653,6 +6943,8 @@ snapshots: isexe@2.0.0: {} + isobject@3.0.1: {} + isstream@0.1.2: {} issue-parser@7.0.1: @@ -6722,6 +7014,8 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} + json-stringify-pretty-compact@3.0.0: {} + json-stringify-safe@5.0.1: {} json5@1.0.2: @@ -6750,6 +7044,8 @@ snapshots: object.assign: 4.1.5 object.values: 1.2.0 + kdbush@4.0.2: {} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -6897,6 +7193,36 @@ snapshots: macos-release@3.2.0: {} + mapbox-gl@3.6.0: + dependencies: + '@mapbox/jsonlint-lines-primitives': 2.0.2 + '@mapbox/mapbox-gl-supported': 3.0.0 + '@mapbox/point-geometry': 0.1.0 + '@mapbox/tiny-sdf': 2.0.6 + '@mapbox/unitbezier': 0.0.1 + '@mapbox/vector-tile': 1.3.1 + '@mapbox/whoots-js': 3.1.0 + '@types/geojson': 7946.0.14 + '@types/mapbox__vector-tile': 1.3.4 + cheap-ruler: 4.0.0 + csscolorparser: 1.0.3 + earcut: 3.0.0 + fflate: 0.8.2 + geojson-vt: 4.0.2 + gl-matrix: 3.4.3 + grid-index: 1.1.0 + kdbush: 4.0.2 + murmurhash-js: 1.0.0 + pbf: 3.3.0 + potpack: 2.0.0 + quickselect: 3.0.0 + rw: 1.3.3 + serialize-to-js: 3.1.2 + supercluster: 8.0.1 + tinyqueue: 3.0.0 + tweakpane: 4.0.4 + vt-pbf: 3.1.3 + meow@12.1.1: {} merge-stream@2.0.0: {} @@ -6944,6 +7270,8 @@ snapshots: ms@2.1.3: {} + murmurhash-js@1.0.0: {} + mute-stream@1.0.0: {} mz@2.7.0: @@ -7236,6 +7564,11 @@ snapshots: path-type@5.0.0: {} + pbf@3.3.0: + dependencies: + ieee754: 1.2.1 + resolve-protobuf-schema: 2.1.0 + pend@1.2.0: {} performance-now@2.1.0: {} @@ -7295,6 +7628,8 @@ snapshots: picocolors: 1.0.1 source-map-js: 1.2.0 + potpack@2.0.0: {} + prelude-ls@1.2.1: {} prettier-plugin-tailwindcss@0.6.5(prettier@3.3.3): @@ -7315,6 +7650,8 @@ snapshots: proto-list@1.2.4: {} + protocol-buffers-schema@3.6.0: {} + protocols@2.0.1: {} proxy-agent@6.4.0: @@ -7357,6 +7694,8 @@ snapshots: quick-lru@5.1.1: {} + quickselect@3.0.0: {} + rc@1.2.8: dependencies: deep-extend: 0.6.0 @@ -7372,6 +7711,15 @@ snapshots: react-is@16.13.1: {} + react-map-gl@7.1.7(mapbox-gl@3.6.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@maplibre/maplibre-gl-style-spec': 19.3.3 + '@types/mapbox-gl': 3.4.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + mapbox-gl: 3.6.0 + react-remove-scroll-bar@2.3.6(@types/react@18.3.3)(react@18.3.1): dependencies: react: 18.3.1 @@ -7510,6 +7858,10 @@ snapshots: resolve-pkg-maps@1.0.0: {} + resolve-protobuf-schema@2.1.0: + dependencies: + protocol-buffers-schema: 3.6.0 + resolve@1.22.8: dependencies: is-core-module: 2.14.0 @@ -7554,6 +7906,8 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rw@1.3.3: {} + rxjs@7.8.1: dependencies: tslib: 2.6.3 @@ -7589,6 +7943,8 @@ snapshots: semver@7.6.3: {} + serialize-to-js@3.1.2: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -7605,6 +7961,13 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + set-value@2.0.1: + dependencies: + extend-shallow: 2.0.1 + is-extendable: 0.1.1 + is-plain-object: 2.0.4 + split-string: 3.1.0 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -7669,6 +8032,19 @@ snapshots: ip-address: 9.0.5 smart-buffer: 4.2.0 + sort-asc@0.2.0: {} + + sort-desc@0.2.0: {} + + sort-object@3.0.3: + dependencies: + bytewise: 1.1.0 + get-value: 2.0.6 + is-extendable: 0.1.1 + sort-asc: 0.2.0 + sort-desc: 0.2.0 + union-value: 1.0.1 + source-map-js@1.2.0: {} source-map@0.6.1: {} @@ -7687,6 +8063,10 @@ snapshots: spdx-license-ids@3.0.18: {} + split-string@3.1.0: + dependencies: + extend-shallow: 3.0.2 + split2@4.2.0: {} sprintf-js@1.1.3: {} @@ -7807,6 +8187,10 @@ snapshots: pirates: 4.0.6 ts-interface-checker: 0.1.13 + supercluster@8.0.1: + dependencies: + kdbush: 4.0.2 + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -7872,6 +8256,8 @@ snapshots: through@2.3.8: {} + tinyqueue@3.0.0: {} + tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 @@ -7908,6 +8294,8 @@ snapshots: dependencies: safe-buffer: 5.2.1 + tweakpane@4.0.4: {} + tweetnacl@0.14.5: {} type-check@0.4.0: @@ -7966,6 +8354,12 @@ snapshots: typescript@5.5.4: {} + typewise-core@1.2.0: {} + + typewise@1.0.3: + dependencies: + typewise-core: 1.2.0 + uglify-js@3.18.0: optional: true @@ -7980,6 +8374,13 @@ snapshots: unicorn-magic@0.1.0: {} + union-value@1.0.1: + dependencies: + arr-union: 3.1.0 + get-value: 2.0.6 + is-extendable: 0.1.1 + set-value: 2.0.1 + unique-string@3.0.0: dependencies: crypto-random-string: 4.0.0 @@ -8054,6 +8455,12 @@ snapshots: core-util-is: 1.0.2 extsprintf: 1.3.0 + vt-pbf@3.1.3: + dependencies: + '@mapbox/point-geometry': 0.1.0 + '@mapbox/vector-tile': 1.3.1 + pbf: 3.3.0 + wcwidth@1.0.1: dependencies: defaults: 1.0.4 diff --git a/src/app/api/fetch.ts b/src/app/api/fetch.ts index 14596e3..15c5974 100644 --- a/src/app/api/fetch.ts +++ b/src/app/api/fetch.ts @@ -1,44 +1,44 @@ -import { bearerToken, serverUrl } from '@/lib/constants'; - -export const fetchAPI = async (endpoint: string) => { - // Headers for authorization - const options = { - headers: { - Authorization: `Bearer ${bearerToken}`, - }, - }; - - // Check if any fetching is in queue - - // If so add to queue - - // Need mechanism to tell code to go to next fetch - - // Fetch from server - const data = await fetch(`${serverUrl}/${endpoint}`, { ...options }) - .then( - (res) => { - // Response is not successful - if (!res.ok) { - throw new Error('Not 2xx response', { cause: res }); - } - - // Success parse data - return res.json(); - }, - // Catch initial fetch error - (err) => { - throw new Error('Server not connecting', { cause: err }); - }, - ) - // Return parsed data - .then((data) => data) - // Catch and handle errors from above - .catch((err) => { - if (typeof err.cause.json === 'function') return err.cause.json(); - - return err.cause; - }); - - return data; -}; +import { bearerToken, serverUrl } from '@/lib/constants'; + +export const fetchAPI = async (endpoint: string) => { + // Headers for authorization + const options = { + headers: { + Authorization: `Bearer ${bearerToken}`, + }, + }; + + // Check if any fetching is in queue + + // If so add to queue + + // Need mechanism to tell code to go to next fetch + + // Fetch from server + const data = await fetch(`${serverUrl}/${endpoint}`, { ...options }) + .then( + (res) => { + // Response is not successful + if (!res.ok) { + throw new Error('Not 2xx response', { cause: res }); + } + + // Success parse data + return res.json(); + }, + // Catch initial fetch error + (err) => { + throw new Error('Server not connecting', { cause: err }); + }, + ) + // Return parsed data + .then((data) => data) + // Catch and handle errors from above + .catch((err) => { + if (typeof err.cause.json === 'function') return err.cause.json(); + + return err.cause; + }); + + return data; +}; diff --git a/src/app/api/fetchMap.tsx b/src/app/api/fetchMap.tsx new file mode 100644 index 0000000..f1e4e5a --- /dev/null +++ b/src/app/api/fetchMap.tsx @@ -0,0 +1,34 @@ +'use client'; + +import { useEffect, useState } from 'react'; + +import { fetchEvents } from '@/app/api/fetchEvents'; + +const CircuitMap = () => { + const [firstEvent, setFirstEvent] = useState(null); + + useEffect(() => { + const getFirstEvent = async () => { + const events = await fetchEvents(); + if (events.length > 0) { + setFirstEvent(events[0]); + } + }; + + getFirstEvent(); + }, []); + return ( +
+ {firstEvent ? ( +
+

First Event

+

{JSON.stringify(firstEvent, null, 2)}

+
+ ) : ( +

No events available.

+ )} +
+ ); +}; + +export default CircuitMap; diff --git a/src/app/mapbox/page.tsx b/src/app/mapbox/page.tsx new file mode 100644 index 0000000..e015a35 --- /dev/null +++ b/src/app/mapbox/page.tsx @@ -0,0 +1,27 @@ +'use client'; + +import { useState } from 'react'; +import Map from 'react-map-gl'; + +import 'mapbox-gl/dist/mapbox-gl.css'; + +const GlobeMap = () => { + return ( +
+

Formula 1 Map

+ +
+ ); +}; + +export default GlobeMap; diff --git a/src/components/TopNav/MainNav.tsx b/src/components/TopNav/MainNav.tsx index d02492b..b3de7c7 100644 --- a/src/components/TopNav/MainNav.tsx +++ b/src/components/TopNav/MainNav.tsx @@ -1,20 +1,26 @@ -import Link from 'next/link'; - -export const MainNav = () => { - return ( - - ); -}; +import Link from 'next/link'; + +export const MainNav = () => { + return ( + + ); +}; diff --git a/src/components/ui/use-toast.ts b/src/components/ui/use-toast.ts index 14c19a5..46fdb80 100644 --- a/src/components/ui/use-toast.ts +++ b/src/components/ui/use-toast.ts @@ -1,191 +1,191 @@ -'use client'; - -// Inspired by react-hot-toast library -import * as React from 'react'; - -import type { ToastActionElement, ToastProps } from '@/components/ui/toast'; - -const TOAST_LIMIT = 1; -const TOAST_REMOVE_DELAY = 1000000; - -export type ToasterToast = ToastProps & { - id: string; - title?: React.ReactNode; - description?: React.ReactNode; - action?: ToastActionElement; -}; - -const _actionTypes = { - ADD_TOAST: 'ADD_TOAST', - UPDATE_TOAST: 'UPDATE_TOAST', - DISMISS_TOAST: 'DISMISS_TOAST', - REMOVE_TOAST: 'REMOVE_TOAST', -} as const; - -let count = 0; - -function genId() { - count = (count + 1) % Number.MAX_SAFE_INTEGER; - return count.toString(); -} - -type ActionType = typeof _actionTypes; - -type Action = - | { - type: ActionType['ADD_TOAST']; - toast: ToasterToast; - } - | { - type: ActionType['UPDATE_TOAST']; - toast: Partial; - } - | { - type: ActionType['DISMISS_TOAST']; - toastId?: ToasterToast['id']; - } - | { - type: ActionType['REMOVE_TOAST']; - toastId?: ToasterToast['id']; - }; - -interface State { - toasts: ToasterToast[]; -} - -const toastTimeouts = new Map>(); - -const addToRemoveQueue = (toastId: string) => { - if (toastTimeouts.has(toastId)) { - return; - } - - const timeout = setTimeout(() => { - toastTimeouts.delete(toastId); - dispatch({ - type: 'REMOVE_TOAST', - toastId: toastId, - }); - }, TOAST_REMOVE_DELAY); - - toastTimeouts.set(toastId, timeout); -}; - -export const reducer = (state: State, action: Action): State => { - switch (action.type) { - case 'ADD_TOAST': - return { - ...state, - toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), - }; - - case 'UPDATE_TOAST': - return { - ...state, - toasts: state.toasts.map((t) => - t.id === action.toast.id ? { ...t, ...action.toast } : t, - ), - }; - - case 'DISMISS_TOAST': { - const { toastId } = action; - - // ! Side effects ! - This could be extracted into a dismissToast() action, - // but I'll keep it here for simplicity - if (toastId) { - addToRemoveQueue(toastId); - } else { - state.toasts.forEach((toast) => { - addToRemoveQueue(toast.id); - }); - } - - return { - ...state, - toasts: state.toasts.map((t) => - t.id === toastId || toastId === undefined - ? { - ...t, - open: false, - } - : t, - ), - }; - } - case 'REMOVE_TOAST': - if (action.toastId === undefined) { - return { - ...state, - toasts: [], - }; - } - return { - ...state, - toasts: state.toasts.filter((t) => t.id !== action.toastId), - }; - } -}; - -const listeners: Array<(state: State) => void> = []; - -let memoryState: State = { toasts: [] }; - -function dispatch(action: Action) { - memoryState = reducer(memoryState, action); - listeners.forEach((listener) => { - listener(memoryState); - }); -} - -type Toast = Omit; - -function toast({ ...props }: Toast) { - const id = genId(); - - const update = (props: ToasterToast) => - dispatch({ - type: 'UPDATE_TOAST', - toast: { ...props, id }, - }); - const dismiss = () => dispatch({ type: 'DISMISS_TOAST', toastId: id }); - - dispatch({ - type: 'ADD_TOAST', - toast: { - ...props, - id, - open: true, - onOpenChange: (open: boolean) => { - if (!open) dismiss(); - }, - }, - }); - - return { - id: id, - dismiss, - update, - }; -} - -function useToast() { - const [state, setState] = React.useState(memoryState); - - React.useEffect(() => { - listeners.push(setState); - return () => { - const index = listeners.indexOf(setState); - if (index > -1) { - listeners.splice(index, 1); - } - }; - }, [state]); - - return { - ...state, - toast, - dismiss: (toastId?: string) => dispatch({ type: 'DISMISS_TOAST', toastId }), - }; -} - -export { toast, useToast }; +'use client'; + +// Inspired by react-hot-toast library +import * as React from 'react'; + +import type { ToastActionElement, ToastProps } from '@/components/ui/toast'; + +const TOAST_LIMIT = 1; +const TOAST_REMOVE_DELAY = 1000000; + +export type ToasterToast = ToastProps & { + id: string; + title?: React.ReactNode; + description?: React.ReactNode; + action?: ToastActionElement; +}; + +const _actionTypes = { + ADD_TOAST: 'ADD_TOAST', + UPDATE_TOAST: 'UPDATE_TOAST', + DISMISS_TOAST: 'DISMISS_TOAST', + REMOVE_TOAST: 'REMOVE_TOAST', +} as const; + +let count = 0; + +function genId() { + count = (count + 1) % Number.MAX_SAFE_INTEGER; + return count.toString(); +} + +type ActionType = typeof _actionTypes; + +type Action = + | { + type: ActionType['ADD_TOAST']; + toast: ToasterToast; + } + | { + type: ActionType['UPDATE_TOAST']; + toast: Partial; + } + | { + type: ActionType['DISMISS_TOAST']; + toastId?: ToasterToast['id']; + } + | { + type: ActionType['REMOVE_TOAST']; + toastId?: ToasterToast['id']; + }; + +interface State { + toasts: ToasterToast[]; +} + +const toastTimeouts = new Map>(); + +const addToRemoveQueue = (toastId: string) => { + if (toastTimeouts.has(toastId)) { + return; + } + + const timeout = setTimeout(() => { + toastTimeouts.delete(toastId); + dispatch({ + type: 'REMOVE_TOAST', + toastId: toastId, + }); + }, TOAST_REMOVE_DELAY); + + toastTimeouts.set(toastId, timeout); +}; + +export const reducer = (state: State, action: Action): State => { + switch (action.type) { + case 'ADD_TOAST': + return { + ...state, + toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), + }; + + case 'UPDATE_TOAST': + return { + ...state, + toasts: state.toasts.map((t) => + t.id === action.toast.id ? { ...t, ...action.toast } : t, + ), + }; + + case 'DISMISS_TOAST': { + const { toastId } = action; + + // ! Side effects ! - This could be extracted into a dismissToast() action, + // but I'll keep it here for simplicity + if (toastId) { + addToRemoveQueue(toastId); + } else { + state.toasts.forEach((toast) => { + addToRemoveQueue(toast.id); + }); + } + + return { + ...state, + toasts: state.toasts.map((t) => + t.id === toastId || toastId === undefined + ? { + ...t, + open: false, + } + : t, + ), + }; + } + case 'REMOVE_TOAST': + if (action.toastId === undefined) { + return { + ...state, + toasts: [], + }; + } + return { + ...state, + toasts: state.toasts.filter((t) => t.id !== action.toastId), + }; + } +}; + +const listeners: Array<(state: State) => void> = []; + +let memoryState: State = { toasts: [] }; + +function dispatch(action: Action) { + memoryState = reducer(memoryState, action); + listeners.forEach((listener) => { + listener(memoryState); + }); +} + +type Toast = Omit; + +function toast({ ...props }: Toast) { + const id = genId(); + + const update = (props: ToasterToast) => + dispatch({ + type: 'UPDATE_TOAST', + toast: { ...props, id }, + }); + const dismiss = () => dispatch({ type: 'DISMISS_TOAST', toastId: id }); + + dispatch({ + type: 'ADD_TOAST', + toast: { + ...props, + id, + open: true, + onOpenChange: (open: boolean) => { + if (!open) dismiss(); + }, + }, + }); + + return { + id: id, + dismiss, + update, + }; +} + +function useToast() { + const [state, setState] = React.useState(memoryState); + + React.useEffect(() => { + listeners.push(setState); + return () => { + const index = listeners.indexOf(setState); + if (index > -1) { + listeners.splice(index, 1); + } + }; + }, [state]); + + return { + ...state, + toast, + dismiss: (toastId?: string) => dispatch({ type: 'DISMISS_TOAST', toastId }), + }; +} + +export { toast, useToast }; diff --git a/src/state-mgmt/store.ts b/src/state-mgmt/store.ts index 65ca5a1..6ec3d16 100644 --- a/src/state-mgmt/store.ts +++ b/src/state-mgmt/store.ts @@ -1,147 +1,147 @@ -import { atom } from 'jotai'; -import { loadable } from 'jotai/utils'; -import { atomWithCache } from 'jotai-cache'; -import { atomEffect } from 'jotai-effect'; - -import { fetchDrivers } from '@/app/api/fetchDrivers'; -import { fetchEvents } from '@/app/api/fetchEvents'; -import { healthFetch } from '@/app/api/fetchHealth'; -import { f1Seasons } from '@/app/api/fetchSeasons'; - -import { - DEFAULT_SESSION_DATA, - EMPTY_DRIVER_DATA, - EMPTY_ERROR, - EMPTY_EVENT_DATA, - INITIAL_SEASON, -} from './constants'; - -export const globalError = atom(EMPTY_ERROR); - -export const healthStatus = atom(false); -export const incrementalHealthCheck = atomEffect((get, set) => { - const toggleStates = (status: boolean) => { - set(healthStatus, !!status); - set( - globalError, - status ? EMPTY_ERROR : { type: 'server', message: 'Server Error' }, - ); - }; - - healthFetch().then(toggleStates); - - const intervalId = setInterval(() => { - healthFetch().then(toggleStates); - }, 10000); - return () => clearInterval(intervalId); -}); - -export const queryState = atom({ - season: INITIAL_SEASON, - event: '', - session: '', - driver: '', -}); - -// *** Start Season -export const seasonId = atom((get) => get(queryState).season); -export const seasonList = atom(f1Seasons()); -// End Season - -// *** Start Event -export const eventId = atom((get) => get(queryState).event); -export const eventData = atom(async (get) => { - const id = get(eventId); - - if (!id) return EMPTY_EVENT_DATA; - const events = await get(eventList); - return events.find((event) => event.EventName === id) || EMPTY_EVENT_DATA; -}); -export const eventList = atom(async (get): Promise => { - // ! if (!get(healthStatus)) return []; - - const id = get(seasonId); - - const eventsFetched = await fetchEvents(id); - return eventsFetched; -}); -// End Event - -// *** Start Session -export const sessionId = atom((get) => get(queryState).session); -export const sessionData = atom(async (get) => { - const id = get(sessionId); - if (!id) return DEFAULT_SESSION_DATA; - - const sessions = await get(sessionList); - return ( - sessions.find((session) => session.name === id) || DEFAULT_SESSION_DATA - ); -}); -export const sessionList = atom(async (get): Promise => { - const event = await get(eventData); - if (!event.RoundNumber) return []; - - const sessionKeys = [ - 'Session1', - 'Session2', - 'Session3', - 'Session4', - 'Session5', - ]; - - // Create array of session objects - const sessions = sessionKeys.map((key, i) => { - return { - index: i + 1, - name: event[key as keyof EventSchedule] as string, - date: event[`${key}Date` as keyof EventSchedule] as string, - dateUtc: event[`${key}DateUtc` as keyof EventSchedule] as string, - }; - }); - - return sessions; -}); -// End Session - -// *** Start Driver -export const driverId = atom((get) => get(queryState).driver); -export const driverData = atom(async (get) => { - const id = get(driverId); - - if (!id) return EMPTY_DRIVER_DATA; - const drivers = await get(driverList); - return drivers.find((driver) => driver.FullName === id) || EMPTY_DRIVER_DATA; -}); - -export const driverList = atomWithCache( - async (get): Promise => { - // ! if (!get(healthStatus)) return []; - - const event = await get(eventData); - const session = await get(sessionData); - if (!event.RoundNumber) return []; - if (!session.index) return []; - - const driversFetched = await fetchDrivers( - get(seasonId), - event.RoundNumber.toString(), - session.index.toString(), - ); - - return driversFetched; - }, -); -// End Driver - -// *** Start Laps - -// End Laps - -// *** Add loadable state to fetch calls, similar to react query -// Return a state, loading, data, or error -export const eventListLoadable = loadable(eventList); -export const eventDataLoadable = loadable(eventData); -export const sessionListLoadable = loadable(sessionList); -export const driverListLoadable = loadable(driverList); -export const driverDataLoadable = loadable(driverData); +import { atom } from 'jotai'; +import { loadable } from 'jotai/utils'; +import { atomWithCache } from 'jotai-cache'; +import { atomEffect } from 'jotai-effect'; + +import { fetchDrivers } from '@/app/api/fetchDrivers'; +import { fetchEvents } from '@/app/api/fetchEvents'; +import { healthFetch } from '@/app/api/fetchHealth'; +import { f1Seasons } from '@/app/api/fetchSeasons'; + +import { + DEFAULT_SESSION_DATA, + EMPTY_DRIVER_DATA, + EMPTY_ERROR, + EMPTY_EVENT_DATA, + INITIAL_SEASON, +} from './constants'; + +export const globalError = atom(EMPTY_ERROR); + +export const healthStatus = atom(false); +export const incrementalHealthCheck = atomEffect((get, set) => { + const toggleStates = (status: boolean) => { + set(healthStatus, !!status); + set( + globalError, + status ? EMPTY_ERROR : { type: 'server', message: 'Server Error' }, + ); + }; + + healthFetch().then(toggleStates); + + const intervalId = setInterval(() => { + healthFetch().then(toggleStates); + }, 10000); + return () => clearInterval(intervalId); +}); + +export const queryState = atom({ + season: INITIAL_SEASON, + event: '', + session: '', + driver: '', +}); + +// *** Start Season +export const seasonId = atom((get) => get(queryState).season); +export const seasonList = atom(f1Seasons()); +// End Season + +// *** Start Event +export const eventId = atom((get) => get(queryState).event); +export const eventData = atom(async (get) => { + const id = get(eventId); + + if (!id) return EMPTY_EVENT_DATA; + const events = await get(eventList); + return events.find((event) => event.EventName === id) || EMPTY_EVENT_DATA; +}); +export const eventList = atom(async (get): Promise => { + // ! if (!get(healthStatus)) return []; + + const id = get(seasonId); + + const eventsFetched = await fetchEvents(id); + return eventsFetched; +}); +// End Event + +// *** Start Session +export const sessionId = atom((get) => get(queryState).session); +export const sessionData = atom(async (get) => { + const id = get(sessionId); + if (!id) return DEFAULT_SESSION_DATA; + + const sessions = await get(sessionList); + return ( + sessions.find((session) => session.name === id) || DEFAULT_SESSION_DATA + ); +}); +export const sessionList = atom(async (get): Promise => { + const event = await get(eventData); + if (!event.RoundNumber) return []; + + const sessionKeys = [ + 'Session1', + 'Session2', + 'Session3', + 'Session4', + 'Session5', + ]; + + // Create array of session objects + const sessions = sessionKeys.map((key, i) => { + return { + index: i + 1, + name: event[key as keyof EventSchedule] as string, + date: event[`${key}Date` as keyof EventSchedule] as string, + dateUtc: event[`${key}DateUtc` as keyof EventSchedule] as string, + }; + }); + + return sessions; +}); +// End Session + +// *** Start Driver +export const driverId = atom((get) => get(queryState).driver); +export const driverData = atom(async (get) => { + const id = get(driverId); + + if (!id) return EMPTY_DRIVER_DATA; + const drivers = await get(driverList); + return drivers.find((driver) => driver.FullName === id) || EMPTY_DRIVER_DATA; +}); + +export const driverList = atomWithCache( + async (get): Promise => { + // ! if (!get(healthStatus)) return []; + + const event = await get(eventData); + const session = await get(sessionData); + if (!event.RoundNumber) return []; + if (!session.index) return []; + + const driversFetched = await fetchDrivers( + get(seasonId), + event.RoundNumber.toString(), + session.index.toString(), + ); + + return driversFetched; + }, +); +// End Driver + +// *** Start Laps + +// End Laps + +// *** Add loadable state to fetch calls, similar to react query +// Return a state, loading, data, or error +export const eventListLoadable = loadable(eventList); +export const eventDataLoadable = loadable(eventData); +export const sessionListLoadable = loadable(sessionList); +export const driverListLoadable = loadable(driverList); +export const driverDataLoadable = loadable(driverData);