fix: clickable trainers in day cards, remove trainer dropdown, fix layout shift
- Remove trainer dropdown from filter bar — filter by clicking names in schedule cards - Make trainer/type clickable in DayCard with gold highlight on active filter - Fix showcase layout shift: track max detail height to prevent section from shrinking - Remove key-based grid remount that re-triggered Reveal animations on filter change Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -283,7 +283,6 @@ export function Schedule({ data: schedule, classItems }: ScheduleProps) {
|
|||||||
{/* Desktop: grid layout */}
|
{/* Desktop: grid layout */}
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<div
|
<div
|
||||||
key={`${locationMode}-${filterTrainer}-${filterType}-${filterStatus}`}
|
|
||||||
className={`mt-8 hidden sm:grid grid-cols-1 gap-3 px-4 sm:px-6 lg:px-8 xl:px-6 ${filteredDays.length >= 7 ? "sm:grid-cols-2 lg:grid-cols-4 xl:grid-cols-7" : filteredDays.length >= 6 ? "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6" : filteredDays.length >= 4 ? "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5" : filteredDays.length === 3 ? "sm:grid-cols-2 lg:grid-cols-3" : filteredDays.length === 2 ? "sm:grid-cols-2" : "justify-items-center"}`}
|
className={`mt-8 hidden sm:grid grid-cols-1 gap-3 px-4 sm:px-6 lg:px-8 xl:px-6 ${filteredDays.length >= 7 ? "sm:grid-cols-2 lg:grid-cols-4 xl:grid-cols-7" : filteredDays.length >= 6 ? "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6" : filteredDays.length >= 4 ? "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5" : filteredDays.length === 3 ? "sm:grid-cols-2 lg:grid-cols-3" : filteredDays.length === 2 ? "sm:grid-cols-2" : "justify-items-center"}`}
|
||||||
style={filteredDays.length === 1 ? undefined : filteredDays.length <= 3 && filteredDays.length > 0 ? { maxWidth: filteredDays.length * 340 + (filteredDays.length - 1) * 12, marginInline: "auto" } : undefined}
|
style={filteredDays.length === 1 ? undefined : filteredDays.length <= 3 && filteredDays.length > 0 ? { maxWidth: filteredDays.length * 340 + (filteredDays.length - 1) * 12, marginInline: "auto" } : undefined}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -25,10 +25,24 @@ export function ShowcaseLayout<T>({
|
|||||||
const selectorRef = useRef<HTMLDivElement>(null);
|
const selectorRef = useRef<HTMLDivElement>(null);
|
||||||
const activeItemRef = useRef<HTMLButtonElement>(null);
|
const activeItemRef = useRef<HTMLButtonElement>(null);
|
||||||
const detailRef = useRef<HTMLDivElement>(null);
|
const detailRef = useRef<HTMLDivElement>(null);
|
||||||
|
const detailWrapRef = useRef<HTMLDivElement>(null);
|
||||||
|
const [minHeight, setMinHeight] = useState<number | undefined>(undefined);
|
||||||
|
const measuredHeights = useRef<number[]>([]);
|
||||||
const [isUserInteracting, setIsUserInteracting] = useState(false);
|
const [isUserInteracting, setIsUserInteracting] = useState(false);
|
||||||
const [displayIndex, setDisplayIndex] = useState(activeIndex);
|
const [displayIndex, setDisplayIndex] = useState(activeIndex);
|
||||||
const [fading, setFading] = useState(false);
|
const [fading, setFading] = useState(false);
|
||||||
|
|
||||||
|
// Track max height across all seen items to prevent shrinking
|
||||||
|
useEffect(() => {
|
||||||
|
if (!detailRef.current || fading) return;
|
||||||
|
const h = detailRef.current.offsetHeight;
|
||||||
|
measuredHeights.current[displayIndex] = h;
|
||||||
|
const maxH = Math.max(...measuredHeights.current.filter(Boolean));
|
||||||
|
if (maxH > (minHeight ?? 0)) {
|
||||||
|
setMinHeight(maxH);
|
||||||
|
}
|
||||||
|
}, [displayIndex, fading]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeIndex === displayIndex) return;
|
if (activeIndex === displayIndex) return;
|
||||||
setFading(true);
|
setFading(true);
|
||||||
@@ -116,16 +130,21 @@ export function ShowcaseLayout<T>({
|
|||||||
{/* Detail area */}
|
{/* Detail area */}
|
||||||
<div className="lg:w-[60%]">
|
<div className="lg:w-[60%]">
|
||||||
<div
|
<div
|
||||||
ref={detailRef}
|
ref={detailWrapRef}
|
||||||
className={`transition-all duration-300 ease-out ${
|
style={minHeight != null ? { minHeight } : undefined}
|
||||||
fading
|
|
||||||
? "opacity-0 translate-y-2"
|
|
||||||
: "opacity-100 translate-y-0"
|
|
||||||
}`}
|
|
||||||
onTouchStart={handleTouchStart}
|
|
||||||
onTouchEnd={handleTouchEnd}
|
|
||||||
>
|
>
|
||||||
{renderDetail(items[displayIndex], displayIndex)}
|
<div
|
||||||
|
ref={detailRef}
|
||||||
|
className={`transition-all duration-300 ease-out ${
|
||||||
|
fading
|
||||||
|
? "opacity-0 translate-y-2"
|
||||||
|
: "opacity-100 translate-y-0"
|
||||||
|
}`}
|
||||||
|
onTouchStart={handleTouchStart}
|
||||||
|
onTouchEnd={handleTouchEnd}
|
||||||
|
>
|
||||||
|
{renderDetail(items[displayIndex], displayIndex)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Counter */}
|
{/* Counter */}
|
||||||
|
|||||||
Reference in New Issue
Block a user