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:
@@ -22,6 +22,7 @@
|
|||||||
"@trpc/react-query": "^11.0.0-rc.446",
|
"@trpc/react-query": "^11.0.0-rc.446",
|
||||||
"@trpc/server": "^11.0.0-rc.446",
|
"@trpc/server": "^11.0.0-rc.446",
|
||||||
"cloudinary": "^2.5.1",
|
"cloudinary": "^2.5.1",
|
||||||
|
"framer-motion": "^11.11.9",
|
||||||
"geist": "^1.3.0",
|
"geist": "^1.3.0",
|
||||||
"ldrs": "^1.0.2",
|
"ldrs": "^1.0.2",
|
||||||
"next": "^14.2.4",
|
"next": "^14.2.4",
|
||||||
|
|||||||
42
pnpm-lock.yaml
generated
42
pnpm-lock.yaml
generated
@@ -29,6 +29,9 @@ importers:
|
|||||||
cloudinary:
|
cloudinary:
|
||||||
specifier: ^2.5.1
|
specifier: ^2.5.1
|
||||||
version: 2.5.1
|
version: 2.5.1
|
||||||
|
framer-motion:
|
||||||
|
specifier: ^11.11.9
|
||||||
|
version: 11.11.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
geist:
|
geist:
|
||||||
specifier: ^1.3.0
|
specifier: ^1.3.0
|
||||||
version: 1.3.1(next@14.2.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
version: 1.3.1(next@14.2.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||||
@@ -880,6 +883,20 @@ packages:
|
|||||||
resolution: {integrity: sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==}
|
resolution: {integrity: sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==}
|
||||||
deprecated: 'Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau'
|
deprecated: 'Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau'
|
||||||
|
|
||||||
|
framer-motion@11.11.9:
|
||||||
|
resolution: {integrity: sha512-XpdZseuCrZehdHGuW22zZt3SF5g6AHJHJi7JwQIigOznW4Jg1n0oGPMJQheMaKLC+0rp5gxUKMRYI6ytd3q4RQ==}
|
||||||
|
peerDependencies:
|
||||||
|
'@emotion/is-prop-valid': '*'
|
||||||
|
react: ^18.0.0
|
||||||
|
react-dom: ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@emotion/is-prop-valid':
|
||||||
|
optional: true
|
||||||
|
react:
|
||||||
|
optional: true
|
||||||
|
react-dom:
|
||||||
|
optional: true
|
||||||
|
|
||||||
fs.realpath@1.0.0:
|
fs.realpath@1.0.0:
|
||||||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||||
|
|
||||||
@@ -2572,8 +2589,8 @@ snapshots:
|
|||||||
'@typescript-eslint/parser': 8.8.1(eslint@8.57.1)(typescript@5.6.3)
|
'@typescript-eslint/parser': 8.8.1(eslint@8.57.1)(typescript@5.6.3)
|
||||||
eslint: 8.57.1
|
eslint: 8.57.1
|
||||||
eslint-import-resolver-node: 0.3.9
|
eslint-import-resolver-node: 0.3.9
|
||||||
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1)
|
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1)
|
||||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||||
eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1)
|
eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1)
|
||||||
eslint-plugin-react: 7.37.1(eslint@8.57.1)
|
eslint-plugin-react: 7.37.1(eslint@8.57.1)
|
||||||
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1)
|
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1)
|
||||||
@@ -2592,37 +2609,37 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1):
|
eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nolyfill/is-core-module': 1.0.39
|
'@nolyfill/is-core-module': 1.0.39
|
||||||
debug: 4.3.7
|
debug: 4.3.7
|
||||||
enhanced-resolve: 5.17.1
|
enhanced-resolve: 5.17.1
|
||||||
eslint: 8.57.1
|
eslint: 8.57.1
|
||||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||||
fast-glob: 3.3.2
|
fast-glob: 3.3.2
|
||||||
get-tsconfig: 4.8.1
|
get-tsconfig: 4.8.1
|
||||||
is-bun-module: 1.2.1
|
is-bun-module: 1.2.1
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@typescript-eslint/parser'
|
- '@typescript-eslint/parser'
|
||||||
- eslint-import-resolver-node
|
- eslint-import-resolver-node
|
||||||
- eslint-import-resolver-webpack
|
- eslint-import-resolver-webpack
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
|
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 3.2.7
|
debug: 3.2.7
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@typescript-eslint/parser': 8.8.1(eslint@8.57.1)(typescript@5.6.3)
|
'@typescript-eslint/parser': 8.8.1(eslint@8.57.1)(typescript@5.6.3)
|
||||||
eslint: 8.57.1
|
eslint: 8.57.1
|
||||||
eslint-import-resolver-node: 0.3.9
|
eslint-import-resolver-node: 0.3.9
|
||||||
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1)
|
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
|
eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rtsao/scc': 1.1.0
|
'@rtsao/scc': 1.1.0
|
||||||
array-includes: 3.1.8
|
array-includes: 3.1.8
|
||||||
@@ -2633,7 +2650,7 @@ snapshots:
|
|||||||
doctrine: 2.1.0
|
doctrine: 2.1.0
|
||||||
eslint: 8.57.1
|
eslint: 8.57.1
|
||||||
eslint-import-resolver-node: 0.3.9
|
eslint-import-resolver-node: 0.3.9
|
||||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
is-core-module: 2.15.1
|
is-core-module: 2.15.1
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
@@ -2823,6 +2840,13 @@ snapshots:
|
|||||||
|
|
||||||
formidable@1.2.6: {}
|
formidable@1.2.6: {}
|
||||||
|
|
||||||
|
framer-motion@11.11.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.7.0
|
||||||
|
optionalDependencies:
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
|
||||||
fs.realpath@1.0.0: {}
|
fs.realpath@1.0.0: {}
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import Tilt from "react-parallax-tilt";
|
|||||||
import { quantum } from "ldrs";
|
import { quantum } from "ldrs";
|
||||||
import { ring2 } from "ldrs";
|
import { ring2 } from "ldrs";
|
||||||
import ErrorComponent from "./error";
|
import ErrorComponent from "./error";
|
||||||
|
import ScrollFadeIn from "./scroll-fade-in";
|
||||||
|
|
||||||
ring2.register();
|
ring2.register();
|
||||||
quantum.register();
|
quantum.register();
|
||||||
@@ -99,7 +100,7 @@ export default function ArtistShowcase({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Tilt tiltMaxAngleX={10} tiltMaxAngleY={10} transitionSpeed={200}>
|
<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"
|
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)}
|
onClick={() => setShowSpookyImage(!showSpookyImage)}
|
||||||
>
|
>
|
||||||
@@ -180,7 +181,7 @@ export default function ArtistShowcase({
|
|||||||
>
|
>
|
||||||
<span className="cursor-default">{name}</span>
|
<span className="cursor-default">{name}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</ScrollFadeIn>
|
||||||
</Tilt>
|
</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 UserShowcase from "./user-showcase";
|
||||||
import { TypographyH2 } from "./h2";
|
import { TypographyH2 } from "./h2";
|
||||||
import { TypographyH1 } from "./h1";
|
import { TypographyH1 } from "./h1";
|
||||||
|
import ScrollSlider from "./scroll-slider";
|
||||||
|
|
||||||
export function Showcase({
|
export function Showcase({
|
||||||
userData,
|
userData,
|
||||||
@@ -30,9 +31,11 @@ export function Showcase({
|
|||||||
<Switch isChecked={spookify} setIsChecked={setSpookify} />
|
<Switch isChecked={spookify} setIsChecked={setSpookify} />
|
||||||
</div>
|
</div>
|
||||||
<UserShowcase spookify={spookify} {...userData} />
|
<UserShowcase spookify={spookify} {...userData} />
|
||||||
<TypographyH1 className="mb-2 mt-8 self-baseline text-3xl lg:text-4xl">
|
<ScrollSlider>
|
||||||
Tracks by album
|
<TypographyH1 className="mb-2 mt-8 self-baseline text-3xl lg:text-4xl">
|
||||||
</TypographyH1>
|
Tracks by album
|
||||||
|
</TypographyH1>
|
||||||
|
</ScrollSlider>
|
||||||
{Object.values(tracksByAlbum)
|
{Object.values(tracksByAlbum)
|
||||||
.sort((a, b) => b.position - a.position)
|
.sort((a, b) => b.position - a.position)
|
||||||
.map((album, index) => {
|
.map((album, index) => {
|
||||||
@@ -47,9 +50,12 @@ export function Showcase({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
<TypographyH1 className="mb-2 mt-8 self-baseline text-3xl lg:text-4xl">
|
<ScrollSlider>
|
||||||
Artists
|
<TypographyH1 className="mb-2 mt-8 self-baseline text-3xl lg:text-4xl">
|
||||||
</TypographyH1>
|
Artists
|
||||||
|
</TypographyH1>
|
||||||
|
</ScrollSlider>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
|||||||
Reference in New Issue
Block a user