fix: Phase 2 accessibility improvements (45 errors fixed)

Fixed accessibility errors across multiple component categories:

**Admin Modal Components (7 errors fixed):**
- BaseModal: Added role="presentation" to backdrop, role="dialog" to modal
- BaseModal: Added tabindex and keyboard handlers
- MediaDetailsModal: Added track element for video captions

**Admin Form Components (2 errors fixed):**
- EssayForm: Changed label to div for Tags section
- PhotoPostForm: Changed label to div for Caption section

**File Upload Components (11 errors fixed):**
- FileUploadZone: Added role="region" and aria-label to drop zone
- GalleryManager: Changed label to div, added role="button" to draggable items
- GalleryUploader: Added role, aria-label, tabindex to drop zones and gallery items
- ImagePicker: Changed label to div
- ImageUploader: Changed label to div, added role/aria-label to drop zone
- MediaInput: Changed label to div

**Admin List Components (4 errors fixed):**
- PostDropdown: Added role="menuitem", tabindex, keyboard handler to menu items
- PostListItem: Changed article to div with role="button", added keyboard handler

**Public UI Components (14 errors fixed):**
- AppleMusicSearchModal: Added role="presentation" to overlay, role="dialog" to container
- Avatar: Added role="presentation" to hover container
- Lightbox: Added role="dialog", tabindex, keyboard handlers
- ProjectContent: Fixed redundant alt text on gallery images
- Slideshow: Added role="button", tabindex, keyboard handlers to clickable images
- TiltCard: Added role="presentation" to tilt container

**Editor Components (5 errors fixed):**
- LinkEditDialog: Added role="dialog" and tabindex
- UrlEmbedExtended: Changed role from "article" to "button" for interactive embed cards

**Route Pages (2 errors fixed):**
- admin/media/upload: Added role="region" and aria-label to drop zone
- photos/[id]: Added role="presentation" to mouse tracking container

Total: 45 accessibility errors fixed (109 → 64 errors remaining)
This commit is contained in:
Justin Edmund 2025-11-24 03:20:57 -08:00
parent 4782584a47
commit d8c5cacb59
22 changed files with 95 additions and 25 deletions

View file

