fix(sf-fe): poi-score TypeError + drawer non-overlay + CSS design tokens (#353)
All checks were successful
Deploy / build-frontend (push) Successful in 4m18s
Deploy / deploy (push) Successful in 49s
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped

This commit is contained in:
lekss361 2026-05-18 00:04:30 +00:00
parent 9ffeee7ed2
commit da8847c0e2
6 changed files with 1094 additions and 357 deletions

View file

@ -738,6 +738,17 @@
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.11",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
"integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
@ -3239,6 +3250,28 @@
"@types/node": "*"
}
},
"node_modules/@types/eslint": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
"integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/estree": "*",
"@types/json-schema": "*"
}
},
"node_modules/@types/eslint-scope": {
"version": "3.7.7",
"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
"integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/eslint": "*",
"@types/estree": "*"
}
},
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@ -3256,7 +3289,6 @@
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/leaflet": {
@ -3837,6 +3869,181 @@
"typescript": ">=4.8.4"
}
},
"node_modules/@webassemblyjs/ast": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
"integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/helper-numbers": "1.13.2",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2"
}
},
"node_modules/@webassemblyjs/floating-point-hex-parser": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
"integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
"license": "MIT",
"peer": true
},
"node_modules/@webassemblyjs/helper-api-error": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
"integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
"license": "MIT",
"peer": true
},
"node_modules/@webassemblyjs/helper-buffer": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
"integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
"license": "MIT",
"peer": true
},
"node_modules/@webassemblyjs/helper-numbers": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz",
"integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/floating-point-hex-parser": "1.13.2",
"@webassemblyjs/helper-api-error": "1.13.2",
"@xtuc/long": "4.2.2"
}
},
"node_modules/@webassemblyjs/helper-wasm-bytecode": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
"integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
"license": "MIT",
"peer": true
},
"node_modules/@webassemblyjs/helper-wasm-section": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz",
"integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
"@webassemblyjs/wasm-gen": "1.14.1"
}
},
"node_modules/@webassemblyjs/ieee754": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz",
"integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@xtuc/ieee754": "^1.2.0"
}
},
"node_modules/@webassemblyjs/leb128": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz",
"integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@xtuc/long": "4.2.2"
}
},
"node_modules/@webassemblyjs/utf8": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
"integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
"license": "MIT",
"peer": true
},
"node_modules/@webassemblyjs/wasm-edit": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz",
"integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
"@webassemblyjs/helper-wasm-section": "1.14.1",
"@webassemblyjs/wasm-gen": "1.14.1",
"@webassemblyjs/wasm-opt": "1.14.1",
"@webassemblyjs/wasm-parser": "1.14.1",
"@webassemblyjs/wast-printer": "1.14.1"
}
},
"node_modules/@webassemblyjs/wasm-gen": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz",
"integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
"@webassemblyjs/ieee754": "1.13.2",
"@webassemblyjs/leb128": "1.13.2",
"@webassemblyjs/utf8": "1.13.2"
}
},
"node_modules/@webassemblyjs/wasm-opt": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz",
"integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
"@webassemblyjs/wasm-gen": "1.14.1",
"@webassemblyjs/wasm-parser": "1.14.1"
}
},
"node_modules/@webassemblyjs/wasm-parser": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz",
"integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-api-error": "1.13.2",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
"@webassemblyjs/ieee754": "1.13.2",
"@webassemblyjs/leb128": "1.13.2",
"@webassemblyjs/utf8": "1.13.2"
}
},
"node_modules/@webassemblyjs/wast-printer": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz",
"integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@xtuc/long": "4.2.2"
}
},
"node_modules/@xtuc/ieee754": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
"integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
"license": "BSD-3-Clause",
"peer": true
},
"node_modules/@xtuc/long": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
"license": "Apache-2.0",
"peer": true
},
"node_modules/acorn": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
@ -3858,6 +4065,19 @@
"acorn": "^8"
}
},
"node_modules/acorn-import-phases": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz",
"integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10.13.0"
},
"peerDependencies": {
"acorn": "^8.14.0"
}
},
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@ -3887,6 +4107,41 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ajv-formats": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"license": "MIT",
"peer": true,
"dependencies": {
"ajv": "^8.0.0"
},
"peerDependencies": {
"ajv": "^8.0.0"
},
"peerDependenciesMeta": {
"ajv": {
"optional": true
}
}
},
"node_modules/ajv-formats/node_modules/ajv": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ajv/node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@ -3997,6 +4252,13 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"license": "MIT",
"peer": true
},
"node_modules/caniuse-lite": {
"version": "1.0.30001790",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001790.tgz",
@ -4090,12 +4352,29 @@
"dev": true,
"license": "MIT"
},
"node_modules/chrome-trace-event": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
"integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.0"
}
},
"node_modules/cjs-module-lexer": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz",
"integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==",
"license": "MIT"
},
"node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"license": "MIT",
"peer": true
},
"node_modules/commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@ -4238,7 +4517,6 @@
"version": "5.21.3",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.3.tgz",
"integrity": "sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.4",
@ -4248,6 +4526,13 @@
"node": ">=10.13.0"
}
},
"node_modules/es-module-lexer": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz",
"integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==",
"license": "MIT",
"peer": true
},
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@ -12206,7 +12491,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"estraverse": "^5.2.0"
@ -12219,12 +12503,21 @@
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=4.0"
}
},
"node_modules/estraverse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"license": "BSD-2-Clause",
"peer": true,
"engines": {
"node": ">=4.0"
}
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
@ -12241,12 +12534,39 @@
"node": ">=0.10.0"
}
},
"node_modules/events": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"license": "MIT"
},
"node_modules/fast-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz",
"integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "BSD-3-Clause",
"peer": true
},
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
@ -12456,6 +12776,13 @@
"node": ">=10.13.0"
}
},
"node_modules/glob-to-regexp": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
"license": "BSD-2-Clause",
"peer": true
},
"node_modules/glob/node_modules/minimatch": {
"version": "10.2.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
@ -12475,14 +12802,12 @@
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true,
"license": "ISC"
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@ -12574,6 +12899,21 @@
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"license": "ISC"
},
"node_modules/jest-worker": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/node": "*",
"merge-stream": "^2.0.0",
"supports-color": "^8.0.0"
},
"engines": {
"node": ">= 10.13.0"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -12596,7 +12936,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true,
"license": "MIT"
},
"node_modules/json-stable-stringify-without-jsonify": {
@ -12630,6 +12969,20 @@
"integrity": "sha512-rsQ6saQO5ST5Aj6XRFylr5zvarWgzWnrg46zQ1MEOEIHsppdC/8hnN8qMoFvACsPvTioAuysya/TVtog15tyAQ==",
"license": "MIT"
},
"node_modules/loader-runner": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz",
"integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.11.5"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@ -12664,6 +13017,23 @@
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"license": "MIT",
"peer": true
},
"node_modules/mime-db": {
"version": "1.54.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
@ -12724,6 +13094,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/neo-async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"license": "MIT",
"peer": true
},
"node_modules/next": {
"version": "15.5.15",
"resolved": "https://registry.npmjs.org/next/-/next-15.5.15.tgz",
@ -13239,7 +13616,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@ -13308,6 +13684,56 @@
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
"license": "MIT"
},
"node_modules/schema-utils": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz",
"integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/json-schema": "^7.0.9",
"ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
"ajv-keywords": "^5.1.0"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/schema-utils/node_modules/ajv": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/schema-utils/node_modules/ajv-keywords": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3"
},
"peerDependencies": {
"ajv": "^8.8.2"
}
},
"node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
@ -13867,6 +14293,27 @@
"integrity": "sha512-+k9mJ2/rQMiRmQUcjn+qznch260leIXY8r4FyYKKyRBO/s5UoeMAHGkCJyE1R/4wrIhTJONfyloY55SkE7ve3A==",
"license": "ISC"
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"license": "BSD-3-Clause",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"license": "MIT",
"peer": true,
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/stacktrace-parser": {
"version": "0.1.11",
"resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz",
@ -13908,6 +14355,22 @@
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT"
},
"node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"license": "MIT",
"peer": true,
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/tailwindcss": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.4.tgz",
@ -13919,7 +14382,6 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
"integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@ -13929,6 +14391,86 @@
"url": "https://opencollective.com/webpack"
}
},
"node_modules/terser": {
"version": "5.47.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.47.1.tgz",
"integrity": "sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==",
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.15.0",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
"bin": {
"terser": "bin/terser"
},
"engines": {
"node": ">=10"
}
},
"node_modules/terser-webpack-plugin": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.0.tgz",
"integrity": "sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.25",
"jest-worker": "^27.4.5",
"schema-utils": "^4.3.0",
"terser": "^5.31.1"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"webpack": "^5.1.0"
},
"peerDependenciesMeta": {
"@minify-html/node": {
"optional": true
},
"@swc/core": {
"optional": true
},
"@swc/css": {
"optional": true
},
"@swc/html": {
"optional": true
},
"clean-css": {
"optional": true
},
"cssnano": {
"optional": true
},
"csso": {
"optional": true
},
"esbuild": {
"optional": true
},
"html-minifier-terser": {
"optional": true
},
"lightningcss": {
"optional": true
},
"postcss": {
"optional": true
},
"uglify-js": {
"optional": true
}
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@ -14000,12 +14542,98 @@
"browserslist": ">= 4.21.0"
}
},
"node_modules/watchpack": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz",
"integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==",
"license": "MIT",
"peer": true,
"dependencies": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"license": "BSD-2-Clause"
},
"node_modules/webpack": {
"version": "5.106.2",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.106.2.tgz",
"integrity": "sha512-wGN3qcrBQIFmQ/c0AiOAQBvrZ5lmY8vbbMv4Mxfgzqd/B6+9pXtLo73WuS1dSGXM5QYY3hZnIbvx+K1xxe6FyA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.8",
"@types/json-schema": "^7.0.15",
"@webassemblyjs/ast": "^1.14.1",
"@webassemblyjs/wasm-edit": "^1.14.1",
"@webassemblyjs/wasm-parser": "^1.14.1",
"acorn": "^8.16.0",
"acorn-import-phases": "^1.0.3",
"browserslist": "^4.28.1",
"chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^5.20.0",
"es-module-lexer": "^2.0.0",
"eslint-scope": "5.1.1",
"events": "^3.2.0",
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.2.11",
"loader-runner": "^4.3.1",
"mime-db": "^1.54.0",
"neo-async": "^2.6.2",
"schema-utils": "^4.3.3",
"tapable": "^2.3.0",
"terser-webpack-plugin": "^5.3.17",
"watchpack": "^2.5.1",
"webpack-sources": "^3.3.4"
},
"bin": {
"webpack": "bin/webpack.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependenciesMeta": {
"webpack-cli": {
"optional": true
}
}
},
"node_modules/webpack-sources": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.4.1.tgz",
"integrity": "sha512-eACpxRN02yaawnt+uUNIF7Qje6A9zArxBbcAJjK1PK3S9Ycg5jIuJ8pW4q8EMnwNZCEGltcjkRx1QzOxOkKD8A==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/webpack/node_modules/eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^4.1.1"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",

