# 📱 Mobile Unified Components System

> **v2.0 - Composants Vue unifiés pour toutes les pages mobiles**

Ce document décrit le **nouveau système de composants Vue** qui remplace les classes CSS disparates.

---

## 🎯 Changements par rapport à v1

| Avant (CSS Classes) | Après (Vue Components) |
|---------------------|------------------------|
| `.mobile-hero` | `<MobilePageHero />` |
| `.mobile-nav-toggle` | `<MobilePageTabs />` |
| `.mobile-card` | `<MobileCard />` |
| `.mobile-empty-state` | `<MobileEmptyState />` |
| Custom action grids | `<MobileActionGrid />` |
| Custom stats | `<MobileStatsGrid />` |
| Custom sliders | `<MobileSlider />` |
| Custom FABs | `<MobileFab />` |

---

## 📦 Installation

```ts
import {
  MobilePageHero,
  MobilePageTabs,
  MobileCard,
  MobileEmptyState,
  MobileActionGrid,
  MobileStatsGrid,
  MobileSlider,
  MobileFab
} from '@/shared/components/mobile'
```

Importer aussi les styles globaux dans `main.ts`:
```ts
import '@/assets/styles/mobile-unified.scss'
```

---

## 🧩 Composants

### `<MobilePageHero />`

Section hero unifiée avec badges, stats, CTA et statuts.

```vue
<MobilePageHero
  title="Mon Voyage en Espagne"
  subtitle="5 étapes • 1,200 km • 4 jours"
  :badges="[
    { label: 'Pro', variant: 'primary', icon: 'sym_r_star' },
    { label: 'En cours', variant: 'success' }
  ]"
  :stats="[
    { icon: 'sym_r_route', value: '1,200', unit: 'km' },
    { icon: 'sym_r_schedule', value: '18h30' },
    { icon: 'sym_r_local_gas_station', value: '€420' }
  ]"
  :primaryCta="{
    label: 'Démarrer Navigation',
    icon: 'sym_r_navigation'
  }"
  :statuses="[
    { label: 'Météo favorable', icon: 'sym_r_wb_sunny', variant: 'success' }
  ]"
  @ctaClick="startNavigation"
/>
```

**Props:**
| Prop | Type | Default |
|------|------|---------|
| `title` | `string` | - |
| `subtitle` | `string?` | - |
| `eyebrow` | `string?` | - |
| `badges` | `HeroBadge[]?` | `[]` |
| `stats` | `HeroStat[]?` | `[]` |
| `actions` | `HeroAction[]?` | `[]` |
| `primaryCta` | `HeroCta?` | - |
| `statuses` | `HeroStatus[]?` | `[]` |

---

### `<MobilePageTabs />`

Navigation par onglets avec support scroll horizontal.

```vue
<MobilePageTabs
  v-model="activeTab"
  :tabs="[
    { id: 'etapes', label: 'Étapes', icon: 'sym_r_timeline' },
    { id: 'poi', label: 'Points d\'intérêt', icon: 'sym_r_place', badge: 12 },
    { id: 'config', label: 'Configuration', icon: 'sym_r_settings' }
  ]"
  :scrollable="true"
/>

<component :is="tabComponents[activeTab]" />
```

**Props:**
| Prop | Type | Default |
|------|------|---------|
| `modelValue` | `string` | - |
| `tabs` | `MobileTab[]` | - |
| `scrollable` | `boolean?` | `false` |

---

### `<MobileCard />`

Carte unifiée avec header, contenu et footer optionnels.

```vue
<MobileCard
  title="Prochaine étape"
  subtitle="Dans 45 min"
  icon="sym_r_flag"
  icon-color="#22c55e"
  :interactive="true"
  @click="openStageDetails"
>
  <p>Barcelone - 120 km restants</p>
  
  <template #header-action>
    <q-btn flat round icon="sym_r_more_vert" />
  </template>
  
  <template #footer>
    <q-btn label="Voir détails" flat />
  </template>
</MobileCard>
```

