11"use client" ;
22
3- import { useEffect , useState } from "react " ;
3+ import { Course , coursesAPI } from "@/lib/api " ;
44import Link from "next/link" ;
5- import { coursesAPI , Course } from "@/lib/api " ;
5+ import { useEffect , useState } from "react " ;
66
77export default function CoursesPage ( ) {
88 const [ courses , setCourses ] = useState < Course [ ] > ( [ ] ) ;
@@ -83,18 +83,23 @@ export default function CoursesPage() {
8383 { /* Search Bar */ }
8484 < div className = "mb-12 relative z-10" >
8585 < div className = "relative max-w-xl" >
86+ < label htmlFor = "course-search" className = "sr-only" > Search courses</ label >
8687 < input
87- type = "text"
88+ id = "course-search"
89+ type = "search"
8890 placeholder = "SEARCH NODE DIRECTORY..."
8991 value = { searchTerm }
9092 onChange = { ( e ) => setSearchTerm ( e . target . value ) }
9193 className = "w-full px-5 py-4 pl-14 rounded-xl border border-white/20 bg-black text-white font-mono focus:ring-1 focus:ring-red-500 focus:border-red-500 transition-colors uppercase tracking-wide placeholder-gray-600 shadow-[0_4px_20px_rgba(0,0,0,0.5)]"
94+ aria-label = "Search courses by title or description"
9295 />
9396 < svg
9497 className = "absolute left-5 top-1/2 transform -translate-y-1/2 w-6 h-6 text-red-600"
9598 fill = "none"
9699 stroke = "currentColor"
97100 viewBox = "0 0 24 24"
101+ aria-hidden = "true"
102+ focusable = "false"
98103 >
99104 < path
100105 strokeLinecap = "round"
@@ -109,13 +114,15 @@ export default function CoursesPage() {
109114 { /* Courses Grid */ }
110115 < div className = "relative z-10" >
111116 { filteredCourses . length === 0 ? (
112- < div className = "text-center py-20 border border-white/10 rounded-2xl bg-zinc-950/50 backdrop-blur-sm" >
113- < div className = "w-20 h-20 bg-red-900/20 rounded-2xl flex items-center justify-center mx-auto mb-6 border border-red-500/20" >
117+ < div className = "text-center py-20 border border-white/10 rounded-2xl bg-zinc-950/50 backdrop-blur-sm" role = "status" >
118+ < div className = "w-20 h-20 bg-red-900/20 rounded-2xl flex items-center justify-center mx-auto mb-6 border border-red-500/20" aria-hidden = "true" >
114119 < svg
115120 className = "h-10 w-10 text-red-500"
116121 fill = "none"
117122 stroke = "currentColor"
118123 viewBox = "0 0 24 24"
124+ aria-hidden = "true"
125+ focusable = "false"
119126 >
120127 < path
121128 strokeLinecap = "round"
@@ -135,22 +142,29 @@ export default function CoursesPage() {
135142 </ p >
136143 </ div >
137144 ) : (
138- < div className = "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8" >
145+ < div
146+ className = "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"
147+ aria-live = "polite"
148+ aria-label = { `${ filteredCourses . length } course${ filteredCourses . length !== 1 ? "s" : "" } found` }
149+ >
139150 { filteredCourses . map ( ( course ) => (
140151 < Link
141152 key = { course . id }
142153 href = { `/courses/${ course . id } ` }
143154 className = "group bg-zinc-950 border border-white/10 rounded-2xl p-8 hover:border-red-500/50 hover:shadow-[0_0_30px_rgba(220,38,38,0.15)] hover:-translate-y-1 transition-all duration-300 flex flex-col h-full relative overflow-hidden"
155+ aria-label = { `${ course . title } - ${ course . credits } credits, taught by ${ course . instructor } ` }
144156 >
145- < div className = "absolute top-0 right-0 w-32 h-32 bg-red-600/5 rounded-bl-[100px] pointer-events-none group-hover:bg-red-600/10 transition-colors" > </ div >
157+ < div className = "absolute top-0 right-0 w-32 h-32 bg-red-600/5 rounded-bl-[100px] pointer-events-none group-hover:bg-red-600/10 transition-colors" aria-hidden = "true" > </ div >
146158
147159 < div className = "flex items-start justify-between mb-8 relative z-10" >
148- < div className = "w-14 h-14 bg-black border border-white/10 rounded-xl flex items-center justify-center flex-shrink-0 group-hover:border-red-500/50 group-hover:bg-red-500/10 transition-colors" >
160+ < div className = "w-14 h-14 bg-black border border-white/10 rounded-xl flex items-center justify-center flex-shrink-0 group-hover:border-red-500/50 group-hover:bg-red-500/10 transition-colors" aria-hidden = "true" >
149161 < svg
150162 className = "w-7 h-7 text-white group-hover:text-red-500 transition-colors"
151163 fill = "none"
152164 stroke = "currentColor"
153165 viewBox = "0 0 24 24"
166+ aria-hidden = "true"
167+ focusable = "false"
154168 >
155169 < path
156170 strokeLinecap = "round"
@@ -176,7 +190,7 @@ export default function CoursesPage() {
176190 < span className = "text-xs font-bold text-gray-500 uppercase tracking-widest" >
177191 { course . instructor }
178192 </ span >
179- < span className = "inline-flex items-center gap-2 text-red-500 font-bold uppercase text-xs tracking-widest group-hover:text-red-400 transition-colors" >
193+ < span className = "inline-flex items-center gap-2 text-red-500 font-bold uppercase text-xs tracking-widest group-hover:text-red-400 transition-colors" aria-hidden = "true" >
180194 Enter Node{ " " }
181195 < span className = "transform group-hover:translate-x-1 transition-transform" >
182196 →
0 commit comments