Lab tabs: fixed 5-across grid instead of horizontal scroll

The Lab category tabs (Coaches/Filmers/Photo/Editors/Builders) overflowed
the viewport and scrolled sideways on phones, hiding Builders. Replace the
overflow-x row with a 5-column grid of compact icon-over-label tabs so all
five are visible at once without lateral scrolling, with the count badge
floated to the corner so it never widens a tab.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
shakespeare.diy 2026-07-24 18:56:06 +07:00
parent 3a96184001
commit cc2e35f569

View file

@ -282,8 +282,10 @@ function LabToolbar({
return ( return (
<div className="sticky top-14 md:top-16 z-30 bg-black/95 backdrop-blur border-b border-white/5 -mx-4 px-4 py-3 space-y-2.5"> <div className="sticky top-14 md:top-16 z-30 bg-black/95 backdrop-blur border-b border-white/5 -mx-4 px-4 py-3 space-y-2.5">
{/* Tab row — horizontally scrollable so 5 tabs stay clean on small phones */} {/* Tab row — fixed 5-across grid so every category is visible without
<div className="flex items-center gap-1.5 sm:gap-2 overflow-x-auto scrollbar-none -mx-1 px-1"> horizontal scrolling. Icon-over-label stack keeps each tab compact
but tappable on small phones; a count badge floats in the corner. */}
<div className="grid grid-cols-5 gap-1.5 sm:gap-2">
{tabs.map(({ key, label, icon: Icon }) => { {tabs.map(({ key, label, icon: Icon }) => {
const isActive = serviceType === key; const isActive = serviceType === key;
const a = ACCENT[key]; const a = ACCENT[key];
@ -292,23 +294,19 @@ function LabToolbar({
key={key} key={key}
onClick={() => onServiceChange(key)} onClick={() => onServiceChange(key)}
className={cn( className={cn(
'relative flex items-center gap-1 sm:gap-1.5 px-2.5 sm:px-3 py-2 rounded-xl font-black text-[11px] sm:text-xs uppercase tracking-wide transition-all duration-150 active:scale-95 flex-1 min-w-fit justify-center whitespace-nowrap', 'relative flex flex-col items-center justify-center gap-1 px-1 py-2 rounded-xl font-black text-[10px] sm:text-xs uppercase tracking-tight sm:tracking-wide transition-all duration-150 active:scale-95',
isActive isActive
? a.active ? a.active
: 'text-gray-500 bg-white/5 hover:bg-white/10 hover:text-white border border-transparent' : 'text-gray-500 bg-white/5 hover:bg-white/10 hover:text-white border border-transparent'
)} )}
> >
<Icon className="h-3.5 w-3.5 flex-shrink-0" /> <Icon className="h-4 w-4 flex-shrink-0" />
<span>{label}</span> <span className="leading-none">{label}</span>
{/* Count badge */} {/* Count badge — floats top-right so it never widens the tab */}
{!isLoading && ( {!isLoading && counts[key] > 0 && (
<span className={cn( <span className={cn(
'ml-0.5 min-w-[18px] h-[18px] px-1 text-[9px] font-black rounded-full flex items-center justify-center leading-none', 'absolute -top-1 -right-1 min-w-[16px] h-[16px] px-1 text-[9px] font-black rounded-full flex items-center justify-center leading-none border border-black/40',
counts[key] > 0 isActive ? 'bg-white text-black' : 'bg-white/15 text-gray-300'
? isActive
? 'bg-white/25 text-white'
: 'bg-white/10 text-gray-400'
: 'bg-white/5 text-gray-600'
)}> )}>
{counts[key]} {counts[key]}
</span> </span>