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>
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
|
|
||||||
{/* Compact filters — scrollable on mobile */}
|
{/* Compact filters — desktop only */}
|
||||||
<Reveal>
|
<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 */}
|
{/* Class types */}
|
||||||
{types.map((type) => (
|
{types.map((type) => (
|
||||||
<button
|
<button
|
||||||
@@ -251,9 +251,36 @@ export function Schedule() {
|
|||||||
</Reveal>
|
</Reveal>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Mobile: compact agenda list */}
|
{/* Mobile: compact agenda list with tap-to-filter */}
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<div className="mt-6 px-4 sm:hidden">
|
<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 ? (
|
{filteredDays.length > 0 ? (
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
{filteredDays.map((day) => (
|
{filteredDays.map((day) => (
|
||||||
@@ -280,12 +307,15 @@ export function Schedule() {
|
|||||||
{cls.time}
|
{cls.time}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
{/* Info */}
|
{/* Info — tappable trainer & type */}
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<div className="flex items-center gap-1.5">
|
<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}
|
{cls.trainer}
|
||||||
</span>
|
</button>
|
||||||
{cls.hasSlots && (
|
{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">
|
<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>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</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={`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>
|
<span className={`text-[11px] ${filterType === cls.type ? "text-[#c9a96e] underline underline-offset-2" : "text-neutral-400 dark:text-white/30"}`}>{cls.type}</span>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user