4518ed8311
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>
193 lines
8.0 KiB
Markdown
193 lines
8.0 KiB
Markdown
# 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**.
|