From 88865bf6a7380fa964ca72f1ddc21f20598e2416 Mon Sep 17 00:00:00 2001 From: Light1YT Date: Sat, 20 Jun 2026 20:13:26 +0500 Subject: [PATCH] fix(ptica): drawer modal a11y (focus-trap + restore) + polish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PticaDrawer: proper modal focus management — - focus-trap: Tab/Shift+Tab wrap inside the dialog (focusables re-queried per Tab so it survives lazy panels/sub-tabs), focus-already-outside pulled back in; - focus-restore: the trigger element is captured on open and re-focused on close (guards null + detached node); - onClose held in a ref so the effect depends on [open] only — fixes focus thrashing when the host's URL/searchParams change mid-open. Esc/scrim close, body-scroll-lock, role=dialog/aria-modal preserved. Cleanups (code-review follow-ups): - MassingScene: drop duplicate initial mass build (floors/sections effect owns it); corrected the effect-ordering comment. - Static inline styles → CSS-module classes (scan/gauge/score/spaced rows). - DrawerPrimitives: remove !important on .dtabActive via specificity (.dtabs button.dtabActive). - Remove unused SoonCard component + its CSS. tsc/lint/prettier clean; next build green (route bundled). ptica-only, no any. --- .../analysis/[cad]/ptica/ptica.module.css | 51 ++++++------ .../site-finder/ptica/BuildabilityGauge.tsx | 5 +- .../site-finder/ptica/DevelopmentScan.tsx | 10 +-- .../site-finder/ptica/InvestScoreBlock.tsx | 2 +- .../ptica/drawers/DrawerPrimitives.tsx | 18 ----- .../site-finder/ptica/drawers/PticaDrawer.tsx | 78 ++++++++++++++++++- .../ptica/massing/MassingScene.tsx | 6 +- .../ptica/scenarios/HorizonForecast.tsx | 2 +- .../ptica/scenarios/RecommendedProduct.tsx | 2 +- 9 files changed, 111 insertions(+), 63 deletions(-) diff --git a/frontend/src/app/site-finder/analysis/[cad]/ptica/ptica.module.css b/frontend/src/app/site-finder/analysis/[cad]/ptica/ptica.module.css index 3c1c16f0..55a0413e 100644 --- a/frontend/src/app/site-finder/analysis/[cad]/ptica/ptica.module.css +++ b/frontend/src/app/site-finder/analysis/[cad]/ptica/ptica.module.css @@ -329,6 +329,11 @@ opacity: 0.45; cursor: not-allowed; } +/* «Подробнее» pinned to the bottom-left of a flex-column card (scan / score). */ +.detailBtnScan { + margin-top: auto; + align-self: flex-start; +} /* ===================== HERO GRID ===================== */ .hero { @@ -438,6 +443,11 @@ align-items: center; gap: 6px; } +/* compact, centred title above a radial gauge. */ +.cardTitleGauge { + font-size: 9.5px; + text-align: center; +} .scoreStack { display: flex; flex-direction: column; @@ -625,6 +635,13 @@ margin-top: auto; align-self: flex-start; } +/* Risks card centres its gauge; title stays left-aligned like the other cards. */ +.scanCardCentered { + align-items: center; +} +.scanCardCentered .cardTitle { + align-self: flex-start; +} .emptyState { display: grid; place-items: center; @@ -805,6 +822,10 @@ font-size: 11px; padding: 3px 0; } +/* sc-kvrow that sits below a table/segment block — adds top separation. */ +.scKvRowSpaced { + margin-top: 8px; +} .scK { color: var(--text-muted); } @@ -1575,29 +1596,6 @@ .drawerLink:hover { text-decoration: underline; } -.soonCard { - display: flex; - flex-direction: column; - align-items: center; - gap: 9px; - text-align: center; - padding: 22px 16px; - border-style: dashed; -} -.soonCard p { - margin: 0; - font-size: 11px; - line-height: 1.5; - color: var(--text-soft); - max-width: 320px; -} -.roadmap { - font-size: 9px; - text-transform: uppercase; - letter-spacing: 0.08em; - color: var(--text-soft); -} - /* ===================== 3D MASSING SANDBOX (Three.js) ===================== */ .massingWrap { display: flex; @@ -1784,9 +1782,10 @@ .dtabs button:hover { color: var(--text-muted); } -.dtabActive { - color: var(--text-strong) !important; - border-bottom-color: var(--accent-cyan) !important; +/* specific enough to beat `.dtabs button` without !important. */ +.dtabs button.dtabActive { + color: var(--text-strong); + border-bottom-color: var(--accent-cyan); } .dtabPanel { display: grid; diff --git a/frontend/src/components/site-finder/ptica/BuildabilityGauge.tsx b/frontend/src/components/site-finder/ptica/BuildabilityGauge.tsx index f08c4f67..1bf46eb2 100644 --- a/frontend/src/components/site-finder/ptica/BuildabilityGauge.tsx +++ b/frontend/src/components/site-finder/ptica/BuildabilityGauge.tsx @@ -41,10 +41,7 @@ export function BuildabilityGauge({ gauge, title }: Props) { return (
-
+
{title}
diff --git a/frontend/src/components/site-finder/ptica/DevelopmentScan.tsx b/frontend/src/components/site-finder/ptica/DevelopmentScan.tsx index f7b2f00a..a10b99a6 100644 --- a/frontend/src/components/site-finder/ptica/DevelopmentScan.tsx +++ b/frontend/src/components/site-finder/ptica/DevelopmentScan.tsx @@ -69,17 +69,13 @@ export function DevelopmentScan({ analysis, onOpenDrawer }: Props) {
-

- Риски -

+

Риски