Chapitre 2 : Navigation
Navbar
La barre de navigation supérieure. Affiche le titre et des actions.
Syntaxe de base
- snippet.javascript
import { Navbar, UpperNavbarItem } from '@cap-rel/smartcommon'; import { FiMenu, FiUser } from 'react-icons/fi'; function MyPage() { return ( <> <Navbar title="Mon Application"> <UpperNavbarItem icon={FiMenu} onClick={openMenu} /> <UpperNavbarItem icon={FiUser} onClick={goToProfile} /> </Navbar> {/* Contenu */} </> ); }
Props Navbar
| Prop | Type | Description |
|---|---|---|
| title | string | Titre principal |
| subtitle | string | Sous-titre optionnel |
| showBack | boolean | Afficher le bouton retour |
| onBack | function | Callback du bouton retour |
Props UpperNavbarItem
| Prop | Type | Description |
|---|---|---|
| icon | Component | Icône react-icons |
| onClick | function | Action au clic |
| badge | number | Compteur de notification |
Sidebar
Menu latéral avec navigation.
Syntaxe
- snippet.javascript
import { useState } from 'react'; import { Sidebar, Button } from '@cap-rel/smartcommon'; import { useNavigation, useGlobalStates, useApi } from '@cap-rel/smartcommon'; import { FiHome, FiList, FiSettings, FiLogOut } from 'react-icons/fi'; function MainLayout({ children }) { const [isSidebarOpen, setIsSidebarOpen] = useState(false); const navigate = useNavigation(); const api = useApi(); const [session] = useGlobalStates('session'); const menuItems = [ { icon: FiHome, label: 'Accueil', path: '/' }, { icon: FiList, label: 'Produits', path: '/products' }, { icon: FiSettings, label: 'Paramètres', path: '/settings' } ]; const handleLogout = async () => { await api.logout(); navigate('/login'); }; return ( <> <Sidebar isOpen={isSidebarOpen} onClose={() => setIsSidebarOpen(false)} > {/* En-tête utilisateur */} <div className="p-4 border-b"> <p className="font-bold">{session?.user?.name}</p> <p className="text-sm text-gray-500">{session?.user?.email}</p> </div> {/* Menu */} <nav className="p-2"> {menuItems.map(item => ( <button key={item.path} onClick={() => { navigate(item.path); setIsSidebarOpen(false); }} className="flex items-center gap-3 w-full p-3 rounded hover:bg-gray-100" > <item.icon /> {item.label} </button> ))} </nav> {/* Déconnexion */} <div className="p-4 border-t mt-auto"> <Button onClick={handleLogout} variant="outline" className="w-full"> <FiLogOut className="mr-2" /> Déconnexion </Button> </div> </Sidebar> {children} </> ); }
Props
| Prop | Type | Description |
|---|---|---|
| isOpen | boolean | Contrôle l'affichage |
| onClose | function | Callback à la fermeture |
| position | string | 'left' ou 'right' |
Tabbar
Barre d'onglets en bas de l'écran (navigation mobile).
Syntaxe
- snippet.javascript
import { Tabbar, TabbarItem } from '@cap-rel/smartcommon'; import { useNavigation } from '@cap-rel/smartcommon'; import { useLocation } from 'react-router-dom'; import { FiHome, FiSearch, FiShoppingCart, FiUser } from 'react-icons/fi'; function AppTabbar() { const navigate = useNavigation(); const location = useLocation(); const tabs = [ { icon: FiHome, label: 'Accueil', path: '/' }, { icon: FiSearch, label: 'Recherche', path: '/search' }, { icon: FiShoppingCart, label: 'Panier', path: '/cart', badge: 3 }, { icon: FiUser, label: 'Profil', path: '/profile' } ]; return ( <Tabbar> {tabs.map(tab => ( <TabbarItem key={tab.path} icon={tab.icon} label={tab.label} active={location.pathname === tab.path} badge={tab.badge} onClick={() => navigate(tab.path)} /> ))} </Tabbar> ); }
Props TabbarItem
| Prop | Type | Description |
|---|---|---|
| icon | Component | Icône react-icons |
| label | string | Texte sous l'icône |
| active | boolean | État sélectionné |
| badge | number | Compteur notification |
| onClick | function | Action au clic |
useNavigation
Hook pour la navigation programmatique.
Syntaxe
- snippet.javascript
import { useNavigation } from '@cap-rel/smartcommon'; function MyComponent() { const navigate = useNavigation(); return ( <div> {/* Navigation vers une route */} <button onClick={() => navigate('/products')}> Voir les produits </button> {/* Navigation avec paramètre */} <button onClick={() => navigate(`/products/${productId}`)}> Détails </button> {/* Retour arrière */} <button onClick={() => navigate(-1)}> Retour </button> {/* Remplacement (pas d'historique) */} <button onClick={() => navigate('/login', { replace: true })}> Se connecter </button> </div> ); }
Exemple complet : Layout avec navigation
- snippet.javascript
// components/layouts/MainLayout/index.jsx import { useState } from 'react'; import { useLocation } from 'react-router-dom'; import { Navbar, Sidebar, Tabbar, TabbarItem, UpperNavbarItem } from '@cap-rel/smartcommon'; import { useNavigation, useGlobalStates, useApi } from '@cap-rel/smartcommon'; import { FiMenu, FiHome, FiList, FiPlus, FiSettings, FiLogOut } from 'react-icons/fi'; export const MainLayout = ({ children, title }) => { const [sidebarOpen, setSidebarOpen] = useState(false); const navigate = useNavigation(); const location = useLocation(); const api = useApi(); const [session] = useGlobalStates('session'); const handleLogout = async () => { await api.logout(); navigate('/login'); }; return ( <div className="min-h-screen flex flex-col"> {/* Navbar */} <Navbar title={title}> <UpperNavbarItem icon={FiMenu} onClick={() => setSidebarOpen(true)} /> </Navbar> {/* Sidebar */} <Sidebar isOpen={sidebarOpen} onClose={() => setSidebarOpen(false)} > <div className="p-4 border-b"> <p className="font-bold">{session?.user?.name}</p> </div> <nav className="flex-1 p-2"> <SidebarLink icon={FiHome} label="Accueil" onClick={() => { navigate('/'); setSidebarOpen(false); }} /> <SidebarLink icon={FiList} label="Produits" onClick={() => { navigate('/products'); setSidebarOpen(false); }} /> <SidebarLink icon={FiSettings} label="Paramètres" onClick={() => { navigate('/settings'); setSidebarOpen(false); }} /> </nav> <div className="p-4 border-t"> <button onClick={handleLogout} className="flex items-center gap-2 text-red-500" > <FiLogOut /> Déconnexion </button> </div> </Sidebar> {/* Contenu principal */} <main className="flex-1 pb-16"> {children} </main> {/* Tabbar */} <Tabbar> <TabbarItem icon={FiHome} label="Accueil" active={location.pathname === '/'} onClick={() => navigate('/')} /> <TabbarItem icon={FiList} label="Produits" active={location.pathname.startsWith('/products')} onClick={() => navigate('/products')} /> <TabbarItem icon={FiPlus} label="Nouveau" onClick={() => navigate('/products/new')} /> <TabbarItem icon={FiSettings} label="Paramètres" active={location.pathname === '/settings'} onClick={() => navigate('/settings')} /> </Tabbar> </div> ); }; // Composant helper const SidebarLink = ({ icon: Icon, label, onClick }) => ( <button onClick={onClick} className="flex items-center gap-3 w-full p-3 rounded hover:bg-gray-100" > <Icon /> {label} </button> );
Utilisation du layout
- snippet.javascript
// components/pages/private/ProductsPage/index.jsx import { MainLayout } from '../../../layouts/MainLayout'; import { Block, List, ListItem } from '@cap-rel/smartcommon'; export const ProductsPage = () => { const products = [...]; return ( <MainLayout title="Produits"> <Block> <List> {products.map(p => ( <ListItem key={p.id} title={p.label} subtitle={`${p.price} €`} /> ))} </List> </Block> </MainLayout> ); };
Points clés à retenir
- Navbar = barre supérieure avec titre et actions
- Sidebar = menu latéral coulissant
- Tabbar = navigation par onglets en bas
- useNavigation = navigation programmatique
- Combiner ces composants dans un Layout réutilisable
← Chapitre précédent | Retour au module | Chapitre suivant : Formulaires →