Skip to content

Commit 7ce55c7

Browse files
feat: create a project card with framer-motion animation to showcase project details
1 parent 415155a commit 7ce55c7

File tree

4 files changed

+95
-3
lines changed

4 files changed

+95
-3
lines changed

src/components/ProjectCard.jsx

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { useRef } from "react";
2+
import {
3+
motion,
4+
useMotionTemplate,
5+
useMotionValue,
6+
useSpring,
7+
} from "motion/react";
8+
9+
const ROTATION_RANGE = 18;
10+
const HALF_ROTATION_RANGE = ROTATION_RANGE / 2;
11+
12+
const ProjectCard = () => {
13+
const ref = useRef(null);
14+
15+
const x = useMotionValue(0);
16+
const y = useMotionValue(0);
17+
18+
const xSpring = useSpring(x);
19+
const ySpring = useSpring(y);
20+
21+
const transform = useMotionTemplate`rotateX(${xSpring}deg) rotateY(${ySpring}deg)`;
22+
23+
const handleMouseMove = (e) => {
24+
if (!ref.current) return [0, 0];
25+
26+
const rect = ref.current.getBoundingClientRect();
27+
28+
const width = rect.width;
29+
const height = rect.height;
30+
31+
const mouseX = (e.clientX - rect.left) * ROTATION_RANGE;
32+
const mouseY = (e.clientY - rect.top) * ROTATION_RANGE;
33+
34+
const rX = (mouseY / height - HALF_ROTATION_RANGE) * -1;
35+
const rY = mouseX / width - HALF_ROTATION_RANGE;
36+
37+
x.set(rX);
38+
y.set(rY);
39+
};
40+
41+
const handleMouseLeave = () => {
42+
x.set(0);
43+
y.set(0);
44+
};
45+
46+
return (
47+
<motion.div
48+
ref={ref}
49+
onMouseMove={handleMouseMove}
50+
onMouseLeave={handleMouseLeave}
51+
style={{
52+
transformStyle: "preserve-3d",
53+
transform,
54+
}}
55+
className="relative h-80 w-2/5 rounded-xl bg-gradient-to-br from-light-blue to-custom-violet"
56+
>
57+
<div
58+
style={{
59+
transform: "translateZ(75px)",
60+
transformStyle: "preserve-3d",
61+
}}
62+
className="absolute inset-4 grid place-content-center rounded-xl bg-white shadow-lg"
63+
>
64+
<div>
65+
<img src="" alt="" />
66+
</div>
67+
<p
68+
style={{
69+
transform: "translateZ(50px)",
70+
}}
71+
className="text-center text-2xl font-bold"
72+
>
73+
Work in Progress...
74+
</p>
75+
</div>
76+
</motion.div>
77+
);
78+
};
79+
80+
export default ProjectCard;

src/components/Tabs.jsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@ const Tabs = ({ tabs, activeTab, setActiveTab }) => {
1818
layoutId="active-pill"
1919
className="absolute inset-0 bg-light-blue dark:bg-custom-yellow"
2020
style={{ borderRadius: 9999 }}
21-
transition={{ type: "spring", duration: 0.6 }}
21+
transition={{
22+
type: "spring",
23+
stiffness: 300,
24+
damping: 20,
25+
duration: 0.6,
26+
}}
2227
/>
2328
)}
2429

src/components/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ export { default as TerminalContactForm } from "./TerminalContactForm";
1717
export { default as SkillBar } from "./SkillBar";
1818
export { default as SkillTabs } from "./SkillTabs";
1919
export { default as ExperienceTabs } from "./ExperienceTabs";
20+
export { default as ProjectCard } from "./ProjectCard";

src/sections/Projects.jsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { motion } from "motion/react";
2-
import { SectionHeading, SectionSubHeading } from "../components";
2+
import { ProjectCard, SectionHeading, SectionSubHeading } from "../components";
33
import useSectionInView from "../hooks/useSectionInView";
44

55
const Projects = () => {
@@ -8,10 +8,16 @@ const Projects = () => {
88
<motion.section
99
ref={sectionRef}
1010
id="projects"
11-
className="flex h-screen w-full flex-col items-center py-10 md:py-14 lg:w-4/5 dark:text-white"
11+
className="flex min-h-screen w-full flex-col items-center py-10 md:py-14 lg:w-4/5 dark:text-white"
1212
>
1313
<SectionHeading headingText="Projects" />
1414
<SectionSubHeading subHeadingText="Proud Creations" />
15+
<div className="container mt-10 flex h-full w-full flex-wrap items-center justify-center gap-5 p-2">
16+
<ProjectCard />
17+
<ProjectCard />
18+
<ProjectCard />
19+
<ProjectCard />
20+
</div>
1521
</motion.section>
1622
);
1723
};

0 commit comments

Comments
 (0)