feat: tap-to-filter on mobile schedule, replace filter bar
On mobile, tapping a trainer name or class type in the agenda list filters to show all their sessions across the week. Active filter shown as a banner with clear button. Desktop filters unchanged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -169,9 +169,9 @@ export function Schedule() {
|
||||
</div>
|
||||
</Reveal>
|
||||
|
||||
{/* Compact filters — scrollable on mobile */}
|
||||
{/* Compact filters — desktop only */}
|
||||
<Reveal>
|
||||
<div className="mt-5 flex items-center justify-center gap-1.5 overflow-x-auto pb-1 scrollbar-hide sm:flex-wrap sm:overflow-visible sm:pb-0">
|
||||
<div className="mt-5 hidden sm:flex items-center justify-center gap-1.5 flex-wrap">
|
||||
{/* Class types */}
|
||||
{types.map((type) => (
|
||||
<button
|
||||
@@ -251,9 +251,36 @@ export function Schedule() {
|
||||
</Reveal>
|
||||
</div>
|
||||
|
||||
{/* Mobile: compact agenda list */}
|
||||
{/* Mobile: compact agenda list with tap-to-filter */}
|
||||
<Reveal>
|
||||
<div className="mt-6 px-4 sm:hidden">
|
||||
{/* Active filter indicator */}
|
||||
{hasActiveFilter && (
|
||||
<div className="mb-3 flex items-center justify-between rounded-xl bg-[#c9a96e]/10 px-4 py-2.5 dark:bg-[#c9a96e]/5">
|
||||
<div className="flex items-center gap-2 text-xs font-medium text-[#a08050] dark:text-[#d4b87a]">
|
||||
{filterTrainer && (
|
||||
<span className="flex items-center gap-1">
|
||||
<User size={11} />
|
||||
{filterTrainer}
|
||||
</span>
|
||||
)}
|
||||
{filterType && (
|
||||
<span className="flex items-center gap-1">
|
||||
<span className={`h-1.5 w-1.5 rounded-full ${TYPE_DOT[filterType] ?? "bg-white/30"}`} />
|
||||
{filterType}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
onClick={clearFilters}
|
||||
className="flex items-center gap-1 rounded-full px-2 py-1 text-[11px] text-[#a08050] dark:text-[#d4b87a] active:bg-[#c9a96e]/20"
|
||||
>
|
||||
<X size={12} />
|
||||
Сбросить
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{filteredDays.length > 0 ? (
|
||||
<div className="space-y-1">
|
||||
{filteredDays.map((day) => (
|
||||
@@ -280,12 +307,15 @@ export function Schedule() {
|
||||
{cls.time}
|
||||
</span>
|
||||
|
||||
{/* Info */}
|
||||
{/* Info — tappable trainer & type */}
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="truncate text-sm font-medium text-neutral-800 dark:text-white/80">
|
||||
<button
|
||||
onClick={() => setFilterTrainer(filterTrainer === cls.trainer ? null : cls.trainer)}
|
||||
className={`truncate text-sm font-medium text-left active:opacity-60 ${filterTrainer === cls.trainer ? "text-[#c9a96e] underline underline-offset-2" : "text-neutral-800 dark:text-white/80"}`}
|
||||
>
|
||||
{cls.trainer}
|
||||
</span>
|
||||
</button>
|
||||
{cls.hasSlots && (
|
||||
<span className="shrink-0 rounded-full bg-emerald-500/15 border border-emerald-500/25 px-1.5 py-px text-[9px] font-semibold text-emerald-600 dark:text-emerald-400">
|
||||
места
|
||||
@@ -302,10 +332,13 @@ export function Schedule() {
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-0.5 flex items-center gap-1.5">
|
||||
<button
|
||||
onClick={() => setFilterType(filterType === cls.type ? null : cls.type)}
|
||||
className={`mt-0.5 flex items-center gap-1.5 active:opacity-60 ${filterType === cls.type ? "opacity-100" : ""}`}
|
||||
>
|
||||
<span className={`h-1.5 w-1.5 shrink-0 rounded-full ${TYPE_DOT[cls.type] ?? "bg-white/30"}`} />
|
||||
<span className="text-[11px] text-neutral-400 dark:text-white/30">{cls.type}</span>
|
||||
</div>
|
||||
<span className={`text-[11px] ${filterType === cls.type ? "text-[#c9a96e] underline underline-offset-2" : "text-neutral-400 dark:text-white/30"}`}>{cls.type}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user