---
name: ui-style
description: Design system et harmonisation UI de Mangarr — layout de page canonique (Toolbar + flex + sections border-t), palette Tailwind, patterns composants (boutons, badges, upload, progression). Utiliser quand on crée ou modifie une page Vue ou un composant UI.
allowed-tools: Read, Grep, Glob
---

# Design system Mangarr — Guide UI

Les pages de référence canoniques sont :
- `assets/vue/app/domain/manga/infrastructure/presentation/pages/NewImportPage.vue`
- `assets/vue/app/domain/conversion/infrastructure/presentation/pages/ConversionPage.vue`

En cas de doute, les lire pour vérifier le pattern en vigueur.

---

## 1. Layout de page canonique

```vue
<template>
  <div class="flex flex-col h-full">
    <Toolbar :config="toolbarConfig" />
    <div class="overflow-y-auto flex-1">
      <div class="px-6 py-8">
        <section class="border-t border-gray-200 dark:border-gray-700 pt-6">
          <h2 class="text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase tracking-wider mb-4">
            Titre section
          </h2>
          <!-- contenu -->
        </section>
        <section class="border-t border-gray-200 dark:border-gray-700 pt-6 mt-6">
          <!-- section suivante -->
        </section>
      </div>
    </div>
  </div>
</template>
```

**Règles absolues :**
- `flex flex-col h-full` toujours à la racine du template
- `<Toolbar>` toujours en premier enfant direct de la racine
- `overflow-y-auto flex-1` pour le contenu scrollable
- `px-6 py-8` comme wrapper interne — **jamais** `container mx-auto`
- Chaque bloc logique = une `<section>` avec `border-t border-gray-200 dark:border-gray-700`
- **Jamais** de `<h1>` volant dans le contenu — le titre de page va dans `toolbarConfig.leftSection`

---

## 2. Configuration Toolbar

```javascript
import { computed } from 'vue';
import { SomeIcon } from '@heroicons/vue/24/outline';

const toolbarConfig = computed(() => ({
  leftSection: [
    { type: 'label', text: 'Titre de la page', class: 'text-sm font-medium' },
  ],
  rightSection: [
    {
      type: 'button',
      icon: SomeIcon,
      label: 'Action principale',
      onClick: handler,
      disabled: condition,
    },
    // Bouton conditionnel :
    ...(showAction ? [{
      type: 'button',
      icon: OtherIcon,
      label: 'Action contextuelle',
      onClick: otherHandler,
    }] : []),
  ],
}));
```

- Icônes : Heroicons v24/outline (`@heroicons/vue/24/outline`)
- Boutons toolbar visibles uniquement si pertinents — utiliser le spread conditionnel
- `rightSection` peut être vide `[]`

---

## 3. Headers de section

```vue
<!-- Header simple -->
<h2 class="text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase tracking-wider mb-4">
  Titre
</h2>

<!-- Header avec info contextuelle à droite -->
<div class="flex items-center justify-between mb-3">
  <h2 class="text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase tracking-wider">
    Titre
  </h2>
  <span class="text-xs text-gray-500 dark:text-gray-400">info contextuelle</span>
</div>
```

---

## 4. Palette de couleurs

| Usage | Classes Tailwind |
|-------|-----------------|
| Primaire (action principale) | `bg-green-600 hover:bg-green-700` |
| Secondaire | `bg-blue-600 hover:bg-blue-700` |
| Danger | `bg-red-600 hover:bg-red-700` |
| Désactivé | `disabled:bg-gray-400 disabled:cursor-not-allowed` |
| Texte principal | `text-gray-900 dark:text-gray-100` |
| Texte secondaire | `text-gray-600 dark:text-gray-300` |
| Texte subtil | `text-gray-500 dark:text-gray-400` |
| Étiquette section | `text-gray-400 dark:text-gray-500` |
| Fond carte / panel | `bg-white dark:bg-gray-800` |
| Bordure | `border-gray-200 dark:border-gray-700` |
| Séparateur de liste | `divide-y divide-gray-100 dark:divide-gray-700/50` |

