From 05db3fd719369d6fd7ee5cc43e2d56852c725b84 Mon Sep 17 00:00:00 2001 From: Max Duval Date: Fri, 10 May 2024 11:19:58 +0100 Subject: [PATCH 1/7] feat(tiles): add protomaps base layer - free non-commercial API usage - less colourful layer blends better in the background - support for high-DPI / retina displays out of the box --- package.json | 1 + pnpm-lock.yaml | 294 +++++++++++++++++-------------- src/components/LooMap/LooMap.tsx | 34 ++-- 3 files changed, 183 insertions(+), 146 deletions(-) diff --git a/package.json b/package.json index 8ae0e7520..7a9a920ef 100644 --- a/package.json +++ b/package.json @@ -166,6 +166,7 @@ "postcss-loader": "^7.3.3", "prettier": "^3.2.5", "prisma": "^4.13.0", + "protomaps-leaflet": "3.1.2", "require-from-string": "^2.0.2", "start-server-and-test": "^2.0.3", "storybook": "7.6.17", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ec80aef49..3ad8db323 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -360,6 +360,9 @@ devDependencies: prisma: specifier: ^4.13.0 version: 4.13.0 + protomaps-leaflet: + specifier: 3.1.2 + version: 3.1.2 require-from-string: specifier: ^2.0.2 version: 2.0.2 @@ -2130,8 +2133,8 @@ packages: '@jridgewell/trace-mapping': 0.3.9 dev: true - /@cypress/request@3.0.1: - resolution: {integrity: sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==} + /@cypress/request@2.88.12: + resolution: {integrity: sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==} engines: {node: '>= 6'} dependencies: aws-sign2: 0.7.0 @@ -4095,6 +4098,16 @@ packages: minimist: 1.2.8 dev: true + /@mapbox/point-geometry@0.1.0: + resolution: {integrity: sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==} + dev: true + + /@mapbox/vector-tile@1.3.1: + resolution: {integrity: sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==} + dependencies: + '@mapbox/point-geometry': 0.1.0 + dev: true + /@mdx-js/react@2.3.0(react@18.2.0): resolution: {integrity: sha512-zQH//gdOmuu7nt2oJR29vFhDv88oGPmVw6BggmrHeMI+xgEkp1B2dX9/bMBSYtK0dyLX/aOmesKS09g222K1/g==} peerDependencies: @@ -5873,7 +5886,7 @@ packages: '@storybook/client-logger': 7.4.4 '@storybook/core-events': 7.4.4 '@storybook/global': 5.0.0 - qs: 6.11.2 + qs: 6.12.0 telejson: 7.2.0 tiny-invariant: 1.3.1 dev: true @@ -6480,7 +6493,7 @@ packages: dependencies: '@storybook/client-logger': 7.6.17 memoizerific: 1.11.3 - qs: 6.11.2 + qs: 6.12.0 dev: true /@storybook/telemetry@7.6.17: @@ -6930,6 +6943,10 @@ packages: '@types/node': 18.16.3 dev: true + /@types/css-font-loading-module@0.0.7: + resolution: {integrity: sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q==} + dev: true + /@types/debug@4.1.12: resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} dependencies: @@ -8238,7 +8255,7 @@ packages: /array-buffer-byte-length@1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 is-array-buffer: 3.0.2 dev: true @@ -8316,10 +8333,10 @@ packages: engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.0 - call-bind: 1.0.2 + call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.2 - get-intrinsic: 1.2.1 + get-intrinsic: 1.2.4 is-array-buffer: 3.0.2 is-shared-array-buffer: 1.0.2 dev: true @@ -9020,8 +9037,9 @@ packages: /call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.2.1 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + dev: true /call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} @@ -9032,7 +9050,6 @@ packages: function-bind: 1.1.2 get-intrinsic: 1.2.4 set-function-length: 1.2.1 - dev: true /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} @@ -9438,6 +9455,10 @@ packages: hasBin: true dev: true + /color2k@2.0.3: + resolution: {integrity: sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog==} + dev: true + /color@4.2.3: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} @@ -9882,7 +9903,7 @@ packages: hasBin: true requiresBuild: true dependencies: - '@cypress/request': 3.0.1 + '@cypress/request': 2.88.12 '@cypress/xvfb': 1.2.4(supports-color@8.1.1) '@types/node': 14.18.63 '@types/sinonjs__fake-timers': 8.1.1 @@ -10036,9 +10057,9 @@ packages: /deep-equal@2.2.0: resolution: {integrity: sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 es-get-iterator: 1.1.3 - get-intrinsic: 1.2.1 + get-intrinsic: 1.2.4 is-arguments: 1.1.1 is-array-buffer: 3.0.2 is-date-object: 1.0.5 @@ -10049,7 +10070,7 @@ packages: object-keys: 1.1.1 object.assign: 4.1.4 regexp.prototype.flags: 1.5.1 - side-channel: 1.0.4 + side-channel: 1.0.6 which-boxed-primitive: 1.0.2 which-collection: 1.0.1 which-typed-array: 1.1.11 @@ -10097,15 +10118,6 @@ packages: resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} engines: {node: '>=10'} - /define-data-property@1.1.0: - resolution: {integrity: sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.1 - gopd: 1.0.1 - has-property-descriptors: 1.0.0 - dev: true - /define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -10113,7 +10125,6 @@ packages: es-define-property: 1.0.0 es-errors: 1.3.0 gopd: 1.0.1 - dev: true /define-lazy-prop@2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} @@ -10124,8 +10135,8 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} dependencies: - define-data-property: 1.1.0 - has-property-descriptors: 1.0.0 + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 object-keys: 1.1.1 dev: true @@ -10532,17 +10543,17 @@ packages: array-buffer-byte-length: 1.0.0 arraybuffer.prototype.slice: 1.0.2 available-typed-arrays: 1.0.5 - call-bind: 1.0.2 + call-bind: 1.0.7 es-set-tostringtag: 2.0.1 es-to-primitive: 1.2.1 function.prototype.name: 1.1.6 - get-intrinsic: 1.2.1 + get-intrinsic: 1.2.4 get-symbol-description: 1.0.0 globalthis: 1.0.3 gopd: 1.0.1 has: 1.0.3 - has-property-descriptors: 1.0.0 - has-proto: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 has-symbols: 1.0.3 internal-slot: 1.0.5 is-array-buffer: 3.0.2 @@ -10553,7 +10564,7 @@ packages: is-string: 1.0.7 is-typed-array: 1.1.12 is-weakref: 1.0.2 - object-inspect: 1.12.3 + object-inspect: 1.13.1 object-keys: 1.1.1 object.assign: 4.1.4 regexp.prototype.flags: 1.5.1 @@ -10590,7 +10601,7 @@ packages: has-property-descriptors: 1.0.2 has-proto: 1.0.3 has-symbols: 1.0.3 - hasown: 2.0.1 + hasown: 2.0.2 internal-slot: 1.0.7 is-array-buffer: 3.0.4 is-callable: 1.2.7 @@ -10622,18 +10633,16 @@ packages: engines: {node: '>= 0.4'} dependencies: get-intrinsic: 1.2.4 - dev: true /es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - dev: true /es-get-iterator@1.1.3: resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bind: 1.0.7 + get-intrinsic: 1.2.4 has-symbols: 1.0.3 is-arguments: 1.1.1 is-map: 2.0.2 @@ -10671,7 +10680,7 @@ packages: resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.2.1 + get-intrinsic: 1.2.4 has: 1.0.3 has-tostringtag: 1.0.0 dev: true @@ -10682,13 +10691,13 @@ packages: dependencies: get-intrinsic: 1.2.4 has-tostringtag: 1.0.2 - hasown: 2.0.1 + hasown: 2.0.2 dev: true /es-shim-unscopables@1.0.2: resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} dependencies: - hasown: 2.0.1 + hasown: 2.0.2 dev: true /es-to-primitive@1.2.1: @@ -11435,6 +11444,10 @@ packages: resolution: {integrity: sha512-3yurQZ2hD9VISAhJJP9bpYFNQrHHBXE2JxxjY5aLEcDi46RmAzJE2OC9FAde0yis5ElW0jTTzs0zfg/Cca4XqQ==} dev: true + /fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + dev: true + /figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -11662,7 +11675,7 @@ packages: dezalgo: 1.0.4 hexoid: 1.0.0 once: 1.4.0 - qs: 6.11.2 + qs: 6.12.0 /forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} @@ -11715,7 +11728,7 @@ packages: dependencies: graceful-fs: 4.2.11 jsonfile: 6.1.0 - universalify: 2.0.0 + universalify: 2.0.1 dev: true /fs-extra@11.2.0: @@ -11758,9 +11771,6 @@ packages: requiresBuild: true optional: true - /function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - /function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} @@ -11768,7 +11778,7 @@ packages: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.2 functions-have-names: 1.2.3 @@ -11818,14 +11828,6 @@ packages: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} dev: true - /get-intrinsic@1.2.1: - resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} - dependencies: - function-bind: 1.1.1 - has: 1.0.3 - has-proto: 1.0.1 - has-symbols: 1.0.3 - /get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} @@ -11834,8 +11836,7 @@ packages: function-bind: 1.1.2 has-proto: 1.0.3 has-symbols: 1.0.3 - hasown: 2.0.1 - dev: true + hasown: 2.0.2 /get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} @@ -11877,8 +11878,8 @@ packages: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bind: 1.0.7 + get-intrinsic: 1.2.4 dev: true /get-symbol-description@1.0.2: @@ -12032,8 +12033,7 @@ packages: /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: - get-intrinsic: 1.2.1 - dev: true + get-intrinsic: 1.2.4 /got@11.8.6: resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} @@ -12260,26 +12260,14 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - /has-property-descriptors@1.0.0: - resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} - dependencies: - get-intrinsic: 1.2.1 - dev: true - /has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} dependencies: es-define-property: 1.0.0 - dev: true - - /has-proto@1.0.1: - resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} - engines: {node: '>= 0.4'} /has-proto@1.0.3: resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} engines: {node: '>= 0.4'} - dev: true /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} @@ -12307,7 +12295,7 @@ packages: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} dependencies: - function-bind: 1.1.1 + function-bind: 1.1.2 /hash-base@3.1.0: resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} @@ -12569,7 +12557,7 @@ packages: resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.1.0 dependencies: postcss: 8.4.38 dev: true @@ -12689,9 +12677,9 @@ packages: resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.2.1 + get-intrinsic: 1.2.4 has: 1.0.3 - side-channel: 1.0.4 + side-channel: 1.0.6 dev: true /internal-slot@1.0.7: @@ -12699,7 +12687,7 @@ packages: engines: {node: '>= 0.4'} dependencies: es-errors: 1.3.0 - hasown: 2.0.1 + hasown: 2.0.2 side-channel: 1.0.6 dev: true @@ -12735,15 +12723,15 @@ packages: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 has-tostringtag: 1.0.0 dev: true /is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bind: 1.0.7 + get-intrinsic: 1.2.4 is-typed-array: 1.1.12 dev: true @@ -12786,7 +12774,7 @@ packages: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 has-tostringtag: 1.0.0 dev: true @@ -12990,7 +12978,7 @@ packages: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 has-tostringtag: 1.0.0 dev: true @@ -13008,7 +12996,7 @@ packages: /is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 dev: true /is-shared-array-buffer@1.0.3: @@ -13090,14 +13078,14 @@ packages: /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 dev: true /is-weakset@2.0.2: resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bind: 1.0.7 + get-intrinsic: 1.2.4 dev: true /is-windows@1.0.2: @@ -13864,7 +13852,7 @@ packages: /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: - universalify: 2.0.0 + universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 dev: true @@ -15392,16 +15380,16 @@ packages: /object-inspect@1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + dev: true /object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} - dev: true /object-is@1.1.5: resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 define-properties: 1.2.1 dev: true @@ -15422,7 +15410,7 @@ packages: resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 define-properties: 1.2.1 has-symbols: 1.0.3 object-keys: 1.1.1 @@ -15861,6 +15849,14 @@ packages: through: 2.3.8 dev: true + /pbf@3.2.1: + resolution: {integrity: sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==} + hasBin: true + dependencies: + ieee754: 1.2.1 + resolve-protobuf-schema: 2.1.0 + dev: true + /pbkdf2@3.1.2: resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} engines: {node: '>=0.12'} @@ -15960,6 +15956,13 @@ packages: engines: {node: '>=4'} dev: true + /pmtiles@3.0.5: + resolution: {integrity: sha512-K6NxVvW/vXE3052VZKF2ppyjdyhLx41FidR5yV8L/+El+lcMJpXS0vHBSPFmjdag5zkYv2XGDdq+3VjB2K7l6w==} + dependencies: + '@types/leaflet': 1.9.9 + fflate: 0.8.2 + dev: true + /pnp-webpack-plugin@1.7.0(typescript@5.4.4): resolution: {integrity: sha512-2Rb3vm+EXble/sMXNSu6eoBx8e79gKqhNq9F5ZWW6ERNCTE/Q0wQNne5541tE5vKjfM8hpNCYL+LGc1YTfI0dg==} engines: {node: '>=6'} @@ -15985,7 +15988,7 @@ packages: resolution: {integrity: sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==} engines: {node: '>= 10.13.0'} peerDependencies: - postcss: '>=8.4.31' + postcss: ^7.0.0 || ^8.0.1 webpack: ^4.0.0 || ^5.0.0 dependencies: cosmiconfig: 7.1.0 @@ -16001,7 +16004,7 @@ packages: resolution: {integrity: sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==} engines: {node: '>= 14.15.0'} peerDependencies: - postcss: '>=8.4.31' + postcss: ^7.0.0 || ^8.0.1 webpack: ^5.0.0 dependencies: cosmiconfig: 8.3.6(typescript@5.4.4) @@ -16024,7 +16027,7 @@ packages: resolution: {integrity: sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.1.0 dependencies: postcss: 8.4.38 dev: true @@ -16043,7 +16046,7 @@ packages: resolution: {integrity: sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.1.0 dependencies: icss-utils: 5.1.0(postcss@8.4.38) postcss: 8.4.38 @@ -16063,7 +16066,7 @@ packages: resolution: {integrity: sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.1.0 dependencies: postcss: 8.4.38 postcss-selector-parser: 6.0.15 @@ -16080,7 +16083,7 @@ packages: resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.1.0 dependencies: icss-utils: 5.1.0(postcss@8.4.38) postcss: 8.4.38 @@ -16115,6 +16118,10 @@ packages: source-map-js: 1.2.0 dev: true + /potpack@1.0.2: + resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==} + dev: true + /prebuild-install@7.1.2: resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} engines: {node: '>=10'} @@ -16243,6 +16250,23 @@ packages: object-assign: 4.1.1 react-is: 16.13.1 + /protocol-buffers-schema@3.6.0: + resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==} + dev: true + + /protomaps-leaflet@3.1.2: + resolution: {integrity: sha512-0joP4mfZqlLY958oFBrpQpYdLkoz9dBpCB0HJtAyp18bA/+JM0Kdh/8NvbyUaLVS6vvLfPaKVnfmu9Yw2g1g8A==} + dependencies: + '@mapbox/point-geometry': 0.1.0 + '@mapbox/vector-tile': 1.3.1 + '@types/css-font-loading-module': 0.0.7 + color2k: 2.0.3 + pbf: 3.2.1 + pmtiles: 3.0.5 + potpack: 1.0.2 + rbush: 3.0.1 + dev: true + /proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -16309,14 +16333,9 @@ packages: /punycode@1.4.1: resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} - /punycode@2.3.0: - resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} - engines: {node: '>=6'} - /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - dev: true /puppeteer-core@2.1.1: resolution: {integrity: sha512-n13AWriBMPYxnpbb6bnaY5YoY6rGj8vPLrz6CZF3o0qJNEwlcfJVxBzYZ0NJsQ21UbdJoijPCDrM++SUVEz7+w==} @@ -16362,21 +16381,21 @@ packages: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} dependencies: - side-channel: 1.0.4 + side-channel: 1.0.6 dev: true /qs@6.11.2: resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} engines: {node: '>=0.6'} dependencies: - side-channel: 1.0.4 + side-channel: 1.0.6 + dev: true /qs@6.12.0: resolution: {integrity: sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==} engines: {node: '>=0.6'} dependencies: side-channel: 1.0.6 - dev: true /querystring-es3@0.2.1: resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} @@ -16406,6 +16425,10 @@ packages: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} + /quickselect@2.0.0: + resolution: {integrity: sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==} + dev: true + /ramda@0.29.0: resolution: {integrity: sha512-BBea6L67bYLtdbOqfp8f58fPMqEwx0doL+pAi8TZyp2YWz8R9G8z9x75CZI8W+ftqhFHCpEX2cRnUUXK130iKA==} dev: true @@ -16437,6 +16460,12 @@ packages: unpipe: 1.0.0 dev: true + /rbush@3.0.1: + resolution: {integrity: sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==} + dependencies: + quickselect: 2.0.0 + dev: true + /rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -16757,7 +16786,7 @@ packages: resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 define-properties: 1.2.1 set-function-name: 2.0.1 dev: true @@ -16928,6 +16957,12 @@ packages: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} dev: true + /resolve-protobuf-schema@2.1.0: + resolution: {integrity: sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==} + dependencies: + protocol-buffers-schema: 3.6.0 + dev: true + /resolve-url-loader@5.0.0: resolution: {integrity: sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==} engines: {node: '>=12'} @@ -17085,8 +17120,8 @@ packages: resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} engines: {node: '>=0.4'} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bind: 1.0.7 + get-intrinsic: 1.2.4 has-symbols: 1.0.3 isarray: 2.0.5 dev: true @@ -17111,8 +17146,8 @@ packages: /safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bind: 1.0.7 + get-intrinsic: 1.2.4 is-regex: 1.1.4 dev: true @@ -17283,15 +17318,14 @@ packages: get-intrinsic: 1.2.4 gopd: 1.0.1 has-property-descriptors: 1.0.2 - dev: true /set-function-name@2.0.1: resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} engines: {node: '>= 0.4'} dependencies: - define-data-property: 1.1.0 + define-data-property: 1.1.4 functions-have-names: 1.2.3 - has-property-descriptors: 1.0.0 + has-property-descriptors: 1.0.2 dev: true /set-function-name@2.0.2: @@ -17373,13 +17407,6 @@ packages: resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} dev: true - /side-channel@1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - object-inspect: 1.12.3 - /side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} @@ -17388,7 +17415,6 @@ packages: es-errors: 1.3.0 get-intrinsic: 1.2.4 object-inspect: 1.13.1 - dev: true /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -17797,7 +17823,7 @@ packages: internal-slot: 1.0.7 regexp.prototype.flags: 1.5.1 set-function-name: 2.0.1 - side-channel: 1.0.4 + side-channel: 1.0.6 dev: true /string.prototype.padend@3.1.4: @@ -17813,7 +17839,7 @@ packages: resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.2 dev: true @@ -17821,7 +17847,7 @@ packages: /string.prototype.trimend@1.0.7: resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.2 dev: true @@ -17829,7 +17855,7 @@ packages: /string.prototype.trimstart@1.0.7: resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.2 dev: true @@ -17980,7 +18006,7 @@ packages: formidable: 2.1.1 methods: 1.1.2 mime: 2.6.0 - qs: 6.11.2 + qs: 6.12.0 readable-stream: 3.6.2 semver: 7.5.4 transitivePeerDependencies: @@ -18551,8 +18577,8 @@ packages: resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bind: 1.0.7 + get-intrinsic: 1.2.4 is-typed-array: 1.1.12 dev: true @@ -18569,9 +18595,9 @@ packages: resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 for-each: 0.3.3 - has-proto: 1.0.1 + has-proto: 1.0.3 is-typed-array: 1.1.12 dev: true @@ -18591,9 +18617,9 @@ packages: engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.5 - call-bind: 1.0.2 + call-bind: 1.0.7 for-each: 0.3.3 - has-proto: 1.0.1 + has-proto: 1.0.3 is-typed-array: 1.1.12 dev: true @@ -18612,7 +18638,7 @@ packages: /typed-array-length@1.0.4: resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 for-each: 0.3.3 is-typed-array: 1.1.12 dev: true @@ -18658,7 +18684,7 @@ packages: /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.7 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 @@ -18840,7 +18866,7 @@ packages: /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: - punycode: 2.3.0 + punycode: 2.3.1 /url-join@4.0.1: resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} @@ -19225,7 +19251,7 @@ packages: engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.5 - call-bind: 1.0.2 + call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 diff --git a/src/components/LooMap/LooMap.tsx b/src/components/LooMap/LooMap.tsx index 88d0e53b5..b46457325 100644 --- a/src/components/LooMap/LooMap.tsx +++ b/src/components/LooMap/LooMap.tsx @@ -1,5 +1,5 @@ import { useMapState } from '../MapState'; -import { MapContainer, TileLayer, useMapEvents } from 'react-leaflet'; +import { MapContainer, useMapEvents } from 'react-leaflet'; import 'leaflet/dist/leaflet.css'; import { css } from '@emotion/react'; import Box from '../Box'; @@ -18,6 +18,7 @@ import React from 'react'; import router from 'next/router'; import ZoomControl from './ZoomControl'; import crosshairSvg from '../../../public/crosshair.svg'; +import { leafletLayer } from 'protomaps-leaflet'; const MapTracker = () => { const [, setMapState] = useMapState(); @@ -68,6 +69,7 @@ const LooMap: React.FC = ({ controlPositionOverride, }) => { const [mapState, setMapState] = useMapState(); + const [tileLayerAdded, setTileLayerAdded] = useState(false); // const [hydratedToilets, setHydratedToilets] = useState([]); const [announcement, setAnnouncement] = React.useState(null); @@ -99,6 +101,21 @@ const LooMap: React.FC = ({ } }, [mapRef, mapState.map, setMapState]); + useEffect(() => { + if (!mapRef.current || tileLayerAdded) return; + + const layer = leafletLayer({ + // Free for non-commercial use https://protomaps.com/ + url: 'https://api.protomaps.com/tiles/v3/{z}/{x}/{y}.mvt?key=73e8a482f059f3f5', + theme: 'white', + }); + // @ts-expect-error -- this is what the docs recommend + // https://github.com/protomaps/protomaps-leaflet?tab=readme-ov-file#how-to-use + layer.addTo(mapRef.current); + // prevent this hook from ever re-running + setTileLayerAdded(true); + }, [mapRef, tileLayerAdded]); + // Begin accessibility overlay useEffect(() => { @@ -131,7 +148,7 @@ const LooMap: React.FC = ({ setMapState({ searchLocation: undefined, focus: toilet }); router.push(`/loos/${toilet.id}`); }, - [intersectingToilets, setMapState] + [intersectingToilets, setMapState], ); React.useEffect(() => { @@ -169,7 +186,7 @@ const LooMap: React.FC = ({ }, }); }, - [setMapState] + [setMapState], ); const onStopLocation = useCallback(() => { @@ -294,13 +311,6 @@ const LooMap: React.FC = ({ } `} > - - {mapState.focus && } @@ -310,8 +320,8 @@ const LooMap: React.FC = ({ controlPosition !== undefined ? controlPosition : mapState.focus - ? controlPositionClassNames['top'] - : controlPositionClassNames['bottom'] + ? controlPositionClassNames['top'] + : controlPositionClassNames['bottom'] } > {alwaysShowGeolocateButton && showControls && } From f2ff5c83c90ddd97d14f04ace28186cb2d10e712 Mon Sep 17 00:00:00 2001 From: Max Duval Date: Fri, 10 May 2024 13:27:29 +0100 Subject: [PATCH 2/7] refactor: use `mapState` as dependency this does not trigger a re-render on every map movement by default, and removes the derived state --- src/components/LooMap/LooMap.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/components/LooMap/LooMap.tsx b/src/components/LooMap/LooMap.tsx index b46457325..6c38c516d 100644 --- a/src/components/LooMap/LooMap.tsx +++ b/src/components/LooMap/LooMap.tsx @@ -69,7 +69,6 @@ const LooMap: React.FC = ({ controlPositionOverride, }) => { const [mapState, setMapState] = useMapState(); - const [tileLayerAdded, setTileLayerAdded] = useState(false); // const [hydratedToilets, setHydratedToilets] = useState([]); const [announcement, setAnnouncement] = React.useState(null); @@ -102,8 +101,7 @@ const LooMap: React.FC = ({ }, [mapRef, mapState.map, setMapState]); useEffect(() => { - if (!mapRef.current || tileLayerAdded) return; - + if (!mapState.map) return; const layer = leafletLayer({ // Free for non-commercial use https://protomaps.com/ url: 'https://api.protomaps.com/tiles/v3/{z}/{x}/{y}.mvt?key=73e8a482f059f3f5', @@ -111,10 +109,8 @@ const LooMap: React.FC = ({ }); // @ts-expect-error -- this is what the docs recommend // https://github.com/protomaps/protomaps-leaflet?tab=readme-ov-file#how-to-use - layer.addTo(mapRef.current); - // prevent this hook from ever re-running - setTileLayerAdded(true); - }, [mapRef, tileLayerAdded]); + layer.addTo(mapState.map); + }, [mapState.map]); // Begin accessibility overlay From 742c6a7db40b38f025400581d942d507662cb40a Mon Sep 17 00:00:00 2001 From: Max Duval Date: Mon, 10 Jun 2024 10:01:58 +0100 Subject: [PATCH 3/7] feat: enable base layer toggle Try new map, or revert to old map --- src/components/LooMap/LooMap.tsx | 46 +++++++++++++++++-------- src/components/LooMap/ProtomapLayer.tsx | 25 ++++++++++++++ 2 files changed, 56 insertions(+), 15 deletions(-) create mode 100644 src/components/LooMap/ProtomapLayer.tsx diff --git a/src/components/LooMap/LooMap.tsx b/src/components/LooMap/LooMap.tsx index 6c38c516d..5dd549128 100644 --- a/src/components/LooMap/LooMap.tsx +++ b/src/components/LooMap/LooMap.tsx @@ -1,12 +1,12 @@ import { useMapState } from '../MapState'; -import { MapContainer, useMapEvents } from 'react-leaflet'; +import { MapContainer, TileLayer, useMapEvents } from 'react-leaflet'; import 'leaflet/dist/leaflet.css'; import { css } from '@emotion/react'; import Box from '../Box'; import { Media } from '../Media'; import Markers from './Markers'; import CurrentLooMarker from './CurrentLooMarker'; -import LocateMapControl from './LocateMapControl'; +import LocateMapControl, { ControlButton } from './LocateMapControl'; import { useCallback, useEffect, useState } from 'react'; import { Map } from 'leaflet'; import useLocateMapControl from './useLocateMapControl'; @@ -18,7 +18,7 @@ import React from 'react'; import router from 'next/router'; import ZoomControl from './ZoomControl'; import crosshairSvg from '../../../public/crosshair.svg'; -import { leafletLayer } from 'protomaps-leaflet'; +import { ProtomapLayer } from './ProtomapLayer'; const MapTracker = () => { const [, setMapState] = useMapState(); @@ -74,6 +74,8 @@ const LooMap: React.FC = ({ const [announcement, setAnnouncement] = React.useState(null); const [intersectingToilets, setIntersectingToilets] = useState([]); + const [useProtomap, setUseProtomaps] = useState(false); + const [renderAccessibilityOverlays, setRenderAccessibilityOverlays] = useState(showAccessibilityOverlay); @@ -100,18 +102,6 @@ const LooMap: React.FC = ({ } }, [mapRef, mapState.map, setMapState]); - useEffect(() => { - if (!mapState.map) return; - const layer = leafletLayer({ - // Free for non-commercial use https://protomaps.com/ - url: 'https://api.protomaps.com/tiles/v3/{z}/{x}/{y}.mvt?key=73e8a482f059f3f5', - theme: 'white', - }); - // @ts-expect-error -- this is what the docs recommend - // https://github.com/protomaps/protomaps-leaflet?tab=readme-ov-file#how-to-use - layer.addTo(mapState.map); - }, [mapState.map]); - // Begin accessibility overlay useEffect(() => { @@ -307,6 +297,17 @@ const LooMap: React.FC = ({ } `} > + {useProtomap ? ( + + ) : ( + + )} + {mapState.focus && } @@ -327,6 +328,21 @@ const LooMap: React.FC = ({ +
+ { + setUseProtomaps((toggle) => !toggle); + }} + className="leaflet-control" + css={css` + padding: 5px 12px; + cursor: pointer; + `} + > + {useProtomap ? 'Revert to old map' : 'Try the new map'} + +
+ {renderAccessibilityOverlays && ( diff --git a/src/components/LooMap/ProtomapLayer.tsx b/src/components/LooMap/ProtomapLayer.tsx new file mode 100644 index 000000000..da5c42000 --- /dev/null +++ b/src/components/LooMap/ProtomapLayer.tsx @@ -0,0 +1,25 @@ +import { Layer } from 'leaflet'; +import { leafletLayer } from 'protomaps-leaflet'; +import { useEffect } from 'react'; +import { useMap } from 'react-leaflet'; + +export const ProtomapLayer = () => { + const map = useMap(); + + useEffect(() => { + // @ts-expect-error -- this works in practice + const layer: Layer = leafletLayer({ + // Free for non-commercial use https://protomaps.com/ + url: 'https://api.protomaps.com/tiles/v3/{z}/{x}/{y}.mvt?key=73e8a482f059f3f5', + theme: 'light', + }); + // https://github.com/protomaps/protomaps-leaflet?tab=readme-ov-file#how-to-use + layer.addTo(map); + + return () => { + map.removeLayer(layer); + }; + }, [map]); + + return null; +}; From 391be3883f23ef0c4f433808978c0c8432cc65c7 Mon Sep 17 00:00:00 2001 From: Rupert Redington Date: Wed, 12 Jun 2024 09:43:19 +0100 Subject: [PATCH 4/7] Switch plausible tracking to map styles control (#1682) Co-authored-by: Rupert Redington --- src/components/LooMap/LooMap.tsx | 9 +++++++-- src/components/Sidebar/Sidebar.tsx | 7 +------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/LooMap/LooMap.tsx b/src/components/LooMap/LooMap.tsx index 5dd549128..280033038 100644 --- a/src/components/LooMap/LooMap.tsx +++ b/src/components/LooMap/LooMap.tsx @@ -2,6 +2,7 @@ import { useMapState } from '../MapState'; import { MapContainer, TileLayer, useMapEvents } from 'react-leaflet'; import 'leaflet/dist/leaflet.css'; import { css } from '@emotion/react'; +import { usePlausible } from 'next-plausible'; import Box from '../Box'; import { Media } from '../Media'; import Markers from './Markers'; @@ -75,6 +76,7 @@ const LooMap: React.FC = ({ const [intersectingToilets, setIntersectingToilets] = useState([]); const [useProtomap, setUseProtomaps] = useState(false); + const plausible = usePlausible(); const [renderAccessibilityOverlays, setRenderAccessibilityOverlays] = useState(showAccessibilityOverlay); @@ -317,8 +319,8 @@ const LooMap: React.FC = ({ controlPosition !== undefined ? controlPosition : mapState.focus - ? controlPositionClassNames['top'] - : controlPositionClassNames['bottom'] + ? controlPositionClassNames['top'] + : controlPositionClassNames['bottom'] } > {alwaysShowGeolocateButton && showControls && } @@ -331,6 +333,9 @@ const LooMap: React.FC = ({
{ + plausible( + useProtomap ? 'Reject New Map Styles' : 'Use New Map Styles', + ); setUseProtomaps((toggle) => !toggle); }} className="leaflet-control" diff --git a/src/components/Sidebar/Sidebar.tsx b/src/components/Sidebar/Sidebar.tsx index 65d0692af..547fbeb1e 100644 --- a/src/components/Sidebar/Sidebar.tsx +++ b/src/components/Sidebar/Sidebar.tsx @@ -13,7 +13,6 @@ import Filters from '../Filters'; import Button from '../../design-system/components/Button'; import { useMapState } from '../MapState'; import config from '../../config'; -import { usePlausible } from 'next-plausible'; import dynamic from 'next/dynamic'; const Drawer = dynamic(() => import('../../design-system/components/Drawer')); @@ -97,7 +96,7 @@ const Sidebar = () => { const appliedFilterCountRendered = useMemo(() => { return appliedFilterCount > 0 && ({appliedFilterCount}); }, [appliedFilterCount]); - const plausible = usePlausible(); + return (
@@ -119,8 +118,6 @@ const Sidebar = () => { ref={filterToggleRef} aria-expanded={isFiltersExpanded} onClick={() => { - const stateText = isFiltersExpanded ? 'Close' : 'Open'; - plausible(`${stateText} Filters Panel`); setIsFiltersExpanded(!isFiltersExpanded); }} aria-label="Filters Panel" @@ -222,8 +219,6 @@ const Sidebar = () => { alignItems="center" aria-expanded={isFilterExpanded} onClick={() => { - const stateText = isFilterExpanded ? 'Close' : 'Open'; - plausible(`${stateText} Filters Panel`); setIsFilterExpanded(!isFilterExpanded); }} > From e27c932b4f89fe11e666c124f0991b214efac8f2 Mon Sep 17 00:00:00 2001 From: Max Duval Date: Wed, 12 Jun 2024 14:04:26 +0100 Subject: [PATCH 5/7] Custom protomaps styles (#1670) - more constrasting colours - more distinct public places - make styles closer to popular maps - add points of interests - add railway stations --- src/components/LooMap/LooMap.tsx | 4 +- src/components/LooMap/ProtomapLayer.tsx | 4 +- src/components/LooMap/mapTheme.ts | 329 ++++++++++++++++++++++++ 3 files changed, 334 insertions(+), 3 deletions(-) create mode 100644 src/components/LooMap/mapTheme.ts diff --git a/src/components/LooMap/LooMap.tsx b/src/components/LooMap/LooMap.tsx index 280033038..2459a6d72 100644 --- a/src/components/LooMap/LooMap.tsx +++ b/src/components/LooMap/LooMap.tsx @@ -319,8 +319,8 @@ const LooMap: React.FC = ({ controlPosition !== undefined ? controlPosition : mapState.focus - ? controlPositionClassNames['top'] - : controlPositionClassNames['bottom'] + ? controlPositionClassNames['top'] + : controlPositionClassNames['bottom'] } > {alwaysShowGeolocateButton && showControls && } diff --git a/src/components/LooMap/ProtomapLayer.tsx b/src/components/LooMap/ProtomapLayer.tsx index da5c42000..148f3fb51 100644 --- a/src/components/LooMap/ProtomapLayer.tsx +++ b/src/components/LooMap/ProtomapLayer.tsx @@ -2,6 +2,7 @@ import { Layer } from 'leaflet'; import { leafletLayer } from 'protomaps-leaflet'; import { useEffect } from 'react'; import { useMap } from 'react-leaflet'; +import { labelRules, paintRules } from './mapTheme'; export const ProtomapLayer = () => { const map = useMap(); @@ -11,7 +12,8 @@ export const ProtomapLayer = () => { const layer: Layer = leafletLayer({ // Free for non-commercial use https://protomaps.com/ url: 'https://api.protomaps.com/tiles/v3/{z}/{x}/{y}.mvt?key=73e8a482f059f3f5', - theme: 'light', + paintRules, + labelRules, }); // https://github.com/protomaps/protomaps-leaflet?tab=readme-ov-file#how-to-use layer.addTo(map); diff --git a/src/components/LooMap/mapTheme.ts b/src/components/LooMap/mapTheme.ts new file mode 100644 index 000000000..715c0437a --- /dev/null +++ b/src/components/LooMap/mapTheme.ts @@ -0,0 +1,329 @@ +import { + CenteredTextSymbolizer, + CircleSymbolizer, + GroupSymbolizer, + Justify, + LineSymbolizer, + OffsetTextSymbolizer, + PaintRule, + TextPlacements, + labelRules as baseLabelRules, + paintRules as basePaintRules, + type JsonValue, + type LabelRule, +} from 'protomaps-leaflet'; + +type Theme = Parameters[0]; + +/** + * Adapted from [`light`](https://github.com/protomaps/protomaps-leaflet/blob/fc1b260bcbfe37aede11c866a4ea39e23b5ad099/src/default_style/themes.ts#L91) + */ +export const mapTheme = { + background: '#eee', + earth: '#efefef', + park_a: '#cfddd5', + park_b: '#bbf3cc', + hospital: '#e4dad9', + industrial: '#d1dde1', + school: '#e4ded7', + wood_a: '#bbf3cc', + wood_b: '#bbf3cc', + pedestrian: '#fff2d5', + scrub_a: '#cedcd7', + scrub_b: '#bbf3cc', + glacier: '#e7e7e7', + sand: '#e2e0d7', + beach: '#e8e4d0', + aerodrome: '#dadbdf', + runway: '#e9e9ed', + water: '#80deea', + pier: '#e0e0e0', + zoo: '#c6dcdc', + military: '#dcdcdc', + + tunnel_other_casing: '#e0e0e0', + tunnel_minor_casing: '#e0e0e0', + tunnel_link_casing: '#e0e0e0', + tunnel_medium_casing: '#e0e0e0', + tunnel_major_casing: '#e0e0e0', + tunnel_highway_casing: '#e0e0e0', + tunnel_other: '#d5d5d5', + tunnel_minor: '#d5d5d5', + tunnel_link: '#d5d5d5', + tunnel_medium: '#d5d5d5', + tunnel_major: '#d5d5d5', + tunnel_highway: '#d5d5d5', + + transit_pier: '#e0e0e0', + buildings: '#ccd', + + minor_service_casing: '#e0e0e0', + minor_casing: '#e0e0e0', + link_casing: '#e0e0e0', + medium_casing: '#e0e0e0', + major_casing_late: '#e0e0e0', + highway_casing_late: '#e0e0e0', + other: '#ebebeb', + minor_service: '#ebebeb', + minor_a: '#ebebeb', + minor_b: '#bbc', + link: '#bbc', + medium: '#f5f5f5', + major_casing_early: '#e0e0e0', + major: '#bbc', + highway_casing_early: '#e0e0e0', + highway: '#bbc', + + railway: '#a7b1b3', + boundaries: '#adadad', + waterway_label: '#ffffff', + + bridges_other_casing: '#e0e0e0', + bridges_minor_casing: '#e0e0e0', + bridges_link_casing: '#e0e0e0', + bridges_medium_casing: '#e0e0e0', + bridges_major_casing: '#e0e0e0', + bridges_highway_casing: '#e0e0e0', + bridges_other: '#ebebeb', + bridges_minor: '#ffffff', + bridges_link: '#ffffff', + bridges_medium: '#f0eded', + bridges_major: '#f5f5f5', + bridges_highway: '#ffffff', + + roads_label_minor: '#669', + roads_label_minor_halo: '#e6e6e6', + roads_label_major: '#556', + roads_label_major_halo: '#eee', + ocean_label: '#7a7a7a', + peak_label: '#5c5c5c', + subplace_label: '#7a7a7a', + subplace_label_halo: '#fff', + city_circle: '#c2c2c2', + city_circle_stroke: '#7a7a7a', + city_label: '#474747', + city_label_halo: '#e9e9f3', + state_label: '#999999', + state_label_halo: '#cccccc', + country_label: '#858585', +} satisfies Theme; + +const font = 'Open Sans, sans-serif'; + +export const paintRules: PaintRule[] = [ + ...basePaintRules(mapTheme), + { + dataLayer: 'roads', + symbolizer: new LineSymbolizer({ + color: '#bbc', + }), + filter: (z, f) => { + const kind = getString(f.props, 'pmap:kind'); + return kind === 'park'; + }, + }, +]; + +export const labelRules: LabelRule[] = [ + { + // railway stations + dataLayer: 'pois', + symbolizer: new GroupSymbolizer([ + new CircleSymbolizer({ + fill: '#0a165e', + stroke: '#f4f4f4', + radius: 6, + width: 1, + }), + new CircleSymbolizer({ + fill: '#f4f4f4', + radius: 3, + }), + new OffsetTextSymbolizer({ + labelProps: ['name', 'railway'], + fill: '#0a165e', + stroke: '#f4f4f4', + width: 1.25, + lineHeight: 1, + font: `600 14px ${font}`, + offsetX: 8, + placements: [TextPlacements.E], + justify: Justify.Left, + }), + ]), + filter: (z, { props }) => !!props['railway'], + }, + ...baseLabelRules(mapTheme).slice(0, -2), // remove the default “places_locality” rule + { + dataLayer: 'places', + minzoom: 9, + symbolizer: new CenteredTextSymbolizer({ + labelProps: ['name'], + fill: mapTheme.city_label, + stroke: mapTheme.city_label_halo, + width: 2, + textTransform: (z) => (z > 12 ? 'uppercase' : undefined), + letterSpacing: (z) => (z > 12 ? 1 : undefined), + lineHeight: 1.5, + font: (z, f) => { + if (!f) return `400 12px ${font}`; + const minZoom = getNumber(f.props, 'pmap:min_zoom'); + let weight = 400; + if (minZoom && minZoom <= 5) { + weight = 600; + } + let size = 12; + const popRank = getNumber(f.props, 'pmap:population_rank'); + if (popRank && popRank > 9) { + size = 16; + } + return `${weight} ${size}px ${font}`; + }, + }), + sort: (a, b) => { + const aRank = getNumber(a, 'pmap:population_rank'); + const bRank = getNumber(b, 'pmap:population_rank'); + return aRank - bRank; + }, + filter: (z, { props }) => { + return props['pmap:kind'] === 'locality'; + }, + }, + { + dataLayer: 'pois', + symbolizer: new GroupSymbolizer([ + new CircleSymbolizer({ + fill: '#0a165e', + stroke: '#f4f4f4', + width: 1, + }), + new OffsetTextSymbolizer({ + labelProps: ['name'], + fill: '#0a165e', + stroke: '#f4f4f4', + width: 1, + lineHeight: 1.125, + font: `400 12px ${font}`, + offsetY: 4, + placements: [TextPlacements.S], + justify: Justify.Center, + }), + ]), + filter: (_, { props }) => + [ + 'attraction', + 'landmark', + 'memorial', + 'social_facility', + 'supermarket', + ].includes(getString(props, 'pmap:kind')), + }, + { + dataLayer: 'pois', + symbolizer: new CenteredTextSymbolizer({ + labelProps: ['name'], + fill: '#669', + stroke: '#eee', + width: 1.5, + lineHeight: 1, + font: `300 12px ${font}`, + }), + filter: (z, { props }) => { + if (z < 18) return false; + return [ + 'aerodrome', + 'amusement_ride', + 'animal', + 'art', + 'artwork', + 'atm', + 'attraction', + 'atv', + 'bakery', + 'beauty', + 'bench', + 'bicycle_rental', + 'books', + 'bureau_de_change', + 'bus_stop', + 'butcher', + 'cafe', + 'car', + 'carousel', + 'cemetery', + 'chalet', + 'childcare', + 'clinic', + 'clothes', + 'college', + 'computer', + 'convenience', + 'dentist', + 'doctors', + 'drinking_water', + 'emergency_phone', + 'fashion', + 'firepit', + 'florist', + 'fuel', + 'garden_centre', + 'gift', + 'greengrocer', + 'grocery', + 'hairdresser', + 'hanami', + 'hospital', + 'hostel', + 'hotel', + 'information', + 'karaoke', + 'library', + 'lottery', + 'marina', + 'military', + 'money_transfer', + 'national_park', + 'newsagent', + 'optician', + 'park', + 'parking', + 'pitch', + 'playground', + 'post_box', + 'post_office', + 'recycling', + 'roller_coaster', + 'sanitary_dump_station', + 'school', + 'shelter', + 'ship_chandler', + 'social_facility', + 'stadium', + 'studio', + 'supermarket', + 'swimming_area', + 'taxi', + 'telephone', + 'tobacco', + 'townhall', + 'trail_riding_station', + 'university', + 'viewpoint', + 'waste_basket', + 'waste_disposal', + 'water_point', + 'watering_place', + ].includes(getString(props, 'pmap:kind')); + }, + }, +]; + +function getString(props: Record, key: string): string { + const val = props[key]; + return typeof val === 'string' ? val : ''; +} + +function getNumber(props: Record, key: string): number { + const val = props[key]; + return typeof val === 'number' ? val : 0; +} From 4d30295b9ca2e587337b1dfc372a866a8fd1c585 Mon Sep 17 00:00:00 2001 From: Max Duval Date: Thu, 13 Jun 2024 09:10:38 +0100 Subject: [PATCH 6/7] feat: save basemap preference for a less jarring return experience --- src/components/LooMap/LooMap.tsx | 12 ++++++------ src/components/MapState.tsx | 13 ++++++++++--- src/config.ts | 5 +++-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/components/LooMap/LooMap.tsx b/src/components/LooMap/LooMap.tsx index 2459a6d72..d869fa7ad 100644 --- a/src/components/LooMap/LooMap.tsx +++ b/src/components/LooMap/LooMap.tsx @@ -74,8 +74,6 @@ const LooMap: React.FC = ({ // const [hydratedToilets, setHydratedToilets] = useState([]); const [announcement, setAnnouncement] = React.useState(null); const [intersectingToilets, setIntersectingToilets] = useState([]); - - const [useProtomap, setUseProtomaps] = useState(false); const plausible = usePlausible(); const [renderAccessibilityOverlays, setRenderAccessibilityOverlays] = @@ -299,7 +297,7 @@ const LooMap: React.FC = ({ } `} > - {useProtomap ? ( + {mapState.useProtomaps ? ( ) : ( = ({ { plausible( - useProtomap ? 'Reject New Map Styles' : 'Use New Map Styles', + mapState.useProtomaps + ? 'Reject New Map Styles' + : 'Use New Map Styles', ); - setUseProtomaps((toggle) => !toggle); + setMapState({ useProtomaps: !mapState.useProtomaps }); }} className="leaflet-control" css={css` @@ -344,7 +344,7 @@ const LooMap: React.FC = ({ cursor: pointer; `} > - {useProtomap ? 'Revert to old map' : 'Try the new map'} + {mapState.useProtomaps ? 'Revert to old map' : 'Try the new map'}
diff --git a/src/components/MapState.tsx b/src/components/MapState.tsx index 8c69f09f0..051edcd3c 100644 --- a/src/components/MapState.tsx +++ b/src/components/MapState.tsx @@ -1,7 +1,7 @@ import { Map } from 'leaflet'; import React, { Dispatch, useEffect } from 'react'; import { Loo } from '../api-client/graphql'; -import config, { Filters, FILTERS_KEY } from '../config'; +import config, { BASEMAP_KEY, Filters, FILTERS_KEY } from '../config'; import { UseLocateMapControl } from './LooMap/useLocateMapControl'; @@ -28,6 +28,7 @@ interface MapState { locationServices?: UseLocateMapControl; currentlyLoadedGeohashes?: string[]; geohashLoadState?: Record; + useProtomaps?: boolean; } const reducer = (state: MapState, newState: MapState) => { @@ -39,6 +40,7 @@ const reducer = (state: MapState, newState: MapState) => { export const MapStateProvider = ({ children }) => { const initialFilterState = config.getSettings(FILTERS_KEY) || []; + const initialBasemap = !!config.getSettings(BASEMAP_KEY); // default any unsaved filters as 'false' config.filters.forEach((filter) => { @@ -53,13 +55,18 @@ export const MapStateProvider = ({ children }) => { searchLocation: undefined, geohashLoadState: {}, currentlyLoadedGeohashes: [], - } as MapState); + useProtomaps: initialBasemap, + } satisfies MapState); // keep local storage and state in sync useEffect(() => { window.localStorage.setItem( FILTERS_KEY, - JSON.stringify(state.appliedFilters || {}) + JSON.stringify(state.appliedFilters || {}), + ); + window.localStorage.setItem( + BASEMAP_KEY, + JSON.stringify(!!state.useProtomaps), ); }, [state]); diff --git a/src/config.ts b/src/config.ts index 2c9c8a3d2..d52688f22 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,4 +1,5 @@ export const FILTERS_KEY = 'filters'; +export const BASEMAP_KEY = 'basemap'; export type Filters = | 'noPayment' @@ -79,7 +80,7 @@ const config = { return JSON.parse( (typeof localStorage !== 'undefined' && localStorage.getItem(namespace)) || - '{}' + '{}', ); } catch (e) { console.warn('Problem parsing JSON setting from local storage: ', e); @@ -101,7 +102,7 @@ const config = { JSON.stringify({ ...this.getSettings(namespace), ...obj, - }) + }), ); }, getTitle(appendText: string) { From 2677bd8a90e853ce7c1e75cbcd27f8d9c856e7c8 Mon Sep 17 00:00:00 2001 From: Max Duval Date: Thu, 13 Jun 2024 14:44:02 +0100 Subject: [PATCH 7/7] fix: default to OSM when no preference set --- src/components/MapState.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/MapState.tsx b/src/components/MapState.tsx index 051edcd3c..1f74df980 100644 --- a/src/components/MapState.tsx +++ b/src/components/MapState.tsx @@ -40,7 +40,7 @@ const reducer = (state: MapState, newState: MapState) => { export const MapStateProvider = ({ children }) => { const initialFilterState = config.getSettings(FILTERS_KEY) || []; - const initialBasemap = !!config.getSettings(BASEMAP_KEY); + const useProtomaps = config.getSettings(BASEMAP_KEY) === 'protomaps'; // default any unsaved filters as 'false' config.filters.forEach((filter) => { @@ -55,7 +55,7 @@ export const MapStateProvider = ({ children }) => { searchLocation: undefined, geohashLoadState: {}, currentlyLoadedGeohashes: [], - useProtomaps: initialBasemap, + useProtomaps, } satisfies MapState); // keep local storage and state in sync @@ -66,7 +66,7 @@ export const MapStateProvider = ({ children }) => { ); window.localStorage.setItem( BASEMAP_KEY, - JSON.stringify(!!state.useProtomaps), + JSON.stringify(state.useProtomaps ? 'protomaps' : 'osm'), ); }, [state]);