mirror of
https://github.com/FranP-code/spooky-spotify-showcase.git
synced 2025-10-13 00:02:36 +00:00
Scroll animations
This commit is contained in:
@@ -6,6 +6,7 @@ import Tilt from "react-parallax-tilt";
|
||||
import { quantum } from "ldrs";
|
||||
import { ring2 } from "ldrs";
|
||||
import ErrorComponent from "./error";
|
||||
import ScrollFadeIn from "./scroll-fade-in";
|
||||
|
||||
ring2.register();
|
||||
quantum.register();
|
||||
@@ -99,7 +100,7 @@ export default function ArtistShowcase({
|
||||
|
||||
return (
|
||||
<Tilt tiltMaxAngleX={10} tiltMaxAngleY={10} transitionSpeed={200}>
|
||||
<div
|
||||
<ScrollFadeIn
|
||||
className="mb-2 w-56 cursor-pointer overflow-hidden rounded-md border-2 border-slate-700 bg-slate-300 bg-opacity-10"
|
||||
onClick={() => setShowSpookyImage(!showSpookyImage)}
|
||||
>
|
||||
@@ -180,7 +181,7 @@ export default function ArtistShowcase({
|
||||
>
|
||||
<span className="cursor-default">{name}</span>
|
||||
</p>
|
||||
</div>
|
||||
</ScrollFadeIn>
|
||||
</Tilt>
|
||||
);
|
||||
}
|
||||
|
||||
44
src/app/_components/scroll-fade-in.tsx
Normal file
44
src/app/_components/scroll-fade-in.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import { motion, useAnimation, useInView } from "framer-motion";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
export const ScrollFadeIn = ({
|
||||
children,
|
||||
className = "",
|
||||
onClick,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
}) => {
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref, { once: true });
|
||||
const controls = useAnimation();
|
||||
|
||||
useEffect(() => {
|
||||
if (isInView) {
|
||||
controls.start("visible");
|
||||
}
|
||||
}, [isInView]);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
onClick={onClick}
|
||||
ref={ref}
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: { opacity: 1 },
|
||||
}}
|
||||
transition={{
|
||||
duration: 0.4, // Adjust the duration as needed
|
||||
ease: "easeOut",
|
||||
}}
|
||||
initial="hidden"
|
||||
animate={controls}
|
||||
className={className}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ScrollFadeIn;
|
||||
43
src/app/_components/scroll-slider.tsx
Normal file
43
src/app/_components/scroll-slider.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import { motion, useAnimation, useInView } from "framer-motion";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
export const ScrollSlider = ({
|
||||
children,
|
||||
className = "",
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}) => {
|
||||
const ref = useRef(null);
|
||||
const isInview = useInView(ref, { once: true });
|
||||
const controls = useAnimation();
|
||||
|
||||
useEffect(() => {
|
||||
if (isInview) {
|
||||
controls.start("visible");
|
||||
}
|
||||
}, [isInview]);
|
||||
return (
|
||||
<motion.div
|
||||
ref={ref}
|
||||
variants={{
|
||||
hidden: { opacity: 0, translateX: 90 },
|
||||
visible: { opacity: 1, translateX: 0 },
|
||||
}}
|
||||
transition={{
|
||||
type: "spring",
|
||||
duration: 0.2,
|
||||
damping: 8,
|
||||
// delay: delay,
|
||||
stiffness: 100,
|
||||
}}
|
||||
initial="hidden"
|
||||
animate={controls}
|
||||
className={className}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ScrollSlider;
|
||||
@@ -7,6 +7,7 @@ import ArtistShowcase from "./artist-showcase";
|
||||
import UserShowcase from "./user-showcase";
|
||||
import { TypographyH2 } from "./h2";
|
||||
import { TypographyH1 } from "./h1";
|
||||
import ScrollSlider from "./scroll-slider";
|
||||
|
||||
export function Showcase({
|
||||
userData,
|
||||
@@ -30,9 +31,11 @@ export function Showcase({
|
||||
<Switch isChecked={spookify} setIsChecked={setSpookify} />
|
||||
</div>
|
||||
<UserShowcase spookify={spookify} {...userData} />
|
||||
<TypographyH1 className="mb-2 mt-8 self-baseline text-3xl lg:text-4xl">
|
||||
Tracks by album
|
||||
</TypographyH1>
|
||||
<ScrollSlider>
|
||||
<TypographyH1 className="mb-2 mt-8 self-baseline text-3xl lg:text-4xl">
|
||||
Tracks by album
|
||||
</TypographyH1>
|
||||
</ScrollSlider>
|
||||
{Object.values(tracksByAlbum)
|
||||
.sort((a, b) => b.position - a.position)
|
||||
.map((album, index) => {
|
||||
@@ -47,9 +50,12 @@ export function Showcase({
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<TypographyH1 className="mb-2 mt-8 self-baseline text-3xl lg:text-4xl">
|
||||
Artists
|
||||
</TypographyH1>
|
||||
<ScrollSlider>
|
||||
<TypographyH1 className="mb-2 mt-8 self-baseline text-3xl lg:text-4xl">
|
||||
Artists
|
||||
</TypographyH1>
|
||||
</ScrollSlider>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
|
||||
Reference in New Issue
Block a user