---

## 5. Boutons

```vue
<!-- Bouton action principale (submit, lancer, confirmer) -->
<button
  class="bg-green-600 hover:bg-green-700 disabled:bg-gray-400 disabled:cursor-not-allowed text-white px-4 py-2 rounded-md font-medium transition-colors"
  :disabled="condition"
>
  Label
</button>

<!-- Bouton ghost / discret -->
<button class="text-sm text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 transition-colors">
  Label
</button>
```

---

## 6. Barre de progression

```vue
<div class="bg-gray-200 dark:bg-gray-700 h-1.5 mb-4">
  <div
    class="bg-green-600 h-1.5 transition-all duration-300"
    :style="{ width: progress + '%' }"
  />
</div>
```

> **Important :** toujours `bg-green-600`, jamais `bg-blue-600` pour les barres de progression.

---

## 7. Liste avec séparateurs

```vue
<div class="divide-y divide-gray-100 dark:divide-gray-700/50">
  <div
    v-for="item in items"
    :key="item.id"
    class="flex items-center justify-between py-3"
  >
    <!-- contenu de l'item -->
  </div>
</div>
```

---

## 8. Zone de drop / upload de fichier

```vue
<div
  class="border-2 border-dashed rounded-lg p-8 text-center transition-colors"
  :class="isDragging
    ? 'border-green-500 bg-green-50 dark:bg-green-900/10'
    : 'border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600'"
  @dragover.prevent="isDragging = true"
  @dragleave="isDragging = false"
  @drop.prevent="handleDrop"
>
  <SomeIcon class="mx-auto h-8 w-8 text-gray-400 mb-3" />
  <p class="text-sm text-gray-600 dark:text-gray-300">
    Message principal
  </p>
  <p class="text-xs text-gray-400 dark:text-gray-500 mt-1">
    Précision format/taille
  </p>
</div>
```

---

## 9. Pages non conformes à corriger

Les pages suivantes dévient encore du pattern canonique :

| Page | Chemin relatif | Déviations principales |
|------|---------------|----------------------|
| `HomePage.vue` | `domain/manga/.../pages/` | Pas de `px-6 py-8`, pas de sections `border-t` |
| `AddManga.vue` | `domain/manga/.../pages/` | Pas de Toolbar, pas de `flex flex-col h-full` |
| `ActivityPage.vue` | `domain/activity/.../pages/` | Pas de `flex flex-col`, pas de Toolbar intégré |
| `UserPreferencesPage.vue` | `domain/setting/.../pages/` | `h1` volant, pas de Toolbar |
| `ScrapperConfigurations.vue` | `domain/setting/.../pages/` | `h1` volant, `container mx-auto` |
| `ScrapperEdit.vue` | `domain/setting/.../pages/` | `container mx-auto` au lieu de `px-6 py-8` |
| `MangaDetails.vue` | `domain/manga/.../pages/` | Layout spécial (cover + chapitres), à traiter séparément |
| `ChapterPage.vue` | `domain/reader/.../pages/` | Layout lecteur spécialisé — **exception justifiée**, ne pas modifier |

---

## 10. Checklist avant de livrer une page

- [ ] Racine : `flex flex-col h-full`
- [ ] Premier enfant : `<Toolbar :config="toolbarConfig" />`
- [ ] Contenu scrollable : `overflow-y-auto flex-1`
- [ ] Wrapper interne : `px-6 py-8` (jamais `container mx-auto`)
- [ ] Blocs logiques : `<section class="border-t border-gray-200 dark:border-gray-700 pt-6">`
- [ ] Titre de page dans `toolbarConfig.leftSection`, pas de `<h1>` dans le contenu
- [ ] Headers de section : classes `text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase tracking-wider`
- [ ] Barres de progression : `bg-green-600` (pas `bg-blue-600`)
- [ ] Dark mode : chaque couleur a sa variante `dark:`
