refactor(PropertyIntelligenceCard): smaller image, larger text, more spacing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-06-12 00:02:03 +02:00
parent beecf754d5
commit 5259579f85
3 changed files with 56 additions and 24 deletions
+17 -1
View File
@@ -13,7 +13,23 @@
"Bash(git pull *)", "Bash(git pull *)",
"Bash(node scripts/check-tokens.js)", "Bash(node scripts/check-tokens.js)",
"Bash(echo \"EXIT:$?\")", "Bash(echo \"EXIT:$?\")",
"Bash(echo \"EXIT_CODE:$?\")" "Bash(echo \"EXIT_CODE:$?\")",
"Bash(Get-ChildItem \"c:\\\\Users\\\\beni_\\\\AppData\\\\Local\\\\Temp\\\\docx-gen\\\\node_modules\\\\docx\" -Recurse -Name)",
"Bash(start \"C:\\\\Users\\\\beni_\\\\OneDrive\\\\Desktop\\\\property-match\\\\Aenderungsprotokoll_Meeting_26052026.docx\")",
"Bash(start http://localhost:5176)",
"Bash(start http://localhost:5176/demand/ai-search)",
"Bash(node -e ' *)",
"Skill(run)",
"Skill(run:*)",
"Bash(curl -s -o /dev/null -w \"%{http_code}\" http://localhost:5173)",
"Bash(powershell.exe -Command \"Start-Process 'http://localhost:5173'\")",
"Bash(findstr \"LISTENING\")",
"Bash(findstr \":517\")",
"Bash(findstr \"LISTEN\")",
"Bash(findstr \":5\")",
"Bash(echo \"Exit: $?\")",
"Bash(npx vercel *)",
"Bash(Start-Process \"http://localhost:5180\")"
] ]
} }
} }
+17 -1
View File
@@ -5,7 +5,23 @@
"Bash(git commit *)", "Bash(git commit *)",
"Bash(node -e ' *)", "Bash(node -e ' *)",
"Bash(git stash *)", "Bash(git stash *)",
"Read(//c/Users/beni_/.claude/projects/c--Users-beni--OneDrive-Desktop-property-match/8e388ddd-e02e-47fe-8bb9-cdb8164c9fc3/tool-results/**)" "Read(//c/Users/beni_/.claude/projects/c--Users-beni--OneDrive-Desktop-property-match/8e388ddd-e02e-47fe-8bb9-cdb8164c9fc3/tool-results/**)",
"Bash(pandoc --version)",
"Bash(npm list *)",
"Read(//c/Program Files/LibreOffice/program/**)",
"Read(//c/Program Files/Microsoft Office/**)",
"Read(//c/Program Files \\(x86\\)/**)",
"Bash(mkdir -p /tmp/docx-gen)",
"Read(//tmp/**)",
"Bash(npm init *)",
"Bash(node generate.js)",
"Bash(timeout 8 bash -c \"until curl -s http://localhost:5173 > /dev/null; do sleep 1; done\")",
"Bash(dir \"c:\\\\Users\\\\beni_\\\\OneDrive\\\\Desktop\\\\property-match\\\\src\" -Depth 2)",
"Bash(start \"\" \"http://localhost:5178/demand/results\")",
"Bash(start \"\" \"http://localhost:5178/supply/properties\")"
],
"additionalDirectories": [
"c:\\Users\\beni_\\AppData\\Local\\Temp\\docx-gen"
] ]
} }
} }
@@ -62,7 +62,7 @@ export const PropertyIntelligenceCard = memo(function PropertyIntelligenceCard({
}} }}
> >
{/* ── Image — clean, no text overlay ── */} {/* ── Image — clean, no text overlay ── */}
<Box sx={{ position: 'relative', aspectRatio: '3/2', flexShrink: 0, bgcolor: '#f4f3f0', overflow: 'hidden' }}> <Box sx={{ position: 'relative', aspectRatio: '15/8', flexShrink: 0, bgcolor: '#f4f3f0', overflow: 'hidden' }}>
{hasImage ? ( {hasImage ? (
<Box component="img" src={p.images![0]} alt={p.title} <Box component="img" src={p.images![0]} alt={p.title}
sx={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} /> sx={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
@@ -85,24 +85,24 @@ export const PropertyIntelligenceCard = memo(function PropertyIntelligenceCard({
</Box> </Box>
{/* ── Body ── */} {/* ── Body ── */}
<Box sx={{ px: 2.25, pt: 1.75, pb: 2, display: 'flex', flexDirection: 'column', gap: 1.5, flex: 1 }}> <Box sx={{ px: 2.5, pt: 2.25, pb: 2.5, display: 'flex', flexDirection: 'column', gap: 2, flex: 1 }}>
{/* Title + location + status inline */} {/* Title + location + status inline */}
<Box> <Box>
<Typography sx={{ fontWeight: 600, fontSize: '0.9375rem', color: DS_TEXT.primary, lineHeight: 1.3 }} noWrap> <Typography sx={{ fontWeight: 600, fontSize: '1.0625rem', color: DS_TEXT.primary, lineHeight: 1.3 }} noWrap>
{p.title} {p.title}
</Typography> </Typography>
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mt: 0.4 }}> <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mt: 0.6 }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.4 }}> <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.4 }}>
<MapPin size={11} color="#9a9a9a" /> <MapPin size={12} color="#9a9a9a" />
<Typography sx={{ fontSize: '0.75rem', color: DS_TEXT.muted }}> <Typography sx={{ fontSize: '0.8125rem', color: DS_TEXT.muted }}>
{p.location.city}{p.location.district ? ` · ${p.location.district}` : ''} {p.location.city}{p.location.district ? ` · ${p.location.district}` : ''}
</Typography> </Typography>
</Box> </Box>
{/* Status — plain dot + text, no pill container */} {/* Status — plain dot + text, no pill container */}
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}> <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
<Box sx={{ width: 6, height: 6, borderRadius: '50%', bgcolor: status.dot, flexShrink: 0 }} /> <Box sx={{ width: 7, height: 7, borderRadius: '50%', bgcolor: status.dot, flexShrink: 0 }} />
<Typography sx={{ fontSize: '0.72rem', fontWeight: 500, color: status.text, lineHeight: 1 }}> <Typography sx={{ fontSize: '0.8rem', fontWeight: 500, color: status.text, lineHeight: 1 }}>
{status.label} {status.label}
{p.availabilityStatus === 'AVAILABLE_SOON' && availDate ? ` · ab ${availDate}` : ''} {p.availabilityStatus === 'AVAILABLE_SOON' && availDate ? ` · ab ${availDate}` : ''}
</Typography> </Typography>
@@ -111,26 +111,26 @@ export const PropertyIntelligenceCard = memo(function PropertyIntelligenceCard({
</Box> </Box>
{/* 3 key metrics — no boxes, whitespace only */} {/* 3 key metrics — no boxes, whitespace only */}
<Box sx={{ display: 'flex', gap: 2 }}> <Box sx={{ display: 'flex', gap: 2.5 }}>
<Box> <Box>
<Typography sx={{ fontSize: '0.68rem', color: DS_TEXT.muted, mb: 0.25 }}>Fläche</Typography> <Typography sx={{ fontSize: '0.75rem', color: DS_TEXT.muted, mb: 0.35 }}>Fläche</Typography>
<Typography sx={{ fontWeight: 600, fontSize: '0.875rem', color: DS_TEXT.primary }}> <Typography sx={{ fontWeight: 600, fontSize: '1rem', color: DS_TEXT.primary }}>
{p.areaSqm.toLocaleString('de-CH')} m² {p.areaSqm.toLocaleString('de-CH')} m²
</Typography> </Typography>
</Box> </Box>
<Box> <Box>
<Typography sx={{ fontSize: '0.68rem', color: DS_TEXT.muted, mb: 0.25 }}>Miete</Typography> <Typography sx={{ fontSize: '0.75rem', color: DS_TEXT.muted, mb: 0.35 }}>Miete</Typography>
<Typography sx={{ fontWeight: 600, fontSize: '0.875rem', color: DS_TEXT.primary }}> <Typography sx={{ fontWeight: 600, fontSize: '1rem', color: DS_TEXT.primary }}>
{p.rentPricePerSqm} {p.rentPricePerSqm}
<Typography component="span" sx={{ fontSize: '0.62rem', fontWeight: 400, color: DS_TEXT.muted }}> CHF/m²/J</Typography> <Typography component="span" sx={{ fontSize: '0.7rem', fontWeight: 400, color: DS_TEXT.muted }}> CHF/m²/J</Typography>
</Typography> </Typography>
</Box> </Box>
<Tooltip title={hasInquiries ? `${inquiryCount} aktive Anfragen` : 'Noch keine Anfragen'} placement="top" arrow> <Tooltip title={hasInquiries ? `${inquiryCount} aktive Anfragen` : 'Noch keine Anfragen'} placement="top" arrow>
<Box> <Box>
<Typography sx={{ fontSize: '0.68rem', color: DS_TEXT.muted, mb: 0.25 }}>Anfragen</Typography> <Typography sx={{ fontSize: '0.75rem', color: DS_TEXT.muted, mb: 0.35 }}>Anfragen</Typography>
<Typography sx={{ fontWeight: 600, fontSize: '0.875rem', color: hasInquiries ? '#a16207' : DS_TEXT.muted }}> <Typography sx={{ fontWeight: 600, fontSize: '1rem', color: hasInquiries ? '#a16207' : DS_TEXT.muted }}>
{inquiryCount ?? 0} {inquiryCount ?? 0}
</Typography> </Typography>
</Box> </Box>
@@ -139,27 +139,27 @@ export const PropertyIntelligenceCard = memo(function PropertyIntelligenceCard({
{/* Chips + Datenvollständigkeit in einer Zeile */} {/* Chips + Datenvollständigkeit in einer Zeile */}
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 1, mt: 'auto' }}> <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 1, mt: 'auto' }}>
<Box sx={{ display: 'flex', gap: 0.5, flexWrap: 'wrap', alignItems: 'center' }}> <Box sx={{ display: 'flex', gap: 0.75, flexWrap: 'wrap', alignItems: 'center' }}>
{p.hardFacts?.fitOut && (() => { {p.hardFacts?.fitOut && (() => {
const meta = FIT_OUT_META[p.hardFacts!.fitOut!] ?? { label: p.hardFacts!.fitOut!, tip: '' } const meta = FIT_OUT_META[p.hardFacts!.fitOut!] ?? { label: p.hardFacts!.fitOut!, tip: '' }
return ( return (
<Tooltip title={meta.tip} placement="top" arrow> <Tooltip title={meta.tip} placement="top" arrow>
<Chip label={meta.label} size="small" <Chip label={meta.label} size="small"
sx={{ height: 20, fontSize: '0.68rem', bgcolor: '#f4f3f0', color: DS_TEXT.secondary, border: `1px solid ${DS_BORDER.default}`, cursor: 'help' }} /> sx={{ height: 22, fontSize: '0.73rem', bgcolor: '#f4f3f0', color: DS_TEXT.secondary, border: `1px solid ${DS_BORDER.default}`, cursor: 'help' }} />
</Tooltip> </Tooltip>
) )
})()} })()}
{p.contractDurationMonths && ( {p.contractDurationMonths && (
<Chip label={`${p.contractDurationMonths}M Vertrag`} size="small" <Chip label={`${p.contractDurationMonths}M Vertrag`} size="small"
sx={{ height: 20, fontSize: '0.68rem', bgcolor: '#f4f3f0', color: DS_TEXT.secondary, border: `1px solid ${DS_BORDER.default}` }} /> sx={{ height: 22, fontSize: '0.73rem', bgcolor: '#f4f3f0', color: DS_TEXT.secondary, border: `1px solid ${DS_BORDER.default}` }} />
)} )}
</Box> </Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, flexShrink: 0 }}> <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, flexShrink: 0 }}>
<Typography sx={{ fontSize: '0.62rem', color: DS_TEXT.disabled }}>Daten</Typography> <Typography sx={{ fontSize: '0.68rem', color: DS_TEXT.disabled }}>Daten</Typography>
<LinearProgress variant="determinate" value={confPct} <LinearProgress variant="determinate" value={confPct}
sx={{ width: 40, height: 3, borderRadius: 1, bgcolor: '#f4f3f0', sx={{ width: 44, height: 3, borderRadius: 1, bgcolor: '#f4f3f0',
'& .MuiLinearProgress-bar': { bgcolor: '#152642', borderRadius: 1 } }} /> '& .MuiLinearProgress-bar': { bgcolor: '#152642', borderRadius: 1 } }} />
<Typography sx={{ fontSize: '0.72rem', fontWeight: 700, color: p.confidenceScore >= 0.75 ? '#b8975a' : DS_TEXT.muted }}> <Typography sx={{ fontSize: '0.78rem', fontWeight: 700, color: p.confidenceScore >= 0.75 ? '#b8975a' : DS_TEXT.muted }}>
{confPct}% {confPct}%
</Typography> </Typography>
</Box> </Box>