Built a complete Netflix-style streaming interface for IndeeHub's decentralized media platform with real film content. Features: - Vue 3 + TypeScript + Vite setup with hot module reloading - Netflix-inspired UI with hero section and horizontal scrolling content rows - Glass morphism design system with custom Tailwind configuration - 20+ real IndeeHub films organized into 6 categories (Bitcoin, Documentaries, Drama, etc.) - Full-featured video player component with custom controls - Mobile-responsive design with bottom navigation - Nostr integration ready (nostr-tools, relay pool, NIP-71 support) - Pinia state management for content - MCP tools configured (Filesystem, Memory, Nostr, Puppeteer) Components: - Browse.vue: Main streaming interface with hero and content rows - ContentRow.vue: Horizontal scrolling film cards with navigation arrows - VideoPlayer.vue: Custom video player with play/pause, seek, volume, fullscreen - MobileNav.vue: Bottom tab navigation for mobile devices Tech Stack: - Frontend: Vue 3 (Composition API), TypeScript - Build: Vite 7 - Styling: Tailwind CSS with custom theme - State: Pinia 3 - Router: Vue Router 4.6 - Protocol: Nostr (nostr-tools 2.22) Design: - 4px grid spacing system - Glass morphism UI components - Netflix-style hero section with featured content - Smooth animations and hover effects - Mobile-first responsive breakpoints - Dark theme with custom color palette Content: - 20+ IndeeHub films with titles, descriptions, categories - Bitcoin documentaries: God Bless Bitcoin, Dirty Coin, Searching for Satoshi - Independent films and documentaries - Working Unsplash CDN images for thumbnails and backdrops Ready for deployment to Umbrel, Start9, and Archy nodes. Co-authored-by: Cursor <cursoragent@cursor.com>
282 lines
5.0 KiB
Plaintext
282 lines
5.0 KiB
Plaintext
---
|
|
description: WCAG AA accessibility standards and patterns
|
|
alwaysApply: false
|
|
globs: **/*.{vue,html,jsx,tsx}
|
|
---
|
|
|
|
# Accessibility Standards (A11y)
|
|
|
|
## Philosophy
|
|
|
|
Accessible design is not optional. It's a fundamental requirement for building inclusive, usable applications.
|
|
|
|
**Target: WCAG AA Compliance**
|
|
|
|
## Color & Contrast
|
|
|
|
### Contrast Ratios (WCAG AA)
|
|
- **Normal text**: 4.5:1 minimum
|
|
- **Large text** (18pt+): 3:1 minimum
|
|
- **UI components**: 3:1 minimum
|
|
|
|
```html
|
|
<!-- ✅ Good - High contrast -->
|
|
<div class="bg-white text-gray-900">
|
|
Readable text with 21:1 ratio
|
|
</div>
|
|
|
|
<!-- ❌ Bad - Low contrast -->
|
|
<div class="bg-gray-300 text-gray-400">
|
|
Hard to read - only 1.5:1 ratio
|
|
</div>
|
|
```
|
|
|
|
### Don't Rely on Color Alone
|
|
|
|
```html
|
|
<!-- ✅ Good - Icon + color + text -->
|
|
<span class="text-red-500 flex items-center gap-2">
|
|
<svg class="w-4 h-4"><!-- Error icon --></svg>
|
|
Error: Invalid input
|
|
</span>
|
|
```
|
|
|
|
## Semantic HTML
|
|
|
|
### Use the Right Elements
|
|
|
|
```html
|
|
<!-- ✅ Good - Semantic -->
|
|
<header>
|
|
<nav>
|
|
<ul>
|
|
<li><a href="/">Home</a></li>
|
|
</ul>
|
|
</nav>
|
|
</header>
|
|
|
|
<main>
|
|
<article>
|
|
<h1>Article Title</h1>
|
|
<p>Content...</p>
|
|
</article>
|
|
</main>
|
|
|
|
<!-- ❌ Bad - Divitis -->
|
|
<div class="header">
|
|
<div class="nav">...</div>
|
|
</div>
|
|
```
|
|
|
|
### Heading Hierarchy
|
|
|
|
```html
|
|
<!-- ✅ Good - Proper hierarchy -->
|
|
<h1>Page Title</h1>
|
|
<h2>Section Title</h2>
|
|
<h3>Subsection Title</h3>
|
|
```
|
|
|
|
## Keyboard Navigation
|
|
|
|
### Focus Indicators
|
|
|
|
**Always show visible focus states.**
|
|
|
|
```html
|
|
<button class="focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2">
|
|
Click Me
|
|
</button>
|
|
|
|
<input class="focus:border-primary focus:ring-2 focus:ring-primary-focus" />
|
|
```
|
|
|
|
### Skip Links
|
|
|
|
```html
|
|
<a href="#main-content" class="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:z-50">
|
|
Skip to main content
|
|
</a>
|
|
|
|
<main id="main-content">
|
|
<!-- Main content -->
|
|
</main>
|
|
```
|
|
|
|
### Test Keyboard Navigation
|
|
- Tab through entire page
|
|
- Shift+Tab to go backwards
|
|
- Enter/Space to activate buttons
|
|
- Escape to close modals/dropdowns
|
|
|
|
## ARIA (Use Sparingly)
|
|
|
|
**First rule of ARIA: Don't use ARIA if you can use semantic HTML instead.**
|
|
|
|
### ARIA Labels
|
|
|
|
```html
|
|
<!-- Button with only icon -->
|
|
<button aria-label="Close modal">
|
|
<svg><!-- X icon --></svg>
|
|
</button>
|
|
|
|
<!-- Decorative image -->
|
|
<img src="decoration.svg" alt="" aria-hidden="true" />
|
|
```
|
|
|
|
### ARIA Live Regions
|
|
|
|
```html
|
|
<!-- Announce status updates -->
|
|
<div
|
|
role="status"
|
|
aria-live="polite"
|
|
aria-atomic="true"
|
|
class="sr-only"
|
|
>
|
|
{{ statusMessage }}
|
|
</div>
|
|
```
|
|
|
|
## Forms Accessibility
|
|
|
|
### Label Every Input
|
|
|
|
```html
|
|
<!-- ✅ Good - Explicit label -->
|
|
<label for="email">Email Address</label>
|
|
<input id="email" type="email" name="email" />
|
|
|
|
<!-- ❌ Bad - No label -->
|
|
<input type="email" placeholder="Email" />
|
|
```
|
|
|
|
### Required Fields
|
|
|
|
```html
|
|
<label for="email">
|
|
Email <span class="text-red-500" aria-label="required">*</span>
|
|
</label>
|
|
<input
|
|
id="email"
|
|
type="email"
|
|
required
|
|
aria-required="true"
|
|
/>
|
|
```
|
|
|
|
### Error Messages
|
|
|
|
```html
|
|
<input
|
|
id="email"
|
|
:aria-invalid="hasError"
|
|
:aria-describedby="hasError ? 'email-error' : undefined"
|
|
/>
|
|
|
|
<div
|
|
v-if="hasError"
|
|
id="email-error"
|
|
role="alert"
|
|
class="text-red-500"
|
|
>
|
|
Please enter a valid email
|
|
</div>
|
|
```
|
|
|
|
## Touch Targets & Mobile
|
|
|
|
### Minimum Touch Target Size
|
|
|
|
**WCAG Guideline: 44x44px minimum**
|
|
|
|
```html
|
|
<!-- ✅ Good - Large enough -->
|
|
<button class="p-4">
|
|
<svg class="w-6 h-6"><!-- Icon --></svg>
|
|
</button>
|
|
|
|
<!-- ❌ Bad - Too small -->
|
|
<button class="p-1">
|
|
<svg class="w-3 h-3"><!-- Icon --></svg>
|
|
</button>
|
|
```
|
|
|
|
### Spacing Between Targets
|
|
|
|
```html
|
|
<!-- ✅ Good - Adequate spacing -->
|
|
<nav class="flex flex-col gap-6 md:gap-2">
|
|
<a href="/home" class="py-3 md:py-2">Home</a>
|
|
</nav>
|
|
```
|
|
|
|
## Motion & Animation
|
|
|
|
### Respect Prefers-Reduced-Motion
|
|
|
|
```css
|
|
@media (prefers-reduced-motion: reduce) {
|
|
* {
|
|
animation-duration: 0.01ms !important;
|
|
transition-duration: 0.01ms !important;
|
|
}
|
|
}
|
|
```
|
|
|
|
## Screen Reader Support
|
|
|
|
### Alt Text for Images
|
|
|
|
```html
|
|
<!-- ✅ Informative image -->
|
|
<img src="chart.png" alt="Bar chart showing 25% revenue increase" />
|
|
|
|
<!-- ✅ Decorative image -->
|
|
<img src="decoration.svg" alt="" />
|
|
```
|
|
|
|
### Screen Reader Only Text
|
|
|
|
```css
|
|
.sr-only {
|
|
position: absolute;
|
|
width: 1px;
|
|
height: 1px;
|
|
padding: 0;
|
|
margin: -1px;
|
|
overflow: hidden;
|
|
clip: rect(0, 0, 0, 0);
|
|
white-space: nowrap;
|
|
border-width: 0;
|
|
}
|
|
```
|
|
|
|
## Accessibility Checklist
|
|
|
|
### Perceivable
|
|
- ✅ Text has sufficient contrast (4.5:1)
|
|
- ✅ Images have alt text
|
|
- ✅ Color is not the only indicator
|
|
- ✅ Content works at 200% zoom
|
|
|
|
### Operable
|
|
- ✅ All functionality keyboard accessible
|
|
- ✅ Focus indicators visible
|
|
- ✅ No keyboard traps
|
|
- ✅ Touch targets at least 44x44px
|
|
|
|
### Understandable
|
|
- ✅ Clear, simple language
|
|
- ✅ Labels for all form inputs
|
|
- ✅ Error messages are clear
|
|
- ✅ Consistent navigation
|
|
|
|
### Robust
|
|
- ✅ Semantic HTML
|
|
- ✅ Valid ARIA attributes
|
|
- ✅ Works with assistive technologies
|
|
|
|
**Remember: Accessibility is not a checklist—it's an ongoing commitment to inclusive design.**
|