feat(app): mode street 'An lari a' - visionneuse mapillary-js lazy, /api/round?mode=street, i18n FR/GCF (ADR-003)
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
# Token client Mapillary (gratuit) : https://www.mapillary.com/dashboard/developers
|
||||
# Requis uniquement pour le mode street « An lari a » (visionneuse mapillary-js).
|
||||
# Token client : conçu pour être exposé côté navigateur (rate-limité par app).
|
||||
PUBLIC_MAPILLARY_TOKEN=
|
||||
|
||||
# Optionnel : URL d'un style/tiles auto-hébergé (tileserver-gl) — voir docs/deploiement.md
|
||||
# PUBLIC_TILES_URL=
|
||||
Generated
+289
-7
@@ -8,6 +8,7 @@
|
||||
"name": "jwe",
|
||||
"version": "2.0.0",
|
||||
"dependencies": {
|
||||
"mapillary-js": "^4.1.2",
|
||||
"maplibre-gl": "^5.1.0",
|
||||
"sharp": "^0.35.3"
|
||||
},
|
||||
@@ -2586,6 +2587,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/earcut": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/earcut/-/earcut-2.1.4.tgz",
|
||||
"integrity": "sha512-qp3m9PPz4gULB9MhjGID7wpo3gJ4bTGXm7ltNDsmOvsPduTeHp8wSW9YckBj3mljeOh4F0m2z/0JKAALRKbmLQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
|
||||
@@ -2609,6 +2616,24 @@
|
||||
"undici-types": "~8.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/pako": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.7.tgz",
|
||||
"integrity": "sha512-YBtzT2ztNF6R/9+UXj2wTGFnC9NklAnASt3sC0h2m1bbH7G6FyBIkt4AN8ThZpNfxUo1b2iMVO0UawiJymEt8A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/pbf": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz",
|
||||
"integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/polylabel": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/polylabel/-/polylabel-1.1.3.tgz",
|
||||
"integrity": "sha512-9Zw2KoDpi+T4PZz2G6pO2xArE0m/GSMTW1MIxF2s8ZY8x9XDO6fv9um0ydRGvcbkFLlaq8yNK6eZxnmMZtDgWQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/proj4": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/proj4/-/proj4-2.5.2.tgz",
|
||||
@@ -2631,6 +2656,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/three": {
|
||||
"version": "0.134.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.134.0.tgz",
|
||||
"integrity": "sha512-4YB+99Rgqq27EjiYTItEoZtdjLnTh8W9LxowgpC9eWsjaQJIL4Kn/ZcUKAnW3gB/jS4hqGN8iqmid+RcUZDzpA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/trusted-types": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
||||
@@ -2638,6 +2669,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/virtual-dom": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/virtual-dom/-/virtual-dom-2.1.4.tgz",
|
||||
"integrity": "sha512-Y7L/frVydXRd16MevczslJZQu+QWsrqZlj6ytk7mST3xen0fkx7Ollw31By/89A8Wq+nfNWm/IoTR1ac/0fRhA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@xmldom/xmldom": {
|
||||
"version": "0.8.13",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.13.tgz",
|
||||
@@ -2836,6 +2873,12 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/browser-split": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/browser-split/-/browser-split-0.0.1.tgz",
|
||||
"integrity": "sha512-JhvgRb2ihQhsljNda3BI8/UcRHVzrVwo3Q+P8vDtSiyobXuFpuZ9mq+MbRGMnC22CjW3RrfXdg6j6ITX8M+7Ow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
@@ -2884,6 +2927,15 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/camelize": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
|
||||
"integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
|
||||
@@ -3221,6 +3273,11 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dom-walk": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
|
||||
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
|
||||
},
|
||||
"node_modules/duplexer": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
||||
@@ -3245,6 +3302,16 @@
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/error": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/error/-/error-4.4.0.tgz",
|
||||
"integrity": "sha512-SNDKualLUtT4StGFP7xNfuFybL2f6iJujFtrWuvJqGbVQGaN+adE23veqzPz1hjUjTunLi2EnJ+0SJxtbJreKw==",
|
||||
"dependencies": {
|
||||
"camelize": "^1.0.0",
|
||||
"string-template": "~0.2.0",
|
||||
"xtend": "~4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
@@ -3329,6 +3396,14 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ev-store": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ev-store/-/ev-store-7.0.0.tgz",
|
||||
"integrity": "sha512-otazchNRnGzp2YarBJ+GXKVGvhxVATB1zmaStxJBYet0Dyq7A9VhH8IUEB/gRcL6Ch52lfpgPTRJ2m49epyMsQ==",
|
||||
"dependencies": {
|
||||
"individual": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/event-stream": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz",
|
||||
@@ -3631,6 +3706,16 @@
|
||||
"integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/global": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
|
||||
"integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"min-document": "^2.19.0",
|
||||
"process": "^0.11.10"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
@@ -3721,7 +3806,6 @@
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -3754,6 +3838,11 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/individual": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/individual/-/individual-3.0.0.tgz",
|
||||
"integrity": "sha512-rUY5vtT748NMRbEMrTNiFfy29BgGZwGXUi2NFUVMWQrogSLzlJvQV9eeMWi+g1aVaQ53tpyLAQtd5x/JH0Nh1g=="
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
@@ -3867,6 +3956,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-object": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz",
|
||||
"integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-reference": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
|
||||
@@ -3983,6 +4081,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
|
||||
"integrity": "sha512-ZYvPPOMqUwPoDsbJaR10iQJYnMuZhRTvHYl62ErLIEX7RgFlziSBUUvrt3OVfc47QlHHpzPZYP17g3Fv7oeJkg==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.21",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||
@@ -4000,6 +4107,63 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mapillary-js": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/mapillary-js/-/mapillary-js-4.1.2.tgz",
|
||||
"integrity": "sha512-LYj6xbp/Y9wfBkr/prRwgJGb3+KwvzUri0yl5QEpMEH7oC1p52ErshWmPXysKefmm6JaFML4D7FJ89viwJ4T5g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/earcut": "^2.1.1",
|
||||
"@types/node": "^14.14.31",
|
||||
"@types/pako": "^1.0.2",
|
||||
"@types/pbf": "^3.0.2",
|
||||
"@types/polylabel": "^1.0.5",
|
||||
"@types/rbush": "^3.0.0",
|
||||
"@types/three": "^0.134.0",
|
||||
"@types/virtual-dom": "^2.1.1",
|
||||
"earcut": "^2.2.3",
|
||||
"martinez-polygon-clipping": "^0.7.1",
|
||||
"pako": "^2.0.4",
|
||||
"pbf": "^3.2.1",
|
||||
"polylabel": "^1.1.0",
|
||||
"rbush": "^3.0.1",
|
||||
"rxjs": "^7.3.0",
|
||||
"s2-geometry": "^1.2.10",
|
||||
"three": "^0.134.0",
|
||||
"virtual-dom": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/mapillary-js/node_modules/@types/node": {
|
||||
"version": "14.18.63",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz",
|
||||
"integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mapillary-js/node_modules/@types/rbush": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/rbush/-/rbush-3.0.4.tgz",
|
||||
"integrity": "sha512-knSt9cCW8jj1ZSFcFeBZaX++OucmfPxxHiRwTahZfJlnQsek7O0bazTJHWD2RVj9LEoejUYF2de3/stf+QXcXw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mapillary-js/node_modules/earcut": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz",
|
||||
"integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/mapillary-js/node_modules/pbf": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz",
|
||||
"integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"ieee754": "^1.1.12",
|
||||
"resolve-protobuf-schema": "^2.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"pbf": "bin/pbf"
|
||||
}
|
||||
},
|
||||
"node_modules/maplibre-gl": {
|
||||
"version": "5.24.0",
|
||||
"resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.24.0.tgz",
|
||||
@@ -4100,6 +4264,35 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/martinez-polygon-clipping": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/martinez-polygon-clipping/-/martinez-polygon-clipping-0.7.4.tgz",
|
||||
"integrity": "sha512-jBEwrKtA0jTagUZj2bnmb4Yg2s4KnJGRePStgI7bAVjtcipKiF39R4LZ2V/UT61jMYWrTcBhPazexeqd6JAVtw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"robust-predicates": "^2.0.4",
|
||||
"splaytree": "^0.1.4",
|
||||
"tinyqueue": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/martinez-polygon-clipping/node_modules/robust-predicates": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-2.0.4.tgz",
|
||||
"integrity": "sha512-l4NwboJM74Ilm4VKfbAtFeGq7aEjWL+5kVFcmgFA2MrdnQWx9iE/tUGvxY5HyMI7o/WpSIUFLbC5fbeaHgSCYg==",
|
||||
"license": "Unlicense"
|
||||
},
|
||||
"node_modules/martinez-polygon-clipping/node_modules/splaytree": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/splaytree/-/splaytree-0.1.4.tgz",
|
||||
"integrity": "sha512-D50hKrjZgBzqD3FT2Ek53f2dcDLAQT8SSGrzj3vidNH5ISRgceeGVJ2dQIthKOuayqFXfFjXheHNo4bbt9LhRQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/martinez-polygon-clipping/node_modules/tinyqueue": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-1.2.3.tgz",
|
||||
"integrity": "sha512-Qz9RgWuO9l8lT+Y9xvbzhPT2efIUIFd69N7eF7tJ9lnQl0iLj1M7peK7IoUGZL9DJHw9XftqLreccfxcQgYLxA==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/mgrs": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz",
|
||||
@@ -4121,6 +4314,15 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/min-document": {
|
||||
"version": "2.19.2",
|
||||
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.2.tgz",
|
||||
"integrity": "sha512-8S5I8db/uZN8r9HSLFVWPdJCvYOejMcEC82VIzNUc6Zkklf/d1gg2psfE79/vyhWOj4+J8MtwmoOz3TmvaGu5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dom-walk": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
@@ -4260,6 +4462,12 @@
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/next-tick": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-0.2.2.tgz",
|
||||
"integrity": "sha512-f7h4svPtl+QidoBv4taKXUjJ70G2asaZ8G28nS0OkqaalX8dwwrtWtyxEDPK62AC00ur/+/E0pUwBwY5EPn15Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.94.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.94.0.tgz",
|
||||
@@ -4382,7 +4590,6 @@
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-2.2.0.tgz",
|
||||
"integrity": "sha512-zJq6RP/5q+TO2OpFV3FHzlPnFjmkb7Nc99a5SNjJE+uu/PkpChs+NIZSSzbBoD+6kjiISXjfYdwj1ZRQ81dz/w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -4489,6 +4696,21 @@
|
||||
"splaytree": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/polylabel": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/polylabel/-/polylabel-1.1.0.tgz",
|
||||
"integrity": "sha512-bxaGcA40sL3d6M4hH72Z4NdLqxpXRsCFk8AITYg6x1rn1Ei3izf00UMLklerBZTO49aPA3CYrIwVulx2Bce2pA==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"tinyqueue": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/polylabel/node_modules/tinyqueue": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz",
|
||||
"integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.19",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.19.tgz",
|
||||
@@ -4570,7 +4792,6 @@
|
||||
"version": "0.11.10",
|
||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
@@ -4638,7 +4859,6 @@
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz",
|
||||
"integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"quickselect": "^2.0.0"
|
||||
@@ -4648,7 +4868,6 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz",
|
||||
"integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/rc": {
|
||||
@@ -4862,6 +5081,24 @@
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/rxjs": {
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/s2-geometry": {
|
||||
"version": "1.2.10",
|
||||
"resolved": "https://registry.npmjs.org/s2-geometry/-/s2-geometry-1.2.10.tgz",
|
||||
"integrity": "sha512-5WejfQu1XZ25ZerW8uL6xP1sM2krcOYKhI6TbfybGRf+vTQLrm3E+4n0+1lWg+MYqFjPzoe51zKhn2sBRMCt5g==",
|
||||
"license": "(MIT or Apache-2 or ISC)",
|
||||
"dependencies": {
|
||||
"long": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sade": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
|
||||
@@ -5117,6 +5354,11 @@
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-template": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz",
|
||||
"integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw=="
|
||||
},
|
||||
"node_modules/strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||
@@ -5284,6 +5526,12 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/three": {
|
||||
"version": "0.134.0",
|
||||
"resolved": "https://registry.npmjs.org/three/-/three-0.134.0.tgz",
|
||||
"integrity": "sha512-LbBerg7GaSPjYtTOnu41AMp7tV6efUNR3p4Wk5NzkSsNTBuA5mDGOfwwZL1jhhVMLx9V20HolIUo0+U3AXehbg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/through": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
@@ -5346,8 +5594,7 @@
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD",
|
||||
"optional": true
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/tsscmp": {
|
||||
"version": "1.0.6",
|
||||
@@ -5419,6 +5666,22 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/virtual-dom": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/virtual-dom/-/virtual-dom-2.1.1.tgz",
|
||||
"integrity": "sha512-wb6Qc9Lbqug0kRqo/iuApfBpJJAq14Sk1faAnSmtqXiwahg7PVTvWMs9L02Z8nNIMqbwsxzBAA90bbtRLbw0zg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browser-split": "0.0.1",
|
||||
"error": "^4.3.0",
|
||||
"ev-store": "^7.0.0",
|
||||
"global": "^4.3.0",
|
||||
"is-object": "^1.0.1",
|
||||
"next-tick": "^0.2.2",
|
||||
"x-is-array": "0.1.0",
|
||||
"x-is-string": "0.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.4.3",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz",
|
||||
@@ -5573,6 +5836,16 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/x-is-array": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/x-is-array/-/x-is-array-0.1.0.tgz",
|
||||
"integrity": "sha512-goHPif61oNrr0jJgsXRfc8oqtYzvfiMJpTqwE7Z4y9uH+T3UozkGqQ4d2nX9mB9khvA8U2o/UbPOFjgC7hLWIA=="
|
||||
},
|
||||
"node_modules/x-is-string": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz",
|
||||
"integrity": "sha512-GojqklwG8gpzOVEVki5KudKNoq7MbbjYZCbyWzEz7tyPA7eleiE0+ePwOWQQRb5fm86rD3S8Tc0tSFf3AOv50w=="
|
||||
},
|
||||
"node_modules/xml-utils": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.10.2.tgz",
|
||||
@@ -5580,6 +5853,15 @@
|
||||
"dev": true,
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/zarrita": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/zarrita/-/zarrita-0.7.3.tgz",
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"vite": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"mapillary-js": "^4.1.2",
|
||||
"maplibre-gl": "^5.1.0",
|
||||
"sharp": "^0.35.3"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { env } from '$env/dynamic/public';
|
||||
import { t } from '$lib/i18n/store.svelte';
|
||||
import type { Viewer } from 'mapillary-js';
|
||||
|
||||
interface Props {
|
||||
mapillaryId: string;
|
||||
credit?: string;
|
||||
}
|
||||
|
||||
let { mapillaryId, credit }: Props = $props();
|
||||
|
||||
let conteneur: HTMLDivElement;
|
||||
let viewer: Viewer | null = null;
|
||||
let etat = $state<'chargement' | 'pret' | 'erreur' | 'token'>('chargement');
|
||||
|
||||
onMount(() => {
|
||||
let detruit = false;
|
||||
// Lazy load : mapillary-js (JS + CSS) n'est chargé que sur l'écran de jeu street.
|
||||
void (async () => {
|
||||
const token = env.PUBLIC_MAPILLARY_TOKEN;
|
||||
if (!token) {
|
||||
etat = 'token';
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const [mod] = await Promise.all([
|
||||
import('mapillary-js'),
|
||||
import('mapillary-js/dist/mapillary.css')
|
||||
]);
|
||||
if (detruit) return;
|
||||
// cover désactivé : la photo s'affiche directement, sans écran d'intro.
|
||||
viewer = new mod.Viewer({
|
||||
accessToken: token,
|
||||
container: conteneur,
|
||||
component: { cover: false }
|
||||
});
|
||||
// moveTo rejette si l'image a été retirée de Mapillary entre-temps.
|
||||
await viewer.moveTo(mapillaryId);
|
||||
if (detruit) return;
|
||||
etat = 'pret';
|
||||
} catch {
|
||||
if (!detruit) etat = 'erreur';
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
detruit = true;
|
||||
viewer?.remove();
|
||||
viewer = null;
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<figure class="street-panel">
|
||||
<div
|
||||
bind:this={conteneur}
|
||||
class="visionneuse"
|
||||
role="application"
|
||||
aria-label={t().jeu.streetAriaLabel}
|
||||
></div>
|
||||
{#if etat !== 'pret'}
|
||||
<div class="voile">
|
||||
<p>
|
||||
{#if etat === 'chargement'}{t().jeu.streetChargement}
|
||||
{:else if etat === 'token'}{t().jeu.streetToken}
|
||||
{:else}{t().jeu.streetErreur}{/if}
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
{#if credit && etat === 'pret'}
|
||||
<figcaption>{credit}</figcaption>
|
||||
{/if}
|
||||
</figure>
|
||||
|
||||
<style>
|
||||
.street-panel {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background: var(--oki-vert);
|
||||
border-radius: var(--oki-radius);
|
||||
}
|
||||
|
||||
.visionneuse {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.voile {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
color: var(--oki-blanc);
|
||||
background: var(--oki-vert);
|
||||
}
|
||||
|
||||
figcaption {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 0.4rem 0.8rem;
|
||||
font-size: 0.72rem;
|
||||
color: #fff;
|
||||
background: linear-gradient(transparent, rgba(11, 61, 46, 0.85));
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
@@ -17,6 +17,8 @@ const fr = {
|
||||
lieuDesc: 'Une rue, un bord de mer, une forêt… devine où tu es.',
|
||||
defi: 'Défi 5 rounds',
|
||||
defiDesc: '5 lieux d’affilée, monuments et lieux mélangés.',
|
||||
street: 'An lari a',
|
||||
streetDesc: 'Navigue dans une rue en photo 360° et devine la commune.',
|
||||
explorer: 'Aprann',
|
||||
explorerDesc: 'Explore la carte librement et lis les fiches Wikipédia. Sans score.'
|
||||
},
|
||||
@@ -40,6 +42,10 @@ const fr = {
|
||||
indicesRestants: 'indices restants',
|
||||
plusDIndice: 'Plus d’indice disponible',
|
||||
poserMarqueur: 'Clique sur la carte pour placer ton marqueur',
|
||||
streetChargement: 'Chargement de la vue de rue…',
|
||||
streetErreur: 'Impossible de charger la photo Mapillary. Réessaie ou passe au lieu suivant.',
|
||||
streetToken: 'Visionneuse indisponible : configuration Mapillary manquante.',
|
||||
streetAriaLabel: 'Vue de rue interactive. Flèches pour avancer, glisser pour regarder autour.',
|
||||
round: 'Manche',
|
||||
sur: 'sur',
|
||||
difficulte: {
|
||||
|
||||
@@ -19,6 +19,8 @@ const gcf: Dict = {
|
||||
lieuDesc: 'On lari, on bodlanmè, on fowé… chwé kote ou yé.',
|
||||
defi: 'Défi 5 rounds',
|
||||
defiDesc: '5 koté youn dèyè ròt, moniman épi plas mélanjé.',
|
||||
street: 'An lari a',
|
||||
streetDesc: 'Mache nan on lari an foto 360° é chwé komin-lan.',
|
||||
explorer: 'Aprann',
|
||||
explorerDesc: 'Flanné asou kat-la é li fich Wikipédia yo. San pwen.'
|
||||
},
|
||||
@@ -42,6 +44,10 @@ const gcf: Dict = {
|
||||
indicesRestants: 'endis ki rété',
|
||||
plusDIndice: 'Pa ni endis ankò',
|
||||
poserMarqueur: 'Kwiké asou kat-la pou mété makò-a',
|
||||
streetChargement: 'Nou ka chajé vi lari-a…',
|
||||
streetErreur: 'Nou pa rivé chajé foto Mapillary-la. Éséyé ankò oben pasé o koté swivan.',
|
||||
streetToken: 'Vi lari-a pa disponib : konfigirasyon Mapillary-la manké.',
|
||||
streetAriaLabel: 'Vi lari-a. Flèch yo pou avansé, glissé pou gadté toutò.',
|
||||
round: 'Mannèk',
|
||||
sur: 'asou',
|
||||
difficulte: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import rawLieux from './data/lieux.json';
|
||||
import rawStreet from './data/street.json';
|
||||
import type {
|
||||
Categorie,
|
||||
Difficulte,
|
||||
@@ -6,10 +7,15 @@ import type {
|
||||
GuessResult,
|
||||
Lieu,
|
||||
Region,
|
||||
RoundPlace
|
||||
RoundPlace,
|
||||
StreetLieu
|
||||
} from '$lib/types';
|
||||
|
||||
const lieux = rawLieux as Lieu[];
|
||||
const street = rawStreet as StreetLieu[];
|
||||
|
||||
/** Lieu « scorable » : les deux corpus partagent les champs du scoring. */
|
||||
type Scoreable = Lieu | StreetLieu;
|
||||
|
||||
const REGIONS: Region[] = ['GUADELOUPE', 'MARTINIQUE', 'GUYANE', 'REUNION'];
|
||||
const CATEGORIES: Categorie[] = ['MONUMENT', 'LIEU'];
|
||||
@@ -43,7 +49,13 @@ function parseCategorie(value: string | null): Categorie | null {
|
||||
return value && CATEGORIES.includes(value as Categorie) ? (value as Categorie) : null;
|
||||
}
|
||||
|
||||
export function getLieuById(id: string): Lieu | undefined {
|
||||
/** Recherche dans les deux corpus (photos classiques + street Mapillary). */
|
||||
export function getLieuById(id: string): Scoreable | undefined {
|
||||
return lieux.find((l) => l.id === id) ?? street.find((l) => l.id === id);
|
||||
}
|
||||
|
||||
/** Recherche limitée au corpus photo classique (défi, proxy photo). */
|
||||
export function getLieuPhotoById(id: string): Lieu | undefined {
|
||||
return lieux.find((l) => l.id === id);
|
||||
}
|
||||
|
||||
@@ -74,6 +86,28 @@ export function getRandomLieu(options: {
|
||||
return pool[Math.floor(Math.random() * pool.length)];
|
||||
}
|
||||
|
||||
/** Sélection aléatoire d'un lieu street (mode « An lari a », corpus Mapillary). */
|
||||
export function getRandomStreet(options: {
|
||||
region?: string | null;
|
||||
exclude?: string | null;
|
||||
}): StreetLieu | null {
|
||||
const region = parseRegion(options.region ?? null);
|
||||
const excluded = new Set(
|
||||
(options.exclude ?? '')
|
||||
.split(',')
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean)
|
||||
);
|
||||
let pool = street.filter((l) => !excluded.has(l.id));
|
||||
if (region) pool = pool.filter((l) => l.region === region);
|
||||
// Si tout a été exclu, on réessaie sans les exclusions (le jeu doit continuer).
|
||||
if (pool.length === 0) {
|
||||
pool = region ? street.filter((l) => l.region === region) : street;
|
||||
}
|
||||
if (pool.length === 0) return null;
|
||||
return pool[Math.floor(Math.random() * pool.length)];
|
||||
}
|
||||
|
||||
/** Largeurs (px) servies par le proxy photo /api/photo/[id]?w=. */
|
||||
export const PHOTO_LARGEURS = [400, 800, 1200] as const;
|
||||
|
||||
@@ -103,6 +137,27 @@ export function sanitizeRound(lieu: Lieu): RoundPlace {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Anti-triche, mode street : ne garde que les champs publics.
|
||||
* Seul `mapillaryId` part au client (la visionneuse doit bien appeler Mapillary) ;
|
||||
* coords/commune/région/wikidata_id ne partent jamais avant le guess.
|
||||
* Limitation documentée (architecture.md §10) : l'image_key est publique côté
|
||||
* Mapillary, un joueur techniquement équipé peut retrouver la position — même
|
||||
* propriété que GeoGuessr/Street View, acceptable en solo sans leaderboard.
|
||||
*/
|
||||
export function sanitizeRoundStreet(lieu: StreetLieu): RoundPlace {
|
||||
return {
|
||||
id: lieu.id,
|
||||
nom: lieu.nom,
|
||||
nom_creole: lieu.nom_creole,
|
||||
categorie: 'LIEU',
|
||||
difficulte: lieu.difficulte,
|
||||
mapillaryId: lieu.mapillary_id,
|
||||
credit: `© ${lieu.credit.username} / Mapillary (CC BY-SA 4.0)`,
|
||||
indices: lieu.indices
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Rayon effectif (km) de la courbe de score (audit A1).
|
||||
* Les communes guyanaises sont immenses (Saint-Laurent-du-Maroni ≈ 4 321 km²) :
|
||||
@@ -111,7 +166,7 @@ export function sanitizeRound(lieu: Lieu): RoundPlace {
|
||||
* au moins celui du disque de même aire que la commune : sqrt(aire / π).
|
||||
* Champ optionnel : sans lui, on retombe sur le rayon de difficulté.
|
||||
*/
|
||||
export function rayonEffectifKm(lieu: Lieu): number {
|
||||
export function rayonEffectifKm(lieu: Scoreable): number {
|
||||
const base = RAYONS[lieu.difficulte];
|
||||
const aire = lieu.aire_commune_km2;
|
||||
if (typeof aire === 'number' && Number.isFinite(aire) && aire > 0) {
|
||||
@@ -126,7 +181,7 @@ export function rayonEffectifKm(lieu: Lieu): number {
|
||||
* bonus temps ≤ +20 % ; total plafonné à 5000.
|
||||
*/
|
||||
export function scoreGuess(
|
||||
lieu: Lieu,
|
||||
lieu: Scoreable,
|
||||
guess: { lat: number; lon: number },
|
||||
hintsUsed: number,
|
||||
timeMs?: number
|
||||
@@ -154,7 +209,7 @@ export function scoreGuess(
|
||||
}
|
||||
|
||||
/** Réponse « Passer » : la vérité est révélée, score 0, pas de distance. */
|
||||
export function skipResult(lieu: Lieu): GuessResult {
|
||||
export function skipResult(lieu: Scoreable): GuessResult {
|
||||
return {
|
||||
distanceKm: null,
|
||||
score: 0,
|
||||
|
||||
+28
-2
@@ -44,6 +44,27 @@ export interface Lieu {
|
||||
aire_commune_km2?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lieu du mode street (« An lari a ») — serveur uniquement.
|
||||
* La photo statique est remplacée par une image Mapillary (CC BY-SA 4.0).
|
||||
* `wikidata_id` pointe vers la COMMUNE (phase éducative : fiche de la commune).
|
||||
*/
|
||||
export interface StreetLieu {
|
||||
id: string;
|
||||
nom: string;
|
||||
nom_creole: string;
|
||||
region: Region;
|
||||
commune: string;
|
||||
coordonnees: Coordonnees;
|
||||
difficulte: Difficulte;
|
||||
mapillary_id: string;
|
||||
credit: { username: string; captured_at: string };
|
||||
is_pano: boolean;
|
||||
wikidata_id: string | null;
|
||||
indices: Indice[];
|
||||
aire_commune_km2?: number;
|
||||
}
|
||||
|
||||
/** Lieu SANITISÉ envoyé par GET /api/round (aucune coordonnée, commune, région, wikidata_id). */
|
||||
export interface RoundPlace {
|
||||
id: string;
|
||||
@@ -51,7 +72,12 @@ export interface RoundPlace {
|
||||
nom_creole: string;
|
||||
categorie: Categorie;
|
||||
difficulte: Difficulte;
|
||||
photo: Photo;
|
||||
/** Modes photo (monument/lieu/defi). Absent en mode street. */
|
||||
photo?: Photo;
|
||||
/** Mode street : identifiant d'image Mapillary à charger dans la visionneuse. */
|
||||
mapillaryId?: string;
|
||||
/** Crédit affiché au résultat en mode street (« © auteur / Mapillary (CC BY-SA 4.0) »). */
|
||||
credit?: string;
|
||||
indices: Indice[];
|
||||
}
|
||||
|
||||
@@ -95,4 +121,4 @@ export interface WikiSummary {
|
||||
thumbnail: string | null;
|
||||
}
|
||||
|
||||
export type GameMode = 'monument' | 'lieu' | 'defi';
|
||||
export type GameMode = 'monument' | 'lieu' | 'defi' | 'street';
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
const modes: { id: GameMode; emoji: string }[] = [
|
||||
{ id: 'monument', emoji: '🏛️' },
|
||||
{ id: 'lieu', emoji: '📍' },
|
||||
{ id: 'defi', emoji: '⛰️' }
|
||||
{ id: 'defi', emoji: '⛰️' },
|
||||
{ id: 'street', emoji: '🛣️' }
|
||||
];
|
||||
|
||||
function jouer(): void {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { getLieuById, sanitizeRound } from '$lib/server/lieux';
|
||||
import { getLieuPhotoById, sanitizeRound } from '$lib/server/lieux';
|
||||
import { idsPourSeed, seedValide } from '$lib/server/tirage';
|
||||
import type { RequestHandler } from './$types';
|
||||
|
||||
@@ -17,7 +17,7 @@ export const GET: RequestHandler = ({ params }) => {
|
||||
);
|
||||
}
|
||||
const rounds = idsPourSeed(params.seed).map((id) => {
|
||||
const lieu = getLieuById(id);
|
||||
const lieu = getLieuPhotoById(id);
|
||||
if (!lieu) throw new Error(`Tirage incohérent : id inconnu (${id})`);
|
||||
return sanitizeRound(lieu);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import sharp from 'sharp';
|
||||
import { getLieuById, PHOTO_LARGEURS } from '$lib/server/lieux';
|
||||
import { getLieuPhotoById, PHOTO_LARGEURS } from '$lib/server/lieux';
|
||||
import type { RequestHandler } from './$types';
|
||||
|
||||
const USER_AGENT = 'JWE-OKI/2.0 (https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/JWE; contact OKI)';
|
||||
@@ -22,7 +22,7 @@ const enVol = new Map<string, Promise<Buffer | null>>();
|
||||
* - conversion WebP + redimensionnement à la largeur demandée.
|
||||
*/
|
||||
async function chargerPhoto(id: string, w: Largeur): Promise<Buffer | null> {
|
||||
const lieu = getLieuById(id);
|
||||
const lieu = getLieuPhotoById(id);
|
||||
if (!lieu) return null;
|
||||
const res = await fetch(lieu.photo.url, { headers: { 'User-Agent': USER_AGENT } });
|
||||
if (!res.ok) throw new Error(`commons ${res.status}`);
|
||||
@@ -59,7 +59,7 @@ export const GET: RequestHandler = async ({ params, url }) => {
|
||||
}
|
||||
|
||||
// 404 immédiat si l'id est inconnu (avant tout fetch amont).
|
||||
if (!getLieuById(id)) {
|
||||
if (!getLieuPhotoById(id)) {
|
||||
return new Response('Lieu inconnu', { status: 404 });
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,25 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { getRandomLieu, sanitizeRound } from '$lib/server/lieux';
|
||||
import { getRandomLieu, getRandomStreet, sanitizeRound, sanitizeRoundStreet } from '$lib/server/lieux';
|
||||
import type { RequestHandler } from './$types';
|
||||
|
||||
/** GET /api/round?region=&categorie=&exclude=id1,id2 → lieu aléatoire SANITISÉ. */
|
||||
/**
|
||||
* GET /api/round?region=&categorie=&exclude=id1,id2 → lieu aléatoire SANITISÉ.
|
||||
* Avec `mode=street` : pioche dans le corpus Mapillary (catégorie ignorée,
|
||||
* réponse avec `mapillaryId` au lieu de `photo`).
|
||||
*/
|
||||
export const GET: RequestHandler = ({ url }) => {
|
||||
if (url.searchParams.get('mode') === 'street') {
|
||||
const lieu = getRandomStreet({
|
||||
region: url.searchParams.get('region'),
|
||||
exclude: url.searchParams.get('exclude')
|
||||
});
|
||||
if (!lieu) {
|
||||
return json({ erreur: 'Aucun lieu street disponible pour ces critères' }, { status: 404 });
|
||||
}
|
||||
return json(sanitizeRoundStreet(lieu), {
|
||||
headers: { 'Cache-Control': 'no-store' }
|
||||
});
|
||||
}
|
||||
const lieu = getRandomLieu({
|
||||
region: url.searchParams.get('region'),
|
||||
categorie: url.searchParams.get('categorie'),
|
||||
|
||||
@@ -252,12 +252,12 @@
|
||||
<div class="resultat-scroll">
|
||||
<ResultPanel
|
||||
{result}
|
||||
creditPhoto={place.photo.credit}
|
||||
creditPhoto={place.photo?.credit}
|
||||
labelBouton={defiTermine ? t().resultat.voirBilan : t().resultat.suivant}
|
||||
onsuivant={defiTermine ? montrerBilan : suivant}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
{:else if place.photo}
|
||||
<PhotoPanel photo={place.photo} />
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import GameMap from '$lib/components/GameMap.svelte';
|
||||
import CarteRegions, { type MarqueurCarte } from '$lib/components/CarteRegions.svelte';
|
||||
import PhotoPanel from '$lib/components/PhotoPanel.svelte';
|
||||
import StreetPanel from '$lib/components/StreetPanel.svelte';
|
||||
import ResultPanel from '$lib/components/ResultPanel.svelte';
|
||||
import TimerRing from '$lib/components/TimerRing.svelte';
|
||||
import { t } from '$lib/i18n/store.svelte';
|
||||
@@ -62,6 +63,7 @@
|
||||
if (regionParam) params.set('region', regionParam);
|
||||
if (mode === 'monument') params.set('categorie', 'MONUMENT');
|
||||
if (mode === 'lieu') params.set('categorie', 'LIEU');
|
||||
if (mode === 'street') params.set('mode', 'street');
|
||||
if (joues.length > 0) params.set('exclude', joues.join(','));
|
||||
const res = await fetch(`/api/round?${params}`);
|
||||
if (!res.ok) throw new Error(String(res.status));
|
||||
@@ -246,12 +248,14 @@
|
||||
<div class="resultat-scroll">
|
||||
<ResultPanel
|
||||
{result}
|
||||
creditPhoto={place.photo.credit}
|
||||
creditPhoto={place.photo?.credit ?? place.credit}
|
||||
labelBouton={estDefi && defiTermine ? t().resultat.voirBilan : t().resultat.suivant}
|
||||
onsuivant={estDefi && defiTermine ? montrerBilan : suivant}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
{:else if place.mapillaryId}
|
||||
<StreetPanel mapillaryId={place.mapillaryId} credit={place.credit} />
|
||||
{:else if place.photo}
|
||||
<PhotoPanel photo={place.photo} />
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { error } from '@sveltejs/kit';
|
||||
import type { GameMode } from '$lib/types';
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
const MODES: GameMode[] = ['monument', 'lieu', 'defi'];
|
||||
const MODES: GameMode[] = ['monument', 'lieu', 'defi', 'street'];
|
||||
|
||||
export const load: PageLoad = ({ params }) => {
|
||||
if (!MODES.includes(params.mode as GameMode)) {
|
||||
|
||||
Reference in New Issue
Block a user