# Story 4.1: Composant ChoiceCards et choix narratifs Status: ready-for-dev ## Story As a visiteur, I want faire des choix qui influencent mon parcours, so that mon expérience est unique et personnalisée. ## Acceptance Criteria 1. **Given** le composant `ChoiceCards` est implémenté **When** le narrateur propose un choix **Then** 2 cards s'affichent côte à côte (desktop) ou empilées (mobile) 2. **And** chaque card affiche : icône, texte narratif du choix 3. **And** un hover/focus highlight la card sélectionnable 4. **And** un clic enregistre le choix dans `choices` du store Pinia 5. **And** une transition animée mène vers la destination choisie 6. **And** le composant est accessible (`role="radiogroup"`, navigation clavier, focus visible) 7. **And** `prefers-reduced-motion` simplifie les animations 8. **And** le style est cohérent avec l'univers narratif (police serif, couleurs des zones) ## Tasks / Subtasks - [ ] **Task 1: Définir les types de choix** (AC: #2, #4) - [ ] Créer `frontend/app/types/choice.ts` - [ ] Interface Choice : id, textFr, textEn, icon, destination, zoneColor - [ ] Interface ChoicePoint : id, choices (2 options), context - [ ] **Task 2: Créer le composant ChoiceCard** (AC: #2, #3, #8) - [ ] Créer `frontend/app/components/feature/ChoiceCard.vue` - [ ] Props : choice (Choice), selected (boolean), disabled (boolean) - [ ] Afficher icône + texte narratif - [ ] Effet hover/focus avec highlight - [ ] Police serif narrative pour le texte - [ ] **Task 3: Créer le composant ChoiceCards** (AC: #1, #4, #5, #6) - [ ] Créer `frontend/app/components/feature/ChoiceCards.vue` - [ ] Props : choicePoint (ChoicePoint) - [ ] Emit : select (choice) - [ ] Layout côte à côte desktop, empilé mobile - [ ] Gérer la sélection et enregistrer dans le store - [ ] Animation de transition vers la destination - [ ] **Task 4: Implémenter l'accessibilité** (AC: #6) - [ ] role="radiogroup" sur le conteneur - [ ] role="radio" sur chaque card - [ ] aria-checked pour indiquer la sélection - [ ] Navigation clavier (flèches gauche/droite) - [ ] Focus visible conforme WCAG - [ ] **Task 5: Gérer les animations** (AC: #5, #7) - [ ] Animation de sélection (scale + glow) - [ ] Transition vers la destination (fade-out) - [ ] Respecter prefers-reduced-motion - [ ] **Task 6: Intégrer avec le store** (AC: #4) - [ ] Appeler `progressionStore.addChoice(id, value)` à la sélection - [ ] Les choix sont persistés avec le reste de la progression - [ ] **Task 7: Tests et validation** - [ ] Tester le layout desktop et mobile - [ ] Valider hover/focus - [ ] Tester navigation clavier - [ ] Vérifier l'enregistrement du choix - [ ] Tester prefers-reduced-motion ## Dev Notes ### Types des choix ```typescript // frontend/app/types/choice.ts export interface Choice { id: string textFr: string textEn: string icon: string // emoji ou URL d'image destination: string // route vers laquelle naviguer zoneColor: string // couleur de la zone associée } export interface ChoicePoint { id: string questionFr: string questionEn: string choices: [Choice, Choice] // Toujours 2 choix binaires context: string // contexte narratif (intro, after_projects, etc.) } // Exemple de point de choix export const CHOICE_POINTS: Record = { intro_first_choice: { id: 'intro_first_choice', questionFr: 'Par où veux-tu commencer ton exploration ?', questionEn: 'Where do you want to start your exploration?', choices: [ { id: 'choice_projects_first', textFr: 'Découvrir les créations', textEn: 'Discover the creations', icon: '💻', destination: '/projets', zoneColor: '#3b82f6', }, { id: 'choice_skills_first', textFr: 'Explorer les compétences', textEn: 'Explore the skills', icon: '⚡', destination: '/competences', zoneColor: '#10b981', }, ], context: 'intro', }, after_projects: { id: 'after_projects', questionFr: 'Quelle sera ta prochaine étape ?', questionEn: 'What will be your next step?', choices: [ { id: 'choice_testimonials', textFr: "Écouter ceux qui l'ont rencontré", textEn: 'Listen to those who met him', icon: '💬', destination: '/temoignages', zoneColor: '#f59e0b', }, { id: 'choice_journey', textFr: 'Suivre son parcours', textEn: 'Follow his journey', icon: '📍', destination: '/parcours', zoneColor: '#8b5cf6', }, ], context: 'after_projects', }, } ``` ### Composant ChoiceCard ```vue ``` ### Composant ChoiceCards ```vue ``` ### Utilisation dans une page/composant ```vue ``` ### Dépendances **Cette story nécessite :** - Story 3.5 : Store de progression (addChoice) - Story 3.2 : useReducedMotion composable **Cette story prépare pour :** - Story 4.2 : Intro narrative (utilise ChoiceCards) - Story 4.3 : Chemins narratifs (points de choix multiples) ### Project Structure Notes **Fichiers à créer :** ``` frontend/app/ ├── types/ │ └── choice.ts # CRÉER └── components/feature/ ├── ChoiceCard.vue # CRÉER └── ChoiceCards.vue # CRÉER ``` ### References - [Source: docs/planning-artifacts/epics.md#Story-4.1] - [Source: docs/planning-artifacts/ux-design-specification.md#Choice-System] - [Source: docs/brainstorming-gamification-2026-01-26.md#Parcours-Narratifs] ### Technical Requirements | Requirement | Value | Source | |-------------|-------|--------| | Choix par point | 2 (binaire) | Epics | | Layout desktop | Côte à côte | Epics | | Layout mobile | Empilé | Epics | | Accessibilité | role="radiogroup", clavier | Epics | | Police | font-narrative | UX Spec | ## Dev Agent Record ### Agent Model Used {{agent_model_name_version}} ### Debug Log References ### Completion Notes List ### Change Log | Date | Change | Author | |------|--------|--------| | 2026-02-04 | Story créée avec contexte complet | SM Agent | ### File List