feat: enhance CategoryShowcaseScroll with manual scroll locking and improved layout adjustments
This commit is contained in:
parent
8457493f49
commit
79f7f9e579
@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useRef, useEffect, useState } from 'react';
|
||||
import { useRef, useEffect, useState, useCallback } from 'react';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { motion, useScroll, useTransform } from 'framer-motion';
|
||||
@ -157,9 +157,12 @@ function CategorySticky() {
|
||||
offset: ['start start', 'end end'],
|
||||
});
|
||||
const [activeIdx, setActiveIdx] = useState(0);
|
||||
const manualLockUntil = useRef<number>(0);
|
||||
|
||||
useEffect(() => {
|
||||
return scrollYProgress.on('change', (v) => {
|
||||
/* honor manual click for a short window so scroll doesn't override */
|
||||
if (Date.now() < manualLockUntil.current) return;
|
||||
const idx = Math.min(
|
||||
CATEGORIES.length - 1,
|
||||
Math.max(0, Math.floor(v * CATEGORIES.length))
|
||||
@ -168,6 +171,12 @@ function CategorySticky() {
|
||||
});
|
||||
}, [scrollYProgress]);
|
||||
|
||||
const handlePick = useCallback((i: number) => {
|
||||
/* swap in place, no scroll. Lock scroll listener for 1.2s. */
|
||||
manualLockUntil.current = Date.now() + 1200;
|
||||
setActiveIdx(i);
|
||||
}, []);
|
||||
|
||||
/* progress bar height */
|
||||
const progressHeight = useTransform(scrollYProgress, [0, 1], ['0%', '100%']);
|
||||
|
||||
@ -176,17 +185,16 @@ function CategorySticky() {
|
||||
ref={containerRef}
|
||||
style={{
|
||||
position: 'relative',
|
||||
/* 65vh per category — total ~520vh feels responsive, not endless */
|
||||
height: `${CATEGORIES.length * 65}vh`,
|
||||
/* ~50vh per category scroll budget on top of sticky height */
|
||||
height: `calc(100svh + ${CATEGORIES.length * 50}vh)`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: 'sticky',
|
||||
top: '5.5rem',
|
||||
/* fill the viewport — no empty area below the panel during sticky */
|
||||
/* fill the entire viewport — no void below the panel */
|
||||
height: 'calc(100svh - 6.5rem)',
|
||||
maxHeight: '780px',
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'minmax(0, 0.95fr) minmax(0, 1.05fr)',
|
||||
gap: 'clamp(1.5rem, 3vw, 2.5rem)',
|
||||
@ -226,13 +234,7 @@ function CategorySticky() {
|
||||
<button
|
||||
key={c.id}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
const el = containerRef.current;
|
||||
if (!el) return;
|
||||
const rect = el.getBoundingClientRect();
|
||||
const targetY = window.scrollY + rect.top + (rect.height * (i + 0.5)) / CATEGORIES.length;
|
||||
window.scrollTo({ top: targetY - window.innerHeight / 2, behavior: 'smooth' });
|
||||
}}
|
||||
onClick={() => handlePick(i)}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user