Skip to content

Commit b981313

Browse files
committed
🃏 UI: Parallax 3D Cards
1 parent f89af9d commit b981313

File tree

4 files changed

+115
-56
lines changed

4 files changed

+115
-56
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
- [x] If [ prefers-reduced-motion ](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) is set, cursor blob won't show kinetic effects.
2727
- [x] Gray BG for Artworks @md as a hacky solution to [ Hermann Grid Optical Illusion ](https://en.wikipedia.org/wiki/Grid_illusion) problem.
2828
- [x] Base64 Placeholder and Lazy-Loading of Resume
29+
- [x] Card tilt effect enabled only for PC users (because it is resource intensive and might cause navigational stuttering for mobile users)
2930
- [x] Show Navbar on Hero to avoid confusion on page structure and layout
3031
- [x] Only show Navbar when needed (i.e. moving to previous section)
3132

@@ -75,6 +76,7 @@ Step 4: Profit?
7576
| @svgr/webpack | Webpack Loader for SVGR |
7677
| @headlessui/react | Headless Component Library |
7778
| react-icon-cloud | Interactive Word Cloud |
79+
| react-parallax-tilt | Card parallax effect |
7880
| framer-motion | Animation Framework |
7981
| react-intersection-observer | Intersection Observer API |
8082
| sharp | Image Optimizer for Web |

package-lock.json

Lines changed: 70 additions & 48 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@
1919
"@svgr/webpack": "^8.1.0",
2020
"blobity": "^0.2.3",
2121
"framer-motion": "^11.3.29",
22-
"next": "14.1.4",
22+
"next": "^14.2.12",
2323
"next-themes": "^0.3.0",
2424
"react": "^18",
2525
"react-dom": "^18",
2626
"react-icon-cloud": "^4.1.4",
2727
"react-intersection-observer": "^9.13.0",
28+
"react-parallax-tilt": "^1.7.239",
2829
"sharp": "^0.33.5"
2930
},
3031
"devDependencies": {

world/projectDev.tsx

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { faBox } from "@fortawesome/free-solid-svg-icons";
1010
import React, { ReactNode } from 'react';
1111
import AnimatedTitle from "@/world/effects/animatedTitle";
1212
import AnimatedBody from "@/world/effects/animatedBody";
13+
import Tilt from 'react-parallax-tilt';
14+
import { useEffect, useState } from "react";
1315

1416

1517
// █▀█ █▀█ █▀█ ░░█ █▀▀ █▀▀ ▀█▀ █▀▀ ▄▀█ █▀█ █▀▄
@@ -24,17 +26,47 @@ type ProjectCardProps = {
2426
};
2527

2628
const ProjectCard = ({ img, head, body, techs, children }: ProjectCardProps) => {
29+
const [tiltEnable, setTiltEnable] = useState(false);
30+
31+
useEffect(() => {
32+
const handleResize = () => {
33+
if (window.innerWidth >= 1024) {
34+
setTiltEnable(true);
35+
} else {
36+
setTiltEnable(false);
37+
}
38+
};
39+
40+
handleResize();
41+
window.addEventListener("resize", handleResize);
42+
// Cleanup event listener on component unmount
43+
return () => {
44+
window.removeEventListener("resize", handleResize);
45+
};
46+
}, []);
47+
2748
return (
28-
<div className="max-w-lg bg-white border border-gray-200 rounded-lg shadow dark:bg-[#161D1F] dark:border-gray-700">
29-
<img className="rounded-t-lg" src={img} alt="" />
30-
<div className="p-5">
49+
<Tilt
50+
tiltEnable={tiltEnable}
51+
perspective={1000}
52+
// scale={1.05}
53+
transitionSpeed={2000}
54+
style={{ transformStyle: 'preserve-3d' }}
55+
className="group max-w-lg bg-white border border-gray-200 rounded-lg shadow dark:bg-[#161D1F] dark:border-gray-700"
56+
>
57+
<div className="rounded-t-lg overflow-hidden">
58+
<img className="group-hover:scale-110 transition duration-500" src={img} alt="" />
59+
</div>
3160

32-
<AnimatedTitle text={`${head}`} />
61+
<div className="p-5" style={{ transformStyle: 'preserve-3d' }}>
62+
<div className="px-2" style={{transform: "translateZ(3rem)"}}>
63+
<AnimatedTitle text={`${head}`} />
64+
</div>
3365
<AnimatedBody text={`${body}`} />
3466

3567
{/* TECHNOLOGIES */}
3668
{techs && (
37-
<ul className="gap-3 flex flex-wrap max-w-md text-gray-500 dark:text-gray-400">
69+
<ul style={{transform: "translateZ(2rem)"}} className="gap-3 flex flex-wrap max-w-md text-gray-500 dark:text-gray-400">
3870
{techs.map((tech, index) => (
3971
<li key={index} className="bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-200 text-xs rounded-lg border border-gray-500 px-2.5 py-1">
4072
{tech}
@@ -43,9 +75,11 @@ const ProjectCard = ({ img, head, body, techs, children }: ProjectCardProps) =>
4375
</ul>
4476
)}
4577
{/* BUTTONS */}
46-
{ children }
78+
<div className="px-3 pb-3" style={{transform: "translateZ(4rem)"}}>
79+
{ children }
80+
</div>
4781
</div>
48-
</div>
82+
</Tilt>
4983
);
5084
};
5185

0 commit comments

Comments
 (0)