View file

@ -0,0 +1,90 @@
/*
* GenDesign global CSS design tokens (UI Brief May 17)
* All CSS vars used across site-finder and analytics components.
* Spacing scale: 4/8/12/16/24/32px only.
* Tabular-nums applied globally for numeric readability.
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
:root {
/* ── Surface ─────────────────────────────────────────────────────────── */
--bg-app: #f6f7f9;
--bg-card: #ffffff;
--bg-card-alt: #fafbfc;
--bg-headline: #0f172a; /* slate-900 — dark verdict bar */
/* ── Borders ─────────────────────────────────────────────────────────── */
--border-soft: #eef0f3;
--border-card: #e6e8ec;
--border-strong: #d1d5db;
/* ── Text ────────────────────────────────────────────────────────────── */
--fg-primary: #111111;
--fg-secondary: #5b6066;
--fg-tertiary: #73767e;
--fg-on-dark: #e2e8f0; /* text on --bg-headline */
--fg-on-dark-muted: #94a3b8; /* caveat text on dark */
/* ── Brand / CTA ─────────────────────────────────────────────────────── */
--accent: #1d4ed8; /* primary blue CTA */
--accent-hover: #1e40af;
--accent-soft: #dbeafe; /* badge bg, active tab bg */
--accent-2: #f2994a; /* secondary orange CTA (Export, Share) */
/* ── Semantic ────────────────────────────────────────────────────────── */
--success: #0a7a3a;
--success-soft: #dcfce7;
--warn: #9a6700;
--warn-soft: #fef3c7;
--danger: #b3261e;
--danger-soft: #fee2e2;
/* ── Data-viz (use in order, no skip) ───────────────────────────────── */
--viz-1: #1d4ed8;
--viz-2: #0ea5e9;
--viz-3: #14b8a6;
--viz-4: #f59e0b;
--viz-5: #8b5cf6;
--prediction-line: #0ea5e9;
--prediction-band: rgba(14, 165, 233, 0.18);
}
html,
body {
margin: 0;
padding: 0;
background: var(--bg-app);
color: var(--fg-primary);
font-family:
Inter,
-apple-system,
"Segoe UI",
system-ui,
sans-serif;
font-size: 14px;
line-height: 1.5;
/* Tabular nums globally for numeric legibility (Bloomberg lesson) */
font-variant-numeric: tabular-nums;
font-feature-settings: "tnum";
-webkit-font-smoothing: antialiased;
}
/* Focus-visible ring — accessible, not outline:none */
:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
/* Remove default outline for mouse users */
:focus:not(:focus-visible) {
outline: none;
}
a {
color: inherit;
}

