Chapter 2: Navigation
Navbar
The top navigation bar. Displays the title and actions.
Basic Syntax
import { Navbar, UpperNavbarItem } from '@cap-rel/smartcommon';
import { FiMenu, FiUser } from 'react-icons/fi';
function MyPage() {
return (
<>
<Navbar title="My Application">
<UpperNavbarItem icon={FiMenu} onClick={openMenu} />
<UpperNavbarItem icon={FiUser} onClick={goToProfile} />
</Navbar>
{/* Content */}
</>
);
}
Navbar Props
| Prop | Type | Description |
|---|---|---|
| title | string | Main title |
| subtitle | string | Optional subtitle |
| showBack | boolean | Show back button |
| onBack | function | Back button callback |
UpperNavbarItem Props
| Prop | Type | Description |
|---|---|---|
| icon | Component | react-icons icon |
| onClick | function | Click action |
| badge | number | Notification counter |
Sidebar
Side menu with navigation.
Syntax
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 nav = useNavigation();
const api = useApi();
const gst = useGlobalStates();
const menuItems = [
{ icon: FiHome, label: 'Home', path: '/' },
{ icon: FiList, label: 'Products', path: '/products' },
{ icon: FiSettings, label: 'Settings', path: '/settings' }
];
const handleLogout = async () => {
await api.logout();
nav.navigate('/login');
};
return (
<>
<Sidebar
isOpen={isSidebarOpen}
onClose={() => setIsSidebarOpen(false)}
>
{/* User header */}
<div className="p-4 border-b">
<p className="font-bold">{gst.get('session')?.user?.name}</p>
<p className="text-sm text-gray-500">{gst.get('session')?.user?.email}</p>
</div>
{/* Menu */}
<nav className="p-2">
{menuItems.map(item => (
<button
key={item.path}
onClick={() => {
nav.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>
{/* Logout */}
<div className="p-4 border-t mt-auto">
<Button onClick={handleLogout} variant="outline" className="w-full">
<FiLogOut className="mr-2" />
Logout
</Button>
</div>
</Sidebar>
{children}
</>
);
}
Props
| Prop | Type | Description |
|---|---|---|
| isOpen | boolean | Controls display |
| onClose | function | Close callback |
| position | string | 'left' or 'right' |
Tabbar
Bottom tab bar (mobile navigation).
Syntax
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 nav = useNavigation();
const location = useLocation();
const tabs = [
{ icon: FiHome, label: 'Home', path: '/' },
{ icon: FiSearch, label: 'Search', path: '/search' },
{ icon: FiShoppingCart, label: 'Cart', path: '/cart', badge: 3 },
{ icon: FiUser, label: 'Profile', 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={() => nav.navigate(tab.path)}
/>
))}
</Tabbar>
);
}
TabbarItem Props
| Prop | Type | Description |
|---|---|---|
| icon | Component | react-icons icon |
| label | string | Text below icon |
| active | boolean | Selected state |
| badge | number | Notification counter |
| onClick | function | Click action |
useNavigation
Hook for programmatic navigation.
Syntax
import { useNavigation } from '@cap-rel/smartcommon';
function MyComponent() {
const nav = useNavigation();
return (
<div>
{/* Navigate to route */}
<button onClick={() => nav.navigate('/products')}>
View products
</button>
{/* Navigate with parameter */}
<button onClick={() => nav.navigate(`/products/${productId}`)}>
Details
</button>
{/* Go back */}
<button onClick={() => nav.navigate(-1)}>
Back
</button>
{/* Replace (no history) */}
<button onClick={() => nav.replace('/login')}>
Login
</button>
</div>
);
}
Complete Example: Layout with Navigation
// 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 nav = useNavigation();
const location = useLocation();
const api = useApi();
const gst = useGlobalStates();
const handleLogout = async () => {
await api.logout();
nav.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">{gst.get('session')?.user?.name}</p>
</div>
<nav className="flex-1 p-2">
<SidebarLink
icon={FiHome}
label="Home"
onClick={() => {
nav.navigate('/');
setSidebarOpen(false);
}}
/>
<SidebarLink
icon={FiList}
label="Products"
onClick={() => {
nav.navigate('/products');
setSidebarOpen(false);
}}
/>
<SidebarLink
icon={FiSettings}
label="Settings"
onClick={() => {
nav.navigate('/settings');
setSidebarOpen(false);
}}
/>
</nav>
<div className="p-4 border-t">
<button
onClick={handleLogout}
className="flex items-center gap-2 text-red-500"
>
<FiLogOut /> Logout
</button>
</div>
</Sidebar>
{/* Main content */}
<main className="flex-1 pb-16">
{children}
</main>
{/* Tabbar */}
<Tabbar>
<TabbarItem
icon={FiHome}
label="Home"
active={location.pathname === '/'}
onClick={() => nav.navigate('/')}
/>
<TabbarItem
icon={FiList}
label="Products"
active={location.pathname.startsWith('/products')}
onClick={() => nav.navigate('/products')}
/>
<TabbarItem
icon={FiPlus}
label="New"
onClick={() => nav.navigate('/products/new')}
/>
<TabbarItem
icon={FiSettings}
label="Settings"
active={location.pathname === '/settings'}
onClick={() => nav.navigate('/settings')}
/>
</Tabbar>
</div>
);
};
// Helper component
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>
);
Using the Layout
// 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="Products">
<Block>
<List>
{products.map(p => (
<ListItem
key={p.id}
title={p.label}
subtitle={`${p.price} €`}
/>
))}
</List>
</Block>
</MainLayout>
);
};
Key Points to Remember
- Navbar = top bar with title and actions
- Sidebar = sliding side menu
- Tabbar = bottom tab navigation
- useNavigation = programmatic navigation
- Combine these components into a Reusable Layout