**Props:**
| Prop | Type | Default |
|------|------|---------|
| `title` | `string?` | - |
| `subtitle` | `string?` | - |
| `icon` | `string?` | - |
| `iconColor` | `string?` | `#3b82f6` |
| `elevated` | `boolean?` | `false` |
| `interactive` | `boolean?` | `false` |
| `noPadding` | `boolean?` | `false` |

**Slots:** `default`, `header-action`, `footer`

---

### `<MobileEmptyState />`

État vide avec 3 variantes de taille.

```vue
<MobileEmptyState
  icon="sym_r_map"
  title="Aucun voyage planifié"
  description="Créez votre premier roadtrip pour commencer l'aventure"
  cta-label="Créer un voyage"
  cta-icon="sym_r_add"
  variant="default"
  @action="createNewTrip"
/>
```

**Variantes:** `default` (grand), `small` (compact), `inline` (dans une card)

---

### `<MobileActionGrid />`

Grille d'actions rapides 2x2 ou 3 colonnes.

```vue
<MobileActionGrid
  :columns="2"
  :actions="[
    { id: 'start', label: 'Démarrer', icon: 'sym_r_play_arrow', primary: true },
    { id: 'share', label: 'Partager', icon: 'sym_r_share' },
    { id: 'edit', label: 'Modifier', icon: 'sym_r_edit' },
    { id: 'delete', label: 'Supprimer', icon: 'sym_r_delete', iconColor: '#ef4444' }
  ]"
  @action="handleAction"
/>
```

---

### `<MobileStatsGrid />`

Affichage de statistiques avec icônes et tendances.

```vue
<MobileStatsGrid
  :columns="3"
  :stats="[
    { 
      id: 'distance', 
      label: 'Distance', 
      value: 1200, 
      unit: 'km',
      icon: 'sym_r_route',
      trend: 'up',
      trendValue: '+50 km'
    },
    { id: 'time', label: 'Durée', value: '18h30', icon: 'sym_r_schedule' },
    { id: 'cost', label: 'Budget', value: '€420', icon: 'sym_r_payments' }
  ]"
/>
```

---

### `<MobileSlider />`

Slider horizontal full-bleed pour cartes.

```vue
<MobileSlider card-width="260px" gap="12px" :full-bleed="true">
  <div
    v-for="stage in stages"
    :key="stage.id"
    class="mobile-slider__card"
    @click="openStage(stage)"
  >
    <h4>{{ stage.name }}</h4>
    <p>{{ stage.distance }} km</p>
  </div>
</MobileSlider>
```

---

### `<MobileFab />`

Floating Action Button avec menu expandable.

```vue
<MobileFab
  icon="sym_r_add"
  color="primary"
  :actions="[
    { id: 'poi', label: 'Ajouter un POI', icon: 'sym_r_place' },
    { id: 'stage', label: 'Ajouter une étape', icon: 'sym_r_flag' },
    { id: 'photo', label: 'Prendre une photo', icon: 'sym_r_photo_camera' }
  ]"
  @action="handleFabAction"
/>

<!-- Ou sans menu -->
<MobileFab
  icon="sym_r_navigation"
  color="success"
  @click="startNavigation"
/>
```

**Colors:** `primary`, `success`, `warning`, `danger`

---

## 🎨 Variables CSS

Le fichier `mobile-unified.scss` définit les variables utilisées par tous les composants:

```scss
// Spacing
--mobile-space-xs: 4px;
--mobile-space-sm: 8px;
--mobile-space-md: 12px;
--mobile-space-lg: 16px;
--mobile-space-xl: 20px;
--mobile-space-2xl: 24px;

// Radius
--mobile-radius-xs: 6px;
--mobile-radius-sm: 10px;
--mobile-radius-md: 14px;
--mobile-radius-lg: 18px;
--mobile-radius-xl: 24px;

// Colors
--mobile-bg-page: linear-gradient(...);
--mobile-bg-card: rgba(30, 41, 59, 0.5);
--mobile-bg-elevated: rgba(45, 55, 72, 0.6);
--mobile-border: rgba(255, 255, 255, 0.06);

// Safe Area
--mobile-safe-bottom: calc(90px + env(safe-area-inset-bottom, 16px));
```

