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.
135 lines (129 loc) • 6.33 kB
JavaScript
;
"use client";
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const ThreeDPerspectiveCard = ({ image, width = "300px", height = "350px", }) => {
const cardRef = (0, react_1.useRef)(null);
const shineRef = (0, react_1.useRef)(null);
const shadowRef = (0, react_1.useRef)(null);
(0, react_1.useEffect)(() => {
// This is an optimization: the mouse move listener should only be
// added if the client is ready and references exist.
if (!cardRef.current || !shineRef.current || !shadowRef.current) {
return;
}
const handleMouseMove = (event) => {
// Get window dimensions
const wHeight = window.innerHeight;
const wWidth = window.innerWidth;
const currentMousePos = { x: event.pageX, y: event.pageY };
const mouseFromCenter = {
x: currentMousePos.x - wWidth / 2,
y: currentMousePos.y - wHeight / 2,
};
// 1. Calculate Rotation for Card (3D Perspective)
const maxRotation = 10; // Max rotation angle in degrees
const mouseXRatio = (currentMousePos.x / wWidth) * 2 - 1; // Range from -1 to 1
const mouseYRatio = (currentMousePos.y / wHeight) * 2 - 1; // Range from -1 to 1
// around1 (RotateX) is inversely proportional to mouse Y
const rotateXDeg = -1 * (mouseYRatio * maxRotation);
// around2 (RotateY) is proportional to mouse X
const rotateYDeg = mouseXRatio * maxRotation;
// 2. Calculate Translation for Floating Effect
const maxTranslate = 20; // Max translation in pixels
const transX = mouseXRatio * maxTranslate;
const transY = mouseYRatio * maxTranslate;
// 3. Calculate Shine Angle (for linear-gradient)
const dy = event.pageY - wHeight / 2;
const dx = event.pageX - wWidth / 2;
// Math.atan2 gives angle in radians, convert to degrees, and adjust
const theta = Math.atan2(dy, dx);
const angle = (theta * 180) / Math.PI - 90;
// 4. Calculate Background Position (Parallax Effect)
const backgroundPositionX = (currentMousePos.x / wWidth) * 100; // 0% to 100%
const backgroundPositionY = (currentMousePos.y / wHeight) * 50; // 0% to 50%
// Apply styles to Shine
shineRef.current.style.background = `linear-gradient(${angle}deg, rgba(255,255,255,${(currentMousePos.y / wHeight) * 0.7 // Intensity based on Y position
}) 0%, rgba(255,255,255, 0) 80%)`;
// Apply styles to Card (3D Rotation, Float, and Parallax)
cardRef.current.style.transform = `translate3d(${transX}px, ${transY}px, 0) scale(1) rotateX(${rotateXDeg}deg) rotateY(${rotateYDeg}deg)`;
cardRef.current.style.backgroundPosition = `${backgroundPositionX}% ${backgroundPositionY}%`;
// Apply styles to Shadow
// This creates a subtle opposite movement and rotation for a deeper shadow effect
shadowRef.current.style.transform = `scale(.9,.9) translateX(${mouseFromCenter.x * -0.02 + 12}px) translateY(${mouseFromCenter.y * -0.02 + 12}px) rotateY(${(mouseFromCenter.x / 25) * 0.5}deg) rotateX(${mouseFromCenter.y / -25}deg)`;
};
// Attach listener to the whole document
document.addEventListener("mousemove", handleMouseMove);
return () => document.removeEventListener("mousemove", handleMouseMove);
}, []);
// The rendering logic remains the same
return ((0, jsx_runtime_1.jsxs)("div", { className: "parent-container", children: [(0, jsx_runtime_1.jsxs)("div", { className: "wrap", children: [(0, jsx_runtime_1.jsx)("div", { className: "card-shadow", ref: shadowRef }), (0, jsx_runtime_1.jsx)("div", { className: "card", ref: cardRef, style: {
width,
height,
backgroundImage: `url(${image})`,
// Background size is large to allow for parallax scrolling effect
backgroundSize: "450%",
}, children: (0, jsx_runtime_1.jsx)("div", { className: "card-front", children: (0, jsx_runtime_1.jsx)("div", { className: "card-shine", ref: shineRef }) }) })] }), (0, jsx_runtime_1.jsx)("style", { dangerouslySetInnerHTML: { __html: `
.parent-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 400px;
position: relative;
width: 100%;
padding: 40px;
}
.wrap {
perspective: 1000px;
position: relative;
width: ${width};
height: ${height};
}
.card-shadow,
.card {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 10px;
transition: transform 0.15s ease-out, background-position 0.15s ease-out;
will-change: transform, background-position;
}
.card {
background: #fff 50% 50%;
z-index: 2;
}
.card-shadow {
background: rgba(0, 0, 0, 0.5);
filter: blur(25px);
opacity: 0.8;
z-index: 1;
transform: scale(0.9) translateY(10px);
transition: transform 0.15s ease-out;
}
.card-front {
background-color: rgba(0, 0, 0, 0.1);
border-radius: 10px;
width: 100%;
height: 100%;
position: relative;
border: 1px solid rgba(255, 255, 255, 0.2);
}
.card-shine {
position: absolute;
width: 100%;
height: 100%;
border-radius: 10px;
z-index: 10;
background: linear-gradient(
135deg,
rgba(255, 255, 255, 0.1) 0%,
rgba(255, 255, 255, 0) 60%
);
}
` } })] }));
};
exports.default = ThreeDPerspectiveCard;
//# sourceMappingURL=3d-perspective-card.js.map