Честная полировка живого /trade-in/v2 без правок архитектуры (FE-only). - Провенанс из data, без хардкодов: footer «ПОСТРОЕНО ПО N АНАЛОГАМ И M СДЕЛКАМ» из meta.builtOn; единый счётчик источников (activeSourceCount = залитые плитки) в шапке 02, СВОДКЕ и оверлее; убраны «6/10», «2/7», «Avito·10», «из 2 источников». - Единый ru-форматтер: запятая везде (CV/площадь/%), NBSP число+единица, один en-dash и одна точность для денежных диапазонов. - CTA «ОЦЕНИТЬ КВАРТИРУ» → solid brand-blue + белый текст; :focus-visible HUD-glow на инпутах и кнопке. - Лендмарки <nav>/<main>/<footer> (display:contents, 0 визуальных изменений); scale-fit артборда — на 1366×768 / 1440×900 ужимается, не режется. - Мини-карта: честный зум (min=1, без пустых краёв при отдалении), убран мёртвый crosshair-двойник, расклеены налезающие метки цен. - CRM-дропдаун явно задизейблен («скоро», без ▼); убран «ШАГ 1/1». - Карточка 02 → «ОЖИДАЕМАЯ ЦЕНА СДЕЛКИ · с учётом торга» + строка-примирение с медианой ДКП; КОЭФ.ЛОКАЦИИ → muted-пилюля «скоро». - Бейдж СВОДКИ «В РАСЧЁТЕ» → «АКТУАЛЬНО»; скрыты целиком-прочерк колонки (ИСТОЧНИКОВ в 07, ОБЪЯВЛЕНИЕ ДО СДЕЛКИ в 04) data-driven.
154 lines
4.4 KiB
TypeScript
154 lines
4.4 KiB
TypeScript
// OVERLAY 07: ПРЕДЫДУЩИЕ ОЦЕНКИ (cache view).
|
||
// Faithful markup port of МЕРА Оценка.dc.html lines 593-613.
|
||
// Data via `data` prop (mapCache output); defaults to fixtures (cacheKpi + cacheRows).
|
||
|
||
import { tokens } from "./tokens";
|
||
import { cacheKpi, cacheRows } from "./fixtures";
|
||
import type { CacheData } from "./mappers";
|
||
|
||
const FIXTURE_CACHE: CacheData = { kpis: cacheKpi, rows: cacheRows };
|
||
|
||
export function CacheView({ data = FIXTURE_CACHE }: { data?: CacheData }) {
|
||
const showSrc = data.rows.some((r) => r.src && r.src !== "—");
|
||
const gridCols = showSrc ? "2.4fr 1fr 1fr 1fr" : "2.4fr 1fr 1fr";
|
||
return (
|
||
<div style={{ display: "flex", flexDirection: "column", gap: 22 }}>
|
||
{/* 3 KPI cards */}
|
||
<div
|
||
style={{
|
||
display: "grid",
|
||
gridTemplateColumns: "repeat(3,1fr)",
|
||
gap: 16,
|
||
}}
|
||
>
|
||
{data.kpis.map((kpi) => (
|
||
<div
|
||
key={kpi.label}
|
||
style={{
|
||
background: tokens.surface.w55,
|
||
border: `1px solid ${tokens.line2}`,
|
||
borderRadius: 8,
|
||
padding: "16px 18px",
|
||
}}
|
||
>
|
||
<div
|
||
style={{
|
||
fontSize: 9.5,
|
||
letterSpacing: 1.5,
|
||
color: tokens.muted2,
|
||
}}
|
||
>
|
||
{kpi.label}
|
||
</div>
|
||
<div
|
||
style={{
|
||
fontFamily: tokens.font.mono,
|
||
fontSize: 30,
|
||
fontWeight: 300,
|
||
color: tokens.ink2,
|
||
margin: "8px 0 5px",
|
||
}}
|
||
>
|
||
{kpi.value}
|
||
{kpi.unit && (
|
||
<>
|
||
{kpi.unit !== "%" && " "}
|
||
<span style={{ fontSize: 14, color: tokens.muted }}>
|
||
{kpi.unit}
|
||
</span>
|
||
</>
|
||
)}
|
||
</div>
|
||
<div style={{ fontSize: 10, color: tokens.hint }}>{kpi.sub}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* Последние оценки table */}
|
||
<div
|
||
style={{
|
||
background: tokens.surface.w55,
|
||
border: `1px solid ${tokens.line2}`,
|
||
borderRadius: 8,
|
||
overflow: "hidden",
|
||
}}
|
||
>
|
||
<div
|
||
style={{
|
||
padding: "14px 18px",
|
||
borderBottom: `1px solid ${tokens.lineSoft}`,
|
||
fontSize: 12,
|
||
fontWeight: 600,
|
||
color: tokens.ink2,
|
||
}}
|
||
>
|
||
Последние оценки
|
||
</div>
|
||
<div
|
||
style={{
|
||
display: "grid",
|
||
gridTemplateColumns: gridCols,
|
||
gap: 10,
|
||
padding: "9px 18px",
|
||
fontSize: 9,
|
||
letterSpacing: 1,
|
||
color: tokens.muted2,
|
||
borderBottom: `1px solid ${tokens.lineSoft2}`,
|
||
}}
|
||
>
|
||
<span>АДРЕС</span>
|
||
<span>ВРЕМЯ</span>
|
||
{showSrc && <span>ИСТОЧНИКОВ</span>}
|
||
<span>СТАТУС</span>
|
||
</div>
|
||
{data.rows.map((r, i) => (
|
||
<div
|
||
key={`${r.addr}-${i}`}
|
||
style={{
|
||
display: "grid",
|
||
gridTemplateColumns: gridCols,
|
||
gap: 10,
|
||
padding: "12px 18px",
|
||
fontSize: 11,
|
||
borderBottom: `1px solid ${tokens.lineSoft3}`,
|
||
alignItems: "center",
|
||
}}
|
||
>
|
||
<span style={{ color: tokens.body }}>{r.addr}</span>
|
||
<span
|
||
style={{ fontFamily: tokens.font.mono, color: tokens.muted2 }}
|
||
>
|
||
{r.time}
|
||
</span>
|
||
{showSrc && (
|
||
<span
|
||
style={{ fontFamily: tokens.font.mono, color: tokens.muted }}
|
||
>
|
||
{r.src}
|
||
</span>
|
||
)}
|
||
<span
|
||
style={{
|
||
display: "flex",
|
||
alignItems: "center",
|
||
gap: 6,
|
||
fontSize: 10,
|
||
color: r.statusColor,
|
||
}}
|
||
>
|
||
<span
|
||
style={{
|
||
width: 7,
|
||
height: 7,
|
||
borderRadius: "50%",
|
||
background: r.statusColor,
|
||
}}
|
||
/>
|
||
{r.status}
|
||
</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|