feat: add animate quote at about page

This commit is contained in:
Alvalen 2024-07-01 15:41:21 +07:00
parent e605b2e975
commit 93eb451880
5 changed files with 167 additions and 1 deletions

View file

@ -100,7 +100,12 @@ const MyPage = () => {
type: "spring", type: "spring",
}}> }}>
<Button variation="primary"> <Button variation="primary">
<Link href={"/docs/cv.pdf"}> <Link
href={"/docs/cv.pdf"}
target="_blank"
rel="noopener noreferrer"
locale={false}
download>
Download CV Download CV
</Link> </Link>
</Button> </Button>

View file

@ -0,0 +1,63 @@
// Quote.js
import "./style.css";
import { motion } from "framer-motion";
import { useIntersectionObserver } from "./useIntersectionObserver";
export default function Quote() {
const text1 = '"There are no limits to what you can accomplish'.split(" ");
const text2 = 'except the limits you place on your own thinking."'.split(
" "
);
const [ref, isIntersecting] = useIntersectionObserver();
return (
<div ref={ref} className="text-center">
<h3 className="text-[2rem]">
{text1.map((word, index) => (
<motion.span
key={index}
initial={{
opacity: 0,
filter: "blur(4px)",
scale: 0.92,
}}
animate={{
opacity: isIntersecting ? 1 : 0,
filter: isIntersecting ? "blur(0px)" : "blur(4px)",
scale: isIntersecting ? 1 : 0.92,
}}
transition={{
delay: isIntersecting ? index * 0.1 : 0,
duration: 0.5,
}}>
{word}{" "}
</motion.span>
))}
</h3>
<h3 className="text-xl">
{text2.map((word, index) => (
<motion.span
key={index + text1.length}
initial={{
opacity: 0,
filter: "blur(4px)",
scale: 0.92,
}}
animate={{
opacity: isIntersecting ? 1 : 0,
filter: isIntersecting ? "blur(0px)" : "blur(4px)",
scale: isIntersecting ? 1 : 0.92,
}}
transition={{
delay: isIntersecting
? (text1.length + index) * 0.1
: 0,
duration: 0.5,
}}>
{word}{" "}
</motion.span>
))}
</h3>
</div>
);
}

View file

@ -0,0 +1,45 @@
@keyframes scale {
100% {
transform: scale(1);
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
}
}
@keyframes fade-in {
100% {
opacity: 1;
filter: blur(0);
-webkit-filter: blur(0);
}
}
.q-wrap {
display: inline-block;
opacity: 1;
filter: blur(4px);
-webkit-filter: blur(4px);
}
.q-wrap:nth-child(1) {
animation: fade-in 0.8s 0.1 forwards cubic-bezier(0.11, 0, 0.5, 0);
-webkit-animation: fade-in 0.8s 0.1 forwards cubic-bezier(0.11, 0, 0.5, 0);
}
.q-wrap:nth-child(2) {
animation: fade-in 0.8s 0.2 forwards cubic-bezier(0.11, 0, 0.5, 0);
-webkit-animation: fade-in 0.8s 0.2 forwards cubic-bezier(0.11, 0, 0.5, 0);
}
.q {
text-align: center;
transform: scale(0.92);
-webkit-transform: scale(0.92);
-moz-transform: scale(0.92);
-ms-transform: scale(0.92);
-o-transform: scale(0.92);
animation: scale 3s forwards cubic-bezier(0.5, 1, 0.89, 1);
-webkit-animation: scale 3s forwards cubic-bezier(0.5, 1, 0.89, 1);
}

View file

@ -0,0 +1,32 @@
// useIntersectionObserver.js
import { useEffect, useState, useRef } from "react";
export function useIntersectionObserver() {
const [isIntersecting, setIsIntersecting] = useState(false);
const ref = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
setIsIntersecting(entry.isIntersecting);
},
{
root: null,
rootMargin: "0px",
threshold: 0.1,
}
);
if (ref.current) {
observer.observe(ref.current);
}
return () => {
if (ref.current) {
observer.unobserve(ref.current);
}
};
}, []);
return [ref, isIntersecting];
}

View file

@ -8,6 +8,7 @@ import FixedButon from "@/components/FixedButton";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronLeft } from "@fortawesome/free-solid-svg-icons"; import { faChevronLeft } from "@fortawesome/free-solid-svg-icons";
import Card from "./(spotify)/card.jsx"; import Card from "./(spotify)/card.jsx";
import Quote from "./(quote)/quote.jsx";
// images // images
import Me1 from "@/public/img/me1.jpg"; import Me1 from "@/public/img/me1.jpg";
@ -453,6 +454,26 @@ export default function Page() {
</p> </p>
</motion.div> </motion.div>
</div> </div>
<div className="min-h-[80vh] w-screen mx-auto container p-10 grid grid-cols-1 mt-10 ">
<motion.div
className="flex justify-center items-center flex-col mb-5 "
initial={{
opacity: 0,
scale: 0.9,
}}
whileInView={{
opacity: 1,
scale: 1,
}}
transition={{
delay: 0.6,
duration: 2,
ease: [0.22, 1, 0.36, 1],
}}>
<Quote />
</motion.div>
</div>
</main> </main>
</> </>
); );