[#56] Landing Pagehttps://project.mdnd-it.cc/work_packages/56
This commit is contained in:
@@ -1,65 +1,68 @@
|
||||
// src/assets/backgrounds/Background.jsx
|
||||
// Kockás háttér, ami a mousemovera reagál
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import React, { useEffect, useState } from "react"
|
||||
import { motion } from "framer-motion"
|
||||
|
||||
const Background = () => {
|
||||
const [gridSize, setGridSize] = useState({ cols: 12, rows: 6 });
|
||||
const [mousePos, setMousePos] = useState({ x: 0, y: 0 });
|
||||
const [path, setPath] = useState([]);
|
||||
const [gridSize, setGridSize] = useState({ cols: 12, rows: 6 })
|
||||
const [mousePos, setMousePos] = useState({ x: 0, y: 0 })
|
||||
const [path, setPath] = useState([])
|
||||
|
||||
useEffect(() => {
|
||||
const updateGrid = () => {
|
||||
const width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
const cols = Math.max(8, Math.floor(width / 100)); // 100px-es cellák
|
||||
const rows = Math.max(5, Math.floor(height / 100)); // 100px-es cellák
|
||||
setGridSize({ cols, rows });
|
||||
};
|
||||
const width = window.innerWidth
|
||||
const height = window.innerHeight
|
||||
const cols = Math.max(8, Math.floor(width / 100)) // 100px-es cellák
|
||||
const rows = Math.max(5, Math.floor(height / 100)) // 100px-es cellák
|
||||
setGridSize({ cols, rows })
|
||||
}
|
||||
|
||||
const handleMouseMove = (e) => {
|
||||
setMousePos({ x: e.clientX, y: e.clientY });
|
||||
};
|
||||
setMousePos({ x: e.clientX, y: e.clientY })
|
||||
}
|
||||
|
||||
updateGrid();
|
||||
window.addEventListener("resize", updateGrid);
|
||||
window.addEventListener("mousemove", handleMouseMove);
|
||||
updateGrid()
|
||||
window.addEventListener("resize", updateGrid)
|
||||
window.addEventListener("mousemove", handleMouseMove)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", updateGrid);
|
||||
window.removeEventListener("mousemove", handleMouseMove);
|
||||
};
|
||||
}, []);
|
||||
window.removeEventListener("resize", updateGrid)
|
||||
window.removeEventListener("mousemove", handleMouseMove)
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
const newCol = Math.floor(Math.random() * gridSize.cols);
|
||||
const newRow = Math.floor(Math.random() * gridSize.rows);
|
||||
const newCol = Math.floor(Math.random() * gridSize.cols)
|
||||
const newRow = Math.floor(Math.random() * gridSize.rows)
|
||||
setPath((prevPath) => {
|
||||
const newPath = [...prevPath, { col: newCol, row: newRow, opacity: 1 }]; // Új pont hozzáadása
|
||||
const newPath = [...prevPath, { col: newCol, row: newRow, opacity: 1 }] // Új pont hozzáadása
|
||||
if (newPath.length > 10) {
|
||||
newPath.shift(); // Max 10 pont az útvonalon
|
||||
newPath.shift() // Max 10 pont az útvonalon
|
||||
}
|
||||
return newPath;
|
||||
});
|
||||
}, 500); // Új pont hozzáadása minden 500ms-ben
|
||||
return newPath
|
||||
})
|
||||
}, 500) // Új pont hozzáadása minden 500ms-ben
|
||||
|
||||
// Az útvonal pontjainak fokozatos eltűnése
|
||||
const fadeInterval = setInterval(() => {
|
||||
setPath((prevPath) =>
|
||||
prevPath.map((point) => ({
|
||||
...point,
|
||||
opacity: Math.max(0, point.opacity - 0.05), // Fokozatosan csökkentjük az opacity-t
|
||||
})).filter((point) => point.opacity > 0) // Eltávolítjuk a teljesen eltűnt pontokat
|
||||
);
|
||||
}, 100); // Opacity frissítése minden 100ms-ben
|
||||
setPath(
|
||||
(prevPath) =>
|
||||
prevPath
|
||||
.map((point) => ({
|
||||
...point,
|
||||
opacity: Math.max(0, point.opacity - 0.05), // Fokozatosan csökkentjük az opacity-t
|
||||
}))
|
||||
.filter((point) => point.opacity > 0) // Eltávolítjuk a teljesen eltűnt pontokat
|
||||
)
|
||||
}, 100) // Opacity frissítése minden 100ms-ben
|
||||
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
clearInterval(fadeInterval);
|
||||
};
|
||||
}, [gridSize]);
|
||||
clearInterval(interval)
|
||||
clearInterval(fadeInterval)
|
||||
}
|
||||
}, [gridSize])
|
||||
|
||||
return (
|
||||
<div className="relative w-full h-screen bg-background flex items-center justify-center overflow-hidden">
|
||||
@@ -71,19 +74,19 @@ const Background = () => {
|
||||
}}
|
||||
>
|
||||
{[...Array(gridSize.cols * gridSize.rows)].map((_, i) => {
|
||||
const col = i % gridSize.cols;
|
||||
const row = Math.floor(i / gridSize.cols);
|
||||
const cellX = (col + 0.5) * (window.innerWidth / gridSize.cols);
|
||||
const cellY = (row + 0.5) * (window.innerHeight / gridSize.rows);
|
||||
const col = i % gridSize.cols
|
||||
const row = Math.floor(i / gridSize.cols)
|
||||
const cellX = (col + 0.5) * (window.innerWidth / gridSize.cols)
|
||||
const cellY = (row + 0.5) * (window.innerHeight / gridSize.rows)
|
||||
|
||||
const dx = cellX - mousePos.x;
|
||||
const dy = cellY - mousePos.y;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
const distanceFactor = Math.max(0, 1 - distance / 300); // Egér hatótávolsága
|
||||
const dx = cellX - mousePos.x
|
||||
const dy = cellY - mousePos.y
|
||||
const distance = Math.sqrt(dx * dx + dy * dy)
|
||||
const distanceFactor = Math.max(0, 1 - distance / 300) // Egér hatótávolsága
|
||||
|
||||
// Az útvonalban lévő pontok opacitása
|
||||
const pathPoint = path.find((p) => p.col === col && p.row === row);
|
||||
const pathOpacity = pathPoint ? pathPoint.opacity : 0;
|
||||
const pathPoint = path.find((p) => p.col === col && p.row === row)
|
||||
const pathOpacity = pathPoint ? pathPoint.opacity : 0
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
@@ -95,11 +98,11 @@ const Background = () => {
|
||||
}}
|
||||
transition={{ duration: 0.5, ease: "easeOut" }} // Lassú és sima átmenet
|
||||
/>
|
||||
);
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Background;
|
||||
export default Background
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
import { useRef, useState } from "react"
|
||||
import { motion, useMotionValue, useSpring } from "framer-motion"
|
||||
|
||||
const springValues = {
|
||||
damping: 30,
|
||||
stiffness: 100,
|
||||
mass: 2,
|
||||
}
|
||||
|
||||
export default function LogoCard({
|
||||
imageSrc,
|
||||
altText = "Tilted card image",
|
||||
captionText = "",
|
||||
containerHeight = "300px",
|
||||
containerWidth = "100%",
|
||||
imageHeight = "300px",
|
||||
imageWidth = "300px",
|
||||
scaleOnHover = 1.1,
|
||||
rotateAmplitude = 14,
|
||||
showMobileWarning = true,
|
||||
showTooltip = true,
|
||||
overlayContent = null,
|
||||
displayOverlayContent = false,
|
||||
}) {
|
||||
const ref = useRef(null)
|
||||
const x = useMotionValue(0)
|
||||
const y = useMotionValue(0)
|
||||
const rotateX = useSpring(useMotionValue(0), springValues)
|
||||
const rotateY = useSpring(useMotionValue(0), springValues)
|
||||
const scale = useSpring(1, springValues)
|
||||
const opacity = useSpring(0)
|
||||
const rotateFigcaption = useSpring(0, {
|
||||
stiffness: 350,
|
||||
damping: 30,
|
||||
mass: 1,
|
||||
})
|
||||
|
||||
const [lastY, setLastY] = useState(0)
|
||||
|
||||
function handleMouse(e) {
|
||||
if (!ref.current) return
|
||||
|
||||
const rect = ref.current.getBoundingClientRect()
|
||||
const offsetX = e.clientX - rect.left - rect.width / 2
|
||||
const offsetY = e.clientY - rect.top - rect.height / 2
|
||||
|
||||
const rotationX = (offsetY / (rect.height / 2)) * -rotateAmplitude
|
||||
const rotationY = (offsetX / (rect.width / 2)) * rotateAmplitude
|
||||
|
||||
rotateX.set(rotationX)
|
||||
rotateY.set(rotationY)
|
||||
|
||||
x.set(e.clientX - rect.left)
|
||||
y.set(e.clientY - rect.top)
|
||||
|
||||
const velocityY = offsetY - lastY
|
||||
rotateFigcaption.set(-velocityY * 0.6)
|
||||
setLastY(offsetY)
|
||||
}
|
||||
|
||||
function handleMouseEnter() {
|
||||
scale.set(scaleOnHover)
|
||||
opacity.set(1)
|
||||
}
|
||||
|
||||
function handleMouseLeave() {
|
||||
opacity.set(0)
|
||||
scale.set(1)
|
||||
rotateX.set(0)
|
||||
rotateY.set(0)
|
||||
rotateFigcaption.set(0)
|
||||
}
|
||||
|
||||
return (
|
||||
<figure
|
||||
ref={ref}
|
||||
className="relative w-full h-full [perspective:800px] flex flex-col items-center justify-center"
|
||||
style={{
|
||||
height: containerHeight,
|
||||
width: containerWidth,
|
||||
}}
|
||||
onMouseMove={handleMouse}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
{showMobileWarning && (
|
||||
<div className="absolute top-4 text-center text-sm block sm:hidden">
|
||||
This effect is not optimized for mobile. Check on desktop.
|
||||
</div>
|
||||
)}
|
||||
|
||||
<motion.div
|
||||
className="relative [transform-style:preserve-3d]"
|
||||
style={{
|
||||
width: imageWidth,
|
||||
height: imageHeight,
|
||||
rotateX,
|
||||
rotateY,
|
||||
scale,
|
||||
}}
|
||||
>
|
||||
<motion.img
|
||||
src={imageSrc}
|
||||
alt={altText}
|
||||
className="absolute top-0 left-0 object-cover rounded-[15px] will-change-transform [transform:translateZ(0)]"
|
||||
style={{
|
||||
width: imageWidth,
|
||||
height: imageHeight,
|
||||
}}
|
||||
/>
|
||||
|
||||
{displayOverlayContent && overlayContent && (
|
||||
<motion.div className="absolute top-0 left-0 z-[2] will-change-transform [transform:translateZ(30px)]">
|
||||
{overlayContent}
|
||||
</motion.div>
|
||||
)}
|
||||
</motion.div>
|
||||
|
||||
{showTooltip && (
|
||||
<motion.figcaption
|
||||
className="pointer-events-none absolute left-0 top-0 rounded-[4px] bg-white px-[10px] py-[4px] text-[10px] text-[#2d2d2d] opacity-0 z-[3] hidden sm:block"
|
||||
style={{
|
||||
x,
|
||||
y,
|
||||
opacity,
|
||||
rotate: rotateFigcaption,
|
||||
}}
|
||||
>
|
||||
{captionText}
|
||||
</motion.figcaption>
|
||||
)}
|
||||
</figure>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user