-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Description
description of the issue
Currently the job list does not use semantic html and only renders a wrapper div. This component should use ul or ol for the list itself, and li for the job cards. This considers that all elements on a given page are contextually related, and should be represented programmatically in addition to stylistically, see WCAG 1.3.1
Proposed change
Two aspects need to be modified here. The JobList component, and the JobCard component. The job list needs to render a ul element here as the ordering of the list items doesn't play into each item's importance. Each JobCard should render a li element as a part of the job list.
JobList: replace div with ul
frontend/src/components/jobs/job-list.tsx
<ul className="space-y-4 pr-1">
{jobs.map((job) => (
<div
key={job.id}
onClick={() => {
setSelectedJob(job);
// Only open modal on mobile
if (window.innerWidth < 1024) {
setIsModalOpen(true);
}
}}
className="cursor-pointer"
>
<JobCard
job={job}
isSelected={selectedJob?.id === job.id}
isSponsor={job.highlight}
/>
</div>
))}
</ul>JobCard: wrap Box with li
/frontend/src/components/jobs/details/job-card.tsx
<li>
<Box
bg={isSelected ? "selected" : "secondary"}
bd="2px solid selected"
className={`p-4 rounded-xl transition-colors flex flex-col justify-between`}
>
{/* Top section - company info */}
<div className="flex flex-col gap-2">
<div className={"flex justify-between"}>
<div className={"flex flex-1 min-w-0"}>
<CompanyLogo
name={job.company.name}
applicationUrl={job.application_url}
logo={job.company.logo}
className="mr-2 lg:h-14 lg:w-14 h-10 w-10"
/>
<div
className={
"flex justify-center flex-col flex-1 min-w-0 space-y-0.5"
}
>
<span className="text-sm lg:text-md font-bold line-clamp-2 leading-tight pr-2">
{job.title}
</span>
<span className="text-xs line-clamp-1 leading-tight">
{job.company.name}
</span>
</div>
</div>
<span className={"text-xs flex-shrink-0"}>
{getTimeAgo(job.created_at)}
</span>
</div>
<div
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(washedDescription),
}}
className="text-xs line-clamp-3 lg:line-clamp-3 mb-2"
/>
</div>
{/* Bottom section - badges */}
<div className="flex gap-2 mt-auto">
{/* Show a yellow "Sponsored" badge if this is a sponsor card */}
{isSponsor && <Badge text="Sponsored" color="accent"></Badge>}
{job.type && <Badge text={formatCapString(job.type)} />}
{job.working_rights?.[0] && (
<Badge
text={
job.working_rights.includes("INTERNATIONAL")
? "International"
: "Citizen/PR"
}
/>
)}
{!isSponsor && job.industry_field && (
<Badge text={formatCapString(job.industry_field)} />
)}
{job.locations && job.locations.length > 0 && (
<Badge
className={"hidden lg:inline"}
text={`${job.locations
.slice(0, 2)
.map((loc) => formatCapString(loc))
.join(", ")}${job.locations.length > 2 ? ", ..." : ""}`}
/>
)}
</div>
</Box>
</li>Metadata
Metadata
Assignees
Labels
No labels