Skip to content

Commit 0df7afb

Browse files
committed
added loading screen
1 parent 61fcc82 commit 0df7afb

File tree

8 files changed

+161
-26
lines changed

8 files changed

+161
-26
lines changed

src/App.tsx

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,65 @@
11
import { ThemeProvider } from "@/components/theme-provider";
22
import { Header } from "@/components/header";
3-
import { Hero } from "./components/sections/Hero";
4-
import { About } from "@/components/sections/About";
5-
import { Projects } from "@/components/sections/Projects";
63
import { BrowserRouter, Route, Routes, useLocation } from "react-router";
74
import ProjectDetails from "./components/pages/project-details";
8-
import { useEffect } from "react";
95
import Apps from "./components/pages/apps";
106
import AppDetails from "./components/pages/app-details";
117
import { Footer } from "./components/footer";
128
import Policy from "./components/pages/policy";
139
import ProjectsPage from "./components/pages/projects-page";
10+
import Root from "./components/pages/root";
11+
import { useEffect, useState } from "react";
12+
import { ShimmeringText } from "./components/ui/shimmering-text";
13+
import { motion } from "motion/react";
1414

15-
function Root() {
16-
const { state } = useLocation();
15+
function RootLayout() {
16+
const [loading, setLoading] = useState(true);
17+
const [isExiting, setIsExiting] = useState(false);
18+
const location = useLocation();
19+
const isRootPath = location.pathname === "/";
1720

1821
useEffect(() => {
19-
if (state?.id) {
20-
document.getElementById(state.id)?.scrollIntoView({ behavior: "smooth" });
22+
if (!isRootPath) {
23+
setLoading(false);
24+
return;
2125
}
22-
}, [state?.id]);
2326

24-
return (
25-
<>
26-
<Hero />
27-
<Projects />
28-
<About />
29-
</>
30-
);
31-
}
27+
const enterDuration = 800;
28+
const showDuration = 1500;
29+
const exitDuration = 600;
30+
31+
const exitTimer = setTimeout(() => {
32+
setIsExiting(true);
33+
}, enterDuration + showDuration);
34+
35+
const finishTimer = setTimeout(() => {
36+
setLoading(false);
37+
}, enterDuration + showDuration + exitDuration);
38+
39+
return () => {
40+
clearTimeout(exitTimer);
41+
clearTimeout(finishTimer);
42+
};
43+
}, []);
44+
45+
if (loading) {
46+
return (
47+
<div className="min-h-dvh bg-background container mx-auto px-4 flex items-center justify-center">
48+
<motion.div
49+
initial={{ opacity: 0, y: 10 }}
50+
animate={isExiting ? { opacity: 0, y: -10 } : { opacity: 1, y: 0 }}
51+
transition={{ duration: isExiting ? 0.6 : 0.8, ease: "easeInOut" }}
52+
>
53+
<ShimmeringText
54+
text="Loading..."
55+
duration={1}
56+
transition={{ duration: 1 }}
57+
/>
58+
</motion.div>
59+
</div>
60+
);
61+
}
3262

