diff --git a/.design-sync/NOTES.md b/.design-sync/NOTES.md index 3dc9d62e..df12c959 100644 --- a/.design-sync/NOTES.md +++ b/.design-sync/NOTES.md @@ -32,3 +32,40 @@ Target: `tradein-mvp/frontend` (NOT the repo-root `frontend/`, which is the Site - Synth scan re-includes Next route/layout/error files on every build → `componentSrcMap` nulls (13 entries) must persist. New app-router pages would need adding. - `.d.ts` props are weak (`[key:string]:unknown`) — synth mode has no built types. Real prop contracts live in each component's source `interface Props`. A real `tsup`/`tsc` lib build would fix this (recommend if the agent needs strong API contracts). - Grades clear on any `cfg.provider`/preview-affecting config change (expected) — re-grade from fresh sheets. + +## Re-sync 2026-07-02 — v2 dashboard sync (main was 223 commits ahead; harness authored on June components) + +**Two source-kit.mjs fork fixes were REQUIRED for the evolved v2 codebase (both committed in the override, declared in cfg.libOverrides):** +1. **Exclude `next/font` importers from the synth-entry.** `src/app/v2/layout.tsx` calls `Manrope()`/`IBM_Plex_Mono()` from `next/font/google` at MODULE TOP-LEVEL. esbuild can't resolve the Next-only loader → stubs it `(void 0)` → `undefined()` aborts the whole browser IIFE → `window.TradeInUI` empty → ALL 58 components vanish (`[RENDER] root empty` everywhere, `[BUNDLE_EXPORT]`). Fix: `comps` filter drops any file whose content matches `/from\s+['"]next\/font/`. If a NEW file top-level-calls a Next build-time loader, same class of crash — extend the filter. +2. **Re-export default-exported components.** `export * from ` does NOT re-export a module's `default`. The v2 views/nav/overlay/panel are authored `export default function ` (AnalyticsView, HeroBar, HistoryView, ParamsPanel, SectionOverlay, SourcesView, TopNav) → absent from `window.TradeInUI` → `[BUNDLE_EXPORT] not a component`. Fix: entry now also emits `export { default as } from ` for each `export default function/class `. Named-export components (`export function X`) were always fine. + +**componentSrcMap:** added `TradeInV2Layout / TradeInV2Page / SaleShareLayout / SaleSharePage` = null (Next route files, never DS components — same as RootLayout et al.). + +**overrides (grid):** MapPicker `{cardMode:single, primaryStory:Default}` (portal/fixed), StreetDealsCard + Topbar `{cardMode:column}` (wider than a grid cell). + +**Floor-card components (6, authorable on any future re-sync):** SaleShareControls, SaleShareList, SaleShareMap, SectionOverlay, LocationDrawer, BuildingListingsDrawer — overlays/drawers whose props don't seed rich data via PreviewProvider, so they show the honest typographic floor. All the OTHER v2 components (views/nav/hero/panel) render richly because the provider seeds their data. + +**Known render warn:** ResultPanel — `variants identical` (Default vs Error cells render near-identically; not broken, the Error cell just doesn't diverge visually enough). Recorded here so re-syncs don't read it as new. + +**Font note (re-sync risk):** the v2 HUD's real typefaces are **Manrope + IBM_Plex_Mono** (loaded by the excluded `v2/layout.tsx` via next/font → CSS vars `--font-manrope`/`--font-plex-mono`). `cfg.extraFonts` ships **Inter + JetBrains Mono** (June brand fonts). v2 previews therefore render Manrope-slot text in the shipped fallback. If brand-exact v2 rendering is wanted, add Manrope + IBM Plex Mono woff2 to `.design-sync/fonts/` + `cfg.extraFonts` and map the `--font-manrope`/`--font-plex-mono` vars. + +**ResultPanel NAME COLLISION (fixed 2026-07-02):** two components named `ResultPanel` in src — `app/scrapers/_components/ScraperPage.tsx` (`export function ResultPanel`, scraper mut-panel) and `components/trade-in/v2/ResultPanel.tsx` (`export default function ResultPanel`, the v2 estimate result / honest hero). The default-re-export fix makes the v2 one win `window.TradeInUI.ResultPanel` (explicit `export {default as ResultPanel}` beats the star export). But the June authored preview `previews/ResultPanel.tsx` was the SCRAPER one (`mut` props) → the v2 component rendered fine (reads data from context) but its prompt.md documented the wrong (scraper) API. FIX: (1) `cfg.componentSrcMap.ResultPanel = "src/components/trade-in/v2/ResultPanel.tsx"` pins enrichment to v2; (2) re-authored `previews/ResultPanel.tsx` → `{}} />` (v2 API; `data` defaults to the component's built-in RESULT_FIXTURE = honest-hero). If a re-sync ever shows ResultPanel with scraper markup, the pin/preview regressed. Any NEW duplicate PascalCase component name will hit the same class of issue — the default-re-export makes the default-export win; pin + author the intended one. + +**Upload gotcha (this machine):** after a follow-up single-component rebuild, `resync-verdict.json upload.deletePaths` came back with ALL other components (318 paths) — a stale-anchor diff artifact, NOT real deletions (ResultPanel + audit/uploads were absent from it). Do NOT feed that deletePaths to delete_files (would nuke the project). For a focused single-component re-upload: write just that component's `components///*` + `_preview/.js` + `_ds_sync.json` (sentinel-fenced), deletes=[]. + - **CORRECTION (2026-07-03):** the 318 deletePaths were NOT a diff artifact — they were REAL local deletions caused by a source-kit fork bug (see below): the July-02 `componentSrcMap.ResultPanel` pin collapsed the synth build to 1 component, so the local ds-bundle genuinely lost the other 53. The "don't feed deletePaths blindly" advice stands (it saved the project), but the root cause is fixed now. + +## Re-sync 2026-07-03 — 6 floor cards authored + v2 brand fonts (#2267) + +**source-kit.mjs fork fix #3 (REQUIRED): componentSrcMap pin must AUGMENT synth discovery, not replace it.** In synth mode there is no shipped `.d.ts`, so `exportedNames()` is empty and `names` contains ONLY the non-null `componentSrcMap` pins. The old guard `if (!components.length && synthEntry) components = deriveComponentsFromSrc(...)` therefore never ran once a single pin existed (ResultPanel, added 2026-07-02) → the whole bundle collapsed to 1 component (`(stale preview: X — component no longer exported)` for everything else; verdict shows all others as `removed` + bogus deletePaths). Fix in the fork: when `synthEntry`, always union `deriveComponentsFromSrc(srcFiles)` (minus `null`-excluded) with the pinned names. Any future pin would have re-triggered this. NB: the fork edit re-keys EVERY component's sourceKey → full re-grade pass (done: 47/54 renderHashes byte-identical to the 2026-07-02 anchor → carry-forward grades; the rest eyeballed). + +**6 floor cards → authored (all graded good):** +- `SaleShareControls` — inline `SaleShareSummary` (histogram 7 корзин, coverage 92.1%); порог 8% приглушает нижнюю корзину; все фильтры. +- `SaleShareList` — 6 инлайн-домов ЕКБ (heat-бейджи, «аварийный», over_100 «возможно, несколько корпусов», selected-row) + Empty cell. `cardMode: column`. +- `SaleShareMap` — 8 heat-маркеров + открытый popup выбранного дома; OSM-тайлы офлайн не красятся (известно, как MapCard). +- `SectionOverlay` (v2) — рендерится contained в relative-«артборде» (absolute-позиционирование против ближайшего positioned ancestor; wrapper height 680 + v2-градиент). 2 cells: HistoryView (04) / AnalyticsView (06) на их встроенных fixtures (data-props не переданы). `cardMode: column`. +- `LocationDrawer` (v2) — open=true в таком же contained-артборде (height 640). `cardMode: column`. +- `BuildingListingsDrawer` — `createPortal` + `.ss-drawer-overlay` = position:fixed → `cardMode: single` (прецедент MapPicker). Шапка богатая (props), тело fetch-coupled (`useBuildingListings`, data-prop нет) → офлайн честный error-state «Не удалось загрузить объявления дома». Сидировать можно было бы ключом `["sale-share","listings",]` в PreviewProvider — сознательно НЕ сделано (кэш-ключ завязан на house_id фикстуры превью; хрупко). + +**v2 brand fonts shipped (Manrope + IBM Plex Mono).** woff2 (latin+cyrillic; Manrope variable 200-800, Plex Mono static 300/400/500 — веса из `app/v2/layout.tsx`) скачаны с Google Fonts → `.design-sync/fonts/`, @font-face добавлены в `brand-fonts.css`. **ГОЧА: extraFonts-пайплайн (`css.mjs extractFonts`) извлекает ТОЛЬКО `@font-face`-блоки — `:root{}` из brand-fonts.css молча выбрасывается.** Маппинг `--font-manrope`/`--font-plex-mono` поэтому живёт в `preview-provider.tsx` (` + {children} + + ); } diff --git a/.design-sync/previews/BuildingListingsDrawer.tsx b/.design-sync/previews/BuildingListingsDrawer.tsx new file mode 100644 index 00000000..84f65b34 --- /dev/null +++ b/.design-sync/previews/BuildingListingsDrawer.tsx @@ -0,0 +1,36 @@ +import { BuildingListingsDrawer } from 'tradein-mvp-frontend'; + +// Правый drawer с активными объявлениями выбранного дома (/trade-in/sale-share): +// createPortal в document.body, .ss-drawer-overlay = position:fixed по всему +// вьюпорту (как MapPicker) → cardMode:single. Шапка — адрес + тепловой бейдж +// доли + «N из M квартир» (из props). Тело FETCH-COUPLED: useBuildingListings +// (GET /buildings/{id}/listings) — data-prop нет, глобальный query-cache пуст → +// в офлайн-capture честный pending/error-state («Загрузка объявлений…» / +// «Не удалось загрузить объявления дома»). На реальной странице — список +// объявлений с ценой, ₽/м², этажом и ссылкой на оригинал. +const building = { + house_id: 3101, + address: 'ул. Викулова, 46', + lat: 56.8412, + lon: 60.5556, + sale_share_pct: 34.6, + sale_share_pct_45d: 41.2, + listings_45d: 33, + over_100: false, + active_secondary: 27, + flat_count_effective: 78, + gar_match_method: 'cadastre', + median_price_rub: 4_950_000, + median_price_per_m2: 158_500, + avg_days_on_market: 74, + year_built: 1972, + house_type: 'panel', + total_floors: 9, + series_name: '1-468', + is_emergency: false, +}; + +/** Открытый drawer дома «ул. Викулова, 46» (34.6% в продаже, 27 из 78 квартир). */ +export const Default = () => ( + {}} /> +); diff --git a/.design-sync/previews/LocationDrawer.tsx b/.design-sync/previews/LocationDrawer.tsx new file mode 100644 index 00000000..15460646 --- /dev/null +++ b/.design-sync/previews/LocationDrawer.tsx @@ -0,0 +1,25 @@ +import { LocationDrawer } from 'tradein-mvp-frontend'; + +// «ПОЯСНЕНИЕ К РАСЧЁТУ» — правый drawer HUD «МЕРА Оценка» (/trade-in/v2), +// открывается с «?» у «КОЭФ. ЛОКАЦИИ» в HeroBar. Честная методика: как +// агрегируются источники (Циан/Я.Недвижимость/Авито/Домклик + Росреестр) и +// явная плашка «коэффициент локации в разработке». Контент статичный — +// данных не принимает, только open/onClose. Drawer absolute-позиционирован +// (width 452 + scrim) — рендерим contained внутри relative-обёртки. + +/** Открытое состояние: scrim + выдвинутая панель с методикой и info-плашкой + * о локации. */ +export const Default = () => ( +
+ {}} /> +
+); diff --git a/.design-sync/previews/ResultPanel.tsx b/.design-sync/previews/ResultPanel.tsx index ca5e60af..a21667db 100644 --- a/.design-sync/previews/ResultPanel.tsx +++ b/.design-sync/previews/ResultPanel.tsx @@ -1,36 +1,10 @@ import { ResultPanel } from 'tradein-mvp-frontend'; -/** Переиспользуемая панель результата мутации скрапера. Успех → JSON-дамп - * ответа в `.scraper-result`. */ -export const Default = () => ( - -); - -/** Ветка ошибки — красная панель `.scraper-result--error` с текстом сбоя. */ -export const Error_ = () => ( - -); +/** + * ResultPanel (v2) — центральная панель результата оценки на `/trade-in/v2`: + * одна цифра-герой (ожидаемая цена продажи / «оценка»), тиры median + ДКП, + * доверительные диапазоны, источники и мини-гистограмма распределения. + * Данные по умолчанию берутся из встроенной `RESULT_FIXTURE` компонента, + * поэтому карточке достаточно передать `onNavigate` (навигация по секциям). + */ +export const Default = () => {}} />; diff --git a/.design-sync/previews/SaleShareControls.tsx b/.design-sync/previews/SaleShareControls.tsx new file mode 100644 index 00000000..cca3fa75 --- /dev/null +++ b/.design-sync/previews/SaleShareControls.tsx @@ -0,0 +1,54 @@ +import { SaleShareControls } from 'tradein-mvp-frontend'; + +// Панель «Порог и фильтры» страницы /trade-in/sale-share. Controlled-компонент: +// состояние живёт в page.tsx и приходит через props. Сводка (гистограмма +// распределения sale_share_pct) — реалистичные значения по покрытию ЕКБ +// (view v_building_sale_share ≈ 6.7k домов вторички, знаменатель ГАР у ~92%). +const summary = { + total_secondary_buildings: 6667, + buildings_with_denominator: 6143, + coverage_pct: 92.1, + max_pct: 42.0, + p95_pct: 11.3, + histogram: [ + { bucket: '0-5', count: 4980 }, + { bucket: '5-10', count: 642 }, + { bucket: '10-20', count: 298 }, + { bucket: '20-30', count: 121 }, + { bucket: '30-50', count: 57 }, + { bucket: '50-100', count: 18 }, + { bucket: '100+', count: 6 }, + ], +}; + +const HOUSE_TYPES = ['panel', 'brick', 'monolith', 'monolith_brick', 'block', 'stalin']; + +/** Порог 8% на слайдере: корзины ниже порога приглушены (opacity), тепловая + * окраска столбцов green→red повторяет цвет маркеров карты. Фильтры: город, + * цена, год постройки, тип дома, мин. объявлений, сортировка. */ +export const Default = () => ( + {}} + city="Екатеринбург" + onCity={() => {}} + priceMin="" + onPriceMin={() => {}} + priceMax="" + onPriceMax={() => {}} + yearMin="" + onYearMin={() => {}} + yearMax="" + onYearMax={() => {}} + houseType="" + onHouseType={() => {}} + houseTypeOptions={HOUSE_TYPES} + sort="share_desc" + onSort={() => {}} + window="now" + onWindow={() => {}} + minCount={3} + onMinCount={() => {}} + /> +); diff --git a/.design-sync/previews/SaleShareList.tsx b/.design-sync/previews/SaleShareList.tsx new file mode 100644 index 00000000..69c1fc9f --- /dev/null +++ b/.design-sync/previews/SaleShareList.tsx @@ -0,0 +1,50 @@ +import { SaleShareList } from 'tradein-mvp-frontend'; + +// Список домов /trade-in/sale-share, отсортирован по доле в продаже (server-side +// share_desc). Реалистичные дома ЕКБ (view v_building_sale_share): адрес, +// тепловой бейдж доли, «N из M квартир», медиана + ₽/м², экспозиция, +// год/тип/этажность/серия. Включены оба edge-бейджа: «аварийный» и +// «возможно, несколько корпусов» (over_100 — ГАР-коллизия адреса). +const buildings = [ + { house_id: 4212, address: 'ул. Космонавтов, 52', lat: 56.8890, lon: 60.6132, sale_share_pct: 128.0, sale_share_pct_45d: 131.5, listings_45d: 46, over_100: true, active_secondary: 32, flat_count_effective: 25, gar_match_method: 'address', median_price_rub: 3_650_000, median_price_per_m2: 121_700, avg_days_on_market: 96, year_built: 1961, house_type: 'brick', total_floors: 5, series_name: null, is_emergency: false }, + { house_id: 3387, address: 'пер. Сапёров, 5', lat: 56.8271, lon: 60.6198, sale_share_pct: 48.9, sale_share_pct_45d: 52.4, listings_45d: 24, over_100: false, active_secondary: 22, flat_count_effective: 45, gar_match_method: 'cadastre', median_price_rub: 2_990_000, median_price_per_m2: 98_400, avg_days_on_market: 148, year_built: 1957, house_type: 'brick', total_floors: 3, series_name: null, is_emergency: true }, + { house_id: 3101, address: 'ул. Викулова, 46', lat: 56.8412, lon: 60.5556, sale_share_pct: 34.6, sale_share_pct_45d: 41.2, listings_45d: 33, over_100: false, active_secondary: 27, flat_count_effective: 78, gar_match_method: 'cadastre', median_price_rub: 4_950_000, median_price_per_m2: 158_500, avg_days_on_market: 74, year_built: 1972, house_type: 'panel', total_floors: 9, series_name: '1-468', is_emergency: false }, + { house_id: 2874, address: 'ул. Бебеля, 138', lat: 56.8664, lon: 60.5721, sale_share_pct: 22.4, sale_share_pct_45d: 25.0, listings_45d: 20, over_100: false, active_secondary: 17, flat_count_effective: 76, gar_match_method: 'cadastre', median_price_rub: 5_400_000, median_price_per_m2: 149_200, avg_days_on_market: 61, year_built: 1978, house_type: 'panel', total_floors: 9, series_name: '141', is_emergency: false }, + { house_id: 5530, address: 'ул. Малышева, 84', lat: 56.8380, lon: 60.6203, sale_share_pct: 12.1, sale_share_pct_45d: 13.8, listings_45d: 16, over_100: false, active_secondary: 14, flat_count_effective: 116, gar_match_method: 'cadastre', median_price_rub: 7_850_000, median_price_per_m2: 172_300, avg_days_on_market: 47, year_built: 1954, house_type: 'stalin', total_floors: 6, series_name: null, is_emergency: false }, + { house_id: 6119, address: 'ул. Щербакова, 20', lat: 56.7791, lon: 60.6120, sale_share_pct: 6.8, sale_share_pct_45d: 8.1, listings_45d: 22, over_100: false, active_secondary: 18, flat_count_effective: 264, gar_match_method: 'cadastre', median_price_rub: 8_900_000, median_price_per_m2: 164_800, avg_days_on_market: 38, year_built: 2016, house_type: 'monolith', total_floors: 25, series_name: null, is_emergency: false }, +]; + +/** Полная таблица (6 домов, выбран «ул. Викулова, 46» — строка is-selected), + * сортировка по доле, кнопка «Объявления →» ведёт в drawer. */ +export const Default = () => ( + {}} + selectedHouseId={3101} + hoveredHouseId={null} + onSelect={() => {}} + onHover={() => {}} + isLoading={false} + isError={false} + minPct={5} + window="now" + /> +); + +/** Пустой результат — фильтры отсекли все дома (честный empty-state). */ +export const Empty = () => ( + {}} + selectedHouseId={null} + hoveredHouseId={null} + onSelect={() => {}} + onHover={() => {}} + isLoading={false} + isError={false} + minPct={25} + window="now" + /> +); diff --git a/.design-sync/previews/SaleShareMap.tsx b/.design-sync/previews/SaleShareMap.tsx new file mode 100644 index 00000000..dd840e90 --- /dev/null +++ b/.design-sync/previews/SaleShareMap.tsx @@ -0,0 +1,30 @@ +import { SaleShareMap } from 'tradein-mvp-frontend'; + +// Тепловая карта домов /trade-in/sale-share (Leaflet + OSM с CDN, как +// MapCard/MapPicker). Цвет и радиус circleMarker растут с sale_share_pct +// (green → red, over_100 → тёмно-красный). 8 домов ЕКБ с координатами; +// выбранный дом (selectedHouseId) получает открытый popup. OSM-тайлы — +// внешний fetch: в офлайн-capture подложка может не прогрузиться, +// маркеры/popup/контролы рендерятся всегда. +const buildings = [ + { house_id: 4212, address: 'ул. Космонавтов, 52', lat: 56.8890, lon: 60.6132, sale_share_pct: 128.0, sale_share_pct_45d: 131.5, listings_45d: 46, over_100: true, active_secondary: 32, flat_count_effective: 25, gar_match_method: 'address', median_price_rub: 3_650_000, median_price_per_m2: 121_700, avg_days_on_market: 96, year_built: 1961, house_type: 'brick', total_floors: 5, series_name: null, is_emergency: false }, + { house_id: 3387, address: 'пер. Сапёров, 5', lat: 56.8271, lon: 60.6198, sale_share_pct: 48.9, sale_share_pct_45d: 52.4, listings_45d: 24, over_100: false, active_secondary: 22, flat_count_effective: 45, gar_match_method: 'cadastre', median_price_rub: 2_990_000, median_price_per_m2: 98_400, avg_days_on_market: 148, year_built: 1957, house_type: 'brick', total_floors: 3, series_name: null, is_emergency: true }, + { house_id: 3101, address: 'ул. Викулова, 46', lat: 56.8412, lon: 60.5556, sale_share_pct: 34.6, sale_share_pct_45d: 41.2, listings_45d: 33, over_100: false, active_secondary: 27, flat_count_effective: 78, gar_match_method: 'cadastre', median_price_rub: 4_950_000, median_price_per_m2: 158_500, avg_days_on_market: 74, year_built: 1972, house_type: 'panel', total_floors: 9, series_name: '1-468', is_emergency: false }, + { house_id: 2874, address: 'ул. Бебеля, 138', lat: 56.8664, lon: 60.5721, sale_share_pct: 22.4, sale_share_pct_45d: 25.0, listings_45d: 20, over_100: false, active_secondary: 17, flat_count_effective: 76, gar_match_method: 'cadastre', median_price_rub: 5_400_000, median_price_per_m2: 149_200, avg_days_on_market: 61, year_built: 1978, house_type: 'panel', total_floors: 9, series_name: '141', is_emergency: false }, + { house_id: 5530, address: 'ул. Малышева, 84', lat: 56.8380, lon: 60.6203, sale_share_pct: 12.1, sale_share_pct_45d: 13.8, listings_45d: 16, over_100: false, active_secondary: 14, flat_count_effective: 116, gar_match_method: 'cadastre', median_price_rub: 7_850_000, median_price_per_m2: 172_300, avg_days_on_market: 47, year_built: 1954, house_type: 'stalin', total_floors: 6, series_name: null, is_emergency: false }, + { house_id: 6119, address: 'ул. Щербакова, 20', lat: 56.7791, lon: 60.6120, sale_share_pct: 6.8, sale_share_pct_45d: 8.1, listings_45d: 22, over_100: false, active_secondary: 18, flat_count_effective: 264, gar_match_method: 'cadastre', median_price_rub: 8_900_000, median_price_per_m2: 164_800, avg_days_on_market: 38, year_built: 2016, house_type: 'monolith', total_floors: 25, series_name: null, is_emergency: false }, + { house_id: 5871, address: 'ул. Крауля, 44', lat: 56.8443, lon: 60.5610, sale_share_pct: 17.9, sale_share_pct_45d: 19.6, listings_45d: 14, over_100: false, active_secondary: 12, flat_count_effective: 67, gar_match_method: 'cadastre', median_price_rub: 5_150_000, median_price_per_m2: 152_900, avg_days_on_market: 58, year_built: 1980, house_type: 'panel', total_floors: 9, series_name: '141', is_emergency: false }, + { house_id: 6402, address: 'ул. 8 Марта, 190', lat: 56.8043, lon: 60.6094, sale_share_pct: 3.4, sale_share_pct_45d: 4.0, listings_45d: 11, over_100: false, active_secondary: 9, flat_count_effective: 262, gar_match_method: 'cadastre', median_price_rub: 9_300_000, median_price_per_m2: 176_400, avg_days_on_market: 33, year_built: 2019, house_type: 'monolith', total_floors: 26, series_name: null, is_emergency: false }, +]; + +/** Карта ЕКБ: 8 тепловых маркеров, выбран «ул. Викулова, 46» — открыт popup + * (адрес, % в продаже, N из M квартир). */ +export const Default = () => ( + {}} + onHover={() => {}} + /> +); diff --git a/.design-sync/previews/SectionOverlay.tsx b/.design-sync/previews/SectionOverlay.tsx new file mode 100644 index 00000000..cdf122de --- /dev/null +++ b/.design-sync/previews/SectionOverlay.tsx @@ -0,0 +1,39 @@ +import { SectionOverlay } from 'tradein-mvp-frontend'; + +// Glass/blur оверлей секций HUD «МЕРА Оценка» (/trade-in/v2): скобки-уголки, +// шапка «номер секции + заголовок + ← К ОЦЕНКЕ», скроллируемое тело со +// сменной view. Позиционируется absolute относительно артборда — в preview +// рендерим contained внутри relative-обёртки с фоном v2-страницы. +// Данные не передаём: каждая view падает на свой встроенный fixture-набор +// (HISTORY_FIXTURE / ANALYTICS_FIXTURE …) — как storybook/unwired usage. + +const Artboard = ({ children }: { children?: unknown }) => ( +
+ {children as React.ReactNode} +
+); + +/** Секция 04 «ПРОДАЖИ В ДОМЕ» (active=1 → HistoryView на fixture-данных): + * таблица ДКП-продаж дома с ценами и датами. */ +export const HistorySection = () => ( + + {}} onNavigate={() => {}} /> + +); + +/** Секция 06 «АНАЛИТИКА ДОМА» (active=3 → AnalyticsView): KPI дома, + * динамика цены, недавние продажи. */ +export const AnalyticsSection = () => ( + + {}} onNavigate={() => {}} /> + +); diff --git a/.gitignore b/.gitignore index 415ae9f7..c54a5b53 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -# Memory graph (hardlink to C:\mcp\.aim\memory-gendesign.jsonl) +# Memory graph (hardlink to C:\mcp\.aim\memory-gendesign.jsonl) *.jsonl !memory/memory-gendesign.jsonl