# Story 1.5: Landing page et choix du héros Status: ready-for-dev ## Story As a visiteur, I want choisir entre l'aventure et le mode express, puis sélectionner mon héros, so that mon expérience est adaptée à mon profil et mon temps disponible. ## Acceptance Criteria 1. **Given** le visiteur arrive sur la landing page (`/`) **When** la page se charge **Then** deux CTA distincts sont visibles : "Partir à l'aventure" et "Mode express" 2. **And** un texte d'accroche intrigant bilingue est affiché 3. **And** une animation d'entrée subtile est présente (respectant `prefers-reduced-motion`) 4. **And** le design est responsive (mobile + desktop) 5. **And** au clic sur "Partir à l'aventure", le composant `HeroSelector` s'affiche avec 3 cards illustrées (Recruteur, Client, Développeur) avec nom et description courte 6. **And** le héros sélectionné est stocké dans le store Pinia `useProgressionStore` (champ `hero`) 7. **And** au clic sur "Mode express", le visiteur est redirigé vers la page résumé 8. **And** le `HeroSelector` est accessible au clavier (`role="radiogroup"`, flèches pour naviguer, Enter pour sélectionner) ## Tasks / Subtasks - [ ] **Task 1: Structure de la landing page** (AC: #1, #2, #4) - [ ] Implémenter `frontend/app/pages/index.vue` - [ ] Section hero avec texte d'accroche bilingue (`$t('landing.title')`, `$t('landing.subtitle')`) - [ ] Deux boutons CTA côte à côte (desktop) ou empilés (mobile) - [ ] Utiliser les couleurs du design system (sky-accent pour CTA principal) - [ ] Layout responsive : centré verticalement, max-width pour le contenu - [ ] **Task 2: Animations d'entrée** (AC: #3) - [ ] Animation fade-in + slide-up pour le texte d'accroche - [ ] Animation staggered pour les CTA (apparition décalée) - [ ] Utiliser CSS animations ou GSAP (lazy-loaded) - [ ] Media query `prefers-reduced-motion` : animations désactivées - [ ] Durée totale : ~1s max - [ ] **Task 3: Composant HeroSelector** (AC: #5, #8) - [ ] Créer `frontend/app/components/feature/HeroSelector.vue` - [ ] Props : `modelValue` (héros sélectionné), emit `update:modelValue` - [ ] Afficher 3 cards : Recruteur, Client, Développeur - [ ] Chaque card : illustration/icône, nom traduit, description courte traduite - [ ] État visuel : card sélectionnée avec bordure accent - [ ] Accessibilité : `role="radiogroup"`, `role="radio"` sur chaque card - [ ] Navigation clavier : flèches gauche/droite, Enter pour confirmer - [ ] Focus visible sur la card active - [ ] **Task 4: Données des héros** (AC: #5) - [ ] Définir les 3 héros dans un fichier de config ou composable - [ ] Structure : `{ id: 'recruteur' | 'client' | 'dev', nameKey, descriptionKey, icon }` - [ ] Traductions dans `i18n/fr.json` et `i18n/en.json` : - `hero.recruteur.name`: "Recruteur" - `hero.recruteur.description`: "Je cherche un talent pour mon équipe" - `hero.client.name`: "Client" - `hero.client.description`: "J'ai un projet à réaliser" - `hero.dev.name`: "Développeur" - `hero.dev.description`: "Je suis curieux de voir ton travail" - [ ] **Task 5: Intégration avec le store Pinia** (AC: #6) - [ ] Importer `useProgressionStore` (créé en Story 1.6, mais interface définie ici) - [ ] Au choix du héros : `store.setHero(heroId)` - [ ] Après sélection : naviguer vers la première zone ou afficher l'intro narrative - [ ] Si store non disponible (Story 1.6 pas encore faite) : utiliser un state local temporaire - [ ] **Task 6: Flow de sélection** (AC: #5, #6) - [ ] État initial : CTA visibles, HeroSelector masqué - [ ] Clic "Partir à l'aventure" : transition vers HeroSelector (fade/slide) - [ ] Clic sur un héros : sélection visuelle - [ ] Bouton "Confirmer" ou double-clic : valider et naviguer - [ ] Bouton "Retour" pour revenir aux CTA - [ ] Animation de transition fluide entre les états - [ ] **Task 7: Redirection Mode Express** (AC: #7) - [ ] Clic "Mode express" : `navigateTo(localePath('/resume'))` - [ ] Pas de sélection de héros requise pour le mode express - [ ] Le store peut rester sans héros défini (mode anonyme) - [ ] **Task 8: SEO et meta tags** (AC: #1) - [ ] Utiliser `useSeo()` pour définir les meta tags de la landing - [ ] Title : "Skycel - Portfolio interactif de Célian" - [ ] Description : "Découvrez mon portfolio gamifié..." - [ ] Open Graph image : image de preview attractive - [ ] **Task 9: Validation finale** (AC: tous) - [ ] Page accessible en FR (`/`) et EN (`/en`) - [ ] Textes traduits correctement - [ ] CTA fonctionnels - [ ] HeroSelector s'affiche et fonctionne - [ ] Navigation clavier complète - [ ] Animations fluides (et désactivées si reduced-motion) - [ ] Responsive : mobile et desktop - [ ] Redirection vers `/resume` fonctionne ## Dev Notes ### Structure de la landing page ``` ┌─────────────────────────────────────────────────────────────────┐ │ LANDING PAGE │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ [Logo ou titre animé] │ │ │ │ "Bienvenue dans mon univers" │ │ Développeur Full-Stack │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ Partir à │ │ Mode express │ │ │ │ l'aventure │ │ (30 secondes) │ │ │ └─────────────────┘ └─────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘ ↓ Clic "Aventure" ┌─────────────────────────────────────────────────────────────────┐ │ HERO SELECTOR │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ "Qui êtes-vous, voyageur ?" │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ 👔 │ │ 💼 │ │ 💻 │ │ │ │Recruteur│ │ Client │ │ Dev │ │ │ │ "Je..." │ │ "J'ai..." │ │"Je suis.."│ │ │ └─────────┘ └─────────┘ └─────────┘ │ │ │ │ [Retour] [Confirmer] │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### Composant HeroSelector ```vue ``` ### Traductions à ajouter ```json // frontend/i18n/fr.json { "landing": { "title": "Bienvenue dans mon univers", "subtitle": "Développeur Full-Stack passionné", "cta_adventure": "Partir à l'aventure", "cta_express": "Mode express (30s)" }, "hero": { "question": "Qui êtes-vous, voyageur ?", "select_label": "Sélectionnez votre profil", "recruteur": { "name": "Recruteur", "description": "Je cherche un talent pour rejoindre mon équipe" }, "client": { "name": "Client", "description": "J'ai un projet à réaliser et je cherche le bon développeur" }, "dev": { "name": "Développeur", "description": "Je suis curieux de découvrir ton travail et tes compétences" } } } ``` ### Animations CSS ```css /* Animations d'entrée pour la landing */ @keyframes fadeSlideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } .animate-fade-slide-up { animation: fadeSlideUp 0.6s ease-out forwards; } .animate-delay-100 { animation-delay: 0.1s; } .animate-delay-200 { animation-delay: 0.2s; } .animate-delay-300 { animation-delay: 0.3s; } /* Respect prefers-reduced-motion */ @media (prefers-reduced-motion: reduce) { .animate-fade-slide-up { animation: none; opacity: 1; transform: none; } } ``` ### Dépendances **Cette story DÉPEND de :** - Story 1.3 : Système i18n pour les traductions - Story 1.4 : Layout default, transitions de page, useSeo() **Cette story PRÉPARE pour :** - Story 1.6 : Le store Pinia stockera le héros sélectionné - Story 4.2 : L'intro narrative suivra la sélection du héros **Note :** Si Story 1.6 n'est pas encore implémentée, utiliser un state local (`ref`) comme placeholder. ### References - [Source: docs/planning-artifacts/epics.md#Story-1.5] - [Source: docs/planning-artifacts/ux-design-specification.md#Hero-System] - [Source: docs/planning-artifacts/architecture.md#Store-Pinia] - [Source: docs/prd-gamification.md#FR1] ### Technical Requirements | Requirement | Value | Source | |-------------|-------|--------| | Héros disponibles | Recruteur, Client, Dev | UX Design | | Accessibilité | WCAG AA, keyboard nav | NFR6 | | Animations | Respecter reduced-motion | NFR6 | | Responsive | Mobile + Desktop | NFR3 | ## Dev Agent Record ### Agent Model Used {{agent_model_name_version}} ### Debug Log References ### Completion Notes List ### Change Log | Date | Change | Author | |------|--------|--------| | 2026-02-03 | Story créée avec contexte complet | SM Agent | ### File List