components/we-inc/responsive-table-that-becomes-cards-on-phones.tsx
// Below 640px each row becomes a card. The markup stays a real table; labels come from data-label.
const sessions = [
{ cls: "Intro to bouldering", coach: "Ayla Brennan", day: "Mon 18:30", level: "Beginner", spaces: 4 },
{ cls: "Lead climbing skills", coach: "Dev Sharma", day: "Tue 19:00", level: "Intermediate", spaces: 0 },
{ cls: "Youth squad", coach: "Marta Kowal", day: "Wed 16:30", level: "Ages 10 to 15", spaces: 7 },
{ cls: "Technique clinic", coach: "Ayla Brennan", day: "Thu 18:00", level: "All levels", spaces: 2 },
{ cls: "Sunday social climb", coach: "Leo Hart", day: "Sun 10:00", level: "All levels", spaces: 12 },
];
const cell = "px-4 py-3.5 max-sm:flex max-sm:items-center max-sm:justify-between max-sm:gap-4 max-sm:px-0 max-sm:py-1.5 max-sm:before:text-xs max-sm:before:font-semibold max-sm:before:uppercase max-sm:before:tracking-wider max-sm:before:text-stone-500 max-sm:before:content-[attr(data-label)]";
export default function ResponsiveTableThatBecomesCardsOnPhones() {
return (
<section className="bg-amber-50 px-5 py-14 sm:py-20">
<div className="mx-auto max-w-4xl">
<table className="w-full border-collapse text-left text-sm max-sm:block">
<caption className="pb-5 text-left max-sm:block">
<span className="block text-2xl font-semibold tracking-tight text-stone-900">This week at Crux Wall</span>
<span className="mt-1 block text-[15px] text-stone-600">Book at the desk or in the app. Spaces update every hour.</span>
</caption>
<thead className="max-sm:sr-only">
<tr className="border-b-2 border-stone-900 text-stone-900">
<th scope="col" className="px-4 py-3 font-semibold">Class</th>
<th scope="col" className="px-4 py-3 font-semibold">Coach</th>
<th scope="col" className="px-4 py-3 font-semibold">When</th>
<th scope="col" className="px-4 py-3 font-semibold">Level</th>
<th scope="col" className="px-4 py-3 text-right font-semibold">Spaces</th>
</tr>
</thead>
<tbody className="max-sm:block max-sm:space-y-3">
{sessions.map((s) => (
<tr key={s.cls} className="border-b border-amber-200 bg-white/0 max-sm:block max-sm:rounded-2xl max-sm:border max-sm:bg-white max-sm:p-4 max-sm:shadow-sm">
<th scope="row" className="px-4 py-3.5 font-semibold text-stone-900 max-sm:block max-sm:px-0 max-sm:pb-2 max-sm:pt-0 max-sm:text-base">{s.cls}</th>
<td data-label="Coach" className={`${cell} text-stone-700`}>{s.coach}</td>
<td data-label="When" className={`${cell} text-stone-700`}>{s.day}</td>
<td data-label="Level" className={`${cell} text-stone-700`}>{s.level}</td>
<td data-label="Spaces" className={`${cell} text-right`}>
<span className={`rounded-full px-2.5 py-1 text-xs font-semibold ${s.spaces === 0 ? "bg-stone-200 text-stone-700" : s.spaces < 4 ? "bg-amber-200 text-amber-900" : "bg-lime-200 text-lime-900"}`}>
{s.spaces === 0 ? "Full" : `${s.spaces} left`}
</span>
</td>
</tr>
))}
</tbody>
</table>
</div>
</section>
);
}