Resto·Ka — tous les restaurants du Québec, menus complets et prix réels (famille ·Ka)
Python 69.3%
TypeScript 16.7%
CSS 7.9%
JavaScript 4.7%
HTML 1.4%
1// ==============================================================================2// Author: Simon-Pierre Boucher <contact@spboucher.ai>3// File: components/RestoCard.tsx4// Desc: Carte de restaurant (grille de résultats) — même patron que la5// ListingCard de Lou·Ka : prix en tête, badge de contexte de prix6// TOUJOURS affiché (CLAUDE.md §6.2), source en pied de carte.7// ==============================================================================8import { Link } from "react-router-dom";9import {10 CONTEXT_SHORT, Restaurant, cuisineLabel, fmtPrice, sourceName, typeLabel,11} from "../api";12import { FavButton } from "../favorites";13import { IcoPlate } from "./Icons";1415export default function RestoCard({ r }: { r: Restaurant }) {16 const ms = r.menu_summary;17 const img = ms?.image || (r.images ?? [])[1] || null; // photo de plat d'abord18 const logo = (r.images ?? [])[0] || null;19 return (20 <Link to={`/resto/${encodeURIComponent(r.uid)}`} className="card">21 <div className="card-img">22 {img ? (23 <img src={img} alt={r.name} loading="lazy" />24 ) : logo ? (25 <div className="noimg"><img className="card-logo" src={logo} alt={r.name} loading="lazy" /></div>26 ) : (27 <div className="noimg"><IcoPlate size={38} strokeWidth={1.6} /></div>28 )}29 {r.price_range && <span className="badge type">{r.price_range}</span>}30 {r.ka_reco && (31 <span32 className="badge ka-reco"33 title="Correspond à vos préférences KA ID — gérez-les sur groupe-ka.com/mon-ka"34 >35 Recommandé pour vous36 </span>37 )}38 {ms && (39 <span className={`badge right ctx ctx-${ms.price_context}`}>40 {CONTEXT_SHORT[ms.price_context] ?? ms.price_context}41 </span>42 )}43 <FavButton r={r} />44 </div>45 <div className="card-body">46 <div className="card-price">47 {ms?.price_median != null ? (48 <>49 {fmtPrice(ms.price_median)} <small>plat médian</small>50 </>51 ) : (52 <span className="no-menu">Menu à venir</span>53 )}54 </div>55 <div className="card-title">{r.name}</div>56 <div className="card-meta">57 <span>{typeLabel(r.establishment_type)}</span>58 {r.cuisines.slice(0, 2).map((c) => (59 <span key={c}>60 <span className="sep" /> {cuisineLabel(c)}61 </span>62 ))}63 </div>64 <div className="card-meta">65 {r.city && <span>{r.city}</span>}66 {r.city && r.region && <span className="sep" />}67 {r.region && <span>{r.region}</span>}68 </div>69 <div className="card-foot">70 <span className="source-tag">{sourceName(r.source)}</span>71 {ms && <span className="avail">{ms.item_count} plats au menu</span>}72 </div>73 </div>74 </Link>75 );76}77