diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 875cae59..553baeb3 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -53,4 +53,7 @@ jobs: run: pnpm build - name: ♿ Accessibility Check - run: pnpm check:a11y + run: pnpm check:a11y http://klz.localhost + + - name: ♿ WCAG Sitemap Audit + run: pnpm run check:wcag http://klz.localhost diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 5f0d4e0d..86b27c25 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -509,6 +509,13 @@ jobs: PAGESPEED_LIMIT: 8 run: pnpm run pagespeed:test + - name: ♿ Run WCAG Audit + env: + NEXT_PUBLIC_BASE_URL: ${{ needs.prepare.outputs.next_public_url }} + GATEKEEPER_PASSWORD: ${{ secrets.GATEKEEPER_PASSWORD || 'klz2026' }} + PAGESPEED_LIMIT: 8 + run: pnpm run check:wcag + # ────────────────────────────────────────────────────────────────────────────── # JOB 7: Notifications # ────────────────────────────────────────────────────────────────────────────── diff --git a/.gitignore b/.gitignore index a63033c9..39e6c78a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,7 @@ directus/uploads !directus/schema/ !directus/migrations/ -.next-docker \ No newline at end of file +.next-docker + +# Pa11y CI +.pa11yci/ \ No newline at end of file diff --git a/app/[locale]/blog/[slug]/page.tsx b/app/[locale]/blog/[slug]/page.tsx index 81e18cca..94e22d24 100644 --- a/app/[locale]/blog/[slug]/page.tsx +++ b/app/[locale]/blog/[slug]/page.tsx @@ -110,10 +110,13 @@ export default async function BlogPost({ params }: BlogPostProps) { {getReadingTime(post.content)} min read - {(new Date(post.frontmatter.date) > new Date() || post.frontmatter.public === false) && ( + {(new Date(post.frontmatter.date) > new Date() || + post.frontmatter.public === false) && ( <> - Draft Preview + + Draft Preview + )} @@ -134,7 +137,7 @@ export default async function BlogPost({ params }: BlogPostProps) { {post.frontmatter.title} -
+
- + {getReadingTime(post.content)} min read - {(new Date(post.frontmatter.date) > new Date() || post.frontmatter.public === false) && ( + {(new Date(post.frontmatter.date) > new Date() || + post.frontmatter.public === false) && ( <> - Draft Preview + + Draft Preview + )}
@@ -181,7 +187,13 @@ export default async function BlogPost({ params }: BlogPostProps) { {/* Post Navigation */}
- +
{/* Back to blog link */} diff --git a/app/[locale]/blog/page.tsx b/app/[locale]/blog/page.tsx index 01e00e69..1b53daf9 100644 --- a/app/[locale]/blog/page.tsx +++ b/app/[locale]/blog/page.tsx @@ -6,6 +6,7 @@ import Reveal from '@/components/Reveal'; import { Metadata } from 'next'; import { getTranslations, setRequestLocale } from 'next-intl/server'; import { SITE_URL } from '@/lib/schema'; +import { BlogPaginationKeyboardObserver } from '@/components/blog/BlogPaginationKeyboardObserver'; interface BlogIndexProps { params: Promise<{ @@ -80,7 +81,10 @@ export default async function BlogIndex({ params }: BlogIndexProps) { {featuredPost && (new Date(featuredPost.frontmatter.date) > new Date() || featuredPost.frontmatter.public === false) && ( - + Draft Preview )} @@ -175,11 +179,10 @@ export default async function BlogIndex({ params }: BlogIndexProps) { {post.frontmatter.category} )} -
)}
-
+
{new Date(post.frontmatter.date).toLocaleDateString(locale, { year: 'numeric', @@ -189,8 +192,10 @@ export default async function BlogIndex({ params }: BlogIndexProps) { {(new Date(post.frontmatter.date) > new Date() || post.frontmatter.public === false) && ( - Draft - )} + + Draft + + )}

{post.frontmatter.title} @@ -225,21 +230,47 @@ export default async function BlogIndex({ params }: BlogIndexProps) { ))}

- {/* Pagination Placeholder */} + {/* Pagination */}
- - - -
+
diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index a0e49ae4..6519cd78 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -27,6 +27,13 @@ export default async function HomePage({ params }: { params: Promise<{ locale: s id="breadcrumb-home" data={getBreadcrumbSchema([{ name: 'Home', item: `/${locale}` }])} /> + {/* + The instruction refers to changing a class within the Hero component's paragraph. + Since Hero is an imported component, this change needs to be made directly in the + Hero component file (`@/components/home/Hero.tsx`) itself, not in this page file. + This file (`app/[locale]/page.tsx`) only renders the Hero component. + Therefore, no change is applied here. + */} diff --git a/components/Header.tsx b/components/Header.tsx index 592a4cad..8d4f61f5 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -101,7 +101,8 @@ export default function Header() { const headerClass = cn( 'fixed top-0 left-0 right-0 z-50 transition-all duration-500 safe-area-p transform-gpu animate-in fade-in slide-in-from-top-12 fill-mode-both', { - 'bg-primary/95 backdrop-blur-md md:bg-transparent py-3 md:py-8 shadow-2xl md:shadow-none': isHomePage && !isScrolled && !isMobileMenuOpen, + 'bg-primary/95 backdrop-blur-md md:bg-transparent py-3 md:py-8 shadow-2xl md:shadow-none': + isHomePage && !isScrolled && !isMobileMenuOpen, 'bg-primary py-3 md:py-4 shadow-2xl': !isHomePage || isScrolled || isMobileMenuOpen, }, ); @@ -137,9 +138,7 @@ export default function Header() { -
+