diff --git a/landing/src/components/KeyBusinessSegments/index.tsx b/landing/src/components/KeyBusinessSegments/index.tsx index f929e47..c747333 100644 --- a/landing/src/components/KeyBusinessSegments/index.tsx +++ b/landing/src/components/KeyBusinessSegments/index.tsx @@ -293,6 +293,35 @@ const RightBrand = styled.div` } `; +function usePreloadImages(urls: string[]) { + useEffect(() => { + if (!urls?.length) return; + const unique = Array.from(new Set(urls.filter(Boolean))); + + unique.forEach((url) => { + if (!url) return; + + // Проверяем, есть ли уже preload в + const exists = document.querySelector( + `link[rel="preload"][as="image"][href="${url}"]` + ); + if (!exists) { + const link = document.createElement("link"); + link.rel = "preload"; + link.as = "image"; + link.href = url; + document.head.appendChild(link); + } + + // Дополнительно сразу грузим в memory cache + const img = new Image(); + img.src = url; + }); + }, [urls]); +} + + + /* ===================== Component ===================== */ export default function KeyBusinessSegments() { @@ -304,20 +333,19 @@ export default function KeyBusinessSegments() { const segments = useMemo(() => mapSegments(data), [data]); // --- предзагрузка иконок --- - useEffect(() => { - if (!segments?.length) return; - const urls = segments.flatMap((seg) => - seg.info.flatMap((block) => - block.items - .map((item) => item.infoLogo) - .filter((u): u is string => Boolean(u)) - ) - ); - urls.forEach((url) => { - const img = new Image(); - img.src = url; - }); + // собираем все картинки для предзагрузки + const preloadUrls = useMemo(() => { + if (!segments?.length) return []; + return segments.flatMap((seg) => + seg.info.flatMap((block) => [ + block.brandLogo, // ← бренд + ...block.items.map((item) => item.infoLogo), // ← иконки + ]) + ).filter((u): u is string => Boolean(u)); }, [segments]); + + // предзагрузка всех логотипов + usePreloadImages(preloadUrls); // --------------------------- @@ -328,11 +356,42 @@ export default function KeyBusinessSegments() { const denom = Math.max(1, N - 1); const defaultCenterIndex = useMemo(() => Math.floor(N / 2), [N]); - const [activeIndex, setActiveIndex] = useState(defaultCenterIndex); + const [activeIndex, _setActiveIndex] = useState(defaultCenterIndex); const [hoverIndex, setHoverIndex] = useState(null); const [isOverflow, setIsOverflow] = useState(false); const [isMobile, setIsMobile] = useState(false); + const [isLocked, setIsLocked] = useState(false); + const lockTimer = useRef(null); + + // обёртка для смены индекса + const setActiveIndex = (idx: number) => { + if (idx === activeIndex) return; + _setActiveIndex(idx); + setIsLocked(true); + if (lockTimer.current) clearTimeout(lockTimer.current); + lockTimer.current = window.setTimeout(() => { + setIsLocked(false); + }, 250); // чуть больше transition + }; + + + useEffect(() => { + const el = scrollerRef.current; + if (!el) return; + let raf = 0; + const onScroll = () => { + cancelAnimationFrame(raf); + raf = requestAnimationFrame(() => { + if (isLocked) return; // 🔒 во время анимации не пересчитываем + setActiveIndex(indexFromScroll(el.scrollLeft)); + }); + }; + el.addEventListener("scroll", onScroll, { passive: true }); + return () => el.removeEventListener("scroll", onScroll); + }, [denom, isLocked]); + + /* ===== reserve-height measuring ===== */ const gridWrapRef = useRef(null); const [gridMinHeight, setGridMinHeight] = useState(0); @@ -393,20 +452,6 @@ export default function KeyBusinessSegments() { return () => window.removeEventListener("resize", onResize); }, [defaultCenterIndex, N]); - useEffect(() => { - const el = scrollerRef.current; - if (!el) return; - let raf = 0; - const onScroll = () => { - cancelAnimationFrame(raf); - raf = requestAnimationFrame(() => { - setActiveIndex(indexFromScroll(el.scrollLeft)); - }); - }; - el.addEventListener("scroll", onScroll, { passive: true }); - return () => el.removeEventListener("scroll", onScroll); - }, [denom]); - const realActiveIndex = hoverIndex ?? activeIndex; const activeSegment = segments[Math.min(Math.max(realActiveIndex, 0), N - 1)]; @@ -471,9 +516,16 @@ export default function KeyBusinessSegments() { {block.items.map((item) => ( - ` display: flex; gap: ${(p) => p.$gap}px; visibility: ${(p) => (p.$hidden ? "hidden" : "visible")}; - padding: 0px 10px; + margin-left:10px; `; const Frame = styled.div`