Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
19104f5
docs: add toast notification system design spec
Tresillo2017 Apr 8, 2026
e4ff2e6
deps: add sileo toast notification library
Tresillo2017 Apr 8, 2026
3ffa89c
style: add toast notification CSS overrides
Tresillo2017 Apr 8, 2026
b556c9a
style: import toast CSS in global stylesheet
Tresillo2017 Apr 8, 2026
e90adaa
feat: integrate Toaster component in App root
Tresillo2017 Apr 8, 2026
0cf7c86
docs: add toast notification usage examples
Tresillo2017 Apr 8, 2026
bca7da3
feat: add toast notifications to like button
Tresillo2017 Apr 8, 2026
81aa95d
fix: connect toast theme to Zephyron theme store
Tresillo2017 Apr 8, 2026
00d99f2
fix: toast background now respects HSL-parametric theme system
Tresillo2017 Apr 8, 2026
cca1280
feat(db): add bio, avatar_url, is_profile_public to user table
Tresillo2017 Apr 8, 2026
e0eaf0b
feat(types): add profile enhancement types
Tresillo2017 Apr 8, 2026
1ca284c
feat(config): add R2 bucket binding for profile avatars
Tresillo2017 Apr 8, 2026
4aea70f
feat(api): add avatar upload endpoint
Tresillo2017 Apr 8, 2026
e70654d
fix(profile): remove unused import and duplicate migration column
Tresillo2017 Apr 8, 2026
050d58c
feat(api): add profile settings update endpoint
Tresillo2017 Apr 8, 2026
f3e90ac
fix(api): align profile settings endpoint with project patterns
Tresillo2017 Apr 8, 2026
1dcdc24
feat(api): add public profile endpoint (Phase 1 stub)
Tresillo2017 Apr 8, 2026
e50f23d
refactor(api): improve public profile endpoint validation
Tresillo2017 Apr 8, 2026
c47ab57
feat(api): add profile API client functions
Tresillo2017 Apr 8, 2026
6c5934e
fix(api): correct FormData field name in uploadAvatar
Tresillo2017 Apr 8, 2026
708be0e
fix(types): add missing role field to PublicUser interface
Tresillo2017 Apr 8, 2026
37e262f
feat(profile): add profile picture upload component
Tresillo2017 Apr 8, 2026
cc068b4
fix(profile): improve ProfilePictureUpload accessibility and cleanup
Tresillo2017 Apr 8, 2026
24584ef
feat(profile): add bio editor component
Tresillo2017 Apr 8, 2026
b86f3cb
feat(profile): add profile header component
Tresillo2017 Apr 8, 2026
5e4ba2a
refactor(profile): remove reputation system UI
Tresillo2017 Apr 8, 2026
723a644
refactor(profile): add tabbed interface with ProfileHeader
Tresillo2017 Apr 8, 2026
56ffe79
feat(settings): replace ProfileTab with profile editor
Tresillo2017 Apr 8, 2026
2932faf
feat(ci): add automated GitHub release workflow
Tresillo2017 Apr 8, 2026
145f8fa
feat(ci): add script to backfill missing GitHub releases
Tresillo2017 Apr 8, 2026
e580417
fix(api): correct avatar URL domain to zephyron.app
Tresillo2017 Apr 8, 2026
6a53087
docs(spec): add Phase 2 Analytics & Wrapped design
Tresillo2017 Apr 9, 2026
929467e
docs(plan): complete Analytics & Wrapped implementation plan
Tresillo2017 Apr 9, 2026
9a046a5
feat(db): add analytics tables for listening sessions and stats
Tresillo2017 Apr 9, 2026
4d8e2bb
fix(migrations): correct listening_sessions schema to match spec
Tresillo2017 Apr 9, 2026
3c27c6b
feat(worker): add timezone utilities for Pacific conversion
Tresillo2017 Apr 9, 2026
82f22a5
refactor(worker): improve timezone utilities error handling and tests
Tresillo2017 Apr 9, 2026
a4e16ef
feat(api): add session start endpoint
Tresillo2017 Apr 9, 2026
5510295
fix(api): return original started_at for existing sessions
Tresillo2017 Apr 9, 2026
e2105a8
refactor(api): improve session start endpoint robustness
Tresillo2017 Apr 9, 2026
f0f58e0
feat(api): add session progress and end endpoints
Tresillo2017 Apr 9, 2026
1b522fd
feat(cron): add hourly session cleanup job
Tresillo2017 Apr 9, 2026
c81a2e3
feat(worker): add stats aggregation utilities
Tresillo2017 Apr 9, 2026
82b3c02
fix(worker): correct stats aggregation queries and types
Tresillo2017 Apr 9, 2026
33c5d93
feat(cron): add monthly stats aggregation job
Tresillo2017 Apr 9, 2026
1528de0
deps: add @napi-rs/canvas for Wrapped image generation
Tresillo2017 Apr 9, 2026
c673993
feat(wrapped): implement canvas-based wrapped image generation
Tresillo2017 Apr 9, 2026
741bf3b
feat(analytics): implement annual stats cron job with Wrapped image g…
Tresillo2017 Apr 9, 2026
de94e44
feat(wrapped): implement Wrapped API endpoints for annual and monthly…
Tresillo2017 Apr 9, 2026
d96c41a
feat(api): add session tracking and Wrapped API functions
Tresillo2017 Apr 9, 2026
9494eff
feat(wrapped): create WrappedPage component for annual analytics display
Tresillo2017 Apr 9, 2026
6cc3ba8
feat(wrapped): add MonthlyWrappedPage component for monthly stats dis…
Tresillo2017 Apr 9, 2026
0d5b454
feat(profile): add quick stats and wrapped CTA to profile page
Tresillo2017 Apr 9, 2026
6a15cf5
feat(player): integrate session tracking into player store
Tresillo2017 Apr 9, 2026
4c0fad6
fix(canvas): handle null values in topArtists array
Tresillo2017 Apr 9, 2026
1deaed6
test: add E2E testing script and results template
Tresillo2017 Apr 9, 2026
4682e9d
fix(vite): stub @napi-rs/canvas for frontend builds
Tresillo2017 Apr 9, 2026
bc7c12e
fix(player): remove legacy updateListenPosition code
Tresillo2017 Apr 9, 2026
5294dc7
fix(api): restore missing stream and playcount functions
Tresillo2017 Apr 9, 2026
d22bfb8
fix(api): add getSongLikeStatus function
Tresillo2017 Apr 9, 2026
4e81e80
fix(api): restore all missing API functions from master
Tresillo2017 Apr 9, 2026
0fb2182
fix(api): restore complete API from pre-Phase-2 + add analytics funct…
Tresillo2017 Apr 9, 2026
0a4d788
fix(migrations): add avatar_url column to profile enhancements
Tresillo2017 Apr 9, 2026
fa6a9c2
fix(toast): make toast text readable on dark backgrounds
Tresillo2017 Apr 9, 2026
126a24e
feat(avatars): organize R2 avatars by user ID folder
Tresillo2017 Apr 9, 2026
29817c9
feat(scripts): add avatar migration scripts for folder organization
Tresillo2017 Apr 9, 2026
47d2464
feat(profile): add avatar to top nav and fix session refresh
Tresillo2017 Apr 9, 2026
f2051f1
feat(design): enhance visual polish with bleh-inspired refinements
Tresillo2017 Apr 10, 2026
21da71a
docs(spec): add Profile Phase 2 & 3 design spec
Tresillo2017 Apr 11, 2026
2b9a3c4
feat(stats): add calculateWeekdayPattern for day-of-week breakdown
Tresillo2017 Apr 11, 2026
d0661bc
chore: add .worktrees to .gitignore
Tresillo2017 Apr 11, 2026
e3d7288
feat(api): add GET /api/profile/:userId/stats endpoint
Tresillo2017 Apr 11, 2026
0f4f7b0
fix(api): improve stats types and test assertions
Tresillo2017 Apr 11, 2026
41e3860
feat(frontend): add profile Zustand store with stats caching
Tresillo2017 Apr 11, 2026
aa4a75f
feat(ui): add stats visualization components
Tresillo2017 Apr 11, 2026
baa322a
feat(profile): add ProfileStatsSection container and integrate into P…
Tresillo2017 Apr 11, 2026
5b590bf
feat(badges): complete badge system with 20 badges, API, cron, and UI
Tresillo2017 Apr 11, 2026
6af2306
feat(api): add activity feed and privacy settings endpoints
Tresillo2017 Apr 11, 2026
ff1269e
feat(frontend): add activity feed types and store with privacy
Tresillo2017 Apr 11, 2026
40615fd
feat(ui): add activity feed UI components and pages
Tresillo2017 Apr 11, 2026
ec5dd4d
feat(avatars): add multi-size generation with Workers Image Resizing
Tresillo2017 Apr 11, 2026
ae22738
fix(profile): persist avatar_url in Better Auth session
Tresillo2017 Apr 11, 2026
bb44ae7
chore: update .gitignore
Tresillo2017 Apr 12, 2026
f62b060
chore: update depencencies
Tresillo2017 Apr 12, 2026
16792a4
feat(stats): add heatmap and weekday pattern calculations
Tresillo2017 Apr 12, 2026
b975c3f
fix(api): update stats endpoint to use DB-querying functions
Tresillo2017 Apr 12, 2026
a9de30d
fix(api): correct user ID validation regex for Better Auth IDs
Tresillo2017 Apr 12, 2026
cd268c3
fix(api): allow users to view their own private profile
Tresillo2017 Apr 12, 2026
d1ac97d
feat(profile): hide yearly wrapped until December
Tresillo2017 Apr 12, 2026
727cd45
feat(ui): add comprehensive skeleton loaders website-wide
Tresillo2017 Apr 12, 2026
0c6b64e
feat(artists): migrate profile images to R2 storage
Tresillo2017 Apr 12, 2026
7a78d9b
feat(branding): add logo and favicon assets
Tresillo2017 Apr 12, 2026
b632579
chore: update CLAUDE.md with autoskills summaries
Tresillo2017 Apr 12, 2026
9963c8e
refactor(admin): remove image_url field from artist editor
Tresillo2017 Apr 12, 2026
74cab85
feat(admin): add artist image R2 migration tooling
Tresillo2017 Apr 12, 2026
0c6cad5
feat(admin): auto-upload artist images from 1001Tracklists
Tresillo2017 Apr 12, 2026
65ea969
feat(scripts): load environment from .env file for migration
Tresillo2017 Apr 12, 2026
e927c11
fix(profile): replace activity placeholder with actual feed
Tresillo2017 Apr 12, 2026
81dc9b1
fix(vite): enable polling for WSL2 file watching
Tresillo2017 Apr 12, 2026
e85f488
chore: add new skills
Tresillo2017 Apr 12, 2026
51a54f5
fix: resolve TypeScript errors in components and worker
Tresillo2017 Apr 14, 2026
58a1a52
feat: add production-ready GitHub Actions workflows
Tresillo2017 Apr 14, 2026
6275094
chore: remove redundant deploy-preview workflow
Tresillo2017 Apr 14, 2026
4d4e5c6
fix: resolve 34 TypeScript errors (66 → 32 remaining)
Tresillo2017 Apr 14, 2026
6aba0e5
release: v0.4.0-alpha - Profile system, badges, and build fixes
Tresillo2017 Apr 14, 2026
4cd63f8
Potential fix for pull request finding 'CodeQL / Workflow does not co…
Tresillo2017 Apr 14, 2026
872e1b8
Potential fix for pull request finding 'CodeQL / Workflow does not co…
Tresillo2017 Apr 14, 2026
3f34c1b
Potential fix for pull request finding 'CodeQL / Incomplete multi-cha…
Tresillo2017 Apr 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
440 changes: 440 additions & 0 deletions .agents/skills/accessibility/SKILL.md

