Skip to content

Commit 01ec2eb

Browse files
committed
swapped achievement progress animation and fixed intersection observer by creating private instance of it for every progress achievement
1 parent f8ea70d commit 01ec2eb

File tree

4 files changed

+127
-122
lines changed

4 files changed

+127
-122
lines changed
Lines changed: 73 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"use client"
1+
"use client";
22

33
import React, { useEffect, useRef, useState } from "react";
44
import { ScrollArea } from "@/components/ui/scroll-area";
@@ -9,94 +9,91 @@ import { Achievement } from "@/types/achievement";
99
import "../timeline.css";
1010

1111
interface Props {
12-
userAchievements: PrsimaAchievement[];
13-
allAchievements: Achievement[];
12+
userAchievements: PrsimaAchievement[];
13+
allAchievements: Achievement[];
1414
}
1515

1616
export default function AchievementProgress({
17-
userAchievements,
18-
allAchievements,
17+
userAchievements,
18+
allAchievements,
1919
}: Props) {
20-
const updatedAllAch = [
21-
...allAchievements,
22-
{
23-
type: "MORE_TO_COME",
24-
image: "/static/first.png",
25-
name: "More to come!",
26-
},
27-
{
28-
type: "MORE_TO_COME_2",
29-
image: "/static/first.png",
30-
name: "More to come!",
31-
},
32-
];
20+
const updatedAllAch = [
21+
...allAchievements,
22+
{
23+
type: "MORE_TO_COME",
24+
image: "/static/first.png",
25+
name: "More to come!",
26+
},
27+
{
28+
type: "MORE_TO_COME_2",
29+
image: "/static/first.png",
30+
name: "More to come!",
31+
},
32+
];
3333

34-
const timelineRef = useRef<HTMLDivElement>(null);
35-
const [animatedItems, setAnimatedItems] = useState<string[]>([]);
34+
return (
35+
<ScrollArea className="rounded-md h-[300px] border-2 border-primary p-4 mt-10">
36+
<h3 className="text-primary font-special">Achievement Progress</h3>
37+
<div className="timeline">
38+
{updatedAllAch.map((achievement) => {
39+
const timelineItemRef = useRef<HTMLDivElement>(null);
3640

37-
useEffect(() => {
38-
const observer = new IntersectionObserver(
39-
(entries) => {
40-
const inViewItems = entries
41-
.filter((entry) => entry.isIntersecting)
42-
.map((entry) => entry.target.id);
41+
const [isVisible, setIsVisible] = useState<boolean>(false);
4342

44-
setAnimatedItems((prevItems) => [...prevItems, ...inViewItems]);
45-
},
46-
{
43+
useEffect(() => {
44+
const observer = new IntersectionObserver(
45+
(entries) => {
46+
const [entry] = entries;
47+
setIsVisible(entry.isIntersecting);
48+
},
49+
{
4750
root: null,
48-
rootMargin: "0px",
49-
threshold: 0.5, // Adjust this threshold as per your needs
50-
}
51-
);
52-
53-
const timelineItems = timelineRef.current?.querySelectorAll(".timeline-item");
54-
if (timelineItems) {
55-
timelineItems.forEach((item) => observer.observe(item));
56-
}
51+
rootMargin: "-20px",
52+
threshold: 0.1, // Adjust this threshold as per your needs
53+
}
54+
);
5755

58-
return () => {
59-
if (timelineItems) {
60-
timelineItems.forEach((item) => observer.unobserve(item));
56+
if (timelineItemRef.current) {
57+
observer.observe(timelineItemRef.current);
6158
}
62-
};
63-
}, []);
6459

60+
return () => {
61+
if (timelineItemRef.current) {
62+
observer.unobserve(timelineItemRef.current);
63+
}
64+
};
65+
}, [timelineItemRef]);
6566

66-
return (
67-
<ScrollArea className="rounded-md h-[300px] border-2 border-primary p-4">
68-
<h3 className="text-primary font-special">Achievement Progress</h3>
69-
<div className="timeline" ref={timelineRef}>
70-
{updatedAllAch.map((achievement) => {
71-
const isUnlocked = userAchievements.some(
72-
(userAchievement) => userAchievement.achievementType === achievement.type
73-
);
67+
const isUnlocked = userAchievements.some(
68+
(userAchievement) =>
69+
userAchievement.achievementType === achievement.type
70+
);
7471

75-
const itemId = `achievement-${achievement.type}`;
72+
const itemId = `achievement-${achievement.type}`;
7673

77-
return (
78-
<div
79-
key={achievement.type}
80-
id={itemId}
81-
className={`timeline-item
82-
${isUnlocked ? "unlocked" : "locked"
83-
} shadow-lg shadow-accent opacity-100
84-
${animatedItems.includes(itemId) ? "animate-fade" : ""} hover:animate-bounce hover:cursor-pointer`}
85-
>
86-
<div className="timeline-content">
87-
{isUnlocked ? (
88-
<Avatar>
89-
<AvatarImage src={achievement.image} />
90-
</Avatar>
91-
) : (
92-
<BanIcon className="text-primary" />
93-
)}
94-
<p>{achievement.name}</p>
95-
</div>
96-
</div>
97-
);
98-
})}
74+
return (
75+
<div
76+
ref={timelineItemRef}
77+
key={achievement.type}
78+
id={itemId}
79+
className={`timeline-item ${isUnlocked ? "unlocked" : "locked"} ${
80+
isVisible && "animate-fade"
81+
} shadow-lg shadow-accent opacity-100 `}
82+
>
83+
<div className="timeline-content">
84+
{isUnlocked ? (
85+
<Avatar>
86+
<AvatarImage src={achievement.image} />
87+
</Avatar>
88+
) : (
89+
<BanIcon className="text-primary" />
90+
)}
91+
<p>{achievement.name}</p>
92+
</div>
9993
</div>
100-
</ScrollArea>
101-
);
94+
);
95+
})}
96+
</div>
97+
</ScrollArea>
98+
);
10299
}

packages/app/src/app/dashboard/timeline.css

Lines changed: 52 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,78 @@
11
/* timeline.css */
22
.timeline {
3-
position: relative;
4-
margin: 20px 0;
5-
display: flex;
6-
flex-direction: column;
7-
justify-content: center;
8-
align-items: center;
3+
position: relative;
4+
margin: 20px 0;
5+
display: flex;
6+
flex-direction: column;
7+
justify-content: center;
8+
align-items: center;
99
}
1010

1111
.timeline-item {
12-
position: relative;
13-
padding: 20px 40px;
14-
width: 25%;
15-
border-radius: 5px;
16-
border: 2px solid hsl(var(--primary));
17-
margin-bottom: 20px;
12+
position: relative;
13+
height: 62px;
14+
padding: 3px;
15+
width: 50%;
16+
border-radius: 5px;
17+
margin-bottom: 20px;
18+
cursor: pointer;
1819
}
1920

2021
.timeline-item.unlocked {
21-
border-color: #7ac70c;
22-
/* Green color for unlocked achievements */
22+
background-image: var(--achievement-progress-gradient);
23+
animation: gradient 0.75s linear infinite;
24+
background-size: 50% 100%;
2325
}
2426

2527
.timeline-item.locked {
26-
border-color: #f44336;
27-
/* Red color for locked achievements */
28+
background-color: red;
2829
}
2930

3031
.timeline-content {
31-
display: flex;
32-
align-items: center;
33-
justify-content: center;
34-
text-align: center;
32+
display: flex;
33+
align-items: center;
34+
justify-content: center;
35+
text-align: center;
36+
width: 100%;
37+
height: 100%;
38+
background-color: hsl(var(--accent));
39+
border-radius: 5px;
3540
}
3641

3742
.timeline-content p {
38-
margin: 0;
39-
padding-left: 3px;
43+
margin: 0;
44+
padding-left: 3px;
4045
}
4146

42-
.timeline-item::before {
43-
content: "";
44-
position: absolute;
45-
top: 0;
46-
height: 100%;
47-
border-left: 4px solid hsl(var(--primary));
47+
/* Float the items alternately */
48+
.timeline-item:nth-child(even) {
49+
margin-left: 50%;
4850
}
4951

50-
.timeline-item:nth-child(even)::before {
51-
left: 0;
52-
transform: translateX(-50%);
52+
.timeline-item:nth-child(odd) {
53+
margin-right: 50%;
5354
}
5455

55-
.timeline-item:nth-child(odd)::before {
56-
right: 0;
57-
transform: translateX(50%);
56+
@keyframes gradient {
57+
0% {
58+
background-position: 0% 25%;
59+
}
60+
25% {
61+
background-position: 25% 50%;
62+
}
63+
50% {
64+
background-position: 50% 75%;
65+
}
66+
75% {
67+
background-position: 75% 100%;
68+
}
69+
100% {
70+
background-position: 100% 0%;
71+
}
5872
}
5973

60-
/* Float the items alternately */
61-
.timeline-item:nth-child(even) {
62-
margin-left: 50%;
74+
@media (min-width: 1024px) {
75+
.timeline-item {
76+
width: 25%;
77+
}
6378
}
64-
65-
.timeline-item:nth-child(odd) {
66-
margin-right: 50%;
67-
}

packages/app/src/styles/globals.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@
4343

4444
--monochrome-color: 0 0% 0%;
4545

46-
--achievement-progress-color: (
46+
--achievement-progress-gradient: linear-gradient(
47+
115deg,
4748
rgb(79, 207, 112),
4849
rgb(250, 214, 72),
4950
rgb(167, 103, 229),

packages/app/tailwind.config.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ module.exports = {
1717
},
1818
extend: {
1919
backgroundSize: { achievement: "50% 100%" },
20-
backgroundImage: {
21-
achievement:
22-
"linear-gradient(115deg, var(--achievement-progress-color))",
23-
},
2420
screens: {
2521
xs: "560px",
2622
},

0 commit comments

Comments
 (0)