Files
indiekit-blog/_includes/components/funkwhale-stats-content.njk
Ricardo e236b4bf65 a11y: comprehensive WCAG 2.1 Level AA accessibility audit
- Add skip-to-main-content link and main content ID target
- Add prefers-reduced-motion media queries for all animations
- Enhance visible focus indicators (2px offset, high-contrast ring)
- Replace ~160 text-surface-500 instances with text-surface-600/dark:text-surface-400
  for 4.5:1+ contrast ratio compliance
- Add aria-hidden="true" to ~30+ decorative SVG icons across sidebars/widgets
- Convert facepile containers from div to semantic ul/li with role="list"
- Add aria-label to icon-only buttons (share, sort controls)
- Add sr-only labels to form inputs (webmention, search)
- Add aria-live="polite" to dynamically loaded webmentions
- Add aria-label with relative+absolute date to time-difference component
- Add keyboard handlers (Enter/Space) to custom interactive elements
- Add aria-label to nav landmarks (table of contents)
- Fix modal focus trap and dialog accessibility
- Fix lightbox keyboard navigation and screen reader announcements

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
2026-03-07 18:58:08 +01:00

67 lines
3.9 KiB
Plaintext

{# Stats Summary Cards #}
{% if summary %}
<div class="grid grid-cols-2 sm:grid-cols-4 gap-3 sm:gap-4 mb-6 sm:mb-8">
<div class="p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm text-center">
<span class="text-2xl font-bold font-mono text-purple-600 dark:text-purple-400 block">{{ summary.totalPlays or 0 }}</span>
<span class="text-xs text-surface-600 dark:text-surface-400 uppercase tracking-wide">Plays</span>
</div>
<div class="p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm text-center">
<span class="text-2xl font-bold font-mono text-purple-600 dark:text-purple-400 block">{{ summary.uniqueTracks or 0 }}</span>
<span class="text-xs text-surface-600 dark:text-surface-400 uppercase tracking-wide">Tracks</span>
</div>
<div class="p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm text-center">
<span class="text-2xl font-bold font-mono text-purple-600 dark:text-purple-400 block">{{ summary.uniqueArtists or 0 }}</span>
<span class="text-xs text-surface-600 dark:text-surface-400 uppercase tracking-wide">Artists</span>
</div>
<div class="p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm text-center">
<span class="text-2xl font-bold font-mono text-purple-600 dark:text-purple-400 block">{{ summary.totalDurationFormatted or '0m' }}</span>
<span class="text-xs text-surface-600 dark:text-surface-400 uppercase tracking-wide">Listened</span>
</div>
</div>
{% endif %}
{# Top Artists #}
{% if topArtists and topArtists.length %}
<div class="mb-8">
<h3 class="text-lg font-semibold text-surface-900 dark:text-surface-100 mb-4">Top Artists</h3>
<div class="space-y-2">
{% for artist in topArtists | head(5) %}
<div class="flex items-center gap-3 p-3 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm">
<span class="w-6 h-6 flex items-center justify-center text-sm font-bold text-surface-400 bg-surface-100 dark:bg-surface-700 rounded-full">{{ loop.index }}</span>
<span class="flex-1 font-medium text-surface-900 dark:text-surface-100">{{ artist.name }}</span>
<span class="text-sm text-surface-600 dark:text-surface-400">{{ artist.playCount }} plays</span>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{# Top Albums #}
{% if topAlbums and topAlbums.length %}
<div>
<h3 class="text-lg font-semibold text-surface-900 dark:text-surface-100 mb-4">Top Albums</h3>
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-3 sm:gap-4">
{% for album in topAlbums | head(5) %}
<div class="text-center">
{% if album.coverUrl %}
<img src="{{ album.coverUrl }}" alt="" class="w-full aspect-square object-cover rounded-lg mb-2 shadow-lg" loading="lazy" eleventy:ignore>
{% else %}
<div class="w-full aspect-square bg-surface-200 dark:bg-surface-700 rounded-lg mb-2 flex items-center justify-center">
<svg class="w-8 h-8 text-surface-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2z"/>
</svg>
</div>
{% endif %}
<p class="text-sm font-medium text-surface-900 dark:text-surface-100 truncate">{{ album.title }}</p>
<p class="text-xs text-surface-600 dark:text-surface-400 truncate">{{ album.artist }}</p>
<p class="text-xs text-surface-400">{{ album.playCount }} plays</p>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% if not summary and not topArtists and not topAlbums %}
<p class="text-surface-600 dark:text-surface-400">No statistics available for this period.</p>
{% endif %}