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>
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
# 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**.
|
||||
Reference in New Issue
Block a user