View file

@ -1,5 +1,6 @@
import type { Metadata } from "next";
import "./globals.css";
import { Providers } from "./providers";
export const metadata: Metadata = {
@ -14,13 +15,7 @@ export default function RootLayout({
}) {
return (
<html lang="ru">
<body
style={{
margin: 0,
fontFamily:
"system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif",
}}
>
<body>
<Providers>{children}</Providers>
</body>
</html>

View file

@ -148,7 +148,7 @@ export default function SiteFinderPage() {
minHeight: 0,
}}
>
{/* Map area */}
{/* Map area — position: relative so ParcelDrawer can anchor absolutely here */}
<div
style={{
flex: 1,
@ -156,6 +156,7 @@ export default function SiteFinderPage() {
display: "flex",
flexDirection: "column",
minHeight: 0,
position: "relative",
}}
>
<EntryMap
@ -165,30 +166,31 @@ export default function SiteFinderPage() {
onParcelDeselect={handleParcelDeselect}
onBboxChange={setBbox}
/>
{/* ParcelDrawer — anchored to map area right edge, not page */}
<ParcelDrawer
parcel={selectedParcel}
onClose={handleParcelDeselect}
/>
</div>
{/* Right sidebar — hidden when ParcelDrawer is open to avoid overlap */}
{selectedParcel == null && (
<div
style={{
width: 300,
flexShrink: 0,
padding: "16px 16px 16px 0",
display: "flex",
flexDirection: "column",
gap: 12,
overflowY: "auto",
}}
>
<CadInput onSubmit={handleCadSubmit} loading={false} />
<RecentParcels />
<ParcelLegend />
</div>
)}
{/* Right sidebar — always visible; CadInput accessible parallel with drawer */}
<div
style={{
width: 300,
flexShrink: 0,
padding: "16px 16px 16px 0",
display: "flex",
flexDirection: "column",
gap: 12,
overflowY: "auto",
}}
>
<CadInput onSubmit={handleCadSubmit} loading={false} />
<RecentParcels />
<ParcelLegend />
</div>
</div>
{/* Parcel drawer (slide-in from right) */}
<ParcelDrawer parcel={selectedParcel} onClose={handleParcelDeselect} />
</main>
);
}

View file

@ -25,350 +25,340 @@ export function ParcelDrawer({ parcel, onClose }: ParcelDrawerProps) {
const statusLabel = STATUS_LABELS[parcel.status] ?? parcel.status;
return (
<>
{/* Backdrop */}
// Drawer panel — absolute within the map container (parent has position:relative).
// This keeps the sidebar (CadInput/RecentParcels/ParcelLegend) always visible
// and only overlaps the map area on parcel select.
<aside
style={{
position: "absolute",
top: 16,
right: 16,
bottom: 16,
width: 360,
zIndex: 20,
background: "var(--bg-card)",
borderLeft: "1px solid var(--border-card)",
border: "1px solid var(--border-card)",
borderRadius: 12,
display: "flex",
flexDirection: "column",
boxShadow: "-4px 0 24px rgba(0,0,0,0.10)",
}}
role="dialog"
aria-label="Карточка участка"
>
{/* Header */}
<div
onClick={onClose}
style={{
position: "fixed",
inset: 0,
zIndex: 40,
background: "transparent",
}}
aria-hidden="true"
/>
{/* Drawer panel */}
<aside
style={{
position: "fixed",
top: 0,
right: 0,
bottom: 0,
width: 360,
zIndex: 50,
background: "var(--bg-card)",
borderLeft: "1px solid var(--border-card)",
padding: "16px 20px 12px",
borderBottom: "1px solid var(--border-soft)",
display: "flex",
flexDirection: "column",
boxShadow: "-4px 0 24px rgba(0,0,0,0.08)",
alignItems: "flex-start",
gap: 8,
}}
role="dialog"
aria-label="Карточка участка"
>
{/* Header */}
<div
<MapPin
size={16}
strokeWidth={1.5}
style={{
padding: "16px 20px 12px",
borderBottom: "1px solid var(--border-soft)",
display: "flex",
alignItems: "flex-start",
gap: 8,
color: "var(--fg-secondary)",
marginTop: 2,
flexShrink: 0,
}}
>
<MapPin
size={16}
strokeWidth={1.5}
/>
<div style={{ flex: 1, minWidth: 0 }}>
<div
style={{
fontSize: 11,
fontWeight: 500,
textTransform: "uppercase",
letterSpacing: "0.04em",
color: "var(--fg-tertiary)",
fontVariantNumeric: "tabular-nums",
}}
>
{parcel.cad_num}
</div>
<div
style={{
fontSize: 13,
color: "var(--fg-secondary)",
marginTop: 2,
flexShrink: 0,
}}
/>
<div style={{ flex: 1, minWidth: 0 }}>
<div
style={{
fontSize: 11,
fontWeight: 500,
textTransform: "uppercase",
letterSpacing: "0.04em",
color: "var(--fg-tertiary)",
fontVariantNumeric: "tabular-nums",
}}
>
{parcel.cad_num}
</div>
<div
style={{
fontSize: 13,
color: "var(--fg-secondary)",
marginTop: 2,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
}}
>
{parcel.address}
</div>
</div>
<button
onClick={onClose}
aria-label="Закрыть"
style={{
background: "none",
border: "none",
cursor: "pointer",
padding: 4,
color: "var(--fg-tertiary)",
flexShrink: 0,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
}}
>
<X size={18} strokeWidth={1.5} />
</button>
</div>
{/* KPI grid */}
<div
style={{
padding: "16px 20px",
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: 12,
}}
>
{/* Status */}
<div
style={{
background: "var(--bg-card-alt)",
border: "1px solid var(--border-card)",
borderRadius: 8,
padding: "10px 12px",
}}
>
<div
style={{
fontSize: 11,
fontWeight: 500,
textTransform: "uppercase",
letterSpacing: "0.04em",
color: "var(--fg-secondary)",
marginBottom: 4,
}}
>
Статус
</div>
<div
style={{
display: "flex",
alignItems: "center",
gap: 6,
}}
>
<span
style={{
width: 8,
height: 8,
borderRadius: "50%",
background: statusColor,
flexShrink: 0,
}}
/>
<span
style={{
fontSize: 13,
fontWeight: 500,
color: "var(--fg-primary)",
}}
>
{statusLabel}
</span>
</div>
</div>
{/* Area */}
<div
style={{
background: "var(--bg-card-alt)",
border: "1px solid var(--border-card)",
borderRadius: 8,
padding: "10px 12px",
}}
>
<div
style={{
fontSize: 11,
fontWeight: 500,
textTransform: "uppercase",
letterSpacing: "0.04em",
color: "var(--fg-secondary)",
marginBottom: 4,
}}
>
Площадь
</div>
<div
style={{
fontSize: 18,
fontWeight: 600,
color: "var(--fg-primary)",
fontVariantNumeric: "tabular-nums",
}}
>
{parcel.area_ha.toFixed(2)}{" "}
<span
style={{
fontSize: 13,
fontWeight: 400,
color: "var(--fg-secondary)",
}}
>
га
</span>
</div>
</div>
{/* District */}
<div
style={{
background: "var(--bg-card-alt)",
border: "1px solid var(--border-card)",
borderRadius: 8,
padding: "10px 12px",
}}
>
<div
style={{
fontSize: 11,
fontWeight: 500,
textTransform: "uppercase",
letterSpacing: "0.04em",
color: "var(--fg-secondary)",
marginBottom: 4,
}}
>
Район
</div>
<div
style={{
fontSize: 13,
fontWeight: 500,
color: "var(--fg-primary)",
}}
>
{parcel.district}
</div>
</div>
{/* VRI */}
<div
style={{
background: "var(--bg-card-alt)",
border: "1px solid var(--border-card)",
borderRadius: 8,
padding: "10px 12px",
}}
>
<div
style={{
fontSize: 11,
fontWeight: 500,
textTransform: "uppercase",
letterSpacing: "0.04em",
color: "var(--fg-secondary)",
marginBottom: 4,
}}
>
ВРИ
</div>
<div
style={{
fontSize: 13,
fontWeight: 500,
color: "var(--fg-primary)",
}}
>
{VRI_LABELS[parcel.vri] ?? parcel.vri}
</div>
</div>
{/* Coords */}
<div
style={{
background: "var(--bg-card-alt)",
border: "1px solid var(--border-card)",
borderRadius: 8,
padding: "10px 12px",
gridColumn: "1 / -1",
}}
>
<div
style={{
fontSize: 11,
fontWeight: 500,
textTransform: "uppercase",
letterSpacing: "0.04em",
color: "var(--fg-secondary)",
marginBottom: 4,
}}
>
Координаты
</div>
<div
style={{
fontSize: 12,
color: "var(--fg-secondary)",
fontVariantNumeric: "tabular-nums",
}}
>
{parcel.lat.toFixed(5)}, {parcel.lon.toFixed(5)}
</div>
{parcel.address}
</div>
</div>
{/* Spacer */}
<div style={{ flex: 1 }} />
{/* CTA */}
<div
<button
onClick={onClose}
aria-label="Закрыть"
style={{
padding: "16px 20px",
borderTop: "1px solid var(--border-soft)",
display: "flex",
flexDirection: "column",
gap: 8,
background: "none",
border: "none",
cursor: "pointer",
padding: 4,
color: "var(--fg-tertiary)",
flexShrink: 0,
}}
>
<Link
href={`/site-finder/analysis/${encodeURIComponent(parcel.cad_num)}`}
<X size={18} strokeWidth={1.5} />
</button>
</div>
{/* KPI grid */}
<div
style={{
padding: "16px 20px",
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: 12,
}}
>
{/* Status */}
<div
style={{
background: "var(--bg-card-alt)",
border: "1px solid var(--border-card)",
borderRadius: 8,
padding: "10px 12px",
}}
>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
gap: 8,
background: "var(--accent)",
color: "#fff",
borderRadius: 8,
padding: "10px 20px",
fontSize: 14,
fontSize: 11,
fontWeight: 500,
textDecoration: "none",
textTransform: "uppercase",
letterSpacing: "0.04em",
color: "var(--fg-secondary)",
marginBottom: 4,
}}
>
Открыть анализ
<ArrowRight size={16} strokeWidth={1.5} />
</Link>
<a
href={`https://pkk.rosreestr.ru/#/search/cadastralNumber/${encodeURIComponent(parcel.cad_num)}`}
target="_blank"
rel="noopener noreferrer"
Статус
</div>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
gap: 8,
background: "none",
color: "var(--fg-secondary)",
borderRadius: 8,
padding: "8px 20px",
fontSize: 13,
textDecoration: "none",
gap: 6,
}}
>
<Maximize2 size={14} strokeWidth={1.5} />
ПКК Росреестр
</a>
<span
style={{
width: 8,
height: 8,
borderRadius: "50%",
background: statusColor,
flexShrink: 0,
}}
/>
<span
style={{
fontSize: 13,
fontWeight: 500,
color: "var(--fg-primary)",
}}
>
{statusLabel}
</span>
</div>
</div>
</aside>
</>
{/* Area */}
<div
style={{
background: "var(--bg-card-alt)",
border: "1px solid var(--border-card)",
borderRadius: 8,
padding: "10px 12px",
}}
>
<div
style={{
fontSize: 11,
fontWeight: 500,
textTransform: "uppercase",
letterSpacing: "0.04em",
color: "var(--fg-secondary)",
marginBottom: 4,
}}
>
Площадь
</div>
<div
style={{
fontSize: 18,
fontWeight: 600,
color: "var(--fg-primary)",
fontVariantNumeric: "tabular-nums",
}}
>
{parcel.area_ha.toFixed(2)}{" "}
<span
style={{
fontSize: 13,
fontWeight: 400,
color: "var(--fg-secondary)",
}}
>
га
</span>
</div>
</div>
{/* District */}
<div
style={{
background: "var(--bg-card-alt)",
border: "1px solid var(--border-card)",
borderRadius: 8,
padding: "10px 12px",
}}
>
<div
style={{
fontSize: 11,
fontWeight: 500,
textTransform: "uppercase",
letterSpacing: "0.04em",
color: "var(--fg-secondary)",
marginBottom: 4,
}}
>
Район
</div>
<div
style={{
fontSize: 13,
fontWeight: 500,
color: "var(--fg-primary)",
}}
>
{parcel.district}
</div>
</div>
{/* VRI */}
<div
style={{
background: "var(--bg-card-alt)",
border: "1px solid var(--border-card)",
borderRadius: 8,
padding: "10px 12px",
}}
>
<div
style={{
fontSize: 11,
fontWeight: 500,
textTransform: "uppercase",
letterSpacing: "0.04em",
color: "var(--fg-secondary)",
marginBottom: 4,
}}
>
ВРИ
</div>
<div
style={{
fontSize: 13,
fontWeight: 500,
color: "var(--fg-primary)",
}}
>
{VRI_LABELS[parcel.vri] ?? parcel.vri}
</div>
</div>
{/* Coords */}
<div
style={{
background: "var(--bg-card-alt)",
border: "1px solid var(--border-card)",
borderRadius: 8,
padding: "10px 12px",
gridColumn: "1 / -1",
}}
>
<div
style={{
fontSize: 11,
fontWeight: 500,
textTransform: "uppercase",
letterSpacing: "0.04em",
color: "var(--fg-secondary)",
marginBottom: 4,
}}
>
Координаты
</div>
<div
style={{
fontSize: 12,
color: "var(--fg-secondary)",
fontVariantNumeric: "tabular-nums",
}}
>
{parcel.lat.toFixed(5)}, {parcel.lon.toFixed(5)}
</div>
</div>
</div>
{/* Spacer */}
<div style={{ flex: 1 }} />
{/* CTA */}
<div
style={{
padding: "16px 20px",
borderTop: "1px solid var(--border-soft)",
display: "flex",
flexDirection: "column",
gap: 8,
}}
>
<Link
href={`/site-finder/analysis/${encodeURIComponent(parcel.cad_num)}`}
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
gap: 8,
background: "var(--accent)",
color: "#fff",
borderRadius: 8,
padding: "10px 20px",
fontSize: 14,
fontWeight: 500,
textDecoration: "none",
}}
>
Открыть анализ
<ArrowRight size={16} strokeWidth={1.5} />
</Link>
<a
href={`https://pkk.rosreestr.ru/#/search/cadastralNumber/${encodeURIComponent(parcel.cad_num)}`}
target="_blank"
rel="noopener noreferrer"
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
gap: 8,
background: "none",
color: "var(--fg-secondary)",
borderRadius: 8,
padding: "8px 20px",
fontSize: 13,
textDecoration: "none",
}}
>
<Maximize2 size={14} strokeWidth={1.5} />
ПКК Росреестр
</a>
</div>
</aside>
);
}

