spb/fabri-ka Public
Agrégateur de produits québécois — www.fabri-ka.com
HTML 57%
Python 19.9%
TypeScript 15.3%
CSS 7.7%
1import { FormEvent, useEffect, useRef, useState } from 'react'2import { NavLink, useLocation, useNavigate } from 'react-router-dom'3import { IconClose, IconGrid, IconHome, IconSearch, IconStore } from './Icons'45/**6 * Mobile bottom tab bar (<768px) — Accueil, Produits, Boutiques, Recherche.7 * "Recherche" opens a full-screen search overlay with an autofocused input.8 */9export default function BottomNav() {10 const [searchOpen, setSearchOpen] = useState(false)11 const [query, setQuery] = useState('')12 const inputRef = useRef<HTMLInputElement>(null)13 const navigate = useNavigate()14 const location = useLocation()1516 // Close the overlay on navigation.17 useEffect(() => {18 setSearchOpen(false)19 }, [location.pathname, location.search])2021 // Autofocus + scroll lock while the overlay is open.22 useEffect(() => {23 if (!searchOpen) return24 document.body.style.overflow = 'hidden'25 const t = window.setTimeout(() => inputRef.current?.focus(), 60)26 const onKey = (e: KeyboardEvent) => {27 if (e.key === 'Escape') setSearchOpen(false)28 }29 window.addEventListener('keydown', onKey)30 return () => {31 document.body.style.overflow = ''32 window.clearTimeout(t)33 window.removeEventListener('keydown', onKey)34 }35 }, [searchOpen])3637 function onSubmit(e: FormEvent) {38 e.preventDefault()39 const q = query.trim()40 setSearchOpen(false)41 setQuery('')42 navigate(q ? `/produits?q=${encodeURIComponent(q)}` : '/produits')43 }4445 return (46 <>47 {searchOpen && (48 <div49 className="search-overlay"50 role="dialog"51 aria-modal="true"52 aria-label="Recherche"53 >54 <div className="search-overlay-bar">55 <form className="search-overlay-form" onSubmit={onSubmit} role="search">56 <span className="search-overlay-icon" aria-hidden="true">57 <IconSearch size={18} />58 </span>59 <input60 ref={inputRef}61 type="search"62 value={query}63 onChange={(e) => setQuery(e.target.value)}64 placeholder="Rechercher un produit québécois…"65 aria-label="Rechercher"66 enterKeyHint="search"67 />68 </form>69 <button70 type="button"71 className="search-overlay-close"72 onClick={() => setSearchOpen(false)}73 aria-label="Fermer la recherche"74 >75 <IconClose size={22} />76 </button>77 </div>78 <p className="search-overlay-hint">79 Produits fabriqués, conçus et vendus au Québec.80 </p>81 </div>82 )}8384 <nav className="bottom-nav" aria-label="Navigation mobile">85 <NavLink to="/" end className="bottom-nav-item">86 <IconHome size={22} />87 <span>Accueil</span>88 </NavLink>89 <NavLink to="/produits" className="bottom-nav-item">90 <IconGrid size={22} />91 <span>Produits</span>92 </NavLink>93 <NavLink to="/boutiques" className="bottom-nav-item">94 <IconStore size={22} />95 <span>Boutiques</span>96 </NavLink>97 <button98 type="button"99 className={100 searchOpen ? 'bottom-nav-item active' : 'bottom-nav-item'101 }102 onClick={() => setSearchOpen(true)}103 aria-label="Ouvrir la recherche"104 >105 <IconSearch size={22} />106 <span>Recherche</span>107 </button>108 </nav>109 </>110 )111}112