@anishpras/create-portfolio
Version:
🏗 Personal CLI to bootstrap new portfolio from the given templates.
317 lines (295 loc) • 9.34 kB
JavaScript
import { useEffect, useState, useRef } from "react";
import { data } from "../data";
import Head from "next/head";
import IntroOverlay from "../components/introOverlay";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/dist/ScrollTrigger";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronDown } from "@fortawesome/free-solid-svg-icons";
import { motion } from "framer-motion";
import Link from "next/link";
export default function Home({ project }) {
const [animationComplete, setAnimationComplete] = useState(false);
const projectsRef = useRef(null);
const completeAnimation = () => {
setAnimationComplete(true);
document.body.style.overflowY = "auto";
};
const executeScroll = () => projectsRef.current.scrollIntoView();
const scrollToProject = () => {
if (typeof window !== "undefined") {
if (project) {
// Use the hash to find the first element with that id
const element = document.getElementById(project);
if (element) {
// Smooth scroll to that elment
element.scrollIntoView();
}
}
}
};
useEffect(() => {
// Inner Page height for mobile devices
let vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty("--vh", `${vh}px`);
// GSAP animation
gsap.registerPlugin(ScrollTrigger);
let tl = gsap.timeline();
let projects = gsap.utils.toArray(".project");
let mediaQuery = window.matchMedia("(min-width: 967px)");
const homeAnimation = (animation) => {
if (!project) {
tl.to(".ball", {
duration: 2,
y: "100vh",
ease: "bounce.out",
})
.to(".ball", {
duration: 1,
scale: 30,
ease: "power3.out",
onComplete: animation,
})
.from(".after-animation", {
duration: 0.8,
opacity: 0,
ease: "power3.out",
})
.from(".title", {
duration: 0.5,
y: 100,
delay: 0.2,
opacity: 0,
ease: "power3.out",
})
.from(".peep-image", {
duration: 0.5,
y: 100,
opacity: 0,
ease: "power3.out",
})
.from(".job-title", {
duration: 0.5,
y: 100,
opacity: 0,
ease: "power3.out",
})
.from(".scroll-indicator", {
duration: 0.5,
y: 100,
opacity: 0,
ease: "power3.out",
});
} else {
completeAnimation();
scrollToProject();
}
if (mediaQuery.matches) {
projects.forEach((project) => {
let tlProject = gsap.timeline({
scrollTrigger: {
trigger: project,
start: "top center",
end: "center center",
scrub: 1,
},
});
let projectImage = project.querySelector("img");
let projectInfo = project.querySelector(".project-info");
tlProject
.from(projectImage, {
x: -300,
opacity: 0,
})
.from(projectInfo, {
x: 300,
opacity: 0,
});
});
} else {
projects.forEach((project) => {
let tlProject = gsap.timeline({
scrollTrigger: {
trigger: project,
start: "top center",
end: "center center",
scrub: 1,
},
});
let projectImage = project.querySelector("img");
let projectInfo = project.querySelector(".project-info");
tlProject
.from(projectImage, {
y: 100,
opacity: 0,
})
.from(projectInfo, {
y: 100,
opacity: 0,
});
});
}
let tlFooter = gsap.timeline({
scrollTrigger: {
trigger: "footer",
start: "top center",
end: "top top",
scrub: 1,
},
});
tlFooter
.from("footer h2", {
y: 100,
opacity: 0,
duration: 0.6,
})
.from("footer .footer-links", {
y: 100,
opacity: 0,
duration: 0.6,
});
};
homeAnimation(completeAnimation);
}, []);
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="container">
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charSet="utf-8" />
<meta
name="description"
content={data.seo.description}></meta>
<meta property="og:url" content={data.seo.url} />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en" />
<meta property="og:image" content={data.seo.image} />
<title>{data.seo.title}</title>
<link rel="icon" href={data.seo.favicon} />
</Head>
{animationComplete === false && <IntroOverlay />}
<div className="after-animation">
<header>
<nav className="home-nav">
<div className="space-between">
<Link href="/">
<div className="logo">{data.initial}</div>
</Link>
<ul className="nav-list">
<li>
<motion.a
href={data.resumeUrl}
target="_blank"
rel="noopener noreferrer"
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
title="Download Resume">
Resume
</motion.a>
</li>
</ul>
</div>
</nav>
</header>
<main className="main-home">
<div className="cta">
<h1 className="title">
I create<span className="playful"> playful </span> experiences.
</h1>
<img
src="/images/My_Peep.png"
alt="My Peep"
className="peep-image"
/>
</div>
<p className="job-title">
<span className="text-reveal">
{`${data.name} / ${data.position}`}
</span>
</p>
<button className="scroll-indicator" onClick={executeScroll}>
<span>Projects</span>
<FontAwesomeIcon icon={faChevronDown} />
</button>
</main>
<div className="project-container" ref={projectsRef}>
{data.projectsList.map(
({
name,
description,
image,
mobileImage,
link,
project,
GitHub,
tools,
index,
}) => (
<div className="project" key={index} id={project}>
<picture>
<source srcSet={image} media="(min-width: 1280px)" />
<img className="project-image" src={mobileImage} alt={name} />
</picture>
<div className="project-info">
<h2>{name}</h2>
{description.split("\n").map((str, index) => (
<p key={index}>{str}</p>
))}
<h3>Tools used:</h3>
<ul className="tools-list">
{tools.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
<motion.div className="project-btns">
<motion.a
href={link}
target="_blank"
rel="noopener noreferrer"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
title={`Open site of ${name}`}
className="project-btn">
Open Site
</motion.a>
{GitHub && (
<motion.a
href={GitHub}
target="_blank"
rel="noopener noreferrer"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
title={`View Code for ${name}`}
className="project-btn">
View Code
</motion.a>
)}
</motion.div>
</div>
</div>
)
)}
</div>
<footer>
<h2>Connect with Me</h2>
<ul className="footer-links">
<li>
<motion.a
href={data.resumeUrl}
target="_blank"
rel="noopener noreferrer"
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
title="Download Resume">
Resume
</motion.a>
</li>
</ul>
</footer>
</div>
</motion.div>
);
}