gendesign/frontend/src/components/trade-in/v2/LocationDrawer.tsx
lekss361 fba41c0cce
All checks were successful
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m22s
Deploy / deploy (push) Successful in 1m20s
feat(tradein/v2): HUD-редизайн страницы оценки (Макс) → /trade-in/v2 (#2035)
2026-06-28 09:58:53 +00:00

330 lines
9.1 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";
// "КОЭФФИЦИЕНТ ЛОКАЦИИ" right-side drawer for the /trade-in/v2 "МЕРА Оценка"
// design port. Faithful markup port of the design drawer (МЕРА Оценка.dc.html,
// lines 618-660): scrim + 452px right slider that slides in via translateX, a
// big location coefficient, intro, base×coef formula, the factors that raise /
// lower price, and a geo-source footer. Static markup, data from fixtures.
// Open/close is driven entirely by props (no internal state, no fetch).
import { tokens } from "./tokens";
import type { LocationFactor } from "./types";
import { locationFactors } from "./fixtures";
interface LocationDrawerProps {
open: boolean;
onClose: () => void;
}
function FactorRow({
factor,
variant,
}: {
factor: LocationFactor;
variant: "pos" | "neg";
}) {
const isPos = variant === "pos";
return (
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
fontSize: 12,
color: tokens.body,
}}
>
<span style={{ display: "flex", alignItems: "center", gap: 9 }}>
<span
style={{
width: 16,
height: 16,
borderRadius: 4,
background: isPos
? "rgba(27,170,107,.12)"
: "rgba(111,129,149,.14)",
color: isPos ? tokens.success : tokens.muted,
display: "flex",
alignItems: "center",
justifyContent: "center",
fontSize: isPos ? 11 : 12,
}}
>
{isPos ? "+" : ""}
</span>
{factor.label}
</span>
<span
style={{
fontFamily: tokens.font.mono,
fontSize: 11,
color: isPos ? tokens.success : tokens.muted,
}}
>
{factor.delta}
</span>
</div>
);
}
export function LocationDrawer({ open, onClose }: LocationDrawerProps) {
return (
<>
<style>{`
.ld-close {
width: 32px;
height: 32px;
flex: 0 0 auto;
border: 1px solid ${tokens.line};
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: ${tokens.muted};
font-size: 16px;
background: ${tokens.surface.w60};
transition: all .15s;
}
.ld-close:hover {
border-color: ${tokens.accent};
color: ${tokens.accent};
}
`}</style>
{/* scrim */}
<div
onClick={onClose}
style={{
position: "absolute",
inset: 0,
background: "rgba(22,42,70,.32)",
backdropFilter: "blur(2px)",
opacity: open ? 1 : 0,
pointerEvents: open ? "auto" : "none",
transition: "opacity .3s",
zIndex: 40,
}}
/>
{/* drawer */}
<div
style={{
position: "absolute",
top: 0,
right: 0,
bottom: 0,
width: 452,
transform: open ? "translateX(0)" : "translateX(108%)",
transition: "transform .38s cubic-bezier(.22,.61,.36,1)",
zIndex: 41,
background:
"linear-gradient(180deg,rgba(245,249,253,.97),rgba(235,242,250,.97))",
backdropFilter: "blur(10px)",
borderLeft: `1px solid ${tokens.line3}`,
boxShadow: "-18px 0 50px rgba(40,80,130,.16)",
display: "flex",
flexDirection: "column",
padding: "30px 32px",
overflowY: "auto",
fontFamily: tokens.font.sans,
}}
>
{/* left accent rail */}
<div
style={{
position: "absolute",
left: 0,
top: 18,
bottom: 18,
width: 1,
background: `linear-gradient(180deg,transparent,${tokens.accent},transparent)`,
opacity: 0.5,
}}
/>
{/* corner brackets */}
<div
style={{
position: "absolute",
left: 14,
top: 14,
width: 16,
height: 16,
borderLeft: `1.5px solid ${tokens.accent}`,
borderTop: `1.5px solid ${tokens.accent}`,
}}
/>
<div
style={{
position: "absolute",
right: 14,
bottom: 14,
width: 16,
height: 16,
borderRight: `1.5px solid ${tokens.accent}`,
borderBottom: `1.5px solid ${tokens.accent}`,
}}
/>
{/* header */}
<div
style={{
display: "flex",
alignItems: "flex-start",
justifyContent: "space-between",
}}
>
<div>
<div
style={{
fontSize: 9,
letterSpacing: "3px",
color: tokens.muted2,
}}
>
ПОЯСНЕНИЕ К РАСЧЁТУ
</div>
<div
style={{
fontSize: 22,
fontWeight: 300,
letterSpacing: "1.5px",
color: tokens.ink2,
marginTop: 8,
}}
>
КОЭФФИЦИЕНТ ЛОКАЦИИ
</div>
</div>
<div className="ld-close" onClick={onClose}>
</div>
</div>
{/* big coefficient */}
<div
style={{
display: "flex",
alignItems: "baseline",
gap: 14,
marginTop: 24,
paddingBottom: 20,
borderBottom: `1px solid ${tokens.lineSoft}`,
}}
>
<span
style={{
fontFamily: tokens.font.mono,
fontSize: 52,
fontWeight: 300,
color: tokens.accent,
lineHeight: 1,
}}
>
{locationFactors.coef}
</span>
<div style={{ fontSize: 11, color: tokens.muted, lineHeight: 1.5 }}>
множитель к базовой
<br />
цене по городу
</div>
</div>
{/* intro */}
<div
style={{
fontSize: 12.5,
lineHeight: 1.7,
color: tokens.body2,
marginTop: 20,
}}
>
Показывает, как адрес корректирует стоимость относительно медианы по
Екатеринбургу. <b style={{ color: tokens.ink2 }}>1.00</b> средний
уровень. <b style={{ color: tokens.accent }}>0.87</b> означает, что
локация снижает цену примерно на{" "}
<b style={{ color: tokens.ink2 }}>13%</b> из-за баланса факторов ниже.
</div>
{/* formula */}
<div
style={{
display: "flex",
alignItems: "center",
gap: 10,
marginTop: 18,
background: tokens.surface.w55,
border: `1px solid ${tokens.lineSoft}`,
borderRadius: 7,
padding: "12px 14px",
fontFamily: tokens.font.mono,
fontSize: 12,
color: tokens.ink2,
}}
>
<span style={{ color: tokens.muted }}>
{locationFactors.formula.base}
</span>
<span style={{ color: tokens.muted2 }}>×</span>
<span style={{ color: tokens.accent }}>
{locationFactors.formula.coef}
</span>
<span style={{ color: tokens.muted2 }}>=</span>
<span style={{ fontWeight: 500 }}>
{locationFactors.formula.result}
</span>
</div>
{/* positives */}
<div
style={{
fontSize: 9,
letterSpacing: "2px",
color: tokens.muted2,
marginTop: 26,
marginBottom: 12,
}}
>
ЧТО ПОВЫШАЕТ ЦЕНУ
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
{locationFactors.positives.map((f, i) => (
<FactorRow key={i} factor={f} variant="pos" />
))}
</div>
{/* negatives */}
<div
style={{
fontSize: 9,
letterSpacing: "2px",
color: tokens.muted2,
marginTop: 24,
marginBottom: 12,
}}
>
ЧТО СНИЖАЕТ ЦЕНУ
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
{locationFactors.negatives.map((f, i) => (
<FactorRow key={i} factor={f} variant="neg" />
))}
</div>
{/* footer source */}
<div
style={{
marginTop: 24,
paddingTop: 16,
borderTop: `1px solid ${tokens.lineSoft}`,
fontSize: 10.5,
lineHeight: 1.6,
color: tokens.hint,
}}
>
{locationFactors.footer}
</div>
</div>
</>
);
}