SPB Git

spb/lou-ka

Public

Lou·Ka — tous les logements à louer du Québec, un seul endroit.

Identité visuelle officielle Lou-Ka — palette marine #0B1330 / bleu vif #2258FF / orange #FF6A00 / gris #F2F2F2 ; logo « porte entrouverte » (Logo.tsx, favicon + icône PWA sur carré marine) ; wordmark Lou-Ka (Ka orange) ; baseline « La porte d'entrée vers votre prochain chez-vous. » ; héro « Trouvez votre prochain chez-vous. » + rangée des 4 avantages ; Inter partout (fin de Space Grotesk/JetBrains Mono) ; coins très arrondis + pill-shaped + ombres douces (styles.css réécrit, mêmes sélecteurs) ; barre de nav mobile 4 onglets (active orange) ; thème Ka Maps marine/orange + immeuble 3D orange ; PDF (pdfgen.py) et SSR SEO alignés

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Simon-Pierre Boucher committed (Aug 15, 2026) parent 2aed158 Browse files

13 changed files +744 −554

modified frontend/index.html +3 −3
@@ -9,7 +9,7 @@
9 <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" /> 9 <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
10 <title>Lou-Ka — Logements à louer au Québec</title> 10 <title>Lou-Ka — Logements à louer au Québec</title>
11 <meta name="description" content="Lou-Ka agrège les appartements et logements à louer publiés par les gestionnaires immobiliers partout au Québec — Montréal, Québec, Lévis, Gatineau et plus — toujours à jour." /> 11 <meta name="description" content="Lou-Ka agrège les appartements et logements à louer publiés par les gestionnaires immobiliers partout au Québec — Montréal, Québec, Lévis, Gatineau et plus — toujours à jour." />
12− <meta name="theme-color" content="#f5f3ee" /> 12+ <meta name="theme-color" content="#ffffff" />
13 <meta name="mobile-web-app-capable" content="yes" /> 13 <meta name="mobile-web-app-capable" content="yes" />
14 <meta name="apple-mobile-web-app-capable" content="yes" /> 14 <meta name="apple-mobile-web-app-capable" content="yes" />
15 <meta name="apple-mobile-web-app-status-bar-style" content="default" /> 15 <meta name="apple-mobile-web-app-status-bar-style" content="default" />
@@ -17,8 +17,8 @@
17 <link rel="manifest" href="/manifest.webmanifest" /> 17 <link rel="manifest" href="/manifest.webmanifest" />
18 <link rel="preconnect" href="https://fonts.googleapis.com" /> 18 <link rel="preconnect" href="https://fonts.googleapis.com" />
19 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> 19 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
20− <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet" /> 20+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
21− <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='12' fill='%23121712'/%3E%3Ctext x='32' y='45' font-family='Arial Black,sans-serif' font-size='32' font-weight='900' fill='%23d9f26b' text-anchor='middle'%3ELK%3C/text%3E%3C/svg%3E" /> 21+ <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%230B1330'/%3E%3Crect x='19' y='9' width='26' height='46' rx='8' fill='none' stroke='%23FF6A00' stroke-width='4'/%3E%3Cpolygon points='24.5,16 36,13.5 36,49 24.5,46' fill='%23ffffff'/%3E%3Cpolygon points='24.5,46 36,49 42,52.5 24.5,52.5' fill='%23FF6A00'/%3E%3C/svg%3E" />
22 </head> 22 </head>
23 <body> 23 <body>
24 <div id="root"></div> 24 <div id="root"></div>
modified frontend/public/manifest.webmanifest +4 −4
@@ -1,15 +1,15 @@
1 { 1 {
2 "name": "Lou-Ka — Logements à louer au Québec", 2 "name": "Lou-Ka — Logements à louer au Québec",
3 "short_name": "Lou-Ka", 3 "short_name": "Lou-Ka",
4− "description": "Tous les logements à louer de Québec et Lévis, un seul endroit.", 4+ "description": "La porte d'entrée vers votre prochain chez-vous. Tous les logements à louer au Québec, regroupés au même endroit.",
5 "start_url": "/", 5 "start_url": "/",
6 "display": "standalone", 6 "display": "standalone",
7− "background_color": "#f5f3ee", 7+ "background_color": "#ffffff",
8− "theme_color": "#f5f3ee", 8+ "theme_color": "#0b1330",
9 "lang": "fr", 9 "lang": "fr",
10 "icons": [ 10 "icons": [
11 { 11 {
12− "src": "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Crect width='512' height='512' rx='96' fill='%23121712'/%3E%3Ctext x='256' y='356' font-family='Arial Black,sans-serif' font-size='256' font-weight='900' fill='%23d9f26b' text-anchor='middle'%3ELK%3C/text%3E%3C/svg%3E", 12+ "src": "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Crect width='512' height='512' rx='112' fill='%230B1330'/%3E%3Crect x='152' y='72' width='208' height='368' rx='64' fill='none' stroke='%23FF6A00' stroke-width='32'/%3E%3Cpolygon points='196,128 288,108 288,392 196,368' fill='%23ffffff'/%3E%3Cpolygon points='196,368 288,392 336,420 196,420' fill='%23FF6A00'/%3E%3C/svg%3E",
13 "sizes": "512x512", 13 "sizes": "512x512",
14 "type": "image/svg+xml", 14 "type": "image/svg+xml",
15 "purpose": "any" 15 "purpose": "any"
modified frontend/src/App.tsx +38 −9
@@ -12,8 +12,10 @@ import {
12 import { AccountProvider, useAccount } from "./account"; 12 import { AccountProvider, useAccount } from "./account";
13 import CookieConsent from "./components/CookieConsent"; 13 import CookieConsent from "./components/CookieConsent";
14 import { 14 import {
15− IcoChart, IcoCompass, IcoDoc, IcoFolder, IcoHouse, IcoLock, IcoMap, 15+ IcoChart, IcoCompass, IcoDoc, IcoFolder, IcoHeart, IcoHouse, IcoLock,
16+ IcoMap, IcoSearch, IcoUser,
16 } from "./components/Icons"; 17 } from "./components/Icons";
18+import { LogoIcon } from "./components/Logo";
17 import Home from "./pages/Home"; 19 import Home from "./pages/Home";
18 import ListingPage from "./pages/Listing"; 20 import ListingPage from "./pages/Listing";
19 import BotPage from "./pages/Bot"; 21 import BotPage from "./pages/Bot";
@@ -97,12 +99,11 @@ function AccountMenu() {
97 justifyContent: "center", 99 justifyContent: "center",
98 width: 18, 100 width: 18,
99 height: 16, 101 height: 16,
100− borderRadius: 4, 102+ borderRadius: 5,
101− background: "#141814", 103+ background: "#ff6a00",
102− color: "#d9f26b", 104+ color: "#ffffff",
103− font: "700 9px/1 'Space Grotesk', system-ui, sans-serif", 105+ font: "700 9px/1 'Inter', system-ui, sans-serif",
104 letterSpacing: "-0.02em", 106 letterSpacing: "-0.02em",
105− transform: "rotate(-2deg)",
106 }} 107 }}
107 > 108 >
108 KA 109 KA
@@ -199,8 +200,9 @@ function Header() {
199 <header className="header"> 200 <header className="header">
200 <div className="container header-inner"> 201 <div className="container header-inner">
201 <NavLink to="/" className="brand" aria-label="Lou-Ka — accueil"> 202 <NavLink to="/" className="brand" aria-label="Lou-Ka — accueil">
202− Lou<span className="ka">Ka</span> 203+ <LogoIcon size={30} />
203− <span className="brand-tag">Québec · Lévis · Montréal — toujours à jour</span> 204+ Lou-<span className="ka">Ka</span>
205+ <span className="brand-tag">La porte d'entrée vers votre prochain chez-vous.</span>
204 </NavLink> 206 </NavLink>
205 <nav className="nav" aria-label="Navigation principale"> 207 <nav className="nav" aria-label="Navigation principale">
206 <NavLink to="/" end className={({ isActive }) => (isActive ? "active" : "")}> 208 <NavLink to="/" end className={({ isActive }) => (isActive ? "active" : "")}>
@@ -258,7 +260,11 @@ function Footer() {
258 <footer className="footer"> 260 <footer className="footer">
259 <div className="container"> 261 <div className="container">
260 <div className="fbrand"> 262 <div className="fbrand">
261− Lou<span className="ka">Ka</span> 263+ <LogoIcon size={32} dark />
264+ Lou-<span className="ka">Ka</span>
265+ </div>
266+ <div className="fbaseline">
267+ La porte d'entrée vers votre prochain <span className="hl">chez-vous.</span>
262 </div> 268 </div>
263 <div className="frow"> 269 <div className="frow">
264 <div> 270 <div>
@@ -294,6 +300,28 @@ function Footer() {
294 ); 300 );
295 } 301 }
296 302
303+/** Barre de navigation inférieure (mobile) — icône active en orange. */
304+function MobileTabBar() {
305+ const location = useLocation();
306+ const isCarte = new URLSearchParams(location.search).get("view") === "carte";
307+ const tabs = [
308+ { to: "/", label: "Rechercher", icon: <IcoSearch size={20} />, on: location.pathname === "/" && !isCarte },
309+ { to: "/?view=carte", label: "Carte", icon: <IcoMap size={20} />, on: location.pathname === "/" && isCarte },
310+ { to: "/favoris", label: "Favoris", icon: <IcoHeart size={20} />, on: location.pathname.startsWith("/favoris") },
311+ { to: "/profil", label: "Profil", icon: <IcoUser size={20} />, on: location.pathname.startsWith("/profil") },
312+ ];
313+ return (
314+ <nav className="tabbar" aria-label="Navigation mobile">
315+ {tabs.map((t) => (
316+ <NavLink key={t.label} to={t.to} className={() => (t.on ? "active" : "")}>
317+ {t.icon}
318+ {t.label}
319+ </NavLink>
320+ ))}
321+ </nav>
322+ );
323+}
324+
297 export default function App() { 325 export default function App() {
298 return ( 326 return (
299 <AccountProvider> 327 <AccountProvider>
@@ -330,6 +358,7 @@ export default function App() {
330 </Routes> 358 </Routes>
331 </main> 359 </main>
332 <Footer /> 360 <Footer />
361+ <MobileTabBar />
333 <CookieConsent /> 362 <CookieConsent />
334 </AccountProvider> 363 </AccountProvider>
335 ); 364 );
modified frontend/src/components/Icons.tsx +12 −5
@@ -1,9 +1,9 @@
1 // ----------------------------------------------------------------------------- 1 // -----------------------------------------------------------------------------
2 // Lou-Ka — Agrégateur de logements à louer (province de Québec) 2 // Lou-Ka — Agrégateur de logements à louer (province de Québec)
3 // Auteur : Simon-Pierre Boucher — contact@spboucher.ai 3 // Auteur : Simon-Pierre Boucher — contact@spboucher.ai
4−// components/Icons.tsx : icônes SVG maison « éditorial sharp » 4+// components/Icons.tsx : icônes SVG maison — style linéaire (outline),
5−// Tracés au trait (stroke) 2 px, coins vifs (square/miter), currentColor — 5+// trait moyen 2 px, extrémités arrondies, currentColor — conformes à
6−// remplacent les emojis génériques pour coller à l'identité de l'app. 6+// l'identité visuelle Lou-Ka (minimaliste et chaleureuse).
7 // ----------------------------------------------------------------------------- 7 // -----------------------------------------------------------------------------
8 import { SVGProps } from "react"; 8 import { SVGProps } from "react";
9 9
@@ -13,8 +13,8 @@ function Base({ size = 16, children, ...rest }: P) {
13 return ( 13 return (
14 <svg 14 <svg
15 width={size} height={size} viewBox="0 0 24 24" fill="none" 15 width={size} height={size} viewBox="0 0 24 24" fill="none"
16− stroke="currentColor" strokeWidth="2" strokeLinecap="square" 16+ stroke="currentColor" strokeWidth="2" strokeLinecap="round"
17− strokeLinejoin="miter" aria-hidden="true" focusable="false" {...rest} 17+ strokeLinejoin="round" aria-hidden="true" focusable="false" {...rest}
18 > 18 >
19 {children} 19 {children}
20 </svg> 20 </svg>
@@ -163,6 +163,13 @@ export const IcoHeart = (p: P & { filled?: boolean }) => {
163 163
164 // -- réseaux sociaux (tracés au trait, même langage que le reste) -------------- 164 // -- réseaux sociaux (tracés au trait, même langage que le reste) --------------
165 165
166+export const IcoUser = (p: P) => (
167+ <Base {...p}>
168+ <circle cx="12" cy="8" r="3.5" />
169+ <path d="M5 20c1.2-3.4 3.8-5 7-5s5.8 1.6 7 5" />
170+ </Base>
171+);
172+
166 export const IcoInstagram = (p: P) => ( 173 export const IcoInstagram = (p: P) => (
167 <Base {...p}> 174 <Base {...p}>
168 <rect x="4" y="4" width="16" height="16" rx="4.5" /> 175 <rect x="4" y="4" width="16" height="16" rx="4.5" />
modified frontend/src/components/ListingMap3D.tsx +2 −2
@@ -17,7 +17,7 @@ import { louKaMapTheme } from "../kamaps/theme";
17 import { MAPBOX_TOKEN } from "../kamaps/config"; 17 import { MAPBOX_TOKEN } from "../kamaps/config";
18 18
19 /** Rouge signal de la fiche — même langage que les badges d'alerte. */ 19 /** Rouge signal de la fiche — même langage que les badges d'alerte. */
20−export const BUILDING_RED = "#e03131"; 20+export const BUILDING_RED = "#ff6a00"; // orange officiel Lou-Ka
21 21
22 export default function ListingMap3D({ l }: { l: Listing }) { 22 export default function ListingMap3D({ l }: { l: Listing }) {
23 const property = useMemo<MapProperty | null>(() => { 23 const property = useMemo<MapProperty | null>(() => {
@@ -41,7 +41,7 @@ export default function ListingMap3D({ l }: { l: Listing }) {
41 41
42 return ( 42 return (
43 <div className="lmap3d" role="img" 43 <div className="lmap3d" role="img"
44− aria-label={`Carte 3D — ${l.address || l.title}, bâtiment de l'annonce en rouge`}> 44+ aria-label={`Carte 3D — ${l.address || l.title}, bâtiment de l'annonce en orange`}>
45 <KaSpotlightMap 45 <KaSpotlightMap
46 theme={louKaMapTheme} 46 theme={louKaMapTheme}
47 mapboxToken={MAPBOX_TOKEN} 47 mapboxToken={MAPBOX_TOKEN}
added frontend/src/components/Logo.tsx +62 −0
@@ -0,0 +1,62 @@
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 d'entrée.
5+// Cadre orange #FF6A00 aux coins très arrondis ; porte entrouverte bleu
6+// marine #0B1330 en perspective (ouverture vers la droite) ; tapis de
7+// lumière orange projeté au sol. Effet « liquid glass » subtil.
8+// Baseline : « La porte d'entrée vers votre prochain chez-vous. »
9+// -----------------------------------------------------------------------------
10+
11+/** Icône seule (fond transparent — pour fonds clairs). */
12+export function LogoIcon({ size = 30, dark = false }: { size?: number; dark?: boolean }) {
13+ // dark = version pour fond bleu marine : la porte devient blanche
14+ const door = dark ? "#ffffff" : "#0b1330";
15+ const doorTop = dark ? "#ffffff" : "#16204a";
16+ const uid = dark ? "lk-dark" : "lk-light-bg";
17+ return (
18+ <svg
19+ className="logo-ico"
20+ width={size}
21+ height={size}
22+ viewBox="0 0 64 64"
23+ fill="none"
24+ aria-hidden="true"
25+ >
26+ <defs>
27+ <linearGradient id={`${uid}-door`} x1="0" y1="0" x2="0" y2="1">
28+ <stop offset="0" stopColor={doorTop} />
29+ <stop offset="1" stopColor={door} />
30+ </linearGradient>
31+ <linearGradient id={`${uid}-light`} x1="0" y1="0" x2="1" y2="0">
32+ <stop offset="0" stopColor="#ff6a00" />
33+ <stop offset="1" stopColor="#ff6a00" stopOpacity="0.72" />
34+ </linearGradient>
35+ <linearGradient id={`${uid}-frame`} x1="0" y1="0" x2="0" y2="1">
36+ <stop offset="0" stopColor="#ff7d1f" />
37+ <stop offset="1" stopColor="#ff6a00" />
38+ </linearGradient>
39+ </defs>
40+ {/* cadre : rectangle vertical, coins très arrondis, contour orange épais */}
41+ <rect x="15" y="5" width="34" height="54" rx="10" stroke={`url(#${uid}-frame)`} strokeWidth="4.5" />
42+ {/* porte entrouverte : parallélogramme en perspective, bord droit plus proche */}
43+ <polygon points="22,13.5 37,10.5 37,52 22,48.5" fill={`url(#${uid}-door)`} />
44+ {/* reflet « liquid glass » sur la porte */}
45+ <polygon points="24,13.2 28,12.4 28,49 24,48.2" fill="#ffffff" opacity="0.08" />
46+ {/* lumière projetée au sol — tapis d'accueil */}
47+ <polygon points="22,48.5 37,52 44.5,55.8 22,55.8" fill={`url(#${uid}-light)`} />
48+ </svg>
49+ );
50+}
51+
52+/** Wordmark complet : icône + « Lou-Ka » (Lou- marine, Ka orange). */
53+export default function Logo({ size = 30 }: { size?: number }) {
54+ return (
55+ <span style={{ display: "inline-flex", alignItems: "center" }}>
56+ <LogoIcon size={size} />
57+ <span style={{ color: "#0b1330", fontWeight: 700 }}>
58+ Lou-<span style={{ color: "#ff6a00" }}>Ka</span>
59+ </span>
60+ </span>
61+ );
62+}
modified frontend/src/kamaps/theme.ts +43 −43
@@ -2,75 +2,75 @@
2 // Author: Simon-Pierre Boucher 2 // Author: Simon-Pierre Boucher
3 // Contact: contact@spboucher.ai 3 // Contact: contact@spboucher.ai
4 // Project: Groupe Ka / Ka Maps (Lou-Ka integration) 4 // Project: Groupe Ka / Ka Maps (Lou-Ka integration)
5−// kamaps/theme.ts : thème Lou-Ka Maps — les jetons du design system 5+// kamaps/theme.ts : thème Lou-Ka Maps — identité officielle Lou-Ka
6−// (encre/lime/vert « éditorial sharp ») appliqués au framework Ka Maps. 6+// (marine #0B1330 / bleu vif #2258FF / orange #FF6A00) appliquée à Ka Maps.
7 // ----------------------------------------------------------------------------- 7 // -----------------------------------------------------------------------------
8 import type { KaMapTheme } from "@groupe-ka/ka-maps"; 8 import type { KaMapTheme } from "@groupe-ka/ka-maps";
9 9
10−const INK = "#141814"; 10+const NAVY = "#0b1330";
11−const PAPER = "#f5f3ee"; 11+const BLUE = "#2258ff";
12−const GREEN = "#1c5c41"; 12+const ORANGE = "#ff6a00";
13−const LIME = "#d9f26b"; 13+const WHITE = "#ffffff";
14 14
15 export const louKaMapTheme: KaMapTheme = { 15 export const louKaMapTheme: KaMapTheme = {
16 id: "lou-ka", 16 id: "lou-ka",
17 productName: "Lou-Ka Maps", 17 productName: "Lou-Ka Maps",
18− accent: GREEN, 18+ accent: BLUE,
19− onAccent: LIME, 19+ onAccent: WHITE,
20 fontFamily: 20 fontFamily:
21 '"Inter", system-ui, -apple-system, "Segoe UI", sans-serif', 21 '"Inter", system-ui, -apple-system, "Segoe UI", sans-serif',
22 markers: { 22 markers: {
23− // Prix : pastille encre, texte BLANC — contraste maximal sur fond clair. 23+ // Prix : pastille bleu marine, texte BLANC — contraste maximal sur fond clair.
24− // Le lime n'apparaît qu'à la sélection (le moment de marque). 24+ // L'orange n'apparaît qu'à la sélection (le moment de marque).
25 sale: { 25 sale: {
26− background: INK, 26+ background: NAVY,
27− text: "#ffffff", 27+ text: WHITE,
28 halo: "rgba(255,255,255,0.45)", 28 halo: "rgba(255,255,255,0.45)",
29− selectedBackground: LIME, 29+ selectedBackground: ORANGE,
30− selectedText: INK, 30+ selectedText: WHITE,
31 }, 31 },
32 rent: { 32 rent: {
33− background: INK, 33+ background: NAVY,
34− text: "#ffffff", 34+ text: WHITE,
35 halo: "rgba(255,255,255,0.45)", 35 halo: "rgba(255,255,255,0.45)",
36− selectedBackground: LIME, 36+ selectedBackground: ORANGE,
37− selectedText: INK, 37+ selectedText: WHITE,
38 }, 38 },
39 highlight: { 39 highlight: {
40− background: GREEN, 40+ background: BLUE,
41− text: "#ffffff", 41+ text: WHITE,
42 halo: "rgba(255,255,255,0.45)", 42 halo: "rgba(255,255,255,0.45)",
43− selectedBackground: LIME, 43+ selectedBackground: ORANGE,
44− selectedText: INK, 44+ selectedText: WHITE,
45 }, 45 },
46 }, 46 },
47 cluster: { 47 cluster: {
48− background: INK, 48+ background: NAVY,
49− text: "#ffffff", 49+ text: WHITE,
50− border: LIME, 50+ border: ORANGE,
51 }, 51 },
52− // Cartographie Lou-Ka : fond neutre et raffiné — papier chaud discret, 52+ // Cartographie Lou-Ka : fond neutre et raffiné — gris très pâle,
53− // eau bleu-gris désaturé, parcs verts subtils, bâtiments bien définis. 53+ // eau bleu désaturé, parcs verts subtils, bâtiments bien définis.
54 // Les prix restent l'élément dominant de la carte. 54 // Les prix restent l'élément dominant de la carte.
55 basemapOverrides: { 55 basemapOverrides: {
56 light: { 56 light: {
57− background: "#f6f5f1", 57+ background: "#f7f8fa",
58− residential: "#efeee8", 58+ residential: "#f0f1f4",
59− water: "#c3d6df", 59+ water: "#c9d8ef",
60− waterway: "#b8cdd8", 60+ waterway: "#bfd0ea",
61− park: "#dde8d1", 61+ park: "#dce8d8",
62− wood: "#d2e0c4", 62+ wood: "#d0e0ca",
63− building: "#e7e4db", 63+ building: "#e6e8ee",
64− buildingOutline: "#d2cec1", 64+ buildingOutline: "#d0d3dd",
65 road: "#ffffff", 65 road: "#ffffff",
66− roadCasing: "#dcd8cc", 66+ roadCasing: "#dcdee6",
67− motorway: "#f0e9d0", 67+ motorway: "#f4ede2",
68− boundary: "#b0a998", 68+ boundary: "#a9adbd",
69− label: "#474b45", 69+ label: "#3e4560",
70− labelHalo: "rgba(246,245,241,0.92)", 70+ labelHalo: "rgba(247,248,250,0.92)",
71− cityLabel: "#1f231e", 71+ cityLabel: "#0b1330",
72− roadLabel: "#8b8d82", 72+ roadLabel: "#8a90a5",
73− waterLabel: "#5c7c8c", 73+ waterLabel: "#5c74a8",
74 }, 74 },
75 }, 75 },
76 supportsDark: false, 76 supportsDark: false,
modified frontend/src/pages/Home.tsx +25 −8
@@ -15,7 +15,8 @@ import {
15 import ListingCard from "../components/ListingCard"; 15 import ListingCard from "../components/ListingCard";
16 import Pager from "../components/Pager"; 16 import Pager from "../components/Pager";
17 import { 17 import {
18− IcoAlert, IcoBolt, IcoList, IcoMap, IcoPaw, IcoSearch, IcoSliders, IcoSofa, 18+ IcoAlert, IcoBolt, IcoHeart, IcoHouse, IcoList, IcoMap, IcoPaw, IcoPin,
19+ IcoSearch, IcoSliders, IcoSofa,
19 } from "../components/Icons"; 20 } from "../components/Icons";
20 21
21 // La carte (MapLibre, ~220 ko) n'est chargée que si l'utilisateur l'ouvre 22 // La carte (MapLibre, ~220 ko) n'est chargée que si l'utilisateur l'ouvre
@@ -196,16 +197,32 @@ export default function Home() {
196 return ( 197 return (
197 <div className="container"> 198 <div className="container">
198 <section className="hero"> 199 <section className="hero">
199− <span className="kicker">Agrégateur — Québec · Lévis · Montréal</span> 200+ <span className="kicker">La porte d'entrée vers votre prochain chez-vous.</span>
200 <h1> 201 <h1>
201− Tous les logements <span className="outline">à louer</span>,<br /> 202+ Trouvez votre prochain <span className="hl">chez-vous.</span>
202− <span className="hl">un seul</span> endroit.
203 </h1> 203 </h1>
204 <p className="lede"> 204 <p className="lede">
205− Lou-Ka rassemble les appartements affichés par les gestionnaires immobiliers du 205+ Tous les logements à louer au Québec, regroupés au même endroit — mis à jour
206− Québec — Québec, Lévis et le Grand Montréal — mis à jour automatiquement, avec 206+ automatiquement, avec toutes les photos et un lien direct vers l'annonce originale.
207− toutes les photos et un lien direct vers l'annonce originale.
208 </p> 207 </p>
208+ <div className="benefits" aria-label="Avantages">
209+ <div className="benefit">
210+ <span className="benefit-ico"><IcoHouse size={20} /></span>
211+ <span className="benefit-label">Nouveaux logements</span>
212+ </div>
213+ <div className="benefit">
214+ <span className="benefit-ico"><IcoSearch size={20} /></span>
215+ <span className="benefit-label">Recherche facile</span>
216+ </div>
217+ <div className="benefit">
218+ <span className="benefit-ico"><IcoHeart size={20} /></span>
219+ <span className="benefit-label">Favoris et alertes</span>
220+ </div>
221+ <div className="benefit">
222+ <span className="benefit-ico blue"><IcoPin size={20} /></span>
223+ <span className="benefit-label">Partout au Québec</span>
224+ </div>
225+ </div>
209 <div className="stat-row"> 226 <div className="stat-row">
210 <span className="stat-chip"><span className="pulse" /> Données synchronisées en continu</span> 227 <span className="stat-chip"><span className="pulse" /> Données synchronisées en continu</span>
211 {stats && ( 228 {stats && (
@@ -245,7 +262,7 @@ export default function Home() {
245 <div className="f-search"> 262 <div className="f-search">
246 <IcoSearch size={15} strokeWidth={2.4} /> 263 <IcoSearch size={15} strokeWidth={2.4} />
247 <input 264 <input
248− id="f-q" placeholder="Adresse, quartier, rue…" value={q} 265+ id="f-q" placeholder="Ville, quartier ou code postal" value={q}
249 onChange={(e) => setQ(e.target.value)} 266 onChange={(e) => setQ(e.target.value)}
250 aria-label="Recherche" 267 aria-label="Recherche"
251 /> 268 />
modified frontend/src/pages/Listing.tsx +1 −1
@@ -342,7 +342,7 @@ export default function ListingPage() {
342 <ListingMap3D l={l} /> 342 <ListingMap3D l={l} />
343 </Suspense> 343 </Suspense>
344 <p className="fine"> 344 <p className="fine">
345− Vue 3D du secteur — l'immeuble de l'annonce est surligné en rouge. 345+ Vue 3D du secteur — l'immeuble de l'annonce est surligné en orange.
346 Position selon l'adresse géocodée (Adresses Québec). 346 Position selon l'adresse géocodée (Adresses Québec).
347 </p> 347 </p>
348 </section> 348 </section>
modified frontend/src/styles.css +537 −462
Large diff (1,790 lines) is not loaded by default to keep the page fast.Load diff
modified frontend/tsconfig.tsbuildinfo +1 −1
Large diff (4 lines) is not loaded by default to keep the page fast.Load diff
modified louka/pdfgen.py +15 −15
Large diff (47 lines) is not loaded by default to keep the page fast.Load diff
modified louka/seo.py +1 −1
Large diff (9 lines) is not loaded by default to keep the page fast.Load diff
Menu

Theme