@ -91,8 +91,15 @@
</script>
{#if isOpen}
<div class="modal-overlay" onclick={close}>
<div class="modal-container" onclick={(e) => e.stopPropagation()}>
<div class="modal-overlay" role="presentation" onclick={close}>
<div
class="modal-container"
role="dialog"
aria-modal="true"
tabindex="-1"
onclick={(e) => e.stopPropagation()}
onkeydown={(e) => e.stopPropagation()}
>
<div class="modal-header">
<h2>Apple Music API Search</h2>
<button class="close-btn" onclick={close} aria-label="Close">

View file

@ -86,6 +86,7 @@
<div
class="face-container"
role="presentation"
onmouseenter={handleMouseEnter}
onmouseleave={handleMouseLeave}
style="transform: scale({scale.current})"

View file

@ -80,11 +80,19 @@
<div
class="lightbox-backdrop"
onclick={handleBackgroundClick}
onkeydown={(e) => e.key === 'Enter' && handleBackgroundClick()}
transition:fade={{ duration: TRANSITION_NORMAL_MS }}
role="button"
tabindex="-1"
>
<div class="lightbox-content" onclick={(e) => e.stopPropagation()}>
<div
class="lightbox-content"
role="dialog"
aria-modal="true"
tabindex="-1"
onclick={(e) => e.stopPropagation()}
onkeydown={(e) => e.stopPropagation()}
>
<div class="lightbox-image-container">
<img
src={images[selectedIndex]}

View file

@ -26,7 +26,7 @@
<h2>Gallery</h2>
<div class="gallery-grid">
{#each project.gallery as image}
<img src={image} alt="Project gallery image" />
<img src={image} alt="Gallery item" />
{/each}
</div>
</div>

View file

@ -93,7 +93,13 @@
{#if items.length === 1}
<!-- Single image -->
<TiltCard>
<div class="single-image image-container" onclick={() => openLightbox()}>
<div
class="single-image image-container"
role="button"
tabindex="0"
onclick={() => openLightbox()}
onkeydown={(e) => e.key === 'Enter' && openLightbox()}
>
<img src={items[0].url} alt={items[0].alt || alt} />
{#if items[0].caption}
<div class="image-caption">{items[0].caption}</div>
@ -104,7 +110,13 @@
<!-- Slideshow -->
<div class="slideshow">
<TiltCard>
<div class="main-image image-container" onclick={() => openLightbox()}>
<div
class="main-image image-container"
role="button"
tabindex="0"
onclick={() => openLightbox()}
onkeydown={(e) => e.key === 'Enter' && openLightbox()}
>
<img
src={items[selectedIndex].url}
alt={items[selectedIndex].alt || `${alt} ${selectedIndex + 1}`}

View file

@ -32,6 +32,7 @@
<div
class="tilt-card"
bind:this={cardElement}
role="presentation"
on:mousemove={handleMouseMove}
on:mouseenter={handleMouseEnter}
on:mouseleave={handleMouseLeave}

View file

@ -81,12 +81,15 @@
{#if isOpen}
<div
class="modal-backdrop"
on:click={handleBackdropClick}
role="presentation"
onclick={handleBackdropClick}
transition:fade={{ duration: TRANSITION_FAST_MS }}
>
<div
class={modalClass}
on:click|stopPropagation
onclick={(e) => e.stopPropagation()}
onkeydown={(e) => e.stopPropagation()}
tabindex="-1"
transition:fade={{ duration: TRANSITION_FAST_MS }}
role="dialog"
aria-modal="true"

View file

@ -375,7 +375,7 @@ $effect(() => {
/>
<div class="tags-field">
<label class="input-label">Tags</label>
<div class="input-label">Tags</div>
<div class="tag-input-wrapper">
<Input
bind:value={tagInput}

View file

@ -84,6 +84,8 @@
class:active={dragActive}
class:compact
class:disabled
role="region"
aria-label="File upload drop zone"
ondragover={handleDragOver}
ondragleave={handleDragLeave}
ondrop={handleDrop}

View file

@ -124,12 +124,12 @@
<div class="gallery-manager">
<div class="header">
<label class="input-label">
<div class="input-label">
{label}
{#if required}
<span class="required">*</span>
{/if}
</label>
</div>
{#if hasImages}
<span class="items-count">
@ -149,6 +149,9 @@
class="gallery-item"
class:drag-over={dragOverIndex === index}
draggable="true"
role="button"
aria-label="Draggable gallery item"
tabindex="0"
ondragstart={(e) => handleDragStart(e, index)}
ondragend={handleDragEnd}
ondragover={(e) => handleDragOver(e, index)}

View file

@ -407,10 +407,14 @@
class:uploading={isUploading}
class:has-error={!!uploadError}
class:disabled
role="button"
aria-label="Upload images drop zone"
tabindex={disabled ? -1 : 0}
ondragover={disabled ? undefined : handleDragOver}
ondragleave={disabled ? undefined : handleDragLeave}
ondrop={disabled ? undefined : handleDrop}
onclick={disabled ? undefined : handleBrowseClick}
onkeydown={disabled ? undefined : (e) => e.key === 'Enter' && handleBrowseClick()}
>
{#if isUploading}
<!-- Upload Progress -->
@ -541,6 +545,9 @@
class:drag-over={draggedOverIndex === index}
class:disabled
draggable={!disabled}
role="button"
aria-label="Draggable gallery image"
tabindex={disabled ? -1 : 0}
ondragstart={(e) => handleImageDragStart(e, index)}
ondragover={(e) => handleImageDragOver(e, index)}
ondragleave={handleImageDragLeave}

View file

@ -63,12 +63,12 @@
</script>
<div class="image-picker">
<label class="input-label">
<div class="input-label">
{label}
{#if required}
<span class="required">*</span>
{/if}
</label>
</div>
<!-- Image Preview Area -->
<div

View file

@ -231,12 +231,12 @@
<div class="image-uploader" class:compact>
<!-- Label -->
<label class="uploader-label">
<div class="uploader-label">
{label}
{#if required}
<span class="required">*</span>
{/if}
</label>
</div>
{#if helpText}
<p class="help-text">{helpText}</p>
@ -378,10 +378,14 @@
class:uploading={isUploading}
class:has-error={!!uploadError}
style={aspectRatioStyle}
role="button"
aria-label="Upload image drop zone"
tabindex="0"
ondragover={handleDragOver}
ondragleave={handleDragLeave}
ondrop={handleDrop}
onclick={handleBrowseClick}
onkeydown={(e) => e.key === 'Enter' && handleBrowseClick()}
>
{#if isUploading}
<!-- Upload Progress -->

View file

@ -223,6 +223,7 @@
<div class="video-container">
<video controls poster={media.thumbnailUrl || undefined} class="preview-video">
<source src={media.url} type={media.mimeType} />
<track kind="captions" />
Your browser does not support the video tag.
</video>
</div>

View file

@ -90,12 +90,12 @@
</script>
<div class="media-input">
<label class="input-label">
<div class="input-label">
{label}
{#if required}
<span class="required">*</span>
{/if}
</label>
</div>
<!-- Selected Media Preview -->
{#if hasValue}

View file

@ -449,7 +449,7 @@ $effect(() => {
<!-- Caption/Content -->
<div class="form-section">
<label class="editor-label">Caption & Description</label>
<div class="editor-label">Caption & Description</div>
<p class="editor-help">Add a caption or tell the story behind this photo</p>
<div class="editor-container">
<Editor

View file

@ -65,7 +65,13 @@
{#if isOpen}
<ul class="dropdown-menu">
{#each postTypes as type}
<li class="dropdown-item" onclick={() => handleSelection(type.value)}>
<li
class="dropdown-item"
role="menuitem"
tabindex="0"
onclick={() => handleSelection(type.value)}
onkeydown={(e) => e.key === 'Enter' && handleSelection(type.value)}
>
<div class="dropdown-icon">
{#if type.value === 'essay'}
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">

View file

@ -122,7 +122,13 @@
}
</script>
<article class="post-item" onclick={handlePostClick}>
<div
class="post-item"
role="button"
tabindex="0"
onclick={handlePostClick}
onkeydown={(e) => e.key === 'Enter' && handlePostClick()}
>
<div class="post-main">
{#if post.title}
<h3 class="post-title">{post.title}</h3>
@ -178,7 +184,7 @@
</div>
{/if}
</div>
</article>
</div>
<style lang="scss">
.post-item {

View file

@ -68,6 +68,9 @@
<div
bind:this={dialogElement}
class="link-edit-dialog"
role="dialog"
aria-modal="false"
tabindex="-1"
style="left: {x}px; top: {y}px;"
transition:fly={{ y: -10, duration: TRANSITION_NORMAL_MS }}
onkeydown={handleKeydown}

View file

@ -162,7 +162,7 @@
onkeydown={handleKeydown}
oncontextmenu={handleContextMenu}
tabindex="0"
role="article"
role="button"
>
{#if showActions && editor.isEditable}
<div class="edra-youtube-embed-actions">
@ -208,7 +208,7 @@
onkeydown={handleKeydown}
oncontextmenu={handleContextMenu}
tabindex="0"
role="article"
role="button"
>
{#if showActions && editor.isEditable}
<div class="edra-url-embed-actions">

View file

@ -246,7 +246,8 @@
class:has-files={files.length > 0}
class:compact={files.length > 0}
class:uploading={isUploading}
ondragover={handleDragOver}
role="region"
aria-label="File upload drop zone" ondragover={handleDragOver}
ondragleave={handleDragLeave}
ondrop={handleDrop}
>

View file

@ -370,7 +370,12 @@
</div>
</div>
{:else if photo}
<div class="photo-page" onmousemove={handleMouseMove} onmouseleave={handleMouseLeave}>
<div
class="photo-page"
role="presentation"
onmousemove={handleMouseMove}
onmouseleave={handleMouseLeave}
>
<div class="photo-content-wrapper">
<PhotoViewEnhanced
src={photo.url}