Chapitre 1 : Mise en page
Page
Le composant Page est le conteneur principal de chaque écran. Il gère :
- Le titre de la page
- Les animations de transition
- Le scroll
Syntaxe de base
import { Page } from '@cap-rel/smartcommon';
function HomePage() {
return (
<Page title="Accueil">
<p>Contenu de la page</p>
</Page>
);
}
Props principales
| Prop | Type | Défaut | Description |
|---|---|---|---|
| title | string | - | Titre affiché dans la navbar |
| subtitle | string | - | Sous-titre optionnel |
| className | string | - | Classes CSS additionnelles |
| onRefresh | function | - | Callback pour pull-to-refresh |
Page avec refresh
function ItemsPage() {
const [items, setItems] = useState([]);
const handleRefresh = async () => {
const data = await api.private.get('items').json();
setItems(data);
};
return (
<Page title="Mes items" onRefresh={handleRefresh}>
{items.map(item => (
<div key={item.id}>{item.label}</div>
))}
</Page>
);
}
Block
Le composant Block structure le contenu en sections visuelles distinctes.
Syntaxe de base
import { Page, Block } from '@cap-rel/smartcommon';
function ProfilePage() {
return (
<Page title="Profil">
<Block>
<h2>Informations personnelles</h2>
<p>Nom : Jean Dupont</p>
</Block>
<Block>
<h2>Préférences</h2>
<p>Langue : Français</p>
</Block>
</Page>
);
}
Props
| Prop | Type | Défaut | Description |
|---|---|---|---|
| title | string | - | Titre du block |
| className | string | - | Classes CSS additionnelles |
| padding | boolean | true | Ajouter du padding interne |
Block avec titre
<Block title="Informations">
<p>Contenu du block</p>
</Block>
Panel
Le composant Panel affiche un panneau coulissant depuis le côté de l'écran.
Syntaxe
import { useState } from 'react';
import { Page, Block, Button, Panel } from '@cap-rel/smartcommon';
function MyPage() {
const [isPanelOpen, setIsPanelOpen] = useState(false);
return (
<Page title="Ma page">
<Block>
<Button onClick={() => setIsPanelOpen(true)}>
Ouvrir le panneau
</Button>
</Block>
<Panel
isOpen={isPanelOpen}
onClose={() => setIsPanelOpen(false)}
position="right"
>
<h2>Contenu du panneau</h2>
<p>Informations supplémentaires</p>
</Panel>
</Page>
);
}
Props
| Prop | Type | Défaut | Description |
|---|---|---|---|
| isOpen | boolean | false | Contrôle l'affichage |
| onClose | function | - | Callback à la fermeture |
| position | string | 'right' | 'left', 'right', 'top', 'bottom' |
| title | string | - | Titre du panneau |
Popup
Le composant Popup affiche une fenêtre modale centrée.
Syntaxe
import { useState } from 'react';
import { Page, Block, Button, Popup } from '@cap-rel/smartcommon';
function MyPage() {
const [isPopupOpen, setIsPopupOpen] = useState(false);
return (
<Page title="Ma page">
<Block>
<Button onClick={() => setIsPopupOpen(true)}>
Supprimer
</Button>
</Block>
<Popup
isOpen={isPopupOpen}
onClose={() => setIsPopupOpen(false)}
title="Confirmation"
>
<p>Voulez-vous vraiment supprimer cet élément ?</p>
<div className="flex gap-2 mt-4">
<Button onClick={() => setIsPopupOpen(false)}>
Annuler
</Button>
<Button variant="danger" onClick={handleDelete}>
Supprimer
</Button>
</div>
</Popup>
</Page>
);
}
Props
| Prop | Type | Défaut | Description |
|---|---|---|---|
| isOpen | boolean | false | Contrôle l'affichage |
| onClose | function | - | Callback à la fermeture |
| title | string | - | Titre du popup |
| closeOnOverlay | boolean | true | Fermer au clic sur l'overlay |
Exemple complet
import { useState } from 'react';
import {
Page,
Block,
Panel,
Popup,
Button,
List,
ListItem
} from '@cap-rel/smartcommon';
export const ProductsPage = () => {
const [selectedProduct, setSelectedProduct] = useState(null);
const [showDeletePopup, setShowDeletePopup] = useState(false);
const [showFilters, setShowFilters] = useState(false);
const products = [
{ id: 1, label: 'Produit A', price: 29.99 },
{ id: 2, label: 'Produit B', price: 49.99 },
{ id: 3, label: 'Produit C', price: 19.99 }
];
const handleDelete = async () => {
// Supprimer le produit
console.log('Suppression de', selectedProduct);
setShowDeletePopup(false);
setSelectedProduct(null);
};
return (
<Page title="Produits">
{/* Actions */}
<Block>
<Button onClick={() => setShowFilters(true)}>
Filtres
</Button>
</Block>
{/* Liste */}
<Block title="Catalogue">
<List>
{products.map(product => (
<ListItem
key={product.id}
title={product.label}
subtitle={`${product.price} €`}
onClick={() => setSelectedProduct(product)}
actions={
<Button
size="sm"
variant="danger"
onClick={(e) => {
e.stopPropagation();
setSelectedProduct(product);
setShowDeletePopup(true);
}}
>
Supprimer
</Button>
}
/>
))}
</List>
</Block>
{/* Panneau filtres */}
<Panel
isOpen={showFilters}
onClose={() => setShowFilters(false)}
title="Filtres"
position="right"
>
<p>Options de filtrage ici</p>
</Panel>
{/* Popup confirmation */}
<Popup
isOpen={showDeletePopup}
onClose={() => setShowDeletePopup(false)}
title="Confirmer la suppression"
>
<p>
Supprimer "{selectedProduct?.label}" ?
</p>
<div className="flex gap-2 mt-4">
<Button onClick={() => setShowDeletePopup(false)}>
Annuler
</Button>
<Button variant="danger" onClick={handleDelete}>
Supprimer
</Button>
</div>
</Popup>
</Page>
);
};
Bonnes pratiques
- Une seule Page par composant de route
- Utiliser Block pour regrouper le contenu logiquement
- Panel pour les actions secondaires (filtres, détails)
- Popup pour les confirmations et actions critiques
Points clés à retenir
- Page = conteneur principal avec titre et animations
- Block = section de contenu avec style
- Panel = panneau coulissant latéral
- Popup = modal centré pour confirmations