feat: unified badges, filter UI overhaul, trainer bio link
- ScheduleBadge: shared gold badge component for all status/level tags - Replace hardcoded emerald/sky/rose badge colors with unified gold style - DayCard, GroupCard, MobileSchedule all use ScheduleBadge - Location tag moved before status badges, gold styling - GroupCard: flex-col with mt-auto button alignment - TeamProfile: pass hasSlots/status to GroupCard Filter modal redesign: - Status: horizontal Airbnb-style toggle cards with ? info tips - Experience: vertical radio list with gold dots - When: days + time inputs on single row - Click-to-toggle InfoTip replacing hover tooltips - Gold speech bubble tooltip design Schedule cards: - Trainer name click opens bio instead of filtering - DayCard location header: gold background, no duplicate address
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { Clock, User, MapPin } from "lucide-react";
|
||||
import { shortAddress } from "./constants";
|
||||
import { ScheduleBadge } from "@/components/ui/ScheduleBadge";
|
||||
import type { ScheduleDayMerged, ScheduleClassWithLocation } from "./constants";
|
||||
|
||||
interface DayCardProps {
|
||||
@@ -34,25 +35,15 @@ function ClassRow({
|
||||
<Clock size={13} />
|
||||
<span className="font-semibold">{cls.time}</span>
|
||||
</div>
|
||||
{cls.hasSlots && (
|
||||
<span className="shrink-0 rounded-full bg-emerald-500/15 border border-emerald-500/25 px-2 py-0.5 text-[10px] font-semibold text-emerald-600 dark:text-emerald-400">
|
||||
есть места
|
||||
</span>
|
||||
)}
|
||||
{cls.recruiting && (
|
||||
<span className="shrink-0 rounded-full bg-sky-500/15 border border-sky-500/25 px-2 py-0.5 text-[10px] font-semibold text-sky-600 dark:text-sky-400">
|
||||
набор
|
||||
</span>
|
||||
)}
|
||||
{cls.hasSlots && <ScheduleBadge>есть места</ScheduleBadge>}
|
||||
{cls.recruiting && <ScheduleBadge>набор</ScheduleBadge>}
|
||||
{cls.status && cls.status !== "hasSlots" && cls.status !== "recruiting" && (
|
||||
<span className="shrink-0 rounded-full bg-gold/15 border border-gold/25 px-2 py-0.5 text-[10px] font-semibold text-gold">
|
||||
{cls.status}
|
||||
</span>
|
||||
<ScheduleBadge>{cls.status}</ScheduleBadge>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => toggleFilterTrainer(cls.trainer)}
|
||||
className="mt-1.5 flex items-center gap-2 text-sm font-medium cursor-pointer active:opacity-60 text-neutral-800 dark:text-white/80"
|
||||
onClick={() => window.dispatchEvent(new CustomEvent("openTrainerProfile", { detail: cls.trainer }))}
|
||||
className="mt-1.5 flex items-center gap-2 text-sm font-medium cursor-pointer active:opacity-60 text-neutral-800 dark:text-white/80 hover:text-gold transition-colors"
|
||||
>
|
||||
<User size={13} className="shrink-0 text-neutral-400 dark:text-white/30" />
|
||||
{cls.trainer}
|
||||
@@ -65,11 +56,7 @@ function ClassRow({
|
||||
<span className={`h-2 w-2 shrink-0 rounded-full ${typeDots[cls.type] ?? "bg-white/30"}`} />
|
||||
<span className="text-xs text-neutral-500 dark:text-white/40">{cls.type}</span>
|
||||
</button>
|
||||
{cls.level && (
|
||||
<span className="rounded-full bg-rose-500/15 border border-rose-500/25 px-2 py-0.5 text-[10px] font-semibold text-rose-600 dark:text-rose-400">
|
||||
{cls.level}
|
||||
</span>
|
||||
)}
|
||||
{cls.level && <ScheduleBadge>{cls.level}</ScheduleBadge>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -111,11 +98,13 @@ export function DayCard({ day, typeDots, showLocation, filterTrainerSet, toggleF
|
||||
{locationGroups.map(([locName, { address, classes }], gi) => (
|
||||
<div key={locName}>
|
||||
{/* Location sub-header */}
|
||||
<div className={`flex items-center gap-1.5 px-5 py-2 bg-neutral-100/60 dark:bg-white/[0.03] ${gi > 0 ? "border-t border-neutral-200 dark:border-white/[0.06]" : ""}`}>
|
||||
<MapPin size={11} className="shrink-0 text-gold/60" />
|
||||
<span className="text-[11px] font-medium text-neutral-600 dark:text-white/50">
|
||||
<div className={`flex items-center gap-1.5 px-5 py-2 bg-gold/10 ${gi > 0 ? "border-t border-gold/10" : ""}`}>
|
||||
<MapPin size={11} className="shrink-0 text-gold" />
|
||||
<span className="text-[11px] font-medium text-white">
|
||||
{locName}
|
||||
{address && <span className="text-neutral-400 dark:text-white/30"> · {shortAddress(address)}</span>}
|
||||
{address && shortAddress(address) !== locName && (
|
||||
<span className="text-white/50"> · {shortAddress(address)}</span>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="divide-y divide-neutral-100 dark:divide-white/[0.04]">
|
||||
|
||||
Reference in New Issue
Block a user