# Story 2.8: Page Parcours - Timeline narrative Status: ready-for-dev ## Story As a visiteur, I want découvrir le parcours professionnel du développeur sous forme de timeline, so that je comprends son évolution et son expérience. ## Acceptance Criteria 1. **Given** le visiteur accède à `/parcours` (FR) ou `/en/journey` (EN) **When** la page se charge **Then** une timeline verticale affiche les étapes chronologiques du parcours 2. **And** chaque étape affiche : date, titre, description narrative traduite 3. **And** sur desktop : les étapes alternent gauche/droite pour un effet visuel dynamique 4. **And** sur mobile : les étapes sont linéaires (toutes du même côté) 5. **And** une animation d'apparition au scroll est présente (respectant `prefers-reduced-motion`) 6. **And** des icônes ou images illustrent les étapes clés 7. **And** le contenu est bilingue (FR/EN) et chargé depuis l'API ou fichiers i18n 8. **And** les meta tags SEO sont dynamiques pour cette page 9. **And** la police serif narrative est utilisée pour les descriptions ## Tasks / Subtasks - [ ] **Task 1: Décider de la source de données** (AC: #7) - [ ] Option A : Fichiers i18n (données statiques) - [ ] Option B : Table BDD + API (données dynamiques) - [ ] Recommandation : Fichiers i18n (le parcours change rarement, pas besoin de CRUD) - [ ] **Task 2: Créer les données du parcours dans i18n** (AC: #2, #7) - [ ] Ajouter les clés `journey.milestones` dans fr.json et en.json - [ ] Structure : date, title, description, icon - [ ] 5-8 étapes du parcours professionnel - [ ] **Task 3: Créer le composant TimelineItem** (AC: #2, #6, #9) - [ ] Créer `frontend/app/components/feature/TimelineItem.vue` - [ ] Props : milestone (date, title, description, icon) - [ ] Afficher l'icône/image, la date, le titre et la description - [ ] Utiliser font-narrative pour la description - [ ] **Task 4: Créer la page parcours.vue** (AC: #1, #3, #4) - [ ] Créer `frontend/app/pages/parcours.vue` - [ ] Charger les milestones depuis i18n - [ ] Layout timeline vertical avec ligne centrale - [ ] Desktop : alternance gauche/droite - [ ] Mobile : toutes les étapes à droite - [ ] **Task 5: Implémenter l'animation au scroll** (AC: #5) - [ ] Utiliser IntersectionObserver pour détecter l'entrée dans le viewport - [ ] Animation fade-in + slide-up pour chaque étape - [ ] Respecter prefers-reduced-motion - [ ] Créer un composable `useIntersectionObserver()` - [ ] **Task 6: Design de la timeline** (AC: #3, #4) - [ ] Ligne centrale verticale (sky-dark-100) - [ ] Points de connexion sur la ligne (circles sky-accent) - [ ] Cards avec flèche vers la ligne centrale - [ ] Responsive : adaptation mobile - [ ] **Task 7: Meta tags SEO** (AC: #8) - [ ] Titre : "Mon Parcours | Skycel" - [ ] Description du parcours - [ ] **Task 8: Tests et validation** - [ ] Tester en FR et EN - [ ] Valider l'alternance desktop - [ ] Vérifier le layout mobile - [ ] Tester l'animation au scroll - [ ] Valider prefers-reduced-motion ## Dev Notes ### Structure des données dans i18n **fr.json :** ```json { "journey": { "title": "Mon Parcours", "pageTitle": "Parcours | Skycel", "pageDescription": "Découvrez le parcours professionnel de Célian, de ses débuts à aujourd'hui.", "milestones": [ { "date": "2018", "title": "Premiers pas en développement", "description": "Découverte du code à travers des projets personnels. HTML, CSS, JavaScript deviennent mes nouveaux compagnons de route. L'étincelle est là.", "icon": "🚀" }, { "date": "2019", "title": "Formation intensive", "description": "Plongée dans le monde du développement web professionnel. Apprentissage de frameworks modernes, bonnes pratiques, et méthodologies agiles.", "icon": "📚" }, { "date": "2020", "title": "Premiers clients", "description": "Lancement en freelance. Premiers projets concrets, premiers défis réels. Chaque client m'apprend quelque chose de nouveau.", "icon": "💼" }, { "date": "2021", "title": "Spécialisation Vue.js & Laravel", "description": "Le duo qui change tout. Vue.js côté front, Laravel côté back. Une stack qui me permet de créer des expériences web complètes et performantes.", "icon": "⚡" }, { "date": "2022", "title": "Création de la micro-entreprise", "description": "Officialisation de l'aventure entrepreneuriale. L'araignée devient la mascotte, le Bug devient le guide. L'identité Skycel prend forme.", "icon": "🕷️" }, { "date": "2023-2024", "title": "Projets ambitieux", "description": "Des applications web complexes aux sites e-commerce, chaque projet repousse les limites. TypeScript, Nuxt 4, et une obsession pour la qualité.", "icon": "🎯" }, { "date": "2025", "title": "Aujourd'hui", "description": "Ce portfolio que vous explorez. Une aventure en soi, qui reflète ma passion pour créer des expériences web mémorables. Et ce n'est que le début...", "icon": "✨" } ] } } ``` **en.json :** ```json { "journey": { "title": "My Journey", "pageTitle": "Journey | Skycel", "pageDescription": "Discover Célian's professional journey, from the beginning to today.", "milestones": [ { "date": "2018", "title": "First steps in development", "description": "Discovering code through personal projects. HTML, CSS, JavaScript became my new travel companions. The spark was there.", "icon": "🚀" }, { "date": "2019", "title": "Intensive training", "description": "Deep dive into professional web development. Learning modern frameworks, best practices, and agile methodologies.", "icon": "📚" }, { "date": "2020", "title": "First clients", "description": "Starting as a freelancer. First real projects, first real challenges. Each client teaches me something new.", "icon": "💼" }, { "date": "2021", "title": "Specialization in Vue.js & Laravel", "description": "The game-changing duo. Vue.js on the front, Laravel on the back. A stack that allows me to create complete, performant web experiences.", "icon": "⚡" }, { "date": "2022", "title": "Creating the micro-enterprise", "description": "Making the entrepreneurial adventure official. The spider becomes the mascot, the Bug becomes the guide. The Skycel identity takes shape.", "icon": "🕷️" }, { "date": "2023-2024", "title": "Ambitious projects", "description": "From complex web applications to e-commerce sites, each project pushes boundaries. TypeScript, Nuxt 4, and an obsession with quality.", "icon": "🎯" }, { "date": "2025", "title": "Today", "description": "This portfolio you're exploring. An adventure in itself, reflecting my passion for creating memorable web experiences. And this is just the beginning...", "icon": "✨" } ] } } ``` ### Composable useIntersectionObserver ```typescript // frontend/app/composables/useIntersectionObserver.ts export interface UseIntersectionObserverOptions { threshold?: number rootMargin?: string once?: boolean } export function useIntersectionObserver( target: Ref, options: UseIntersectionObserverOptions = {} ) { const { threshold = 0.1, rootMargin = '0px', once = true } = options const isVisible = ref(false) let observer: IntersectionObserver | null = null onMounted(() => { if (!target.value) return observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { isVisible.value = true if (once && observer) { observer.unobserve(entry.target) } } else if (!once) { isVisible.value = false } }) }, { threshold, rootMargin } ) observer.observe(target.value) }) onUnmounted(() => { if (observer) { observer.disconnect() } }) return { isVisible } } ``` ### Composant TimelineItem ```vue ``` ### Page parcours.vue ```vue ``` ### Clés i18n supplémentaires **fr.json :** ```json { "journey": { "endMessage": "L'aventure continue... Qui sait où le code me mènera demain ?" } } ``` **en.json :** ```json { "journey": { "endMessage": "The adventure continues... Who knows where code will take me tomorrow?" } } ``` ### Design de la timeline ``` DESKTOP (alternance gauche/droite) : ┌─────────────────┐ │ 2018 │ │ Description │──●── └─────────────────┘ │ │ ──●────┼────┌─────────────────┐ │ │ 2019 │ │ │ Description │ │ └─────────────────┘ │ ┌─────────────────┐ │ │ 2020 │──●── │ Description │ │ └─────────────────┘ │ MOBILE (linéaire à droite) : │ ┌─────────────────┐ ●──│ 2018 │ │ │ Description │ │ └─────────────────┘ │ │ ┌─────────────────┐ ●──│ 2019 │ │ │ Description │ │ └─────────────────┘ ``` ### Dépendances **Cette story nécessite :** - Story 1.3 : Système i18n configuré - Story 1.4 : Layouts et routing **Cette story prépare pour :** - Aucune dépendance directe (dernière story de l'Epic 2) ### Project Structure Notes **Fichiers à créer :** ``` frontend/app/ ├── pages/ │ └── parcours.vue # CRÉER ├── components/feature/ │ └── TimelineItem.vue # CRÉER └── composables/ └── useIntersectionObserver.ts # CRÉER ``` **Fichiers à modifier :** ``` frontend/i18n/fr.json # AJOUTER journey.* frontend/i18n/en.json # AJOUTER journey.* ``` ### References - [Source: docs/planning-artifacts/epics.md#Story-2.8] - [Source: docs/planning-artifacts/ux-design-specification.md#Screen-Architecture-Summary] - [Source: docs/planning-artifacts/ux-design-specification.md#Typography-System] ### Technical Requirements | Requirement | Value | Source | |-------------|-------|--------| | Source données | Fichiers i18n | Décision technique | | Layout desktop | Alternance gauche/droite | Epics | | Layout mobile | Linéaire à droite | Epics | | Animation | IntersectionObserver + fade-in | Epics | | Police | font-narrative pour descriptions | 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