๐Ÿ‘๏ธ
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

start fixing a11y issues, contrast, labels ect

+57 -22
+5 -5
src/components/SearchPrimer.tsx
··· 14 14 <Link 15 15 to="/cards" 16 16 search={{ q, sort: undefined, sort2: undefined }} 17 - className="font-mono text-sm bg-gray-200 dark:bg-zinc-700 px-1.5 py-0.5 rounded text-cyan-700 dark:text-cyan-300 hover:bg-cyan-100 dark:hover:bg-cyan-900/50 transition-colors" 17 + className="font-mono text-sm bg-gray-200 dark:bg-zinc-700 px-1.5 py-0.5 rounded text-cyan-800 dark:text-cyan-300 underline decoration-cyan-800/30 dark:decoration-cyan-300/30 hover:bg-cyan-100 dark:hover:bg-cyan-900/50 hover:decoration-cyan-800 dark:hover:decoration-cyan-300 transition-colors" 18 18 > 19 19 {q} 20 20 </Link> ··· 34 34 <div 35 35 className={`bg-gray-50 dark:bg-zinc-800/50 border border-gray-200 dark:border-zinc-600 rounded-lg p-4 ${className}`} 36 36 > 37 - <h3 className="font-semibold text-gray-900 dark:text-white mb-2"> 37 + <h2 className="font-semibold text-gray-900 dark:text-white mb-2"> 38 38 {title} 39 - </h3> 39 + </h2> 40 40 {children} 41 41 </div> 42 42 ); ··· 55 55 <div 56 56 className={`bg-gray-50/50 dark:bg-zinc-800/30 border border-gray-200/50 dark:border-zinc-600/50 rounded-lg p-3 ${className}`} 57 57 > 58 - <h4 className="text-sm font-medium text-gray-500 dark:text-zinc-300 mb-2"> 58 + <h3 className="text-sm font-medium text-gray-500 dark:text-zinc-300 mb-2"> 59 59 {title} 60 - </h4> 60 + </h3> 61 61 {children} 62 62 </div> 63 63 );
+7 -2
src/components/deck/CardModal.tsx
··· 35 35 const [tags, setTags] = useState<string[]>(card.tags ?? []); 36 36 37 37 const titleId = useId(); 38 + const sectionId = useId(); 38 39 39 40 const { data: cardData } = useQuery(getCardByIdQueryOptions(card.scryfallId)); 40 41 const primaryFace = cardData ? getPrimaryFace(cardData) : null; ··· 216 217 217 218 {/* Section */} 218 219 <div> 219 - <div className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2"> 220 + <label 221 + htmlFor={sectionId} 222 + className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2" 223 + > 220 224 Section 221 - </div> 225 + </label> 222 226 <select 227 + id={sectionId} 223 228 value={card.section} 224 229 onChange={(e) => onMoveToSection(e.target.value as Section)} 225 230 disabled={readOnly}
+1
src/components/deck/DeckHeader.tsx
··· 66 66 )} 67 67 68 68 <select 69 + aria-label="Deck format" 69 70 value={format || ""} 70 71 onChange={(e) => onFormatChange(e.target.value)} 71 72 disabled={readOnly}
+2 -2
src/components/profile/ProfileLayout.tsx
··· 81 81 to="/profile/$did" 82 82 params={{ did }} 83 83 activeOptions={{ exact: true }} 84 - className="px-4 py-2 font-medium text-sm border-b-2 transition-colors text-gray-500 dark:text-zinc-300 hover:text-gray-700 dark:hover:text-zinc-300 border-transparent hover:border-gray-300 dark:hover:border-zinc-600 [&.active]:border-cyan-500 [&.active]:text-cyan-600 dark:[&.active]:text-cyan-400" 84 + className="px-4 py-2 font-medium text-sm border-b-2 transition-colors text-gray-500 dark:text-zinc-300 hover:text-gray-700 dark:hover:text-zinc-300 border-transparent hover:border-gray-300 dark:hover:border-zinc-600 [&.active]:border-cyan-500 [&.active]:text-cyan-700 dark:[&.active]:text-cyan-400" 85 85 > 86 86 Decks 87 87 </Link> 88 88 <Link 89 89 to="/profile/$did/lists" 90 90 params={{ did }} 91 - className="px-4 py-2 font-medium text-sm border-b-2 transition-colors text-gray-500 dark:text-zinc-300 hover:text-gray-700 dark:hover:text-zinc-300 border-transparent hover:border-gray-300 dark:hover:border-zinc-600 [&.active]:border-cyan-500 [&.active]:text-cyan-600 dark:[&.active]:text-cyan-400" 91 + className="px-4 py-2 font-medium text-sm border-b-2 transition-colors text-gray-500 dark:text-zinc-300 hover:text-gray-700 dark:hover:text-zinc-300 border-transparent hover:border-gray-300 dark:hover:border-zinc-600 [&.active]:border-cyan-500 [&.active]:text-cyan-700 dark:[&.active]:text-cyan-400" 92 92 > 93 93 Lists 94 94 </Link>
+1 -1
src/routes/__root.tsx
··· 134 134 <HoverCardPreviewProvider> 135 135 <WorkerStatusIndicator /> 136 136 <Header /> 137 - {children} 137 + <main>{children}</main> 138 138 <Suspense> 139 139 <DevTools /> 140 140 </Suspense>
+3 -1
src/routes/cards/index.tsx
··· 56 56 href="https://scryfall.com" 57 57 target="_blank" 58 58 rel="noopener noreferrer" 59 - className="text-cyan-600 dark:text-cyan-400 hover:underline" 59 + className="text-cyan-600 dark:text-cyan-400 underline" 60 60 > 61 61 Scryfall 62 62 </a> ··· 353 353 <div className="flex gap-2"> 354 354 <div className="relative"> 355 355 <select 356 + aria-label="Sort by" 356 357 value={primarySort.value} 357 358 onChange={(e) => 358 359 navigate({ ··· 373 374 </div> 374 375 <div className="relative"> 375 376 <select 377 + aria-label="Then sort by" 376 378 value={secondarySort?.value ?? ""} 377 379 onChange={(e) => 378 380 navigate({
+4 -4
src/routes/index.tsx
··· 110 110 href="https://ufos.microcosm.blue" 111 111 target="_blank" 112 112 rel="noopener noreferrer" 113 - className="text-cyan-600 dark:text-cyan-400 hover:underline" 113 + className="text-cyan-600 dark:text-cyan-400 underline" 114 114 > 115 115 UFOs 116 116 </a> ··· 125 125 href="https://atproto.com" 126 126 target="_blank" 127 127 rel="noopener noreferrer" 128 - className="text-cyan-600 dark:text-cyan-400 hover:underline" 128 + className="text-cyan-600 dark:text-cyan-400 underline" 129 129 > 130 130 atproto 131 131 </a>{" "} ··· 134 134 href="https://deer.social/profile/did:plc:jx4g6baqkwdlonylsetvpu7c" 135 135 target="_blank" 136 136 rel="noopener noreferrer" 137 - className="text-cyan-600 dark:text-cyan-400 hover:underline" 137 + className="text-cyan-600 dark:text-cyan-400 underline" 138 138 > 139 139 @aviva.gay 140 140 </a>{" "} ··· 143 143 href="https://forsythpeak.com/" 144 144 target="_blank" 145 145 rel="noopener noreferrer" 146 - className="text-cyan-600 dark:text-cyan-400 hover:underline" 146 + className="text-cyan-600 dark:text-cyan-400 underline" 147 147 > 148 148 forsyth peak llc 149 149 </a>
+2
src/routes/profile/$did/index.tsx
··· 186 186 {decks.length > 0 && ( 187 187 <div className="flex flex-wrap gap-4"> 188 188 <select 189 + aria-label="Sort decks by" 189 190 value={search.sort ?? "updated-desc"} 190 191 onChange={handleSortChange} 191 192 className="px-4 py-2 bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:border-cyan-500" ··· 199 200 200 201 {availableFormats.length > 0 && ( 201 202 <select 203 + aria-label="Filter by format" 202 204 value={search.format ?? ""} 203 205 onChange={handleFormatChange} 204 206 className="px-4 py-2 bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:border-cyan-500"
+32 -7
todos.md
··· 147 147 148 148 ## Accessibility (a11y) 149 149 150 - Run `npm run test:a11y` to check. Currently failing on Card Search, Profile, Deck pages. 150 + Run `npm run test:a11y` to check. Currently 12/13 tests failing. 151 + 152 + ### Structural / Landmarks 153 + 154 + #### landmark-one-main: Missing main landmark 155 + - **Location**: Card pages, Profile, Deck pages 156 + - **Issue**: Document should have exactly one `<main>` landmark 157 + - **Fix**: Wrap primary content in `<main>` element in route layouts 158 + - **Pages affected**: Card detail, Profile, Deck 151 159 152 - ### color-contrast: cyan links on gray backgrounds 153 - - **Location**: Search primer (`src/components/SearchPrimer.tsx`) 160 + #### region: Content outside landmarks 161 + - **Location**: All pages 162 + - **Issue**: Page content not contained by landmarks (`<header>`, `<main>`, `<nav>`, `<footer>`, etc.) 163 + - **Fix**: Ensure all visible content is inside semantic landmark elements 164 + - **Selectors flagged**: `.text-red-900`, `p`, various buttons 165 + 166 + ### Contrast / Visual 167 + 168 + #### color-contrast: cyan links on gray backgrounds 169 + - **Location**: Search primer (`src/components/SearchPrimer.tsx`), Home page 154 170 - **Issue**: cyan-600 (#007595) on gray-200 (#e5e7eb) = 4.26:1, need 4.5:1 for AA 155 171 - **Fix**: Either darken cyan to ~cyan-700 or lighten background 156 172 157 - ### link-in-text-block: links not distinguishable 173 + #### link-in-text-block: links not distinguishable 158 174 - **Location**: Inline links in search primer, profile bio, etc. 159 175 - **Issue**: Links only distinguished by color, need underline or 3:1 contrast vs surrounding text 160 - - **Fix**: Add `hover:underline` โ†’ `underline hover:no-underline` or ensure sufficient contrast 176 + - **Fix**: Add `underline` class to inline links (not just `hover:underline`) 177 + 178 + ### Form Controls 161 179 162 - ### select-name: dropdowns missing accessible names 180 + #### select-name: dropdowns missing accessible names 163 181 - **Location**: Sort dropdowns on card search, deck page 164 182 - **Issue**: `<select>` elements have no `aria-label` or associated `<label>` 165 - - **Fix**: Add `aria-label="Sort by"` or wrap with `<label>` 183 + - **Fix**: Add `aria-label="Sort by"` or wrap with visible `<label>` 184 + 185 + ### Keyboard / Focus 186 + 187 + #### scrollable-region-focusable: Scrollable areas not keyboard accessible 188 + - **Location**: Profile page, Deck page (horizontal scroll areas) 189 + - **Issue**: Scrollable regions without focusable content can't be scrolled via keyboard 190 + - **Fix**: Add `tabIndex={0}` to scrollable containers, or ensure they contain focusable elements