3.6 KiB
Trade-In UI — how to build with this design system
React components from the GenDesign trade-in product (real-estate trade-in valuation, RU/ЕКБ). Import everything from tradein-mvp-frontend (bound at window.TradeInUI). The cards are domain-specific and prop-driven — you compose them with data, you don't restyle their internals.
Setup & wrapping (required for data components)
Most cards take their data as props and render standalone. But several read app state through TanStack Query hooks (UserMenu, Topbar, RouteGuard → useMe; HouseAnalyticsSection, PlacementHistoryCard, StreetDealsCard → estimate sub-queries). Those MUST be rendered inside a QueryClientProvider (the app ships one as Providers). Without it they throw "No QueryClient set"; with an empty client they render their loading/null state. Prop-only cards (HeroSummary, OfferCard, PriceRangeBar, DealsCard, ListingsCard, charts…) need no provider.
import { Providers, HeroSummary, OfferCard } from "tradein-mvp-frontend";
<Providers>
<main className="page" style={{ display: "flex", flexDirection: "column", gap: 24 }}>
<HeroSummary estimate={estimate} input={input} onResubmit={fn} />
<OfferCard estimate={estimate} brandSlug={null} />
</main>
</Providers>
Load styles.css once at the root — it pulls the component CSS + design tokens.
Styling idiom — global stylesheet + CSS custom properties
This is not Tailwind and not CSS-in-JS. Styling is a global stylesheet of semantic class names plus CSS custom-property design tokens. Two rules:
- The components carry their own classes (
.card,.card-head,.section-kicker,.count-strip,.pricebar,.source-chip,.control,.pill,.mono,.top-nav,.meta-grid…). Don't reach inside them; compose via props. New class names you invent will not exist in the stylesheet. - For your own layout/wrapper glue, use the token vars + inline styles, on the 4/8/12/16/24/32 spacing scale (tabular-nums for numbers). Color/shape tokens, all defined in the shipped CSS:
| Group | Tokens |
|---|---|
| Surface | --bg-app --bg-card --bg-card-alt --bg-headline |
| Text | --fg-primary --fg-secondary --fg-tertiary --fg-on-dark |
| Brand/CTA | --accent --accent-hover --accent-soft --accent-2 |
| Semantic | --success --warn --danger (*-soft variants) |
| Border | --border-soft --border-card --border-strong |
| Shape/type | --radius --radius-sm --radius-lg --shadow-md --font-sans (Manrope) --font-mono --container |
v2 (МЕРА HUD) fonts: the v2/* components read var(--font-manrope) / var(--font-plex-mono) (in the app these come from next/font). The woff2 for both families ships in fonts/fonts.css; define the vars once at your design root:
:root { --font-manrope: 'Manrope'; --font-plex-mono: 'IBM Plex Mono'; }
<div style={{ background: "var(--bg-card)", border: "1px solid var(--border-card)",
borderRadius: "var(--radius)", padding: 16, color: "var(--fg-primary)",
fontFamily: "var(--font-sans)" }}>
<b style={{ color: "var(--accent)" }}>9 850 000 ₽</b>
</div>
Where the truth is
- Styles/tokens: read the bound
styles.cssand its@import_ds_bundle.css— the authoritative class + token list. - Per component:
<Name>.d.ts(props) and<Name>.prompt.md(usage). NB: synth-built.d.tsprops are loose ([key: string]: unknown); the.prompt.md+ preview card show real prop shapes and realistic data. - Money/area/dates are RU-formatted (
toLocaleString("ru-RU"),₽,м²). Keep that idiom.