Skip to content

Commit

Permalink
feat: enhance blog component accessibility with ARIA roles and improv…
Browse files Browse the repository at this point in the history
…e markup structure
  • Loading branch information
TeshaneCrawford committed Jan 12, 2025
1 parent 4843c23 commit 56b1700
Showing 1 changed file with 85 additions and 64 deletions.
149 changes: 85 additions & 64 deletions app/components/blog/IndexMain.server.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,90 +38,111 @@ const cardTransition = {
</h1>

<!-- Loading, error, and empty states handling -->
<div v-if="pending" class="flex items-center justify-center py-12">
<div
v-if="pending"
class="flex items-center justify-center py-12"
role="status"
aria-label="Loading blog posts"
>
<div class="loading-spinner">
Loading...
</div>
</div>

<div v-else-if="error" class="py-12 text-center text-red-11">
<div
v-else-if="error"
class="py-12 text-center text-red-11"
role="alert"
aria-label="Error loading blog posts"
>
Failed to load blog posts: {{ error.message }}
</div>

<!-- Blog post grid with staggered animation on card entrance -->
<section
<!-- Blog post grid -->
<ul
v-else-if="blog"
class="grid grid-cols-1 gap-6 md:grid-cols-2"
aria-label="Blog post list"
class="grid grid-cols-1 list-none gap-6 p-0 md:grid-cols-2"
aria-label="Blog posts"
>
<NuxtLink
<li
v-for="(blogs, index) in blog"
:key="blogs.id"
v-motion
:initial="cardTransition.initial"
:enter="{ ...cardTransition.enter, transition: { ...cardTransition.transition, delay: 150 * index } }"
:to="`${blogs.path}`"
class="group"
:aria-label="`Read ${blogs.title || 'Untitled post'}`"
>
<!-- Blog post card with hover effects and accessibility features -->
<article
class="h-full overflow-hidden border border-gray-7 rounded-md bg-gray-1 bg-transparent transition-all duration-300 hover:border-dashed hover:shadow-sm hover:-translate-y-1"
role="article"
<NuxtLink
v-motion
:initial="cardTransition.initial"
:enter="{ ...cardTransition.enter, transition: { ...cardTransition.transition, delay: 150 * index } }"
:to="`${blogs.path}`"
class="group block h-full"
:aria-labelledby="`post-title-${blogs.id}`"
>
<div class="p-6">
<!-- Blog post metadata: tags, title, description -->
<div class="mb-3 flex gap-2" aria-label="Post categories">
<span
v-for="tag in blogs.tags"
:key="tag"
class="badge-xs-gray text-gray-11 important-rounded-sm"
role="tag"
<article
class="h-full overflow-hidden border border-gray-7 rounded-md bg-gray-1 bg-transparent transition-all duration-300 hover:border-dashed hover:shadow-sm hover:-translate-y-1"
>
<div class="p-6">
<!-- Post metadata -->
<div class="mb-3 flex gap-2">
<ul class="m-0 flex list-none gap-2 p-0" aria-label="Tags">
<li v-for="tag in blogs.tags" :key="tag">
<span class="badge-xs-gray text-gray-11 important-rounded-sm">
{{ tag }}
</span>
</li>
</ul>
</div>

<h3
:id="`post-title-${blogs.id}`"
class="mb-2 text-lg text-gray-11 transition-colors group-hover:text-gray-12"
>
{{ tag }}
</span>
</div>
<h2 class="mb-2 text-lg text-gray-11 transition-colors group-hover:text-gray-12">
{{ blogs.title || 'Untitled post' }}
</h2>
<p class="line-clamp-2 mb-4 text-sm text-gray-11">
{{ blogs.description }}
</p>
{{ blogs.title || 'Untitled post' }}
</h3>

<!-- Author info and publication date -->
<div class="flex items-center justify-between text-sm text-gray-11">
<div class="flex items-center gap-2">
<img
v-if="blogs.authors?.[0]?.picture"
:src="blogs.authors[0].picture"
:alt="`Profile picture of ${blogs.authors[0].name}`"
class="h-6 w-6 rounded-full"
loading="lazy"
decoding="async"
<!-- ...rest of the existing article content... -->
<p class="line-clamp-2 mb-4 text-sm text-gray-11">
{{ blogs.description }}
</p>

<!-- Author info and publication date -->
<div class="flex items-center justify-between text-sm text-gray-11">
<div class="flex items-center gap-2">
<img
v-if="blogs.authors?.[0]?.picture"
:src="blogs.authors[0].picture"
:alt="`Profile picture of ${blogs.authors[0].name}`"
class="h-6 w-6 rounded-full"
loading="lazy"
decoding="async"
>
<span>{{ blogs.authors?.[0]?.name || 'Anonymous' }}</span>
</div>
<dl
v-if="blogs.date"
class="text-sm text-gray-11 leading-normal"
>
<span>{{ blogs.authors?.[0]?.name || 'Anonymous' }}</span>
<dt class="sr-only">Published</dt>
<dd>
<time
:datetime="toISODateString(blogs.date)"
:aria-label="'Published on ' + toLocaleDateString(blogs.date)"
>
{{ toLocaleDateString(blogs.date) }}
</time>
</dd>
</dl>
</div>
<dl
v-if="blogs.date"
class="text-sm text-gray-11 leading-normal"
>
<dt class="sr-only">Published</dt>
<dd>
<time
:datetime="toISODateString(blogs.date)"
:aria-label="'Published on ' + toLocaleDateString(blogs.date)"
>
{{ toLocaleDateString(blogs.date) }}
</time>
</dd>
</dl>
</div>
</div>
</article>
</NuxtLink>
</section>
</article>
</NuxtLink>
</li>
</ul>

<div v-else class="py-12 text-center text-gray-11">
<div
v-else
class="py-12 text-center text-gray-11"
role="status"
aria-label="No blog posts found"
>
No blog posts found.
</div>
</div>
Expand Down

0 comments on commit 56b1700

Please sign in to comment.