diff --git a/Dockerfile b/Dockerfile index e1bece0..b71b606 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,6 @@ -FROM node:24-alpine AS build +ARG NODE_IMAGE=node:24.22.1-alpine@sha256:06d7adf3e0ef61a13f1d28682726366f97a15aa1888c934d3ecec86c33918b53 + +FROM ${NODE_IMAGE} AS build WORKDIR /app RUN corepack enable @@ -9,15 +11,24 @@ RUN pnpm install --frozen-lockfile COPY . . RUN pnpm build -FROM caddy:2.10.2-alpine +FROM caddy:2.10.2-alpine@sha256:4c6e91c6ed0e2fa03efd5b44747b625fec79bc9cd06ac5235a779726618e530d AS caddy-bin -RUN apk add --no-cache jq nodejs +FROM ${NODE_IMAGE} AS runner + +RUN apk add --no-cache ca-certificates jq mailcap && \ + mkdir -p /config/caddy /data/caddy /etc/caddy /srv && \ + chmod 1777 /config/caddy /data/caddy +ENV XDG_CONFIG_HOME=/config +ENV XDG_DATA_HOME=/data +COPY --from=caddy-bin /usr/bin/caddy /usr/bin/caddy COPY Caddyfile /etc/caddy/Caddyfile COPY docker-entrypoint.sh /usr/local/bin/drainage-frontend-entrypoint COPY --from=build /app/dist /srv COPY --from=build /app/dist-server/edge-tts-server.cjs /usr/local/lib/drainage-frontend/edge-tts-server.cjs RUN chmod 755 /usr/local/bin/drainage-frontend-entrypoint +WORKDIR /srv + EXPOSE 80 ENTRYPOINT ["/usr/local/bin/drainage-frontend-entrypoint"] CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"] diff --git a/package.json b/package.json index 522fea6..3146ab1 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,9 @@ "private": true, "type": "module", "packageManager": "pnpm@11.8.0", + "engines": { + "node": ">=24.22.1 <25" + }, "scripts": { "dev": "vite", "build": "tsc --noEmit && vite build && pnpm build:tts", @@ -46,7 +49,7 @@ "edge-tts-ts": "^1.0.0", "katex": "^0.17.0", "lucide-react": "^0.468.0", - "maplibre-gl": "^4.7.1", + "maplibre-gl": "^6.4.1", "motion": "^12.40.0", "nanoid": "^5.1.14", "react": "^19.2.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c1523ed..d3c63b2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -96,8 +96,8 @@ importers: specifier: ^0.468.0 version: 0.468.0(react@19.2.7) maplibre-gl: - specifier: ^4.7.1 - version: 4.7.1 + specifier: ^6.4.1 + version: 6.15.0 motion: specifier: ^12.40.0 version: 12.42.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -807,34 +807,38 @@ packages: peerDependencies: '@luma.gl/core': ~9.3.0 - '@mapbox/geojson-rewind@0.5.2': - resolution: {integrity: sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==} - hasBin: true - '@mapbox/jsonlint-lines-primitives@2.0.3': resolution: {integrity: sha512-0SElaV0uMxEnxzBhhX9WTuPyUeMsAN/SS0i16tjuba4/mio63MG9khjC1a0JAiPGXAwvwm4UfHJURCN7nyudQg==} engines: {node: '>= 22'} - '@mapbox/point-geometry@0.1.0': - resolution: {integrity: sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==} + '@mapbox/point-geometry@1.1.0': + resolution: {integrity: sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ==} '@mapbox/tiny-sdf@2.2.0': resolution: {integrity: sha512-LVL4wgI9YAum5V+LNVQO6QgFBPw7/MIIY4XJPNsPDMrjEwcE+JfKk1LuIl8GnF197ejVdC9QdPaxrx5gfgdGXg==} - '@mapbox/unitbezier@0.0.1': - resolution: {integrity: sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==} + '@mapbox/tiny-sdf@2.3.0': + resolution: {integrity: sha512-gBvcNDBBB66bgQYvnaJ6Jk+VCaMmVq5+IZR2kWPisT88Z8s0kBQt6hfVi8QgRW8Vpg0UWZzBA4ZSyzHHC+VeRA==} - '@mapbox/vector-tile@1.3.1': - resolution: {integrity: sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==} + '@mapbox/unitbezier@1.0.0': + resolution: {integrity: sha512-fqd515fjBmANKGGsQ286E2Wvj/XvDFpGzwJxq4CI6jMQue6Oy04uCKp+JWKF00xRTmk6cEu1jPJ9p3xqH8YWqQ==} - '@mapbox/whoots-js@3.1.0': - resolution: {integrity: sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==} - engines: {node: '>=6.0.0'} + '@mapbox/vector-tile@3.0.0': + resolution: {integrity: sha512-Qf10S1uIHMk20ri/IVBnpS+esUEkVaR5Hftmz88jTInrpmWgPGJfPe3LVjjlE77trLx8tH6qjTG7uWH9hIq/0Q==} - '@maplibre/maplibre-gl-style-spec@20.4.0': - resolution: {integrity: sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw==} + '@maplibre/geojson-vt@6.3.0': + resolution: {integrity: sha512-3Zw2jsU9pIJG3G2CQFbLjWj2MlAHodhD7cSY+15iywUuLmmkgzcKRnueVRZ4AcC/5wOtfhidcJAAzBpoBNs3Xg==} + + '@maplibre/maplibre-gl-style-spec@26.4.4': + resolution: {integrity: sha512-hG4RZR4PBd/+6A3ODdZ3AnQRF106ZQk1y3bhwDg8bH/A4Oz2tnRUJVVWs9BZa6gXZ1d3UKe89C+Mm+olGBELvA==} hasBin: true + '@maplibre/mlt@1.3.0': + resolution: {integrity: sha512-7M2O7ABM80Oi8XPkfkrjKB8mOBIxGoVgkA52Mu4RMWoBvvMdagQ522+WxVYujZsMpqIr3BpzrTbXrm4k8lCzCQ==} + + '@maplibre/vt-pbf@4.3.2': + resolution: {integrity: sha512-j6p0AdjvAR19Z3XaCysle7A4ZSo08tYOzxD0Y9NQylwPAkwJJeYub5b2eVucdeDh7erhv69DahoLOevDRERRUw==} + '@math.gl/core@4.1.0': resolution: {integrity: sha512-FrdHBCVG3QdrworwrUSzXIaK+/9OCRLscxI2OUy6sLOHyHgBMyfnEGs99/m3KNvs+95BsnQLWklVfpKfQzfwKA==} @@ -1825,9 +1829,6 @@ packages: '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - '@types/geojson-vt@3.2.5': - resolution: {integrity: sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==} - '@types/geojson@7946.0.16': resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} @@ -1840,12 +1841,6 @@ packages: '@types/katex@0.16.8': resolution: {integrity: sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==} - '@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/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} @@ -1858,9 +1853,6 @@ packages: '@types/offscreencanvas@2019.7.3': resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==} - '@types/pbf@3.0.5': - resolution: {integrity: sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==} - '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: @@ -1875,9 +1867,6 @@ packages: '@types/statuses@2.0.6': resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} - '@types/supercluster@7.1.3': - resolution: {integrity: sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==} - '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -2130,6 +2119,9 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + bidi-js@1.1.0: + resolution: {integrity: sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==} + brace-expansion@1.1.16: resolution: {integrity: sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==} @@ -2484,8 +2476,8 @@ packages: earcut@2.2.4: resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==} - earcut@3.2.3: - resolution: {integrity: sha512-vnS4AVwp1KHAF13i1vp1/2D5evWy3k5u/iW/B81QVsUZtV8cv2tU0b2VNFlqvh4kYwrFMDdjPCfAmfyJW9y14Q==} + earcut@3.2.4: + resolution: {integrity: sha512-FHc6yNpnTORB0tM5kmZ03iD2mDuNakDE2lvf4Hw1XkfxtEHIGVi01B/GqUSwx+NcC1WGjidAfpTXzeALtPtfpg==} echarts-for-react@3.0.6: resolution: {integrity: sha512-4zqLgTGWS3JvkQDXjzkR1k1CHRdpd6by0988TWMJgnvDytegWLbeP/VNZmMa+0VJx2eD7Y632bi2JquXDgiGJg==} @@ -2587,6 +2579,7 @@ packages: eslint@9.39.5: resolution: {integrity: sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true peerDependencies: jiti: '*' @@ -2724,9 +2717,6 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - geojson-vt@4.0.3: - resolution: {integrity: sha512-jR1MwkLaZGa8Zftct9ZFruyWFrdl9ZyD2OliXNy9Qq5bBPeg5wHVpBQF9p5GjnicSDQqvBVpysxTPKmWdsfWMA==} - get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -2747,10 +2737,6 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - gl-matrix@3.4.4: resolution: {integrity: sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==} @@ -2758,10 +2744,6 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - global-prefix@4.0.0: - resolution: {integrity: sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==} - engines: {node: '>=16'} - globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -2867,9 +2849,6 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -2889,10 +2868,6 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - ini@4.1.3: - resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - inline-style-parser@0.2.7: resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} @@ -2940,10 +2915,6 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isexe@3.1.5: - resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} - engines: {node: '>=18'} - isomorphic-ws@5.0.0: resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==} peerDependencies: @@ -3015,10 +2986,6 @@ packages: khroma@2.1.0: resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} - kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - layout-base@1.0.2: resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} @@ -3137,8 +3104,8 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - maplibre-gl@4.7.1: - resolution: {integrity: sha512-lgL7XpIwsgICiL82ITplfS7IGwrB1OJIw/pCvprDp2dhmSSEBgmPzYRvwYYYvJGJD7fxUv1Tvpih4nZ6VrLuaA==} + maplibre-gl@6.15.0: + resolution: {integrity: sha512-kxFetbvUHDOVaAP1CYb226Mdk2QhzIPddqM0xJTFD35wu78Mpd6NM7+H68ALjc6Oa0kAOX5EAdMKyvD2u3qfcg==} engines: {node: '>=16.14.0', npm: '>=8.1.0'} markdown-table@3.0.4: @@ -3479,8 +3446,8 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - pbf@3.3.0: - resolution: {integrity: sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==} + pbf@5.1.2: + resolution: {integrity: sha512-mnvGdvOrIvJOBGUEdGkrVXjN8E/VkIJCkf2eS1DH2yv82ORUlLttmDt0rWY38yYZmVwciZwBUvHM20qxBZf40w==} hasBin: true picocolors@1.1.1: @@ -3540,9 +3507,6 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - quickselect@2.0.0: - resolution: {integrity: sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==} - quickselect@3.0.0: resolution: {integrity: sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==} @@ -3655,6 +3619,10 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -3790,9 +3758,6 @@ packages: stylis@4.4.0: resolution: {integrity: sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==} - supercluster@8.0.1: - resolution: {integrity: sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==} - supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -4074,9 +4039,6 @@ packages: jsdom: optional: true - vt-pbf@3.1.3: - resolution: {integrity: sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==} - w3c-xmlserializer@5.0.0: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} @@ -4106,11 +4068,6 @@ packages: engines: {node: '>= 8'} hasBin: true - which@4.0.0: - resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} - engines: {node: ^16.13.0 || >=18.0.0} - hasBin: true - why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -4825,35 +4782,45 @@ snapshots: '@math.gl/types': 4.1.0 '@probe.gl/env': 4.1.1 - '@mapbox/geojson-rewind@0.5.2': - dependencies: - get-stream: 6.0.1 - minimist: 1.2.8 - '@mapbox/jsonlint-lines-primitives@2.0.3': {} - '@mapbox/point-geometry@0.1.0': {} + '@mapbox/point-geometry@1.1.0': {} '@mapbox/tiny-sdf@2.2.0': {} - '@mapbox/unitbezier@0.0.1': {} + '@mapbox/tiny-sdf@2.3.0': {} - '@mapbox/vector-tile@1.3.1': + '@mapbox/unitbezier@1.0.0': {} + + '@mapbox/vector-tile@3.0.0': dependencies: - '@mapbox/point-geometry': 0.1.0 + '@mapbox/point-geometry': 1.1.0 + '@types/geojson': 7946.0.16 + pbf: 5.1.2 - '@mapbox/whoots-js@3.1.0': {} + '@maplibre/geojson-vt@6.3.0': + dependencies: + kdbush: 4.1.0 - '@maplibre/maplibre-gl-style-spec@20.4.0': + '@maplibre/maplibre-gl-style-spec@26.4.4': dependencies: '@mapbox/jsonlint-lines-primitives': 2.0.3 - '@mapbox/unitbezier': 0.0.1 + '@mapbox/unitbezier': 1.0.0 json-stringify-pretty-compact: 4.0.0 minimist: 1.2.8 - quickselect: 2.0.0 - rw: 1.3.3 + quickselect: 3.0.0 tinyqueue: 3.0.0 + '@maplibre/mlt@1.3.0': + dependencies: + '@mapbox/point-geometry': 1.1.0 + + '@maplibre/vt-pbf@4.3.2': + dependencies: + '@mapbox/point-geometry': 1.1.0 + '@types/geojson': 7946.0.16 + pbf: 5.1.2 + '@math.gl/core@4.1.0': dependencies: '@math.gl/types': 4.1.0 @@ -5797,10 +5764,6 @@ snapshots: '@types/estree@1.0.9': {} - '@types/geojson-vt@3.2.5': - dependencies: - '@types/geojson': 7946.0.16 - '@types/geojson@7946.0.16': {} '@types/hast@3.0.5': @@ -5811,14 +5774,6 @@ snapshots: '@types/katex@0.16.8': {} - '@types/mapbox__point-geometry@0.1.4': {} - - '@types/mapbox__vector-tile@1.3.4': - dependencies: - '@types/geojson': 7946.0.16 - '@types/mapbox__point-geometry': 0.1.4 - '@types/pbf': 3.0.5 - '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 @@ -5831,8 +5786,6 @@ snapshots: '@types/offscreencanvas@2019.7.3': {} - '@types/pbf@3.0.5': {} - '@types/react-dom@19.2.3(@types/react@19.2.17)': dependencies: '@types/react': 19.2.17 @@ -5847,10 +5800,6 @@ snapshots: '@types/statuses@2.0.6': {} - '@types/supercluster@7.1.3': - dependencies: - '@types/geojson': 7946.0.16 - '@types/trusted-types@2.0.7': optional: true @@ -6047,6 +5996,10 @@ snapshots: baseline-browser-mapping@2.10.43: {} + bidi-js@1.1.0: + dependencies: + require-from-string: 2.0.2 + brace-expansion@1.1.16: dependencies: balanced-match: 1.0.2 @@ -6412,7 +6365,7 @@ snapshots: earcut@2.2.4: {} - earcut@3.2.3: {} + earcut@3.2.4: {} echarts-for-react@3.0.6(echarts@6.1.0)(react@19.2.7): dependencies: @@ -6666,8 +6619,6 @@ snapshots: gensync@1.0.0-beta.2: {} - geojson-vt@4.0.3: {} - get-caller-file@2.0.5: {} get-east-asian-width@1.6.0: {} @@ -6692,20 +6643,12 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.2 - get-stream@6.0.1: {} - gl-matrix@3.4.4: {} glob-parent@6.0.2: dependencies: is-glob: 4.0.3 - global-prefix@4.0.0: - dependencies: - ini: 4.1.3 - kind-of: 6.0.3 - which: 4.0.0 - globals@14.0.0: {} globals@15.15.0: {} @@ -6887,8 +6830,6 @@ snapshots: dependencies: safer-buffer: 2.1.2 - ieee754@1.2.1: {} - ignore@5.3.2: {} import-fresh@3.3.1: @@ -6902,8 +6843,6 @@ snapshots: indent-string@4.0.0: {} - ini@4.1.3: {} - inline-style-parser@0.2.7: {} internmap@1.0.1: {} @@ -6937,8 +6876,6 @@ snapshots: isexe@2.0.0: {} - isexe@3.1.5: {} - isomorphic-ws@5.0.0(ws@8.21.1): dependencies: ws: 8.21.1 @@ -7011,8 +6948,6 @@ snapshots: khroma@2.1.0: {} - kind-of@6.0.3: {} - layout-base@1.0.2: {} layout-base@2.0.1: {} @@ -7099,34 +7034,26 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - maplibre-gl@4.7.1: + maplibre-gl@6.15.0: dependencies: - '@mapbox/geojson-rewind': 0.5.2 - '@mapbox/jsonlint-lines-primitives': 2.0.3 - '@mapbox/point-geometry': 0.1.0 - '@mapbox/tiny-sdf': 2.2.0 - '@mapbox/unitbezier': 0.0.1 - '@mapbox/vector-tile': 1.3.1 - '@mapbox/whoots-js': 3.1.0 - '@maplibre/maplibre-gl-style-spec': 20.4.0 + '@mapbox/point-geometry': 1.1.0 + '@mapbox/tiny-sdf': 2.3.0 + '@mapbox/unitbezier': 1.0.0 + '@mapbox/vector-tile': 3.0.0 + '@maplibre/geojson-vt': 6.3.0 + '@maplibre/maplibre-gl-style-spec': 26.4.4 + '@maplibre/mlt': 1.3.0 + '@maplibre/vt-pbf': 4.3.2 '@types/geojson': 7946.0.16 - '@types/geojson-vt': 3.2.5 - '@types/mapbox__point-geometry': 0.1.4 - '@types/mapbox__vector-tile': 1.3.4 - '@types/pbf': 3.0.5 - '@types/supercluster': 7.1.3 - earcut: 3.2.3 - geojson-vt: 4.0.3 + bidi-js: 1.1.0 + earcut: 3.2.4 gl-matrix: 3.4.4 - global-prefix: 4.0.0 kdbush: 4.1.0 murmurhash-js: 1.0.0 - pbf: 3.3.0 + pbf: 5.1.2 potpack: 2.1.0 quickselect: 3.0.0 - supercluster: 8.0.1 tinyqueue: 3.0.0 - vt-pbf: 3.1.3 markdown-table@3.0.4: {} @@ -7710,9 +7637,8 @@ snapshots: pathe@2.0.3: {} - pbf@3.3.0: + pbf@5.1.2: dependencies: - ieee754: 1.2.1 resolve-protobuf-schema: 2.1.0 picocolors@1.1.1: {} @@ -7760,8 +7686,6 @@ snapshots: punycode@2.3.1: {} - quickselect@2.0.0: {} - quickselect@3.0.0: {} react-dom@19.2.7(react@19.2.7): @@ -7910,6 +7834,8 @@ snapshots: require-directory@2.1.1: {} + require-from-string@2.0.2: {} + resolve-from@4.0.0: {} resolve-protobuf-schema@2.1.0: @@ -8083,10 +8009,6 @@ snapshots: stylis@4.4.0: {} - supercluster@8.0.1: - dependencies: - kdbush: 4.1.0 - supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -8337,12 +8259,6 @@ snapshots: transitivePeerDependencies: - msw - vt-pbf@3.1.3: - dependencies: - '@mapbox/point-geometry': 0.1.0 - '@mapbox/vector-tile': 1.3.1 - pbf: 3.3.0 - w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 @@ -8366,10 +8282,6 @@ snapshots: dependencies: isexe: 2.0.0 - which@4.0.0: - dependencies: - isexe: 3.1.5 - why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 diff --git a/src/features/workbench/hooks/use-workbench-map.ts b/src/features/workbench/hooks/use-workbench-map.ts index 6e8c900..285152e 100644 --- a/src/features/workbench/hooks/use-workbench-map.ts +++ b/src/features/workbench/hooks/use-workbench-map.ts @@ -1,6 +1,7 @@ import "maplibre-gl/dist/maplibre-gl.css"; -import maplibregl, { type Map as MapLibreMap, type MapSourceDataEvent } from "maplibre-gl"; +import * as maplibregl from "maplibre-gl"; +import type { Map as MapLibreMap, MapSourceDataEvent } from "maplibre-gl"; import { useEffect, useRef, useState, type RefObject } from "react"; import { env } from "@/shared/config/env"; import type { DetailFeature } from "../types"; @@ -128,7 +129,7 @@ export function useWorkbenchMap({ pitch: 0, bearing: 0, maxZoom: MAP_MAX_ZOOM, - preserveDrawingBuffer: true, + canvasContextAttributes: { preserveDrawingBuffer: true }, attributionControl: false }); diff --git a/src/features/workbench/map/camera.ts b/src/features/workbench/map/camera.ts index 0d3f2f2..1a8245e 100644 --- a/src/features/workbench/map/camera.ts +++ b/src/features/workbench/map/camera.ts @@ -6,6 +6,7 @@ import { WATER_NETWORK_GLOBAL_VIEW } from "./sources"; type LngLatBounds = [[number, number], [number, number]]; type WebMercatorBbox = readonly [number, number, number, number]; +type CompletePaddingOptions = Required; export type NetworkViewParams = { bbox3857: WebMercatorBbox; @@ -13,19 +14,22 @@ export type NetworkViewParams = { const WEB_MERCATOR_RADIUS = 6378137; const GLOBAL_VIEW_MAX_ZOOM = 13; -const GLOBAL_VIEW_PADDING: PaddingOptions = { top: 96, right: 48, bottom: 48, left: 48 }; -export function getWorkbenchPadding(leftPanelOpen: boolean, rightPanelOpen: boolean): PaddingOptions { - return getWorkbenchCameraPadding(1280, { +const GLOBAL_VIEW_PADDING: CompletePaddingOptions = { top: 96, right: 48, bottom: 48, left: 48 }; +export function getWorkbenchPadding( + leftPanelOpen: boolean, + rightPanelOpen: boolean +): CompletePaddingOptions { + return completePadding(getWorkbenchCameraPadding(1280, { agentOpen: leftPanelOpen, conditionOpen: rightPanelOpen - }); + })); } export function getResponsiveWorkbenchPadding( map: MapLibreMap, leftPanelOpen: boolean, rightPanelOpen: boolean -): PaddingOptions { +): CompletePaddingOptions { const width = getMapViewportSize(map).width; return getResponsivePadding( map, @@ -51,10 +55,14 @@ export function fitNetworkBounds( ); } -export function getResponsivePadding(map: MapLibreMap, padding: PaddingOptions): PaddingOptions { +export function getResponsivePadding( + map: MapLibreMap, + padding: PaddingOptions +): CompletePaddingOptions { + const complete = completePadding(padding); const { width, height } = getMapViewportSize(map); - const horizontalPadding = padding.left + padding.right; - const verticalPadding = padding.top + padding.bottom; + const horizontalPadding = complete.left + complete.right; + const verticalPadding = complete.top + complete.bottom; const maxHorizontalPadding = width * 0.58; const maxVerticalPadding = height * 0.58; const horizontalScale = horizontalPadding > 0 ? maxHorizontalPadding / horizontalPadding : 1; @@ -62,14 +70,23 @@ export function getResponsivePadding(map: MapLibreMap, padding: PaddingOptions): const scale = Math.min(1, horizontalScale, verticalScale); if (scale >= 1) { - return padding; + return complete; } return { - top: Math.round(padding.top * scale), - right: Math.round(padding.right * scale), - bottom: Math.round(padding.bottom * scale), - left: Math.round(padding.left * scale) + top: Math.round(complete.top * scale), + right: Math.round(complete.right * scale), + bottom: Math.round(complete.bottom * scale), + left: Math.round(complete.left * scale) + }; +} + +function completePadding(padding: PaddingOptions): CompletePaddingOptions { + return { + top: padding.top ?? 0, + right: padding.right ?? 0, + bottom: padding.bottom ?? 0, + left: padding.left ?? 0 }; } diff --git a/src/features/workbench/map/export-view.ts b/src/features/workbench/map/export-view.ts index a4c1fbb..291201d 100644 --- a/src/features/workbench/map/export-view.ts +++ b/src/features/workbench/map/export-view.ts @@ -1,4 +1,5 @@ -import maplibregl, { type Map as MapLibreMap, type StyleSpecification } from "maplibre-gl"; +import * as maplibregl from "maplibre-gl"; +import type { Map as MapLibreMap, StyleSpecification } from "maplibre-gl"; import type { MapFeatureInteractionState } from "../hooks/use-map-interactions"; const MAX_EXPORT_DIMENSION = 4096; @@ -37,7 +38,7 @@ export async function exportMapViewImage(map: MapLibreMap, { scale, targetLongEd zoom: map.getZoom(), pitch: map.getPitch(), bearing: map.getBearing(), - preserveDrawingBuffer: true, + canvasContextAttributes: { preserveDrawingBuffer: true }, interactive: false, attributionControl: false, fadeDuration: 0 diff --git a/src/features/workbench/map/layer-group-style.ts b/src/features/workbench/map/layer-group-style.ts index d0d2d88..bbfeff2 100644 --- a/src/features/workbench/map/layer-group-style.ts +++ b/src/features/workbench/map/layer-group-style.ts @@ -1,4 +1,7 @@ import type { Map as MapLibreMap } from "maplibre-gl"; + +type PaintPropertyName = Parameters[1]; +type LayoutPropertyName = Parameters[1]; import { DRAINAGE_LAYER_VISUALS } from "./map-layer-visuals"; import { MAP_STYLE_TOKENS } from "./map-colors"; @@ -195,11 +198,11 @@ function stateColor(color: string): unknown { ]; } -function setPaint(map: MapLibreMap, layerId: string, property: string, value: unknown) { +function setPaint(map: MapLibreMap, layerId: string, property: PaintPropertyName, value: unknown) { if (map.getLayer(layerId)) map.setPaintProperty(layerId, property, (value ?? null) as never); } -function setLayout(map: MapLibreMap, layerId: string, property: string, value: unknown) { +function setLayout(map: MapLibreMap, layerId: string, property: LayoutPropertyName, value: unknown) { if (map.getLayer(layerId)) map.setLayoutProperty(layerId, property, value as never); } diff --git a/src/main.tsx b/src/main.tsx index 34756c6..2eb9503 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,5 +1,7 @@ import React from "react"; import ReactDOM from "react-dom/client"; +import { setWorkerUrl } from "maplibre-gl"; +import maplibreWorkerUrl from "maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url"; import { App } from "@/app/app"; import { env } from "@/shared/config/env"; @@ -8,6 +10,8 @@ import "maplibre-gl/dist/maplibre-gl.css"; import "katex/dist/katex.min.css"; import "streamdown/styles.css"; +setWorkerUrl(maplibreWorkerUrl); + async function prepareMocks() { if (!env.DRAINAGE_ENABLE_MSW) return; const { worker } = await import("@/mocks/browser");