Large diffs are not rendered by default.

233 changes: 233 additions & 0 deletions .agents/skills/accessibility/references/A11Y-PATTERNS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
# Accessibility Code Patterns

Practical, copy-paste-ready patterns for common accessibility requirements. Each pattern is self-contained and linked from the main [SKILL.md](../SKILL.md).

---

## Modal focus trap

Trap keyboard focus inside a modal dialog so Tab/Shift+Tab cycle through its focusable elements and Escape closes it.

```javascript
function openModal(modal) {
const focusableElements = modal.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];

modal.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === firstElement) {
e.preventDefault();
lastElement.focus();
} else if (!e.shiftKey && document.activeElement === lastElement) {
e.preventDefault();
firstElement.focus();
}
}
if (e.key === 'Escape') {
closeModal();
}
});

firstElement.focus();
}
```

The native `<dialog>` element handles focus trapping automatically—prefer it when browser support allows.

---

## Skip link

Allows keyboard users to bypass repetitive navigation and jump straight to main content.

```html
<body>
<a href="#main-content" class="skip-link">Skip to main content</a>
<header><!-- navigation --></header>
<main id="main-content" tabindex="-1">
<!-- main content -->
</main>
</body>
```

```css
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: #fff;
padding: 8px 16px;
z-index: 100;
}

.skip-link:focus {
top: 0;
}
```

