gendesign/frontend/src/components/site-finder/entry/ParcelDrawer.tsx
Light1YT 7cb008c551
All checks were successful
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 57s
CI / changes (pull_request) Successful in 6s
CI / openapi-codegen-check (pull_request) Successful in 1m55s
revert(site-finder): rollback dark entry-landing skin to light
The ПТИЦА dark "operator terminal" skin was applied to the main
/site-finder map page in b3fd053 ("dark Site Finder"), but the
2026-06-21 rollback (#1865) only reverted the analysis route — the
entry-landing stayed dark.

Точечно откатывает 8 файлов entry-landing (page.tsx + 7 entry-компонентов)
до состояния b3fd053~1 и удаляет осиротевший site-finder.module.css.

НЕ трогает: PticaMapInner / ptica.module.css (используются и старым ptica,
и Site Finder v2 cockpit) — карта аналитики остаётся glyph-pin как была.
2026-06-22 11:08:44 +05:00

375 lines
9.8 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 Link from "next/link";
import { X, MapPin, Maximize2, ArrowRight } from "lucide-react";
import type { ParcelBboxItem } from "@/lib/site-finder-api";
import { addLocalRecentParcel } from "@/lib/site-finder-api";
import { STATUS_COLORS, STATUS_LABELS } from "./ParcelLegend";
interface ParcelDrawerProps {
parcel: ParcelBboxItem | null;
onClose: () => void;
}
const VRI_LABELS: Record<string, string> = {
multistory: "Многоэтажный",
mixed: "Смешанный",
individual: "ИЖС",
office: "Офисный",
other: "Иное",
};
export function ParcelDrawer({ parcel, onClose }: ParcelDrawerProps) {
if (!parcel) return null;
const statusColor = STATUS_COLORS[parcel.status] ?? "#73767E";
const statusLabel = STATUS_LABELS[parcel.status] ?? parcel.status;
return (
// 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
style={{
padding: "16px 20px 12px",
borderBottom: "1px solid var(--border-soft)",
display: "flex",
alignItems: "flex-start",
gap: 8,
}}
>
<MapPin
size={16}
strokeWidth={1.5}
style={{
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,
}}
>
<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 != null ? 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)}`}
onClick={() => {
// Record the visit so this entry path also lands in RecentParcels (#1477).
addLocalRecentParcel({
cad_num: parcel.cad_num,
address: parcel.address,
area_ha: parcel.area_ha,
district: parcel.district,
visited_at: new Date().toISOString(),
});
}}
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>
);
}