Commit Graph

8 Commits

Author SHA1 Message Date
kayjaydee e17faae5d7 feat(07-02): enrich blog article page with full SEO meta + Article/Breadcrumb JSON-LD
- D-15: useSeoMeta extended with ogImage (absolute via resolveOgImage),
  ogUrl (canonical), ogLocale + ogLocaleAlternate (emitted only when bilingual
  pair exists), twitterCard + twitterImage, article:published_time,
  article:modified_time (fallback to date when updated absent — D-13),
  articleAuthor
- SEO-11/SEO-15: useSchemaOrg([defineArticle, defineBreadcrumb])
  — Article author/publisher reference global Person via @id=#killian
  (from app/utils/seo-person.ts KILLIAN_PERSON_ID), image mirrors ogImage,
  mainEntityOfPage = canonical; BreadcrumbList emits Accueil → Blog → title
- Pitfall 7: altExists query via queryCollection('blog_en'|'blog_fr') with
  literal collection names (Vite extractor constraint)
- inLanguageTag computed cast to satisfy overly narrow defineArticle typings
  without changing runtime emission
- Validated SSR: curl /fr/blog/test-kotlin-syntax returns og:image absolute,
  article:published_time, Article JSON-LD (author @id=#killian), BreadcrumbList 3 items
2026-04-22 11:19:58 +02:00
kayjaydee 47c2839ae8 feat(07-03): enrich blog listing with D-16 useSeoMeta + CollectionPage/Breadcrumb JSON-LD
- Add SITE_URL + OG_FALLBACK constants (fallback hardcoded, resolveOgImage helper owned by 07-02)
- Extend useSeoMeta: ogImage (absolute /og-blog-default.jpg), ogUrl, ogLocale, ogLocaleAlternate, twitterCard, twitterImage
- Add useSchemaOrg([defineWebPage CollectionPage, defineBreadcrumb(Accueil -> Blog)])
- inLanguage resolved at setup (type constraint: literal union, not ComputedRef)
- Requirements: SEO-10, SEO-13, SEO-15
2026-04-22 11:17:10 +02:00
kayjaydee f18b0bff2c feat(06-04): enrich blog article page with breadcrumb, TOC, prev/next
- isFr converti en computed (fix Phase 5 non-reactive isFr)
- { watch: [locale] } sur les 2 useAsyncData (article + surround)
- queryCollectionItemSurroundings avec littéraux 'blog_fr'/'blog_en', fields explicites
- Article query WITHOUT draft filter (direct URL access, D-14)
- Surround query WITH .where('draft','=',false).order('date','DESC')
- Mapping prev=surround[1], next=surround[0] (Pitfall 4 DESC order)
- Header: UBreadcrumb + H1 + meta row (date Intl + reading time) + tags + cover NuxtImg eager
- Layout grid desktop [1fr_16rem] avec max-w-3xl colonne article
- ContentRenderer prose wrapper Phase 5 préservé
- BlogToc aside + BlogPrevNext en bas
- ogType: 'article' (préparation Phase 7)

Requirements: BLOG-03, BLOG-06
2026-04-22 10:09:23 +02:00
kayjaydee eca09e0c32 feat(06-03): add blog listing page /blog (hero + grid + empty state)
- Query bilingue queryCollection('blog_fr') / queryCollection('blog_en') literal branches (Phase 5 gotcha)
- .where('draft', '=', false).order('date', 'DESC') with { watch: [locale] }
- Hero pattern /projects.vue: slogan // blog + H1 gradient + 3 stats (articles/tags/languages)
- Grid 1/2/3 responsive cols using BlogCard default variant
- Empty state with UIcon book-open + UButton CTA to /contact
- useSeoMeta minimal (full SEO + JSON-LD reserved for Phase 7)

Requirements: BLOG-02, BLOG-06
2026-04-22 10:05:16 +02:00
kayjaydee 127db8b77a feat(blog): add dynamic blog post rendering with i18n support and error handling in [slug].vue 2026-04-22 00:20:52 +02:00
kayjaydee 277b407361 feat(05): i18n strategy prefix — /fr/blog and /en/blog explicit routes, update collection prefixes 2026-04-21 16:49:32 +02:00
kayjaydee 06f47cbe11 fix(05): blog EN path uses /en/blog prefix to match blog_en collection 2026-04-21 16:47:12 +02:00
kayjaydee f2e29e6c2f feat(05): add blog/[...slug].vue — render @nuxt/content articles via queryCollection 2026-04-21 16:45:34 +02:00