feat(crews): compact focus toggle group + mobile-only Near me

- Replace the eight wrapping filter chips with a single-row ToggleGroup
  (short labels; full names in tooltip/aria-label). Scrolls horizontally on
  mobile instead of wrapping to two rows.
- Near me is now mobile-only on the Crews page — it was clutter on desktop.
This commit is contained in:
SkateSpots 2026-09-27 09:56:14 +07:00
parent f5ce4002e9
commit 6b925a4fc0

View file

@ -5,6 +5,7 @@ import { Layout } from '@/components/Layout';
import { LazyMount } from '@/components/LazyMount'; import { LazyMount } from '@/components/LazyMount';
import { Card, CardContent } from '@/components/ui/card'; import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
import { Skeleton } from '@/components/ui/skeleton'; import { Skeleton } from '@/components/ui/skeleton';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { CrewRepBadge, CrewActivityPulse } from '@/components/CrewBadge'; import { CrewRepBadge, CrewActivityPulse } from '@/components/CrewBadge';
@ -18,15 +19,17 @@ import type { CrewActivity } from '@/lib/crewHelpers';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { Users, Plus, Search, MapPin, X, HardHat, Camera, GraduationCap, Sparkles, Navigation, Loader2, Music, Palette, Dumbbell, Film } from 'lucide-react'; import { Users, Plus, Search, MapPin, X, HardHat, Camera, GraduationCap, Sparkles, Navigation, Loader2, Music, Palette, Dumbbell, Film } from 'lucide-react';
const FOCUS_FILTERS: { key: CrewFocus | 'all'; label: string; icon: typeof Users }[] = [ // `label` is the full name (used for the tooltip + screen readers); `short` is
{ key: 'all', label: 'All', icon: Users }, // what the compact toggle shows, to keep the filter bar to a single row.
{ key: 'builder', label: CREW_FOCUS_LABELS.builder, icon: HardHat }, const FOCUS_FILTERS: { key: CrewFocus | 'all'; label: string; short: string; icon: typeof Users }[] = [
{ key: 'photo', label: CREW_FOCUS_LABELS.photo, icon: Camera }, { key: 'all', label: 'All', short: 'All', icon: Users },
{ key: 'coaching', label: CREW_FOCUS_LABELS.coaching, icon: GraduationCap }, { key: 'builder', label: CREW_FOCUS_LABELS.builder, short: 'DIY', icon: HardHat },
{ key: 'art', label: CREW_FOCUS_LABELS.art, icon: Palette }, { key: 'photo', label: CREW_FOCUS_LABELS.photo, short: 'Photo', icon: Camera },
{ key: 'music', label: CREW_FOCUS_LABELS.music, icon: Music }, { key: 'coaching', label: CREW_FOCUS_LABELS.coaching, short: 'Coaching', icon: GraduationCap },
{ key: 'wellness', label: CREW_FOCUS_LABELS.wellness, icon: Dumbbell }, { key: 'art', label: CREW_FOCUS_LABELS.art, short: 'Art', icon: Palette },
{ key: 'mixed', label: CREW_FOCUS_LABELS.mixed, icon: Sparkles }, { key: 'music', label: CREW_FOCUS_LABELS.music, short: 'Music', icon: Music },
{ key: 'wellness', label: CREW_FOCUS_LABELS.wellness, short: 'Physio', icon: Dumbbell },
{ key: 'mixed', label: CREW_FOCUS_LABELS.mixed, short: 'Mixed', icon: Sparkles },
]; ];
const FOCUS_BADGE_ICONS: Record<CrewFocus, typeof Users> = { const FOCUS_BADGE_ICONS: Record<CrewFocus, typeof Users> = {
@ -272,33 +275,42 @@ export default function CrewsPage() {
)} )}
</div> </div>
{/* Filters row: focus chips + Near me */} {/* Filters: one compact focus toggle group (scrolls on mobile) */}
<div className="mb-5 flex flex-wrap items-center gap-2"> <div className="mb-5 flex items-center gap-2">
{FOCUS_FILTERS.map(({ key, label, icon: Icon }) => { <div className="scroll-container min-w-0 flex-1 overflow-x-auto">
const active = focusFilter === key; <ToggleGroup
return ( type="single"
<button value={focusFilter}
onValueChange={(v) => {
if (v) setFocusFilter(v as CrewFocus | 'all');
}}
className="inline-flex w-max items-center gap-0.5 rounded-xl border border-white/10 bg-white/[0.04] p-1"
>
{FOCUS_FILTERS.map(({ key, label, short, icon: Icon }) => (
<ToggleGroupItem
key={key} key={key}
type="button" value={key}
onClick={() => setFocusFilter(key)} title={label}
aria-label={label}
className={cn( className={cn(
'inline-flex items-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-bold transition-all active:scale-95', 'h-7 shrink-0 gap-1 rounded-lg px-2 text-xs font-bold text-gray-300 transition-colors',
active 'hover:bg-white/5 hover:text-teal-300',
? 'border-teal-500 bg-teal-500 text-black' 'data-[state=on]:bg-teal-500 data-[state=on]:text-black data-[state=on]:hover:bg-teal-500 data-[state=on]:hover:text-black',
: 'border-white/10 bg-white/5 text-gray-300 hover:border-teal-500/40 hover:text-teal-300',
)} )}
> >
<Icon className="h-3.5 w-3.5" /> <Icon className="h-3.5 w-3.5" />
{label} {short}
</button> </ToggleGroupItem>
); ))}
})} </ToggleGroup>
</div>
{/* Near me — mobile only; on desktop it was just clutter in this bar. */}
<button <button
type="button" type="button"
onClick={handleNearMe} onClick={handleNearMe}
className={cn( className={cn(
'ml-auto inline-flex items-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-bold transition-all active:scale-95', 'inline-flex shrink-0 items-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-bold transition-all active:scale-95 sm:hidden',
nearMe nearMe
? 'border-orange-500 bg-orange-500 text-black' ? 'border-orange-500 bg-orange-500 text-black'
: 'border-white/10 bg-white/5 text-gray-300 hover:border-orange-500/40 hover:text-orange-300', : 'border-white/10 bg-white/5 text-gray-300 hover:border-orange-500/40 hover:text-orange-300',