33-
function RootLayout() {
3463
return (
3564
<div className="min-h-screen bg-background container mx-auto px-4">
3665
<div className="mx-auto max-w-4xl">

src/components/motion/threshold-container.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ interface ThresholdContainerProps {
3434
*/
3535
export const ThresholdContainer = ({
3636
children,
37-
threshold = 0.3,
37+
threshold = 0.25,
3838
className,
3939
}: ThresholdContainerProps) => {
4040
const ref = useRef<HTMLDivElement>(null);

src/components/motion/threshold-motion-div.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ interface ThresholdMotionDivProps
4141
*/
4242
const ThresholdMotionDiv = ({
4343
children,
44-
threshold = 0.3,
44+
threshold = 0.25,
4545
onThresholdChange,
4646
animate = { opacity: 1, y: 0 },
4747
initial = { opacity: 0, y: 30 },

src/components/pages/projects-page.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import { useProjects } from "@/hooks/useProjects";
22
import { H1, Lead } from "../ui/typography";
33
import ProjectCard from "../ui/project-card";
4+
import { useEffect } from "react";
45

56
const ProjectsPage = () => {
67
const { projects } = useProjects();
78

9+
useEffect(() => {
10+
window.scrollTo(0, 0);
11+
}, []);
12+
813
return (
914
<div className="min-h-screen flex flex-col gap-8">
1015
<div>

src/components/pages/root.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { useEffect } from "react";
2+
import { About } from "../sections/About";
3+
import { Hero } from "../sections/Hero";
4+
import { Projects } from "../sections/Projects";
5+
import { useLocation } from "react-router";
6+
7+
const Root = () => {
8+
const { state } = useLocation();
9+
10+
useEffect(() => {
11+
if (state?.id) {
12+
document.getElementById(state.id)?.scrollIntoView({ behavior: "smooth" });
13+
}
14+
}, [state?.id]);
15+
16+
return (
17+
<>
18+
<Hero />
19+
<Projects />
20+
<About />
21+
</>
22+
);
23+
};
24+
25+
export default Root;

src/components/sections/Hero.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import profileImage from "@/assets/simon.jpeg";
55
import { useState } from "react";
66
import { Card, CardContent, CardFooter, CardHeader } from "../ui/card";
77
import { Button } from "../ui/button";
8-
import { XIcon } from "lucide-react";
8+
import { ArrowDown, XIcon } from "lucide-react";
99

1010
const DELAY = 0.07;
1111
const DURATION = 0.3;
@@ -157,11 +157,12 @@ export function Hero() {
157157
{...LAYOUT_OPTIONS}
158158
>
159159
<Button
160-
variant="outline"
160+
variant="link"
161161
className="w-full"
162162
onClick={() => handleScroll("about")}
163163
>
164164
More About Me
165+
<ArrowDown />
165166
</Button>
166167
</motion.div>
167168
</CardFooter>
@@ -211,7 +212,7 @@ export function Hero() {
211212
className="mt-12"
212213
>
213214
<Button
214-
variant="outline"
215+
variant="default"
215216
className="w-[min(calc(100vw-2rem),200px)]"
216217
onClick={() => handleScroll("projects")}
217218
>

src/components/ui/featured-project-card.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ const FeaturedProjectCard = ({
3232
)}
3333
<div
3434
className={cn(
35-
"absolute inset-0 bg-gradient-to-t from-black to-transparent",
35+
"absolute inset-0 bg-gradient-to-t from-white/20 dark:from-black to-transparent",
3636
side === "left" ? "bg-gradient-to-tr" : "bg-gradient-to-tl"
3737
)}
3838
></div>
3939

40-
<div
40+
<ThresholdMotionDiv
4141
className={cn(
4242
"absolute bottom-6 z-1 w-[min(calc(100%-2rem),400px)] flex flex-col justify-between gap-3 p-6 backdrop-blur-sm supports-[backdrop-filter]:bg-white/40 dark:supports-[backdrop-filter]:bg-input/90 rounded-xl",
4343
side === "left" ? "left-6" : "right-6"
@@ -83,7 +83,7 @@ const FeaturedProjectCard = ({
8383
)}
8484
</div>
8585
</div>
86-
</div>
86+
</ThresholdMotionDiv>
8787
</ThresholdMotionDiv>
8888
);
8989
};
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import * as React from "react";
2+
import { type HTMLMotionProps, motion, type Transition } from "motion/react";
3+
import { cn } from "@/lib/utils";
4+
5+
type ShimmeringTextProps = {
6+
text: string;
7+
duration?: number;
8+
transition?: Transition;
9+
wave?: boolean;
10+
color?: string;
11+
shimmeringColor?: string;
12+
} & Omit<HTMLMotionProps<"span">, "children">;
13+
function ShimmeringText({
14+
text,
15+
duration = 1,
16+
transition,
17+
wave = false,
18+
className,
19+
color = "var(--color-neutral-500)",
20+
shimmeringColor = "var(--color-neutral-300)",
21+
...props
22+
}: ShimmeringTextProps) {
23+
return (
24+
<motion.span
25+
className={cn("relative inline-block [perspective:500px]", className)}
26+
style={
27+
{
28+
"--shimmering-color": shimmeringColor,
29+
"--color": color,
30+
color: "var(--color)",
31+
} as React.CSSProperties
32+
}
33+
{...props}
34+
>
35+
{text?.split("")?.map((char, i) => (
36+
<motion.span
37+
key={i}
38+
className="inline-block whitespace-pre [transform-style:preserve-3d]"
39+
initial={{
40+
...(wave
41+
? {
42+
scale: 1,
43+
rotateY: 0,
44+
}
45+
: {}),
46+
color: "var(--color)",
47+
}}
48+
animate={{
49+
...(wave
50+
? {
51+
x: [0, 5, 0],
52+
y: [0, -5, 0],
53+
scale: [1, 1.1, 1],
54+
rotateY: [0, 15, 0],
55+
}
56+
: {}),
57+
color: ["var(--color)", "var(--shimmering-color)", "var(--color)"],
58+
}}
59+
transition={{
60+
duration,
61+
repeat: Infinity,
62+
repeatType: "loop",
63+
repeatDelay: text.length * 0.05,
64+
delay: (i * duration) / text.length,
65+
ease: "easeInOut",
66+
...transition,
67+
}}
68+
>
69+
{char}
70+
</motion.span>
71+
))}
72+
</motion.span>
73+
);
74+
}
75+
export { ShimmeringText, type ShimmeringTextProps };

0 commit comments

Comments
 (0)