UNPKG

lightswind

Version:

A collection of beautifully crafted React Components, Blocks & Templates for Modern Developers. Create stunning web applications effortlessly by using our 160+ professional and animated react components.

137 lines (127 loc) 8.83 kB
"use strict"; "use client"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SlidingLogoMarquee = SlidingLogoMarquee; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); // Import your actual utility const utils_1 = require("@/components/lib/utils"); // Assuming this is your actual path const lucide_react_1 = require("lucide-react"); function SlidingLogoMarquee({ items, speed = 1, pauseOnHover = true, enableBlur = true, blurIntensity = 1, height = "100px", width = "100%", gap = "2rem", scale = 1, direction = "horizontal", autoPlay = true, backgroundColor = '!transparent', showGridBackground = false, className, onItemClick, enableSpillEffect = false, animationSteps = 8, showControls = true, }) { const containerRef = (0, react_1.useRef)(null); const [isPlaying, setIsPlaying] = (0, react_1.useState)(autoPlay); // CORE FIX: Duplicating the items for a seamless loop const duplicatedItems = (0, react_1.useMemo)(() => [...items, ...items], [items]); const handleItemClick = (item) => { if (item.href) { window.open(item.href, "_blank", "noopener,noreferrer"); } onItemClick?.(item); }; const togglePlayState = () => { setIsPlaying(!isPlaying); }; const blurDivs = Array.from({ length: animationSteps }, (_, index) => ((0, jsx_runtime_1.jsx)("div", { style: { "--index": index }, className: "absolute inset-0 z-[var(--index)]" }, index))); const itemRenderer = (item, index, isDuplicate) => ((0, jsx_runtime_1.jsx)("li", { className: (0, utils_1.cn)("sliding-marquee-item text-foreground", "grid place-items-center cursor-pointer transition-transform duration-200 ease-in-out", "hover:scale-[1.05] focus:scale-[1.05] focus:outline-none focus:ring-2 focus:ring-primary", " backdrop-blur-sm"), onClick: () => handleItemClick(item), role: "button", tabIndex: 0, onKeyDown: (e) => { if (e.key === "Enter" || e.key === " ") { handleItemClick(item); } }, children: (0, jsx_runtime_1.jsx)("div", { className: "h-4/5 w-auto", children: item.content }) }, `${item.id}-${index}-${isDuplicate ? 'dup' : 'orig'}`)); return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("style", { children: ` .sliding-marquee-container { --speed: ${speed}; --gap: ${gap}; --blur: ${blurIntensity}; --blurs: ${animationSteps}; /* Dynamic Duration: Higher speed (e.g., 60) results in a shorter duration */ /* Use a large fixed distance (e.g., 200vw) divided by speed to control rate */ --duration: calc(200s / var(--speed)); } /* ------------------------------------------------ */ /* --- CORE INFINITE LOOP FIX: Animating by -50% -- */ /* ------------------------------------------------ */ @keyframes marquee-horizontal { /* Translates the doubled content by exactly half its length to loop seamlessly */ from { transform: translateX(0); } to { transform: translateX(-50%); } } @keyframes marquee-vertical { from { transform: translateY(0); } to { transform: translateY(-50%); } } .sliding-marquee-list { display: flex; flex-shrink: 0; min-width: 200%; gap: var(--gap); height: 100%; align-items: center; list-style-type: none; padding-inline: 0; margin: 0; pointer-events: auto; animation: marquee-horizontal var(--duration) linear infinite paused; transform: translateZ(0); /* Add this for mobile GPU layer */ will-change: transform; /* Hint browser to optimize for animation */ } /* Conditional Animation based on Direction */ .sliding-marquee-resizable[data-direction="vertical"] .sliding-marquee-list { flex-direction: column; min-width: unset; min-height: 200%; width: 100%; animation: marquee-vertical var(--duration) linear infinite paused; } .sliding-marquee-item { /* Ensure item size is well-defined to calculate total list width accurately */ min-width: clamp(100px, 15vw, 250px); height: 80%; aspect-ratio: 16 / 9; font-size: clamp(1rem, 1vw + 0.5rem, 2rem); } /* Play State Controls */ [data-play-state="running"] .sliding-marquee-list { animation-play-state: running !important; } [data-play-state="paused"] .sliding-marquee-list { animation-play-state: paused !important; } /* --- Layout & Effects (Tailwind-Ready/Hybrid) --- */ .sliding-marquee-resizable { overflow: hidden; scale: var(--scale); width: 100%; height: ${height}; position: relative; } .sliding-marquee-inner { height: 100%; width: 100%; position: relative; mask: linear-gradient(90deg, transparent, black 15% 85%, transparent); display: flex; pointer-events: none; } /* The rest of the blur and spill effect CSS... */ .sliding-marquee-blur { position: absolute; top: 0; bottom: 0; width: 25%; z-index: 2; pointer-events: none; } .sliding-marquee-blur--right { right: 0; } .sliding-marquee-blur--left { left: 0; rotate: 180deg; } .sliding-marquee-blur div { mask: linear-gradient(90deg, transparent calc(var(--index) * calc((100 / var(--blurs)) * 1%)), black calc((var(--index) + 1) * calc((100 / var(--blurs)) * 1%)), black calc((var(--index) + 2) * calc((100 / var(--blurs)) * 1%)), transparent calc((var(--index) + 3) * calc((100 / var(--blurs)) * 1%))); backdrop-filter: blur(calc((var(--index, 0) * var(--blur, 0)) * 1px)); } .sliding-marquee-resizable[data-spill="true"] { container-type: size; } .sliding-marquee-resizable[data-spill="true"] .sliding-marquee-inner::after { content: ""; position: fixed; top: 50%; left: 50%; width: calc(var(--scale) * 10000vw); height: calc(var(--scale) * 10000vh); pointer-events: none; translate: -50% -50%; mask: linear-gradient(white, white) 50% 50% / 100% 100% no-repeat, linear-gradient(white, white) 50% 50% / 100cqi 100cqh no-repeat; mask-composite: exclude; } ` }), (0, jsx_runtime_1.jsxs)("div", { ref: containerRef, className: (0, utils_1.cn)("sliding-marquee-container relative", className), style: { width, background: backgroundColor, scale: scale }, onMouseEnter: () => pauseOnHover && setIsPlaying(false), onMouseLeave: () => pauseOnHover && setIsPlaying(true), children: [showGridBackground && ((0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 pointer-events-none opacity-5", children: (0, jsx_runtime_1.jsx)("div", { className: "h-full w-full bg-[radial-gradient(#4b5563_1px,transparent_1px)]\r\n [background-size:16px_16px]" }) })), (0, jsx_runtime_1.jsx)("div", { className: "sliding-marquee-resizable", "data-direction": direction, "data-blurring": enableBlur, "data-play-state": isPlaying ? "running" : "paused", "data-spill": enableSpillEffect, children: (0, jsx_runtime_1.jsxs)("div", { className: "sliding-marquee-inner", children: [enableBlur && ((0, jsx_runtime_1.jsx)("div", { className: "sliding-marquee-blur sliding-marquee-blur--left", children: blurDivs })), (0, jsx_runtime_1.jsxs)("ul", { className: "sliding-marquee-list text-foreground", "aria-hidden": false, children: [items.map((item, index) => itemRenderer(item, index, false)), items.map((item, index) => itemRenderer(item, index, true))] }), enableBlur && ((0, jsx_runtime_1.jsx)("div", { className: "sliding-marquee-blur sliding-marquee-blur--right", children: blurDivs }))] }) }), showControls && ((0, jsx_runtime_1.jsx)("button", { onClick: togglePlayState, className: (0, utils_1.cn)("absolute top-1/2 right-2 transform -translate-y-1/2 z-10 p-2 text-xs", "bg-gray-800/50 text-white", "rounded-full hover:bg-gray-700/70 transition-colors", "focus:outline-none focus:ring-2 focus:ring-primary"), "aria-label": isPlaying ? "Pause animation" : "Play animation", children: isPlaying ? (0, jsx_runtime_1.jsx)(lucide_react_1.Pause, { className: "h-4 w-4" }) : (0, jsx_runtime_1.jsx)(lucide_react_1.Play, { className: "h-4 w-4" }) }))] })] })); } exports.default = SlidingLogoMarquee; //# sourceMappingURL=sliding-logo-marquee.js.map