Commit Graph

66 Commits

Author SHA1 Message Date
kayjaydee bf2ec8671c feat(08-01): inject HytaleRecentArticles in /hytale + add i18n keys FR/EN
- app/pages/hytale.vue: <HytaleRecentArticles /> inserted after TestimonialsSection wrapper, before closing root div
- i18n/locales/fr.json: hytale.recentArticles {title, subtitle, viewAll} accentue style (aligned with blog.* 2026)
- i18n/locales/en.json: mirror keys
- No script changes (auto-import Nuxt)
2026-04-22 21:47:57 +02:00
kayjaydee ddfc685421 feat(08-01): add HytaleRecentArticles component (queryCollection bilingual + JS tag filter)
- Bilingual literal branches queryCollection('blog_fr'|'blog_en') (Phase 5 Pitfall D-03)
- JS post-filter tags.includes('hytale') + slice(0,2) (D-11 — SQLite LIKE unreliable on JSON array)
- v-if=articles.length hides section when no hytale-tagged articles (D-12)
- BlogCard variant=compact in grid 2 col desktop / 1 col mobile
- NuxtLink localePath('/blog') viewAll CTA
- useAsyncData key hytale-recent-${locale.value} + watch:[locale]
2026-04-22 21:47:23 +02:00
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 fae410243b feat(07-02): add resolveOgImage helper + og-blog-default.jpg fallback asset
- app/utils/resolve-og-image.ts: absolutises frontmatter image or falls back to /og-blog-default.jpg
- public/og-blog-default.jpg: placeholder (copied from og-image.png) — branded 1200x630 design follow-up pending
2026-04-22 11:16:37 +02:00
kayjaydee 654842ba44 feat(07-01): wire global schema.org Person + WebSite and sitemap sources
- nuxt.config.ts: register 'nuxt-schema-org' module + sitemap.sources=['/api/__sitemap__/urls']
- app/utils/seo-person.ts: KILLIAN_PERSON_ID + killianPerson (derived from siteConfig, email excluded)
- app/app.vue: useSchemaOrg([definePerson(killianPerson), defineWebSite({name, inLanguage})]) appended (D-12)
- Verified SSR: /fr emits JSON-LD Person @id=#killian + WebSite (curl, pas d'hydratation)
2026-04-22 11:13:51 +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 0ff36784e9 feat(06-04): add BlogPrevNext component (grid 2 cols, BlogCard compact variant) 2026-04-22 10:06:52 +02:00
kayjaydee b72b564b69 feat(06-04): add BlogToc component (sticky desktop + drawer mobile + IntersectionObserver highlight) 2026-04-22 10:06:38 +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 d0ebf35119 feat(06-02): add BlogCard component with default + compact variants
- variant="default" (listing): cover image conditional (D-03 no fallback),
  aspect-[16/9], first tag UBadge, date i18n via Intl.DateTimeFormat,
  h2 title, line-clamp-2 description, reading time + extra tags pills,
  absolute inset-0 NuxtLink for SEO/a11y (D-02 tags non-clickable)
- variant="compact" (prev/next, D-09/D-10): no image, label row with
  UIcon arrow (left/right per direction), h3 title, date mono,
  text-right on next / text-left on prev
- Props: article, variant?='default'|'compact', direction?='prev'|'next'
- Slug derived from article.path last segment (locale-agnostic)
- readingMinutes: uses article.minutes (Nitro hook) with useReadingTime
  fallback on article.description
- Schema.org BlogPosting markup (headline/description/keywords/url/image/
  datePublished) — ready for Phase 7 JSON-LD Article
- a11y aria-label interpolated via t('a11y.blogPrev'|'blogNext', {title})
2026-04-22 09:13:09 +02:00
kayjaydee 0e42a0591e feat(06-02): add Blog nav link in AppHeader between Hytale and Projects
- Insert { key: 'blog', path: '/blog' } in navLinks computed array
- Position: between hytale and projects (D-15 ordering)
- Template v-for iterations unchanged — new link auto-propagates to
  desktop nav + mobile slideover
- Label resolved via t(`nav.${link.key}`) → uses nav.blog key
  added in Task 2.1
2026-04-22 09:11:27 +02:00
kayjaydee dd9ce6e8b4 feat(06-01): add useReadingTime composable fallback (200 wpm)
- Pure synchronous helper returning minutes (>= 1) from either a pre-computed
  word count (number) or raw text (string, tokenized on whitespace).
- Client-side safety net when `article.minutes` isn't yet populated
  (e.g., dev hot-reload before the Nitro hook re-parsed). Source of truth
  remains the Nitro `content:file:afterParse` hook (D-19).
