Files
home_hub/design_system/package-smartphone/consigne_mobile.md
T
gilles 4518ed8311 chore(design): ajout du package design system smartphone
Contient les tokens, composants et exemples adaptés au mobile,
à utiliser comme référence lors du développement des vues smartphone.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 08:53:36 +02:00

193 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Consignes mobile — mon design system
> **Tu es un agent IA qui produit du code mobile avec ce design system.**
> Lis ce fichier ENTIER avant d'écrire la moindre ligne. Suis les règles à la lettre.
---
## 🎯 Identité
- **Cibles** : iOS et Android via HTML/JS (Cordova, Capacitor, ou PWA)
- **Largeur ref** : 390px (iPhone 14 / Galaxy S22)
- **Hit target min** : 44 × 44px (Apple HIG / Material)
- **Style** : Gruvbox seventies — orange brûlé, fond brun délavé en sombre / gris clair usé en clair
---
## 📁 Fichiers
| Fichier | Composants exposés sur window |
|-------------------------------|----------------------------------------------------------------------------|
| `components/ui-kit.jsx` | Icon, Tooltip, Button, IconButton, Toggle, StatusLed, Popup, BatteryGauge, RadialGauge, BigRadialGauge, TreeNav, Sparkline, LineChart |
| `components/mobile-kit.jsx` | StatusBar, NavBar, TabBar, ListRow, ListSection, ActionCard, PrimaryButton, SegmentedControl, SearchBar |
| `components/mobile-sheets.jsx`| BottomSheet, ActionSheet, AlertDialog, Toast, FAB, PullToRefresh |
| `components/mobile-gestures.jsx`| useGesture, GestureZone, GESTURE_CATALOG |
| `components/mobile-swipeable.jsx`| SwipeableRow |
| `components/mobile-forms.jsx` | FormField, TextInput, DateInput, Dropdown, CheckboxItem, RadioGroup, MediaInsert, AvatarLogo, BiometricButton |
| `components/mobile-apps.jsx` | Avatar, AvatarMenu, OnboardingSlider, ChatBubble, ChatComposer, CalendarMonth, MapView, FilterChips, QrScannerView, CameraView, FileExplorer |
---
## ⚠️ Règles absolues
1. **Hit targets ≥ 44 × 44 px** sur TOUT élément tactile. Pas de petits boutons.
2. **Pas de hover** — c'est du tactile. Utilise la pression au touch via `.touch-press`.
3. **Tooltips** sur tous les `<IconButton>` isolés (la prop `label` les active automatiquement).
4. **Toujours des polices natives mobile** : Inter / JetBrains Mono / Share Tech Mono via tokens.
5. **Animations fluides** : 180-300ms, easing `cubic-bezier(.3,.7,.3,1.2)` pour entrée, `cubic-bezier(.3,.6,.3,1)` pour mouvement.
6. **Toujours `<TabBar>` en bas** comme navigation primaire (3-5 sections).
7. **JAMAIS de popup centrée modale standard** — utilise `BottomSheet`, `ActionSheet`, `AlertDialog` ou `Toast`.
8. **Bouton Avatar en haut à droite** de chaque écran principal pour accès rapide au menu utilisateur.
9. **Variables CSS uniquement** — pas de hex en dur (`color: var(--accent)`, jamais `color: #fe8019`).
10. **Smartphone d'abord** — toute interaction doit fonctionner avec un seul pouce.
---
## 🧩 Cas → Composant à utiliser
### Structure d'écran (toujours)
```jsx
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<StatusBar />
<NavBar large title="Mon écran" right={<Avatar name="M" onClick={openMenu} />} />
<div style={{ flex: 1, overflowY: 'auto', padding: 14 }}>
{/* contenu */}
</div>
</div>
```
Si la page fait partie d'une nav principale, ajoute `<TabBar>` après. Si elle a une action principale flottante, ajoute `<FAB>`.
### Liste à actions cachées
```jsx
<SwipeableRow
onTap={() => open(item)}
leftActions={[{ label: 'Suppr.', icon: 'close', color: 'var(--err)', onClick: del }]} // swipe gauche
rightActions={[{ label: 'Lu', icon: 'play', color: 'var(--info)', onClick: read }]} // swipe droit
>
<div>{contenu de la ligne}</div>
</SwipeableRow>
```
### Champ texte typé
```jsx
// Email
<TextInput value={...} onChange={...} keyboard="email" autocomplete="email" autocapitalize="off" />
// Mot de passe
<TextInput value={...} onChange={...} type="password" autocomplete="current-password" />
// OTP SMS
<TextInput value={...} onChange={...} keyboard="numeric" autocomplete="one-time-code" maxLength={6} />
// Recherche
<TextInput value={...} onChange={...} keyboard="search" enterHint="search" />
```
### Confirmation destructive
```jsx
<AlertDialog open={open} onClose={...}
icon="alert" iconColor="var(--err)"
title="Supprimer ?"
message="Cette action est irréversible."
actions={[
{ label: 'Annuler' },
{ label: 'Supprimer', danger: true, primary: true, onClick: del },
]} />
```
### Choix dans une liste
```jsx
<BottomSheet open={...} onClose={...} title="Choisir">
<RadioGroup value={...} onChange={...} options={[...]} />
</BottomSheet>
```
### Menu d'actions sur élément
```jsx
<ActionSheet open={...} onClose={...} title="Actions"
actions={[
{ label: 'Modifier', icon: 'cog' },
{ label: 'Partager', icon: 'download' },
{ label: 'Supprimer', icon: 'close', danger: true },
]} />
```
### Feedback après action
```jsx
<Toast open={msg !== null} onClose={() => setMsg(null)} message={msg} variant="ok" />
```
### Menu utilisateur (avatar haut-droite)
```jsx
<AvatarMenu open={...} onClose={...} name="Marc" email="marc@..."
items={[
{ icon: 'user', label: 'Mon profil' },
{ icon: 'cog', label: 'Paramètres' },
{ icon: 'power', label: 'Se déconnecter', danger: true },
]} />
```
---
## 🚫 Anti-patterns
-`window.alert / confirm` → utilise `AlertDialog`
-`<button>` nu sans hit target → utilise `IconButton` ou `PrimaryButton`
- ❌ Hover effects → pas d'hover sur mobile, utilise `.touch-press`
- ❌ Popups centrées pour formulaire court → `BottomSheet`
- ❌ Sidebars > 240px → utilise plutôt drawer ou TabBar
- ❌ Tableaux denses → liste swipeable avec actions
- ❌ Couleurs en dur → toujours `var(--token)`
- ❌ Police arbitraire → `var(--font-ui)`, `var(--font-mono)`, `var(--font-terminal)`
- ❌ Boutons texte sans icône pour actions critiques → ajoute toujours une icône
- ❌ Inputs sans `keyboard`/`autocomplete` adaptés → frustre l'utilisateur
---
## 📐 Tailles
| Élément | Taille |
|----------------------|--------------------------------------------------|
| StatusBar | 44px |
| NavBar compact | 52px |
| NavBar large | ~90px |
| TabBar | 70px (avec safe area) |
| ListRow | min 52px |
| PrimaryButton lg | 52px |
| IconButton | 34px (def) / 26px (compact) / 44px (large) |
| FAB | 56 × 56 ronde |
| Toggle | 42 × 22 |
| Radius cartes | 10-14px |
| Radius boutons | 8-12px |
| Avatar | 36px (header) / 48-72px (profile) |
| Espacement standard | 8 / 12 / 14 / 18 / 24px |
---
## 💡 Détails à respecter
- **Safe area bottom** : la TabBar a déjà un `padding-bottom: 18px` pour la home indicator iOS.
- **Backdrop-filter blur** : utilisé sur NavBar/TabBar/AlertBg pour effet vitre.
- **SwipeableRow** snap : ouvre/ferme à 50% de la largeur des actions.
- **AvatarMenu** : un seul ouvert à la fois, ferme au clic extérieur (backdrop).
- **Toast** : auto-ferme à 2.5s sauf prop `duration` différent.
- **PullToRefresh** : seulement quand `scrollTop === 0`.
---
## 🌗 Dark / Light
Tout fonctionne automatiquement via `data-theme="dark|light"` sur un parent. **Toujours tester les deux** :
- En sombre : tokens chauds bruns
- En clair : gris clair usé (pas blanc pur), accent orange plus contrasté
---
## 🔚 En cas de doute
- Composant pas sûr ? → `examples/exemple-mobile-apps.html` montre quasi tous les cas
- Geste pas clair ? → onglet Gestes du smartphone dans `exemple-mobile.html`
- Saisie spéciale ? → `exemple-mobile-saisie.html` + section "Antisèche"
Toujours préférer un composant existant à un custom. Quand tu doutes, **demande**.