Navigation mobile : tabbar flottante (meme langage que Lou-Ka v2)
- Nouveau MobileTabBar : Decouvrir (/), Carte (/?view=carte), Taux (/taux-hypothecaires), Profil — pilule detachee des bords (radius 18, hairline, blur, ombre portee), trait cerise sous l onglet actif - Icones fines (stroke 1.6) du set Ico existant ; etat actif Carte deduit du parametre d URL view=carte comme sur Lou-Ka - body et ka-footer compenses sous 760px ; widget KA Agent remonte au-dessus de la barre (surcharge a specificite doublee, style injecte apres bundle)
2 changed files +56 −0
modified
frontend/src/App.tsx
+24 −0
@@ -230,6 +230,29 @@ const LOCAL_LEGAL = [ | ||
| 230 | 230 | { label: "Contact", href: "/contact" }, |
| 231 | 231 | ]; |
| 232 | 232 | |
| 233 | +/** Barre de navigation inférieure (mobile) — pilule flottante détachée des | |
| 234 | + bords, trait cerise sous l'onglet actif (même langage que Lou-Ka v2). */ | |
| 235 | +function MobileTabBar() { | |
| 236 | + const location = useLocation(); | |
| 237 | + const isCarte = new URLSearchParams(location.search).get("view") === "carte"; | |
| 238 | + const tabs = [ | |
| 239 | + { to: "/", label: "Découvrir", icon: <Ico name="search" size={20} stroke={1.6} />, on: location.pathname === "/" && !isCarte }, | |
| 240 | + { to: "/?view=carte", label: "Carte", icon: <Ico name="map" size={20} stroke={1.6} />, on: location.pathname === "/" && isCarte }, | |
| 241 | + { to: "/taux-hypothecaires", label: "Taux", icon: <Ico name="trendup" size={20} stroke={1.6} />, on: location.pathname.startsWith("/taux") }, | |
| 242 | + { to: "/profil", label: "Profil", icon: <Ico name="people" size={20} stroke={1.6} />, on: location.pathname.startsWith("/profil") }, | |
| 243 | + ]; | |
| 244 | + return ( | |
| 245 | + <nav className="tabbar" aria-label="Navigation mobile"> | |
| 246 | + {tabs.map((t) => ( | |
| 247 | + <NavLink key={t.label} to={t.to} className={() => (t.on ? "active" : "")}> | |
| 248 | + {t.icon} | |
| 249 | + {t.label} | |
| 250 | + </NavLink> | |
| 251 | + ))} | |
| 252 | + </nav> | |
| 253 | + ); | |
| 254 | +} | |
| 255 | + | |
| 233 | 256 | export default function App() { |
| 234 | 257 | return ( |
| 235 | 258 | <> |
@@ -263,6 +286,7 @@ export default function App() { | ||
| 263 | 286 | /> |
| 264 | 287 | </Routes> |
| 265 | 288 | </main> |
| 289 | + <MobileTabBar /> | |
| 266 | 290 | <KaFooter siteId="immo-ka" localLegal={LOCAL_LEGAL} /> |
| 267 | 291 | </> |
| 268 | 292 | ); |
modified
frontend/src/styles.css
+32 −0
@@ -1609,3 +1609,35 @@ table.rooms tbody tr:hover td { background: var(--accent-soft); } | ||
| 1609 | 1609 | box-shadow: 0 -14px 18px -12px rgba(20, 24, 20, 0.35); |
| 1610 | 1610 | } |
| 1611 | 1611 | } |
| 1612 | + | |
| 1613 | +/* ---- Navigation mobile flottante (pilule détachée du bord) ---- */ | |
| 1614 | +.tabbar { display: none; } | |
| 1615 | +@media (max-width: 760px) { | |
| 1616 | + .tabbar { | |
| 1617 | + display: grid; grid-template-columns: repeat(4, 1fr); | |
| 1618 | + position: fixed; left: 12px; right: 12px; | |
| 1619 | + bottom: calc(10px + env(safe-area-inset-bottom)); | |
| 1620 | + z-index: var(--z-bottombar, 600); | |
| 1621 | + border: 1px solid var(--hairline-strong); border-radius: var(--r-3); | |
| 1622 | + background: rgba(250, 249, 245, 0.88); | |
| 1623 | + backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); | |
| 1624 | + box-shadow: 0 14px 34px rgba(20, 24, 20, 0.16); | |
| 1625 | + padding: 6px; | |
| 1626 | + } | |
| 1627 | + .tabbar a { | |
| 1628 | + display: flex; flex-direction: column; align-items: center; justify-content: center; | |
| 1629 | + gap: 2px; padding: 5px 2px; min-height: 48px; border-radius: 12px; | |
| 1630 | + font-family: var(--font-display); font-size: 10px; font-weight: 600; | |
| 1631 | + color: var(--ink-3); text-decoration: none; transition: color var(--dur-1) ease; | |
| 1632 | + } | |
| 1633 | + .tabbar a svg { display: block; } | |
| 1634 | + .tabbar a.active { color: var(--ink); } | |
| 1635 | + .tabbar a.active::after { content: ""; width: 16px; height: 2.5px; border-radius: 2px; background: var(--lime); } | |
| 1636 | + body { padding-bottom: calc(80px + env(safe-area-inset-bottom)); } | |
| 1637 | + .ka-footer { padding-bottom: calc(56px + env(safe-area-inset-bottom)); } | |
| 1638 | + | |
| 1639 | + /* widget KA Agent : dégagé de la tabbar (style injecté après le bundle → | |
| 1640 | + spécificité doublée pour gagner) */ | |
| 1641 | + .kaa-btn.kaa-btn { bottom: calc(86px + env(safe-area-inset-bottom, 0px)); right: 14px; } | |
| 1642 | + .kaa-panel.kaa-panel:not(.kaa-full) { bottom: calc(152px + env(safe-area-inset-bottom, 0px)); } | |
| 1643 | +} | |
| 1612 | 1644 | |