gendesign/frontend/src/components/site-finder/GeotechRiskBlock.tsx
Light1YT f7773c71d4
All checks were successful
CI / openapi-codegen-check (pull_request) Successful in 1m46s
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 48s
fix(site-finder): P3 a11y/UI batch from audit #1871
- add <h1> page title to analysis page (иерархия стартовала с h2 — a11y)
- emoji → Lucide во всех вердикт/баннер/статус UI (ui-conventions: emoji
  запрещены): GateVerdictBanner (VerdictColor.icon string→ComponentType,
  sourceHint→ReactNode, SectionLabels), + найдены ещё 3 файла:
  OverviewTab (⚠ ЛЭП/трамвай), GeotechRiskBlock (🟡 вечная мерзлота → Snowflake,
  ⚠ загрязнение), HydrologyBlock (⚠ паводок, 🏞💦🪷🚣💧 subtype-map → Waves/Droplet).
  Все иконки декоративные → aria-hidden, семантика дублируется текстом.
  Семантические цвета через var(--success/--warn/--danger) + hex-fallback.
- расшифровка аббревиатур при первом упоминании (ui-microcopy):
  Section2 «строительство в охранной зоне (ОЗ)... зоне с особыми условиями
  использования территорий (ЗОУИТ), тип 5»; Section4 title-tooltip для ЗОУИТ.
- ForecastChart: axis-chrome hex (:65/67/68) задокументирован как canvas-renderer
  исключение (echarts canvas не резолвит CSS var() — var() сломал бы chrome,
  как и VIZ-series). Цвета не тронуты, только комментарий.

НЕ в scope: ForecastChart CI-band (±p25/p75 — backend не отдаёт, отдельная
задача); ★ в WeightProfilePanel <option> (SVG в option невозможен);
токенизация legacy-hex в Geotech/Hydrology (отдельный pass).

138 frontend vitest passed, tsc/lint clean. lucide-react уже в deps.

Refs #1871
2026-06-23 12:52:32 +05:00

142 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { AlertTriangle, Snowflake } from "lucide-react";
import type { GeotechRisk } from "@/types/site-finder";
interface Props {
risk: GeotechRisk;
}
function seismicBadgeStyle(balls: number): { bg: string; color: string } {
if (balls <= 5) return { bg: "#dcfce7", color: "#15803d" };
if (balls <= 7) return { bg: "#fef3c7", color: "#92400e" };
return { bg: "#fecaca", color: "#b91c1c" };
}
export function GeotechRiskBlock({ risk }: Props) {
return (
<div
style={{
borderRadius: 10,
padding: "14px 16px",
background: "#fafafa",
border: "1px solid #e5e7eb",
display: "flex",
flexDirection: "column",
gap: 10,
}}
>
<div style={{ fontSize: 13, fontWeight: 700, color: "#374151" }}>
Геотехнический риск
</div>
{/* Seismics */}
<div
style={{
display: "flex",
alignItems: "center",
gap: 8,
flexWrap: "wrap",
}}
>
{risk.seismic_intensity_balls !== null ? (
<>
<div
style={{
width: 36,
height: 36,
borderRadius: "50%",
display: "flex",
alignItems: "center",
justifyContent: "center",
fontSize: 14,
fontWeight: 800,
flexShrink: 0,
...seismicBadgeStyle(risk.seismic_intensity_balls),
}}
>
{risk.seismic_intensity_balls}
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 2 }}>
<div style={{ fontSize: 13, fontWeight: 600, color: "#374151" }}>
{risk.seismic_label}
</div>
{risk.seismic_description && (
<div style={{ fontSize: 11, color: "#6b7280" }}>
{risk.seismic_description}
</div>
)}
</div>
</>
) : (
<div
style={{
borderRadius: 8,
padding: "6px 12px",
background: "#f3f4f6",
fontSize: 13,
color: "#6b7280",
}}
>
{risk.seismic_label}
</div>
)}
</div>
{/* Permafrost */}
{risk.permafrost && (
<div
style={{
display: "flex",
alignItems: "center",
gap: 6,
fontSize: 13,
color: "#374151",
}}
>
<Snowflake
size={16}
strokeWidth={1.5}
aria-hidden
style={{ flexShrink: 0, color: "#92400e" }}
/>
<span>Вечная мерзлота особые фундаменты</span>
</div>
)}
{/* Industrial contamination */}
{risk.industrial_contamination_flag && (
<div
style={{
borderRadius: 8,
padding: "10px 14px",
background: "#fff7ed",
border: "1px solid #fdba74",
fontSize: 13,
fontWeight: 600,
color: "#c2410c",
display: "flex",
alignItems: "center",
gap: 6,
}}
>
<AlertTriangle
size={16}
strokeWidth={1.5}
aria-hidden
style={{ flexShrink: 0 }}
/>
<span>
{risk.industrial_within_500m} промзон(ы) в &lt;500м (риск
загрязнения почв)
</span>
</div>
)}
{/* Note */}
{risk.note && (
<div style={{ fontSize: 11, color: "#9ca3af" }}>{risk.note}</div>
)}
</div>
);
}