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
JavaScript
"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