Skip to content

Commit ace4098

Browse files
hariMoamal-2000Copilot
authored
improve orbiting item's performance on the landing page (#451)
Co-authored-by: Moamal Alaa <moamalalaapro1@gmail.com> Co-authored-by: Copilot <copilot@github.com>
1 parent f53fbd1 commit ace4098

2 files changed

Lines changed: 76 additions & 36 deletions

File tree

app/(main)/_landing/stats-bento.tsx

Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"use client";
22

33
import Link from "next/link";
4-
import { useEffect, useState } from "react";
4+
import { type CSSProperties, useEffect, useState } from "react";
55

66
import AnimatedBorderTrail from "@/animata/container/animated-border-trail";
77
import Marquee from "@/animata/container/marquee";
@@ -87,52 +87,42 @@ function OrbitItem({
8787
duration: number;
8888
children: React.ReactNode;
8989
}) {
90-
const startAngle = Math.round((index / total) * 360);
91-
const [angle, setAngle] = useState(startAngle);
92-
const [mounted, setMounted] = useState(false);
90+
const delay = (duration / total) * index * -1;
9391

94-
useEffect(() => {
95-
setMounted(true);
96-
const id = setInterval(() => setAngle((a) => (a + 1) % 360), duration);
97-
return () => clearInterval(id);
98-
}, [duration]);
99-
100-
const rad = (angle * Math.PI) / 180;
101-
const x = 35 * Math.cos(rad);
102-
const y = 15 * Math.sin(rad);
103-
const tilt = (-30 * Math.PI) / 180;
104-
const xT = x * Math.cos(tilt) - y * Math.sin(tilt);
105-
const yT = x * Math.sin(tilt) + y * Math.cos(tilt);
106-
const depth = (Math.sin(rad) + 1) / 2;
107-
108-
// Round to 2 decimals to prevent hydration mismatch
109-
const left = Math.round((50 + xT) * 100) / 100;
110-
const top = Math.round((50 + yT) * 100) / 100;
111-
const scale = Math.round((0.7 + depth * 0.5) * 100) / 100;
112-
const op = Math.round((0.35 + depth * 0.65) * 100) / 100;
92+
const orbitContainerStyle: CSSProperties = {
93+
top: "50%",
94+
left: "50%",
95+
animation: `
96+
orbit-move ${duration}s linear infinite,
97+
orbit-indexes ${duration}s linear infinite
98+
`,
99+
animationDelay: `${delay}s, ${delay}s`,
100+
transformStyle: "preserve-3d",
101+
};
102+
const itemCorrectionStyle: CSSProperties = {
103+
animation: `counter-rotate ${duration}s linear infinite`,
104+
animationDelay: `${delay}s`,
105+
backfaceVisibility: "hidden",
106+
};
113107

114108
return (
115-
<div
116-
className="absolute flex h-8 w-8 items-center justify-center rounded-full border border-border bg-[hsl(var(--surface-card))] sm:h-10 sm:w-10"
117-
style={{
118-
left: `${left}%`,
119-
top: `${top}%`,
120-
transform: `translate(-50%, -50%) scale(${scale})`,
121-
zIndex: Math.round(depth * 10),
122-
opacity: op,
123-
}}
124-
>
125-
{children}
109+
<div className="absolute" style={orbitContainerStyle}>
110+
<div
111+
className="flex h-8 w-8 items-center justify-center rounded-full border border-border bg-[hsl(var(--surface-card))] sm:h-10 sm:w-10"
112+
style={itemCorrectionStyle}
113+
>
114+
{children}
115+
</div>
126116
</div>
127117
);
128118
}
129119

130120
function FrameworkOrbit() {
131121
return (
132122
<div className="relative flex h-40 w-full items-center justify-center overflow-hidden rounded-xl border border-border bg-[hsl(var(--surface-alt))] sm:h-48">
133-
<Icons.logo className="z-10 h-8 w-8 rounded-full bg-linear-to-br from-violet-500 to-indigo-600 p-1.5 shadow-lg sm:h-10 sm:w-10 sm:p-2" />
123+
<Icons.logo className="relative z-10 h-8 w-8 rounded-full bg-linear-to-br from-violet-500 to-indigo-600 p-1.5 shadow-lg sm:h-10 sm:w-10 sm:p-2" />
134124
{frameworkItems.map((item, i) => (
135-
<OrbitItem key={item.key} index={i} total={frameworkItems.length} duration={35}>
125+
<OrbitItem key={item.key} index={i} total={frameworkItems.length} duration={12}>
136126
{item.icon}
137127
</OrbitItem>
138128
))}

styles/globals.css

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,3 +563,53 @@
563563
[style*="opacity: 1"] > .scroll-file {
564564
@apply text-blue-300 dark:text-blue-500;
565565
}
566+
567+
@layer utilities {
568+
@keyframes orbit-move {
569+
from {
570+
transform: translate(-50%, -50%) rotateY(-40deg) rotateX(70deg) rotateZ(0deg)
571+
translateX(100px);
572+
}
573+
to {
574+
transform: translate(-50%, -50%) rotateY(-40deg) rotateX(70deg) rotateZ(360deg)
575+
translateX(100px);
576+
}
577+
}
578+
579+
@keyframes counter-rotate {
580+
0% {
581+
transform: rotateZ(0deg) rotateX(-70deg) rotateY(40deg) scale(1);
582+
opacity: 1;
583+
}
584+
25% {
585+
transform: rotateZ(-90deg) rotateX(-70deg) rotateY(40deg) scale(1.2);
586+
opacity: 1;
587+
}
588+
50% {
589+
transform: rotateZ(-180deg) rotateX(-70deg) rotateY(40deg) scale(0.8);
590+
opacity: 0.3;
591+
}
592+
75% {
593+
transform: rotateZ(-270deg) rotateX(-70deg) rotateY(40deg) scale(0.8);
594+
opacity: 0.3;
595+
}
596+
100% {
597+
transform: rotateZ(-360deg) rotateX(-70deg) rotateY(40deg) scale(1);
598+
opacity: 1;
599+
}
600+
}
601+
}
602+
603+
@layer utilities {
604+
@keyframes orbit-indexes {
605+
0%,
606+
25%,
607+
100% {
608+
z-index: 11;
609+
}
610+
50%,
611+
99% {
612+
z-index: 9;
613+
}
614+
}
615+
}

0 commit comments

Comments
 (0)