---

## Error handling

Announce errors to screen readers and focus the first invalid field on submit.

```html
<form novalidate>
<div class="field" aria-live="polite">
<label for="email">Email</label>
<input type="email" id="email"
aria-invalid="true"
aria-describedby="email-error">
<p id="email-error" class="error" role="alert">
Please enter a valid email address (e.g., name@example.com)
</p>
</div>
</form>
```

```javascript
form.addEventListener('submit', (e) => {
const firstError = form.querySelector('[aria-invalid="true"]');
if (firstError) {
e.preventDefault();
firstError.focus();

const errorSummary = document.getElementById('error-summary');
errorSummary.textContent =
`${errors.length} errors found. Please fix them and try again.`;
errorSummary.focus();
}
});
```

---

## Form labels

Every input needs an associated label—either explicit (`for`/`id`) or implicit (wrapping `<label>`).

```html
<!-- ❌ No label association -->
<input type="email" placeholder="Email">

<!-- ✅ Explicit label -->
<label for="email">Email address</label>
<input type="email" id="email" name="email"
autocomplete="email" required>

<!-- ✅ Implicit label -->
<label>
Email address
<input type="email" name="email" autocomplete="email" required>
</label>

<!-- ✅ With instructions -->
<label for="password">Password</label>
<input type="password" id="password"
aria-describedby="password-requirements">
<p id="password-requirements">
Must be at least 8 characters with one number.
</p>
```

