✨ Add projects gallery page with responsive grid (Story 2.2)
- Create useFetchProjects composable for API integration - Implement responsive grid layout (1/2/3/4 columns) - Add stagger fadeInUp animation with prefers-reduced-motion support - Include loading skeleton, error state with retry, and empty state - Configure SEO meta tags via useSeo composable - Update Project model ordered scope for proper sorting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Story 2.2: Page Projets - Galerie
|
||||
|
||||
Status: ready-for-dev
|
||||
Status: review
|
||||
|
||||
## Story
|
||||
|
||||
@@ -19,55 +19,55 @@ so that je peux évaluer son expérience et choisir lesquels explorer en détail
|
||||
|
||||
## Tasks / Subtasks
|
||||
|
||||
- [ ] **Task 1: Créer l'endpoint API Laravel** (AC: #4)
|
||||
- [ ] Créer `app/Http/Controllers/Api/ProjectController.php`
|
||||
- [ ] Créer la méthode `index()` pour lister tous les projets
|
||||
- [ ] Implémenter le tri : featured en premier, puis par date_completed DESC
|
||||
- [ ] Joindre les traductions selon le header `Accept-Language`
|
||||
- [ ] Créer `app/Http/Resources/ProjectResource.php` pour formater la réponse
|
||||
- [ ] Ajouter la route `GET /api/projects` dans `routes/api.php`
|
||||
- [x] **Task 1: Créer l'endpoint API Laravel** (AC: #4)
|
||||
- [x] Créer `app/Http/Controllers/Api/ProjectController.php`
|
||||
- [x] Créer la méthode `index()` pour lister tous les projets
|
||||
- [x] Implémenter le tri : featured en premier, puis par date_completed DESC
|
||||
- [x] Joindre les traductions selon le header `Accept-Language`
|
||||
- [x] Créer `app/Http/Resources/ProjectResource.php` pour formater la réponse
|
||||
- [x] Ajouter la route `GET /api/projects` dans `routes/api.php`
|
||||
|
||||
- [ ] **Task 2: Créer le composable useFetchProjects** (AC: #4)
|
||||
- [ ] Créer `frontend/app/composables/useFetchProjects.ts`
|
||||
- [ ] Utiliser `useFetch()` pour appeler l'API avec le header `Accept-Language`
|
||||
- [ ] Gérer les états loading, error, data
|
||||
- [ ] Typer la réponse avec l'interface Project[]
|
||||
- [x] **Task 2: Créer le composable useFetchProjects** (AC: #4)
|
||||
- [x] Créer `frontend/app/composables/useFetchProjects.ts`
|
||||
- [x] Utiliser `useFetch()` pour appeler l'API avec le header `Accept-Language`
|
||||
- [x] Gérer les états loading, error, data
|
||||
- [x] Typer la réponse avec l'interface Project[]
|
||||
|
||||
- [ ] **Task 3: Créer la page projets.vue** (AC: #1, #6)
|
||||
- [ ] Créer `frontend/app/pages/projets.vue`
|
||||
- [ ] Utiliser le composable `useFetchProjects()` pour charger les données
|
||||
- [ ] Afficher une grille de `ProjectCard` avec les données
|
||||
- [ ] Implémenter le layout responsive : 1 colonne mobile, 2 tablette, 3-4 desktop
|
||||
- [x] **Task 3: Créer la page projets.vue** (AC: #1, #6)
|
||||
- [x] Créer `frontend/app/pages/projets.vue`
|
||||
- [x] Utiliser le composable `useFetchProjects()` pour charger les données
|
||||
- [x] Afficher une grille de `ProjectCard` avec les données
|
||||
- [x] Implémenter le layout responsive : 1 colonne mobile, 2 tablette, 3-4 desktop
|
||||
|
||||
- [ ] **Task 4: Implémenter l'animation d'entrée** (AC: #3)
|
||||
- [ ] Animer l'apparition progressive des cards (stagger animation)
|
||||
- [ ] Utiliser CSS animations ou GSAP pour un effet fade-in + slide-up
|
||||
- [ ] Respecter `prefers-reduced-motion` : pas d'animation si activé
|
||||
- [ ] Délai de 50-100ms entre chaque card
|
||||
- [x] **Task 4: Implémenter l'animation d'entrée** (AC: #3)
|
||||
- [x] Animer l'apparition progressive des cards (stagger animation)
|
||||
- [x] Utiliser CSS animations ou GSAP pour un effet fade-in + slide-up
|
||||
- [x] Respecter `prefers-reduced-motion` : pas d'animation si activé
|
||||
- [x] Délai de 50-100ms entre chaque card
|
||||
|
||||
- [ ] **Task 5: Tri des projets** (AC: #2)
|
||||
- [ ] S'assurer que l'API retourne les projets dans le bon ordre
|
||||
- [ ] Vérifier côté frontend que l'ordre est respecté
|
||||
- [ ] Les projets `is_featured: true` apparaissent en premier
|
||||
- [ ] Puis tri par `date_completed` DESC
|
||||
- [x] **Task 5: Tri des projets** (AC: #2)
|
||||
- [x] S'assurer que l'API retourne les projets dans le bon ordre
|
||||
- [x] Vérifier côté frontend que l'ordre est respecté
|
||||
- [x] Les projets `is_featured: true` apparaissent en premier
|
||||
- [x] Puis tri par `date_completed` DESC
|
||||
|
||||
- [ ] **Task 6: Meta tags SEO** (AC: #5)
|
||||
- [ ] Utiliser `useHead()` pour définir le titre dynamique
|
||||
- [ ] Utiliser `useSeoMeta()` pour les meta description, og:title, og:description
|
||||
- [ ] Ajouter les clés i18n pour titre et description de la page
|
||||
- [ ] Exemple titre : "Projets | Skycel" / "Projects | Skycel"
|
||||
- [x] **Task 6: Meta tags SEO** (AC: #5)
|
||||
- [x] Utiliser `useHead()` pour définir le titre dynamique
|
||||
- [x] Utiliser `useSeoMeta()` pour les meta description, og:title, og:description
|
||||
- [x] Ajouter les clés i18n pour titre et description de la page
|
||||
- [x] Exemple titre : "Projets | Skycel" / "Projects | Skycel"
|
||||
|
||||
- [ ] **Task 7: État loading et erreur**
|
||||
- [ ] Afficher un skeleton/loading state pendant le chargement
|
||||
- [ ] Afficher un message d'erreur narratif si l'API échoue
|
||||
- [ ] Bouton "Réessayer" en cas d'erreur
|
||||
- [x] **Task 7: État loading et erreur**
|
||||
- [x] Afficher un skeleton/loading state pendant le chargement
|
||||
- [x] Afficher un message d'erreur narratif si l'API échoue
|
||||
- [x] Bouton "Réessayer" en cas d'erreur
|
||||
|
||||
- [ ] **Task 8: Tests et validation**
|
||||
- [ ] Tester la page en FR et EN
|
||||
- [ ] Vérifier le tri des projets
|
||||
- [ ] Tester l'animation d'entrée
|
||||
- [ ] Valider le responsive sur mobile/tablette/desktop
|
||||
- [ ] Vérifier les meta tags avec l'inspecteur
|
||||
- [x] **Task 8: Tests et validation**
|
||||
- [x] Tester la page en FR et EN
|
||||
- [x] Vérifier le tri des projets
|
||||
- [x] Tester l'animation d'entrée
|
||||
- [x] Valider le responsive sur mobile/tablette/desktop
|
||||
- [x] Vérifier les meta tags avec l'inspecteur
|
||||
|
||||
## Dev Notes
|
||||
|
||||
@@ -372,16 +372,35 @@ frontend/i18n/en.json # AJOUTER clés projects.*
|
||||
|
||||
### Agent Model Used
|
||||
|
||||
{{agent_model_name_version}}
|
||||
Claude Opus 4.5 (claude-opus-4-5-20251101)
|
||||
|
||||
### Debug Log References
|
||||
|
||||
- Aucun problème. API ProjectController existait déjà (Story 1.3), scope ordered() mis à jour.
|
||||
|
||||
### Completion Notes List
|
||||
|
||||
- Scope `ordered()` mis à jour : featured DESC, date_completed DESC, display_order
|
||||
- Composable `useFetchProjects` créé avec typage et transform
|
||||
- Page projets complète avec grille responsive (1/2/3/4 colonnes selon breakpoint)
|
||||
- Animation stagger fadeInUp avec délai 80ms entre cards
|
||||
- prefers-reduced-motion respecté
|
||||
- États loading (skeleton), error (avec retry), empty
|
||||
- SEO meta tags dynamiques via useSeo()
|
||||
- Intégration store progression (visitSection sur mount)
|
||||
- Traductions FR/EN ajoutées (title, page_title, page_description, load_error, retry)
|
||||
|
||||
### Change Log
|
||||
| Date | Change | Author |
|
||||
|------|--------|--------|
|
||||
| 2026-02-04 | Story créée avec contexte complet | SM Agent |
|
||||
| 2026-02-06 | Tasks 1-8 implémentées et validées | Dev Agent (Claude Opus 4.5) |
|
||||
|
||||
### File List
|
||||
|
||||
- `api/app/Models/Project.php` — MODIFIÉ (scope ordered amélioré)
|
||||
- `frontend/app/composables/useFetchProjects.ts` — CRÉÉ
|
||||
- `frontend/app/pages/projets/index.vue` — RÉÉCRIT (page complète)
|
||||
- `frontend/i18n/fr.json` — MODIFIÉ (ajout projects.*, common.retry)
|
||||
- `frontend/i18n/en.json` — MODIFIÉ (ajout projects.*, common.retry)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user