État du nœud — captures README régénérées en prod + Logo.tsx ; gitignore data/uploads/
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
11 changed files +106 −0
modified
.gitignore
+1 −0
@@ -12,3 +12,4 @@ data/quartier.db | |||||
| 12 | 12 | ||||
| 13 | # app iOS native — dépôt séparé (git.spboucher.ai/lou-ka-ios) | 13 | # app iOS native — dépôt séparé (git.spboucher.ai/lou-ka-ios) | ||
| 14 | /ios/ | 14 | /ios/ | ||
| 15 | +data/uploads/ | ||||
modified
docs/screenshots/accueil-mobile.png
+0 −0
Binary file not shown.
modified
docs/screenshots/accueil.png
+0 −0
Binary file not shown.
modified
docs/screenshots/annonces.jpg
+0 −0
Binary file not shown.
modified
docs/screenshots/carte.jpg
+0 −0
Binary file not shown.
modified
docs/screenshots/fiche-logement.jpg
+0 −0
Binary file not shown.
modified
docs/screenshots/sources.png
+0 −0
Binary file not shown.
modified
docs/screenshots/stats.png
+0 −0
Binary file not shown.
modified
docs/screenshots/ville-quebec.jpg
+0 −0
Binary file not shown.
modified
docs/screenshots/villes.jpg
+0 −0
Binary file not shown.
added
frontend/src/Logo.tsx
+105 −0
@@ -0,0 +1,105 @@ | |||||
| 1 | +// ----------------------------------------------------------------------------- | ||||
| 2 | +// Lou-Ka — Agrégateur de logements à louer (province de Québec) | ||||
| 3 | +// Auteur : Simon-Pierre Boucher — contact@spboucher.ai | ||||
| 4 | +// components/Logo.tsx : icône officielle Lou-Ka — la porte entrouverte qui | ||||
| 5 | +// laisse entrer la lumière. Spécifications géométriques (grille 100 × 100) : | ||||
| 6 | +// A. cadre : rect vertical 60 × 90 centré, rx 19 (squircle), contour seul | ||||
| 7 | +// 7,5 u, dégradé orange #FF7A1A → #F56000, extrémités arrondies ; | ||||
| 8 | +// B. porte : parallélogramme charnières à GAUCHE, ouverte ≈ 30° vers le | ||||
| 9 | +// spectateur, coins droits rapprochés verticalement (fuite ≈ 9°), marine | ||||
| 10 | +// #101A3D → #0B1330, coins adoucis ; coin de lumière (espace négatif) | ||||
| 11 | +// entre la porte et le cadre droit, s'élargissant vers le bas ; | ||||
| 12 | +// C. tapis de lumière : trapèze au seuil (≈ 30 u) s'évasant vers l'avant | ||||
| 13 | +// (≈ 49 u), bord avant arrondi touchant le trait bas du cadre, | ||||
| 14 | +// dégradé #FF8533 → #FF6A00. | ||||
| 15 | +// Ordre des calques : porte → tapis → cadre → reflet. Finition « liquid | ||||
| 16 | +// glass » : reflet blanc 28 % sur la courbe haute + ombre portée douce | ||||
| 17 | +// marine 14 %. Version flat (sans dégradés) : favicon + icône PWA. | ||||
| 18 | +// Baseline : « La porte d'entrée vers votre prochain chez-vous. » | ||||
| 19 | +// ----------------------------------------------------------------------------- | ||||
| 20 | + | ||||
| 21 | +/** Icône seule (fond transparent — pour fonds clairs ; dark = porte blanche). */ | ||||
| 22 | +export function LogoIcon({ size = 30, dark = false }: { size?: number; dark?: boolean }) { | ||||
| 23 | + // dark = version pour fond bleu marine : la porte devient blanche | ||||
| 24 | + const doorTop = dark ? "#ffffff" : "#101a3d"; | ||||
| 25 | + const doorBot = dark ? "#e8edf8" : "#0b1330"; | ||||
| 26 | + const uid = dark ? "lk-dark" : "lk-light-bg"; | ||||
| 27 | + return ( | ||||
| 28 | + <svg | ||||
| 29 | + className="logo-ico" | ||||
| 30 | + width={size} | ||||
| 31 | + height={size} | ||||
| 32 | + viewBox="0 0 100 100" | ||||
| 33 | + fill="none" | ||||
| 34 | + aria-hidden="true" | ||||
| 35 | + > | ||||
| 36 | + <defs> | ||||
| 37 | + {/* cadre : orange plus lumineux en haut, plus saturé en bas */} | ||||
| 38 | + <linearGradient id={`${uid}-frame`} x1="0" y1="0" x2="0" y2="1"> | ||||
| 39 | + <stop offset="0" stopColor="#ff7a1a" /> | ||||
| 40 | + <stop offset="1" stopColor="#f56000" /> | ||||
| 41 | + </linearGradient> | ||||
| 42 | + {/* porte : micro-dégradé de profondeur */} | ||||
| 43 | + <linearGradient id={`${uid}-door`} x1="0" y1="0" x2="0" y2="1"> | ||||
| 44 | + <stop offset="0" stopColor={doorTop} /> | ||||
| 45 | + <stop offset="1" stopColor={doorBot} /> | ||||
| 46 | + </linearGradient> | ||||
| 47 | + {/* tapis : lumière chaude qui se diffuse vers l'avant */} | ||||
| 48 | + <linearGradient id={`${uid}-light`} x1="0" y1="0" x2="0" y2="1"> | ||||
| 49 | + <stop offset="0" stopColor="#ff8533" /> | ||||
| 50 | + <stop offset="1" stopColor="#ff6a00" /> | ||||
| 51 | + </linearGradient> | ||||
| 52 | + {/* ombre portée très douce, teinte marine — jamais d'ombre dure */} | ||||
| 53 | + <filter id={`${uid}-soft`} x="-25%" y="-25%" width="150%" height="150%"> | ||||
| 54 | + <feDropShadow dx="0" dy="2" stdDeviation="3" floodColor="#0b1330" floodOpacity="0.14" /> | ||||
| 55 | + </filter> | ||||
| 56 | + </defs> | ||||
| 57 | + <g filter={`url(#${uid}-soft)`}> | ||||
| 58 | + {/* B — porte entrouverte : charnière gauche, fuite en perspective à droite ; | ||||
| 59 | + le coin de lumière (espace vide) s'élargit vers le bas */} | ||||
| 60 | + <path | ||||
| 61 | + d="M29 17 L66 22.5 L62 73.5 L29 79 Z" | ||||
| 62 | + fill={`url(#${uid}-door)`} | ||||
| 63 | + stroke={`url(#${uid}-door)`} | ||||
| 64 | + strokeWidth="4" | ||||
| 65 | + strokeLinejoin="round" | ||||
| 66 | + /> | ||||
| 67 | + {/* C — tapis de lumière : du seuil vers l'avant-droite, bord avant arrondi | ||||
| 68 | + qui touche le trait inférieur du cadre */} | ||||
| 69 | + <path | ||||
| 70 | + d="M37 77.4 L63 73.2 L74.8 88.5 Q76.4 92.5 71.6 92.5 L34.5 92.5 Q30.2 92.5 32 88.6 Z" | ||||
| 71 | + fill={`url(#${uid}-light)`} | ||||
| 72 | + /> | ||||
| 73 | + {/* A — cadre : contour seul, coins très arrondis (squircle vertical) */} | ||||
| 74 | + <rect | ||||
| 75 | + x="20" y="5" width="60" height="90" rx="19" | ||||
| 76 | + stroke={`url(#${uid}-frame)`} | ||||
| 77 | + strokeWidth="7.5" | ||||
| 78 | + strokeLinecap="round" | ||||
| 79 | + strokeLinejoin="round" | ||||
| 80 | + /> | ||||
| 81 | + {/* reflet spéculaire « liquid glass » sur la courbe supérieure */} | ||||
| 82 | + <path | ||||
| 83 | + d="M31 6.8 Q50 4.4 69 6.8" | ||||
| 84 | + stroke="#ffffff" | ||||
| 85 | + strokeOpacity="0.28" | ||||
| 86 | + strokeWidth="2.6" | ||||
| 87 | + strokeLinecap="round" | ||||
| 88 | + /> | ||||
| 89 | + </g> | ||||
| 90 | + </svg> | ||||
| 91 | + ); | ||||
| 92 | +} | ||||
| 93 | + | ||||
| 94 | +/** Logo horizontal complet : icône + wordmark « Lou-Ka » | ||||
| 95 | + * (Lou- marine, Ka orange ; espace icône↔texte ≈ 40 % de la largeur d'icône). */ | ||||
| 96 | +export default function Logo({ size = 30 }: { size?: number }) { | ||||
| 97 | + return ( | ||||
| 98 | + <span style={{ display: "inline-flex", alignItems: "center", gap: size * 0.4 * 0.6 }}> | ||||
| 99 | + <LogoIcon size={size} /> | ||||
| 100 | + <span style={{ color: "#0b1330", fontWeight: 700, letterSpacing: "-0.005em" }}> | ||||
| 101 | + Lou-<span style={{ color: "#ff6a00" }}>Ka</span> | ||||
| 102 | + </span> | ||||
| 103 | + </span> | ||||
| 104 | + ); | ||||
| 105 | +} | ||||
| 106 | |||||