Python 67%
TypeScript 18.2%
CSS 14.4%
1// -----------------------------------------------------------------------------2// House-Ka — Homes-for-sale aggregator (Canada outside Québec, Ontario first)3// Author: Simon-Pierre Boucher — contact@spboucher.ai4// components/ListingCard.tsx : property card (results grid)5// -----------------------------------------------------------------------------6import { Link } from "react-router-dom";7import { Listing, fmtArea, fmtPrice, sourceName } from "../api";8import { Ico } from "./Icons";9import PropertyImg from "./PropertyImg";1011export default function ListingCard({ l }: { l: Listing }) {12 // light thumbnail when the connector provides one (mobile/cellular),13 // otherwise the full-size cover photo14 const img = (typeof l.details?.cover_thumb === "string" && l.details.cover_thumb)15 || (l.images && l.images.length > 0 ? l.images[0] : null);16 const rent = l.details?.transaction === "location";17 const meta: { ico: string; txt: string }[] = [];18 if (l.bedrooms != null) meta.push({ ico: "bed", txt: `${l.bedrooms} bed` });19 if (l.bathrooms != null) meta.push({ ico: "bath", txt: `${l.bathrooms} bath` });20 const area = fmtArea(l.area_sqft);21 if (area) meta.push({ ico: "area", txt: area });2223 return (24 <Link to={`/property/${encodeURIComponent(l.uid)}`} className="card">25 <div className="card-img">26 <PropertyImg src={img} alt={l.title || l.address} type={l.property_type} />27 {l.property_type && <span className="badge type">{l.property_type}</span>}28 {l.images.length > 1 && (29 <span className="badge right"><Ico name="camera" size={12} /> {l.images.length}</span>30 )}31 </div>32 <div className="card-body">33 <div className="card-price">34 {fmtPrice(l.price, l.price_label)}35 {rent && <span className="per-month"> /month</span>}36 </div>37 <div className="card-title">{l.address || l.title}</div>38 <div className="card-meta">39 {l.sector && <span>{l.sector}</span>}40 {l.sector && l.city && <span className="sep" />}41 {l.city && <span>{l.city}</span>}42 </div>43 {meta.length > 0 && (44 <div className="card-specs">45 {meta.map((m) => (46 <span key={m.ico}><Ico name={m.ico} size={13} /> {m.txt}</span>47 ))}48 </div>49 )}50 <div className="card-foot">51 <span className="source-tag">{sourceName(l.source)}</span>52 {l.mls && <span className="avail">MLS® {l.mls}</span>}53 </div>54 </div>55 </Link>56 );57}58