---

## Dragging movements

Any action triggered by dragging must offer a single-pointer alternative (WCAG 2.5.7).

```html
<!-- ❌ Drag-only reorder -->
<ul class="sortable-list" draggable="true">
<li>Item 1</li>
<li>Item 2</li>
</ul>

<!-- ✅ Drag + button alternatives -->
<ul class="sortable-list">
<li>
<span>Item 1</span>
<button aria-label="Move Item 1 up">↑</button>
<button aria-label="Move Item 1 down">↓</button>
</li>
<li>
<span>Item 2</span>
<button aria-label="Move Item 2 up">↑</button>
<button aria-label="Move Item 2 down">↓</button>
</li>
</ul>
```

Also applies to sliders, map panning, colour pickers, and similar drag-based widgets—always provide an equivalent click/tap or keyboard path.

---

## ARIA tabs

Tabs require `role="tablist"`, `role="tab"`, and `role="tabpanel"` with proper `aria-selected`, `aria-controls`, and keyboard support.

```html
<div role="tablist" aria-label="Product information">
<button role="tab" id="tab-1" aria-selected="true"
aria-controls="panel-1">Description</button>
<button role="tab" id="tab-2" aria-selected="false"
aria-controls="panel-2" tabindex="-1">Reviews</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">
<!-- Panel content -->
</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>
<!-- Panel content -->
</div>
```

Arrow keys should move focus between tabs; the active tab receives `tabindex="0"` while inactive tabs use `tabindex="-1"`.

---

## Live regions and notifications

Use `aria-live` to announce dynamic content changes to screen readers without moving focus.

```html
<!-- Status updates (polite — waits for pause in speech) -->
<div aria-live="polite" aria-atomic="true" class="status">
<!-- Content updates announced to screen readers -->
</div>

<!-- Urgent alerts (assertive — interrupts) -->
<div role="alert" aria-live="assertive">
<!-- Interrupts current announcement -->
</div>
```

```javascript
function showNotification(message, type = 'polite') {
const container = document.getElementById(`${type}-announcer`);
container.textContent = '';
requestAnimationFrame(() => {
container.textContent = message;
});
}
```

Clear the container before writing to ensure the same message triggers a new announcement.

---

## Screen reader commands

Quick reference for the most common screen reader shortcuts.

| Action | VoiceOver (Mac) | NVDA (Windows) |
|--------|-----------------|----------------|
| Start/Stop | ⌘ + F5 | Ctrl + Alt + N |
| Next item | VO + → | ↓ |
| Previous item | VO + ← | ↑ |
| Activate | VO + Space | Enter |
| Headings list | VO + U, then arrows | H / Shift + H |
| Links list | VO + U | K / Shift + K |
Loading
Loading