View file

@ -319,6 +319,23 @@ export function useParcelAnalyzeQuery(cad: string) {
// ── Hook: useParcelPoiScoreQuery (B6) ────────────────────────────────────────
/**
* Raw shape from backend /api/v1/parcels/{cad}/poi-score.
* Backend returns top_poi array with address field (not score_contribution).
* We adapt to PoiScoreResponse so downstream components are stable.
*/
interface PoiScoreRaw {
cad_num: string;
radius_m: number;
top_poi: Array<{
name: string;
category: string;
distance_m: number;
weight: number;
address?: string | null;
}>;
}
export function useParcelPoiScoreQuery(cad: string) {
return useQuery({
queryKey: ["parcel-poi-score", cad],
@ -326,9 +343,24 @@ export function useParcelPoiScoreQuery(cad: string) {
if (MOCK_POI_SCORE) {
return fixturePoiScore as PoiScoreResponse;
}
return apiFetch<PoiScoreResponse>(
// Backend returns {cad_num, radius_m, top_poi: [{name,category,distance_m,weight,address}]}
// Adapt to PoiScoreResponse {cad_num, poi_weighted_score, items} for stable consumer API.
const raw = await apiFetch<PoiScoreRaw>(
`/api/v1/parcels/${encodeURIComponent(cad)}/poi-score`,
);
const items: PoiScoreItem[] = (raw.top_poi ?? []).map((p) => ({
category: p.category,
name: p.name,
distance_m: p.distance_m,
weight: p.weight,
// score_contribution not in backend response — derive from weight (0..1) × 100
score_contribution: Math.round(p.weight * 100),
}));
const poi_weighted_score = items.reduce(
(s, p) => s + p.score_contribution,
0,
);
return { cad_num: raw.cad_num, poi_weighted_score, items };
},
staleTime: 5 * 60_000,
retry: 1,