---

## 📐 Structure de Page Standard

```vue
<template>
  <q-page class="mobile-page">
    <!-- 1. Hero Section -->
    <MobilePageHero
      :title="trip.name"
      :subtitle="tripSummary"
      :stats="tripStats"
      :primaryCta="mainAction"
      @ctaClick="handleMainAction"
    />
    
    <!-- 2. Container avec padding et safe area -->
    <div class="mobile-page__container">
      
      <!-- 3. Tabs (optionnel) -->
      <MobilePageTabs v-model="activeTab" :tabs="tabs" />
      
      <!-- 4. Content -->
      <div class="mobile-page__content">
        
        <!-- Cards, Grids, Lists... -->
        <MobileCard title="Section 1" icon="sym_r_list">
          <MobileStatsGrid :stats="stats" />
        </MobileCard>
        
        <MobileCard title="Actions rapides">
          <MobileActionGrid :actions="actions" @action="handleAction" />
        </MobileCard>
        
        <!-- Empty State si nécessaire -->
        <MobileEmptyState
          v-if="!hasData"
          title="Aucune donnée"
          cta-label="Ajouter"
          @action="addData"
        />
        
      </div>
    </div>
    
    <!-- 5. FAB (optionnel) -->
    <MobileFab :actions="fabActions" @action="handleFabAction" />
  </q-page>
</template>
```

---

## ✅ Checklist Migration

### DashboardPage.mobile.vue
- [ ] Remplacer `DashboardMobileHero` par `MobilePageHero`
- [ ] Utiliser `MobileStatsGrid` pour les stats
- [ ] Utiliser `MobileActionGrid` pour les actions rapides
- [ ] Utiliser `MobileSlider` pour le carousel d'étapes

### PlannerPage.mobile.vue
- [ ] Remplacer `PlannerMobileHero` par `MobilePageHero`
- [ ] Remplacer `.premium-tabs` par `MobilePageTabs`
- [ ] Utiliser `MobileCard` pour les sections

### ProfilePage.mobile.vue
- [ ] Remplacer `ProfileMobileHero` par `MobilePageHero`
- [ ] Remplacer `q-btn-toggle` par `MobilePageTabs` (scrollable)
- [ ] Utiliser `MobileCard` pour chaque section

### ExplorePage.mobile.vue
- [ ] Remplacer le hero inline par `MobilePageHero`
- [ ] Utiliser `MobileEmptyState` pour l'état non connecté

### MapPage.mobile.vue
- [ ] Garder la structure actuelle (full-screen map)
- [ ] Utiliser `MobileCard` pour les panneaux overlay

---

## 📁 Fichiers Créés

```
apps/web/src/
├── assets/styles/
│   └── mobile-unified.scss           # Variables & classes utilitaires
└── shared/components/mobile/
    ├── index.ts                       # Exports centralisés
    ├── MobilePageHero.vue            # ~250 lignes
    ├── MobilePageTabs.vue            # ~140 lignes
    ├── MobileCard.vue                # ~120 lignes
    ├── MobileEmptyState.vue          # ~100 lignes
    ├── MobileActionGrid.vue          # ~110 lignes
    ├── MobileStatsGrid.vue           # ~90 lignes
    ├── MobileSlider.vue              # ~60 lignes
    └── MobileFab.vue                 # ~180 lignes
```

---

## 🚫 Règles

1. **TOUJOURS** utiliser ces composants pour les nouvelles pages mobiles
2. **NE PAS** créer de nouveaux composants hero/tabs/cards/FAB
3. **NE PAS** utiliser des valeurs hardcodées (utiliser `--mobile-space-*`)
4. **TOUJOURS** respecter le safe area bottom pour la bottom nav
5. **MIGRER** progressivement les pages existantes
