- 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
142 lines
3.7 KiB
TypeScript
142 lines
3.7 KiB
TypeScript
"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} промзон(ы) в <500м (риск
|
||
загрязнения почв)
|
||
</span>
|
||
</div>
|
||
)}
|
||
|
||
{/* Note */}
|
||
{risk.note && (
|
||
<div style={{ fontSize: 11, color: "#9ca3af" }}>{risk.note}</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|