SPB Git forge

spb/sorti-ka

Public

Toutes les sorties et tous les événements du Québec, un seul endroit — 7 connecteurs, fiches SSR, design Groupe KA.

58commits 1branches 0releases
13.7 MBsize
maindefault branch
17 days agolast push
HTML 82.9% Python 15.2% TypeScript 0.9% JavaScript 0.7%

Barre de navigation mobile commune Groupe KA (KA Tabbar v1)

Pilule flottante fixe en bas (standard ka-ui/nav, version vanilla inline) :
Découvrir · Recherche · Carte · Favoris, accent magenta signature, safe-area
iOS, micro-interactions. Recherche = retour accueil + focus du champ central ;
Carte = toutes les sorties sur la carte (drapeau state.mapAll one-shot dans
isFiltering, remis à zéro à toute navigation hors tabbar).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Simon-Pierre Boucher committed 29 days ago (Aug 25, 2026) parent 318cada

1 changed file +102 −1

modified frontend/index.html +102 −1
@@ -713,6 +713,48 @@ html.ka-menu-locked,html.ka-menu-locked body{overflow:hidden}
713 713
714 714 #ssr{display:none}
715 715 .hidden{display:none!important}
716 +
717 +/* ============================================================
718 + KA Tabbar v1 — barre de navigation mobile commune Groupe KA
719 + (canonique : ka-ui.git/nav/ka-tabbar.css — accent magenta via
720 + var(--accent) du site) ============================================ */
721 +.ka-tabbar{display:none}
722 +@media (max-width:760px){
723 + .ka-tabbar{
724 + --ktb-bg:rgba(250,249,245,.94);
725 + --ktb-ink:var(--ink,#16191a);
726 + --ktb-dim:var(--ink-3,#70756d);
727 + --ktb-accent:var(--accent,#d6336c);
728 + --ktb-line:var(--hairline-strong,rgba(20,24,20,.16));
729 + --ktb-shadow:0 10px 30px rgba(20,24,20,.16),0 2px 6px rgba(20,24,20,.07);
730 + position:fixed;left:max(12px,env(safe-area-inset-left));right:max(12px,env(safe-area-inset-right));
731 + bottom:calc(10px + env(safe-area-inset-bottom));z-index:var(--z-bottombar,600);
732 + display:grid;grid-auto-flow:column;grid-auto-columns:1fr;max-width:440px;margin-inline:auto;
733 + padding:5px;background:var(--ktb-bg);
734 + -webkit-backdrop-filter:blur(14px) saturate(1.1);backdrop-filter:blur(14px) saturate(1.1);
735 + border:1px solid var(--ktb-line);border-radius:18px;box-shadow:var(--ktb-shadow)}
736 + .ka-tabbar a,.ka-tabbar button{appearance:none;background:none;border:0;cursor:pointer;
737 + display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
738 + min-height:50px;padding:6px 2px 5px;border-radius:13px;
739 + font-family:var(--font-display,inherit);font-size:10px;font-weight:650;letter-spacing:.01em;
740 + line-height:1;color:var(--ktb-dim);text-decoration:none;-webkit-tap-highlight-color:transparent;
741 + transition:color .15s ease}
742 + .ka-tabbar svg{display:block;transition:transform .15s ease}
743 + .ka-tabbar a:active svg,.ka-tabbar button:active svg{transform:translateY(1px) scale(.9)}
744 + .ka-tabbar .active{color:var(--ktb-active-label,var(--ktb-ink))}
745 + .ka-tabbar .active svg{color:var(--ktb-accent);animation:ktb-pop .25s ease}
746 + .ka-tabbar .active::after{content:"";width:16px;height:2.5px;border-radius:2px;
747 + background:var(--ktb-accent);animation:ktb-under .22s ease}
748 + body:has(.ka-tabbar){padding-bottom:calc(84px + env(safe-area-inset-bottom))}
749 + body:has(.ka-tabbar) .kaa-btn.kaa-btn{bottom:calc(88px + env(safe-area-inset-bottom,0px));right:14px}
750 + body:has(.ka-tabbar) .kaa-panel.kaa-panel:not(.kaa-full){bottom:calc(154px + env(safe-area-inset-bottom,0px))}
751 +}
752 +@keyframes ktb-under{from{transform:scaleX(0);opacity:0}}
753 +@keyframes ktb-pop{40%{transform:translateY(-2px)}}
754 +@media (prefers-reduced-motion:reduce){
755 + .ka-tabbar svg{transition:none}
756 + .ka-tabbar .active svg,.ka-tabbar .active::after{animation:none}
757 +}
716 758 </style>
717 759 </head>
718 760 <body>
@@ -1229,7 +1271,8 @@ function plusDays(n){
1229 1271 }
1230 1272 function isFiltering(){
1231 1273 return !!(state.q || state.region || state.category || state.free
1232 − || state.from || state.to || state.near);
1274 + || state.from || state.to || state.near
1275 + || state.mapAll); // onglet Carte (KA Tabbar) : résultats sans filtre
1233 1276 }
1234 1277 function params(){
1235 1278 const p = new URLSearchParams();
@@ -2773,5 +2816,63 @@ init();
2773 2816 </script>
2774 2817 <script>window.KA_AGENT={site:"sorti-ka"}</script>
2775 2818 <script src="/ka-agent.js" defer></script>
2819 +
2820 +<!-- ======== KA Tabbar v1 — navigation mobile commune Groupe KA (ka-ui/nav) ======== -->
2821 +<nav class="ka-tabbar" id="ka-tabbar" aria-label="Navigation mobile">
2822 + <a data-nav data-tab="decouvrir" href="/"><svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="m15.5 8.5-2.2 5-4.8 2 2.2-5 4.8-2z"/></svg>Découvrir</a>
2823 + <button type="button" data-tab="recherche" id="ktb-search"><svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20.5 20.5-4.2-4.2"/></svg>Recherche</button>
2824 + <button type="button" data-tab="carte" id="ktb-carte"><svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 21s-7-5.6-7-11a7 7 0 0 1 14 0c0 5.4-7 11-7 11z"/><circle cx="12" cy="10" r="2.6"/></svg>Carte</button>
2825 + <a data-nav data-tab="favoris" href="/favoris"><svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 20.5S4.5 15.8 2.6 11.4A5.3 5.3 0 0 1 12 6.6a5.3 5.3 0 0 1 9.4 4.8C19.5 15.8 12 20.5 12 20.5z"/></svg>Favoris</a>
2826 +</nav>
2827 +<script>
2828 +/* KA Tabbar : liaisons (routeur maison data-nav + actions locales) */
2829 +(function(){
2830 + const bar = document.getElementById("ka-tabbar");
2831 + bindNav(bar); // les <a data-nav> passent par le routeur SPA
2832 +
2833 + function ktbSync(){
2834 + const p = location.pathname;
2835 + const mapOn = !$("results").classList.contains("hidden")
2836 + && !$("mapwrap").classList.contains("hidden");
2837 + let k = null;
2838 + if(p === "/favoris") k = "favoris";
2839 + else if(p === "/" || p.startsWith("/region/") || p.startsWith("/categorie/")
2840 + || p.startsWith("/evenement/")) k = mapOn ? "carte" : "decouvrir";
2841 + bar.querySelectorAll("[data-tab]").forEach(b =>
2842 + b.classList.toggle("active", b.dataset.tab === k));
2843 + }
2844 +
2845 + /* Recherche : accueil + focus du champ central */
2846 + $("ktb-search").onclick = () => {
2847 + const wasMap = state.mapAll;
2848 + state.mapAll = false;
2849 + if(location.pathname !== "/") go("/");
2850 + else if(wasMap) load();
2851 + window.scrollTo({top:0, behavior:"smooth"});
2852 + setTimeout(() => $("q").focus({preventScroll:true}), 60);
2853 + setTimeout(ktbSync, 80);
2854 + };
2855 +
2856 + /* Carte : toutes les sorties sur la carte (vue résultats forcée) */
2857 + $("ktb-carte").onclick = () => {
2858 + state.mapAll = true;
2859 + if(location.pathname !== "/") go("/");
2860 + else load();
2861 + setView("map");
2862 + setTimeout(() => $("results").scrollIntoView({behavior:"smooth", block:"start"}), 120);
2863 + setTimeout(ktbSync, 150);
2864 + };
2865 +
2866 + /* toute navigation hors tabbar sort du mode carte-de-tout (one-shot) */
2867 + document.addEventListener("click", e => {
2868 + const a = e.target.closest && e.target.closest("a[data-nav]");
2869 + if(a && !bar.contains(a)) state.mapAll = false;
2870 + setTimeout(ktbSync, 80);
2871 + }, true);
2872 + window.addEventListener("popstate", () => { state.mapAll = false; setTimeout(ktbSync, 80); });
2873 +
2874 + ktbSync();
2875 +})();
2876 +</script>
2776 2877 </body>
2777 2878 </html>
2778 2879