Files
property-match/src/components/anfragencenter/SelectablePropertyMatchCard.tsx
T
Benjamin Sutter da50f3b5ea feat: premium redesign — DM Serif, refined palette, flat score badges
- Design tokens (ds.ts, theme.ts, scoreTheme.ts): new warm palette
  (#152642 navy, #f9f8f6 warm white, #e8e7e4 borders, #b8975a gold accent),
  flat score tier badges replacing CSS gradients, Inter + DM Serif Display typography
- Card components: white-background cards, DM Serif score numbers, max-2 badge
  chips with +N overflow tooltip, editorial score badge positioning
- Layout shell: gold left-accent nav active state, 64px top bar, outlined
  workspace chip, DM Serif page titles
- Shared atoms: GenericBadge (outlined/solid variants), ResultFilterBar
  (simplified chip styles), DecisionContextPanel (dot metrics, no left accent)
- Global replacement (118 files): #1e3a5f→#152642, #e2e8f0→#e8e7e4,
  #f4f6f9→#f9f8f6 — all handled via Node.js for proper UTF-8 safety

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:26:30 +02:00

119 lines
3.4 KiB
TypeScript

import { Box, Checkbox, Paper, Typography } from '@mui/material'
import { Building2, MapPin } from 'lucide-react'
import type { Property } from '../../domain/property'
import { getScoreTier, SCORE_THEME } from '../shared/scoreTheme'
import { assetTypeLabel } from './latentNeedUtils'
interface SelectablePropertyMatchCardProps {
property: Property
matchScore: number
selected: boolean
onToggle: () => void
reason: string
}
export function SelectablePropertyMatchCard({
property,
matchScore,
selected,
onToggle,
reason,
}: SelectablePropertyMatchCardProps) {
const tier = getScoreTier(matchScore)
const theme = SCORE_THEME[tier]
const image = property.images?.[0]
return (
<Paper
elevation={0}
onClick={onToggle}
sx={{
p: 1.25,
borderRadius: 1.5,
border: '1px solid',
borderColor: selected ? '#152642' : '#e8e7e4',
bgcolor: selected ? '#eff6ff' : 'white',
cursor: 'pointer',
transition: 'all 0.15s',
'&:hover': {
borderColor: selected ? '#152642' : '#94a3b8',
},
display: 'flex',
gap: 1.25,
alignItems: 'flex-start',
}}
>
<Checkbox
checked={selected}
onChange={onToggle}
onClick={e => e.stopPropagation()}
size="small"
sx={{ p: 0.5, mt: -0.5, ml: -0.5 }}
/>
<Box
sx={{
width: 40,
height: 40,
flexShrink: 0,
borderRadius: 1,
bgcolor: '#e8e7e4',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundImage: image ? `url(${image})` : 'none',
backgroundSize: 'cover',
backgroundPosition: 'center',
}}
>
{!image && <Building2 size={18} color="#94a3b8" />}
</Box>
<Box sx={{ flex: 1, minWidth: 0 }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 1 }}>
<Typography
variant="body2"
sx={{
fontWeight: 600,
color: '#0f172a',
fontSize: '0.8125rem',
lineHeight: 1.3,
overflow: 'hidden',
textOverflow: 'ellipsis',
display: '-webkit-box',
WebkitLineClamp: 1,
WebkitBoxOrient: 'vertical',
}}
>
{property.title}
</Typography>
<Box
sx={{
background: theme.gradient,
color: theme.text,
px: 0.75,
py: 0.125,
borderRadius: 1,
fontSize: '0.7rem',
fontWeight: 700,
flexShrink: 0,
border: `1px solid ${theme.border}`,
}}
>
{matchScore}%
</Box>
</Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, mt: 0.25, color: '#64748b' }}>
<MapPin size={11} />
<Typography variant="caption" sx={{ fontSize: '0.7rem' }}>
{property.location.city} · {assetTypeLabel(property.assetType)} · {property.areaSqm.toLocaleString('de-CH')} m²
</Typography>
</Box>
<Typography variant="caption" sx={{ fontSize: '0.7rem', color: '#475569', display: 'block', mt: 0.25 }}>
{reason}
</Typography>
</Box>
</Paper>
)
}