--- phase: 06-blog-pages plan: 02 subsystem: ui-components tags: [blog, i18n, nav, blog-card, shared-components] requires: - phase: 06-blog-pages plan: 01 provides: "blogSchema étendu (draft/wordCount/minutes) + useReadingTime composable fallback — consommés par BlogCard.vue" provides: - "Clés i18n complètes blog.* + nav.blog + a11y.blog* en FR et EN (14 clés par locale)" - "Lien nav Blog dans AppHeader entre Hytale et Projects (desktop + mobile)" - "Composant BlogCard.vue unifié avec variant default (listing) + compact (prev/next)" affects: [06-03-blog-listing, 06-04-blog-article-chrome] tech-stack: added: [] patterns: - "Pattern composant multi-variant via prop discriminante + v-if branch (variant='default'|'compact')" - "Pattern slug derivation depuis article.path @nuxt/content (split /filter(Boolean).pop())" - "Pattern i18n date formatting via Intl.DateTimeFormat + locale.value guard" - "Pattern absolute inset-0 NuxtLink pour SEO + full-card click (cohabite avec tags non-cliquables D-02)" - "Pattern Schema.org BlogPosting prêt pour JSON-LD Phase 7 (headline/description/keywords/url/image/datePublished)" - "Pattern reading-time avec injection hook + fallback composable (minutes ?? useReadingTime(description))" key-files: created: - app/components/BlogCard.vue modified: - i18n/locales/fr.json - i18n/locales/en.json - app/components/layout/AppHeader.vue key-decisions: - "BlogCard unique avec variant prop (D-20) plutôt que 2 composants séparés — 1 source of truth pour date/slug/reading-time" - "Slug extrait du dernier segment du path (split/filter/pop) plutôt qu'un champ frontmatter dédié — cohérent @nuxt/content convention, zero burden pour auteur" - "Reading-time : minutes injecté par hook Nitro prioritaire, useReadingTime(description) en fallback uniquement — évite drift listing vs article" - "Variant compact sans image (D-10) + text-right sur next / text-left sur prev — UX directionnelle (flèche + texte suivent la direction du clic)" - "FR i18n accentué dans bloc blog.* (Bientôt, précédent, Sommaire) suivant convention PATTERNS.md §i18n — cohérent avec bloc projects, distinct de a11y/seo (ASCII)" requirements-completed: [BLOG-02, BLOG-03, BLOG-06] duration: ~15min completed: 2026-04-22 --- # Phase 6 Plan 02 : Components UI + i18n Locales Summary **Couche composition partagée : clés i18n blog complètes (FR+EN), lien nav Blog, composant BlogCard.vue unifié variant default/compact — prêt pour Wave 3 (pages listing + article).** ## Performance - **Duration:** ~15 min - **Started:** 2026-04-22T09:10Z - **Completed:** 2026-04-22T09:25Z - **Tasks:** 3 / 3 - **Files modified:** 4 (1 créé, 3 modifiés) ## Accomplishments - **i18n complet** : 14 clés par locale ajoutées — `nav.blog`, 3 clés `a11y.blog*` avec interpolation `{title}`, bloc `blog.*` de 14 clés (title, subtitle, stats.articles/tags/languages, readingTime avec `{minutes}`, prevArticle, nextArticle, backToBlog, toc.title, emptyState.title/description/cta, breadcrumb.home/blog). FR accentué, EN traduction complète. JSON valide des 2 fichiers. - **Nav link Blog** : insertion d'1 ligne dans `navLinks` computed de AppHeader.vue, position ligne 11 (entre hytale ligne 10 et projects ligne 12). Aucune autre modification — template `v-for` existant propage automatiquement au desktop + mobile slideover. - **BlogCard.vue** : composant unique 192 lignes, 2 variants branchés par `v-if="variant === 'default'"` / `v-else` (compact). Script setup TS strict. Props `article` + `variant?='default'|'compact'` + `direction?='prev'|'next'`. Date formatée `Intl.DateTimeFormat` avec locale dynamique. Reading time avec fallback composable. Schema.org `BlogPosting` markup prêt pour JSON-LD Phase 7. 3 occurrences de `localePath(\`/blog/\${slug}\`)` (NuxtLink image + full-card SEO + variant compact). ## Task Commits 1. **Task 2.1 : i18n FR + EN** — `d299383` (feat) 2. **Task 2.2 : Nav link Blog dans AppHeader** — `0e42a05` (feat) 3. **Task 2.3 : BlogCard.vue variant default + compact** — `d0ebf35` (feat) ## Files Created/Modified ### Created - `app/components/BlogCard.vue` *(NEW, 192 lignes)* - `