spb/ora-ka Public
Ora-Ka — cinq agrégateurs Ka, une barre de recherche hybride (exact + sémantique)
Python 80%
TypeScript 12.9%
CSS 6.8%
1// -----------------------------------------------------------------------------2// Immo-Ka — Agrégateur de propriétés à vendre (province de Québec)3// Auteur : Simon-Pierre Boucher — contact@spboucher.ai4// components/ListingCard.tsx : carte de propriété (grille de résultats)5// -----------------------------------------------------------------------------6import { Link } from "react-router-dom";7import { Listing, fmtArea, fmtPrice, sourceName } from "../api";8import { Ico } from "./Icons";910export default function ListingCard({ l }: { l: Listing }) {11 const img = l.images && l.images.length > 0 ? l.images[0] : null;12 const meta: { ico: string; txt: string }[] = [];13 if (l.bedrooms != null) meta.push({ ico: "bed", txt: `${l.bedrooms} ch.` });14 if (l.bathrooms != null) meta.push({ ico: "bath", txt: `${l.bathrooms} sdb` });15 const area = fmtArea(l.area_sqft);16 if (area) meta.push({ ico: "area", txt: area });1718 return (19 <Link to={`/propriete/${encodeURIComponent(l.uid)}`} className="card">20 <div className="card-img">21 {img ? (22 <img src={img} alt={l.title || l.address} loading="lazy" />23 ) : (24 <div className="noimg"><Ico name="home" size={34} /></div>25 )}26 {l.property_type && <span className="badge type">{l.property_type}</span>}27 {l.images.length > 1 && (28 <span className="badge right"><Ico name="camera" size={12} /> {l.images.length}</span>29 )}30 </div>31 <div className="card-body">32 <div className="card-price">{fmtPrice(l.price, l.price_label)}</div>33 <div className="card-title">{l.address || l.title}</div>34 <div className="card-meta">35 {l.sector && <span>{l.sector}</span>}36 {l.sector && l.city && <span className="sep" />}37 {l.city && <span>{l.city}</span>}38 </div>39 {meta.length > 0 && (40 <div className="card-specs">41 {meta.map((m) => (42 <span key={m.ico}><Ico name={m.ico} size={13} /> {m.txt}</span>43 ))}44 </div>45 )}46 <div className="card-foot">47 <span className="source-tag">{sourceName(l.source)}</span>48 {l.mls && <span className="avail">MLS {l.mls}</span>}49 </div>50 </div>51 </Link>52 );53}54