- Same 200 wpm formula as server-side hook — ensures listing ↔ article parity.
- Auto-imported by Nuxt thanks to `use*` naming convention.
2026-04-22 09:04:53 +02:00
kayjaydee 63d0173b2d feat(06-01): add countWordsInMinimalBody util for reading-time computation
- Pure AST traversal of @nuxt/content v3 minimal body shape
- Skips code and pre tags (code snippets are not readable prose)
- Zero dependency, zero import, reused by Nitro hook
2026-04-22 08:57:05 +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 839c584b0a refactor(config): update nuxt.config.ts to enhance module configuration, remove deprecated files, and improve contact form validation with zod schema 2026-04-21 23:15:04 +02:00
kayjaydee 7cd1531e06 fix(05): update test.vue path to /fr/blog prefix, add compatibilityDate 2026-04-21 16:55:57 +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
kayjaydee c5be72bdd9 fix(05-02): single dark theme for code blocks — github-dark always, remove dual-theme CSS 2026-04-21 16:35:06 +02:00
kayjaydee b0af1d3913 fix(05-02): ProseImg use span.block instead of figure — fix SSR hydration mismatch (block-in-p invalid HTML) 2026-04-21 15:58:41 +02:00
kayjaydee 006df6ad30 fix(05-02): Clear.vue MDC component, replace raw div clear:both (hydration mismatch) 2026-04-21 15:51:06 +02:00
kayjaydee 3e20e9ece9 fix(05-02): ProseImg inheritAttrs false — classes MDC custom overrident le layout auto 2026-04-21 15:37:51 +02:00
kayjaydee 221b1a076c fix(05-02): restore Shiki token colors — add .shiki to ProsePre pre, broaden CSS selector to pre span 2026-04-21 15:34:02 +02:00
kayjaydee f179d64253 feat(05-02): ProsePre override — dark bg fixe #0d1117, badge langage, Shiki tokens transparents 2026-04-21 15:31:40 +02:00
kayjaydee 60e05f7a56 feat(05-02): add Columns/Details/Video/Badge MDC components + full showcase article 2026-04-21 15:31:00 +02:00
kayjaydee b63869f042 feat(05-02): ProseImg flexible — align left/right/center/full + caption + width 2026-04-21 15:28:39 +02:00
kayjaydee 37b6ef9112 fix(05-02): widen test page to max-w-6xl 2026-04-21 15:26:05 +02:00
kayjaydee ee7509cff0 fix(05-02): widen test page to max-w-3xl 2026-04-21 15:25:41 +02:00
kayjaydee 9849c18da4 fix(05-02): rebuild Alert sans UAlert, ProseImg img natif, test.vue layout propre 2026-04-21 15:24:22 +02:00
kayjaydee e1c91e583f fix(05-02): alert alignment via #title slot, dark-only code theme, simplify ProseImg 2026-04-21 15:20:14 +02:00
kayjaydee b5c3250a4e fix(05-02): ContentSlot→slot, image path, Shiki dual-theme CSS 2026-04-21 15:16:04 +02:00
kayjaydee 0fa19a7701 feat(05-02): add test articles FR/EN and temporary test page
- content/fr/blog/test-kotlin-syntax.md: FR test article covering all 4 validation criteria
- content/en/blog/test-kotlin-syntax.md: EN version with same slug
- app/pages/test.vue: temporary page at /test for visual checkpoint verification
- Both articles contain: kotlin code block, NuxtImg image, markdown table, 4 callout types
2026-04-21 14:36:49 +02:00
kayjaydee c9a14a9086 feat(05-02): create MDC components ProseImg.vue and Alert.vue
- ProseImg.vue: transparent NuxtImg override for markdown images (BLOG-05)
- Alert.vue: MDC callout component with 4 types (info/warning/tip/danger) via UAlert
- ContentSlot required for MDC slot content rendering (Pitfall 4)
2026-04-21 14:36:22 +02:00
kayjaydee 3381b2efb3 feat(05-01): configure @nuxt/content with Shiki dual-theme and typography plugin
- Add '@nuxt/content' to modules array in nuxt.config.ts
- Add content block: Shiki dual-theme github-light/github-dark
- Add Shiki langs: kotlin, java, typescript, shell, bash, json, vue, html, css
- Add experimental.sqliteConnector: 'native' (Node 22 native SQLite)
- Add @plugin "@tailwindcss/typography" in main.css
2026-04-21 14:33:54 +02:00
kayjaydee 39f2a81e8f feat(hytale): implement Hytale plugin development page and related components
- Added a new `/hytale` page with sections for hero, services, and pricing.
- Updated existing components to support Hytale-specific content and i18n.
- Modified site configuration and state to reflect the new focus on Hytale plugin development.
- Enhanced testimonials section to feature relevant client feedback.
- Adjusted navigation to include a link to the new Hytale page.
2026-04-11 04:19:27 +02:00
kayjaydee 8b69a12342 chore: update Dockerfile for pnpm, modify package.json dependencies, and implement rate limiting
- Switched from npm to pnpm for dependency management in Dockerfile, improving build efficiency.
- Updated Vue and Vue Router versions in package.json for better compatibility.
- Changed placeholder URLs in site.ts to actual Fiverr links and adjusted review count.
- Removed obsolete sitemap.xml file to streamline the project.
- Added a new rate limiting plugin to manage API request limits for the contact endpoint.
2026-04-10 19:19:36 +02:00
kayjaydee c8dac9ac88 fix: update portfolio branding to "Killian' DAL-CIN" across all documentation and components
- Corrected the name in various files including CLAUDE.md, README.md, and configuration files to reflect the updated branding.
- Ensured consistency in the use of the new name throughout the project, enhancing brand identity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 19:54:46 +02:00
kayjaydee 9779e4e133 feat: redesign entire portfolio with bold modern dark theme
Complete visual overhaul of all pages and components with generous spacing,
bold typography, hover effects, gradient accents, and section differentiation.
Hero features animated terminal mockup and gradient text. Cards use hover
transforms with brand-colored shadows. CTAs use gradient backgrounds.
All i18n keys, data structures, SEO meta, and composable logic preserved.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 19:08:55 +02:00
kayjaydee 9739becbb7 fix: rewrite AppHeader — replace UDrawer with USlideover, clean design
UDrawer (vaul-vue bottom-sheet) rendered content in DOM even when closed,
causing mobile nav to show on desktop. Replaced with USlideover (proper
sidebar panel). Also: backdrop-blur header, UButton for actions, Lucide
icons, brand color active states.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:55:58 +02:00
kayjaydee 08b7e37acc fix: correct i18n key paths for projects, featured, testimonials
- useProjects: projects.${id}.* → projectData.${id}.* (matches locale structure)
- FeaturedProjectsSection: home.projects.* → home.featuredProjects.*
- TestimonialsSection: home.testimonials.* → testimonials.*

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:53:49 +02:00
kayjaydee 55f9c8eaf6 feat(03-03): create error.vue (404 page) with i18n keys
- error.vue in app/ with statusCode display, i18n message, clearError redirect
- Added error.notFound, error.generic, error.backHome keys to fr.json and en.json
2026-04-08 18:38:35 +02:00
kayjaydee 91ac322c57 feat(03-03): build Fiverr page with hero, service cards, FAQ accordion, and CTA
- Hero with stats (available services count, rating) and profile CTA
- Service cards grid with NuxtImg, price/status badges, order buttons
- FAQSection with UAccordion using homeFAQs data
- Final CTA section linking to Fiverr profile
2026-04-08 18:38:01 +02:00
kayjaydee af12fa5e4f feat(03-02): project detail page with dynamic route and gallery
- Dynamic route /project/[id] with findById composable
- 404 via createError if project not found
- Hero grid: image + info + CTA buttons (demo, source, custom)
- About section with features list (checkmarks)
- Technologies section with TechBadge
- Gallery thumbnails with zoom overlay, opens ProjectGallery modal
- Sidebar: project info card + related projects
- Responsive 2-col layout (main + sidebar)
2026-04-08 18:37:58 +02:00
kayjaydee ffa6ba8bfe feat(03-03): build About page with tech stack badges and Contact page with form
- About: hero bio, 5 tech categories with TechBadge (UCard grid), approach cards, CTA
- Contact: hero stats, ContactForm component, contact info from siteConfig, social links, FAQ cards
2026-04-08 18:37:34 +02:00
kayjaydee 8e9c6c7848 feat(03-02): projects page with search and category filters
- Text search filtering by title, description, technologies
- Category filter buttons (UButton solid/soft variants)
- ProjectCard grid responsive 1/2/3 columns
- Empty state with reset button
- Stats: total projects, featured, categories
2026-04-08 18:37:17 +02:00
kayjaydee a4b53caaa2 feat(03-02): landing page with 6 sections
- HeroSection, FeaturedProjectsSection, ServicesSection
- TestimonialsSection, FAQSection with homeFAQs, CTASection
- Preserved useSeoMeta and JSON-LD from Phase 2 stub
2026-04-08 18:36:49 +02:00
kayjaydee 84e4202536 feat(03-01): create ContactForm with Zod validation and nodemailer SMTP server route
- ContactForm.vue: UForm + Zod schema (name/email/message) + useToast feedback
- server/api/contact.post.ts: nodemailer SMTP with server-side validation + HTML escaping
- SMTP credentials in private runtimeConfig (T-03-03)
- HTML escaping prevents XSS in email body (T-03-02)
2026-04-08 18:34:38 +02:00
kayjaydee 7f715e4b01 feat(03-01): create 9 shared components for landing sections and project display
- HeroSection: title + subtitle + 3 CTA UButtons
- FeaturedProjectsSection: 3 featured projects via useProjects()
- ServicesSection: 4 service cards with UCard + UIcon
- TestimonialsSection: UCard per testimonial with ratings and stats
- FAQSection: UAccordion with i18n-resolved items
- CTASection: final CTA with 2 UButtons
- ProjectCard: NuxtLink + NuxtImg + UBadge + schema.org microdata
- TechBadge: Technology lookup with NuxtImg + UBadge level
- ProjectGallery: UModal fullscreen + UCarousel + thumbnails + keyboard nav
2026-04-08 18:34:03 +02:00