Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
39b344f
updated Landing.tsx component to mobile friendly
chigoezeh Feb 14, 2025
28608fa
components/Projects.tsx: updating css classes - 01
chigoezeh Feb 14, 2025
8068df1
components/Projects.tsx: updated css class for project list
chigoezeh Feb 14, 2025
e3263d6
components/Projects.tsx: added little padding to project lists
chigoezeh Feb 14, 2025
dfdcd1c
components/Projects.tsx: expanded the selected project box
chigoezeh Feb 14, 2025
feb4a31
components/Projects.tsx: reduced the font size of the selected projec…
chigoezeh Feb 14, 2025
609b217
page.tsx: optimized AnimatePresence - 01
chigoezeh Feb 14, 2025
ce11b75
page.tsx: optimized AnimatePresence - 02
chigoezeh Feb 14, 2025
017b4b3
page.tsx: removed commented out codes
chigoezeh Feb 14, 2025
7047b71
revert to wider box
chigoezeh Feb 28, 2025
dfa0d38
added the wider box for large screen
chigoezeh Feb 28, 2025
3b47d0c
made the action buttons be on the same line
chigoezeh Feb 28, 2025
8a2b3de
added menuOpen variable to Project.tsx
chigoezeh Mar 1, 2025
2158340
introduced new div to render menu on small screens
chigoezeh Mar 1, 2025
1d134a6
added menu button
chigoezeh Mar 1, 2025
7a18636
hide all the project lists
chigoezeh Mar 1, 2025
669d3a1
close menu on mobile after selection
chigoezeh Mar 1, 2025
bab954a
installed react-icons to dependencies
chigoezeh Mar 1, 2025
8c5beff
replaced menu text description with icons
chigoezeh Mar 1, 2025
c4cd1fc
updated button classes to center icons nicely
chigoezeh Mar 1, 2025
3aeb99b
created varibale to hold variants for mobile animation
chigoezeh Mar 1, 2025
5398710
menuVariants: added variants for closing
chigoezeh Mar 1, 2025
405d8a2
menuVariants: implemented smooth animation
chigoezeh Mar 1, 2025
d1e3b00
removed w-full from button to capture the size of the icon
chigoezeh Mar 1, 2025
01c229a
moved the menu icon up to the same row with the go back button
chigoezeh Mar 1, 2025
548e3b8
created isDesktop variable
chigoezeh Mar 1, 2025
0d47245
initialized useEffect
chigoezeh Mar 1, 2025
a6b541e
set isDesktop based on window width: sm breakpoint: 640px
chigoezeh Mar 1, 2025
80124be
implement hndleResize function
chigoezeh Mar 1, 2025
fb99fe1
add the isDesktop check on animate of project list
chigoezeh Mar 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"next": "15.0.2",
"react": "19.0.0-rc-02c0e824-20241028",
"react-dom": "19.0.0-rc-02c0e824-20241028",
"react-icons": "^5.5.0",
"styled-components": "^6.1.13"
},
"devDependencies": {
Expand Down
74 changes: 6 additions & 68 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,42 +18,30 @@ const Home: NextPage = () => {
<AnimatePresence mode="wait">
<motion.div
key={screen}
// initial={{ opacity: 0 }}
// animate={{ opacity: 1 }}
// exit={{ opacity: 0 }}

initial={{ y: "100%" }}
animate={{ y: 0 }}
exit={{ y: "-100%" }}
transition={{ duration: 0.5 }}
className="absolute top-0 left-0 w-screen h-screen bg-cover bg-no-repeat"
style={{
position: "absolute",
top: 0,
left: 0,
backgroundImage: `url("${backgroundImages[screen]}")`,
backgroundRepeat: "no-repeat",
backgroundSize: "cover",
width: "100vw",
height: "100vh",
zIndex: -1,
}}
></motion.div>
</AnimatePresence>

<AnimatePresence mode="wait">
<motion.div style={{ width: "100vw", height: "100vh" }}>
<motion.div className="w-screen h-screen flex items-start">
<motion.div
key={`${screen}-container`}
className={`w-full max-w-${
screen === "projects" ? "4xl" : "3xl"
} ml-auto mr-auto pt-48`}
className={`w-full ${
screen === "projects" ? "max-w-4xl" : "max-w-3xl"
} mx-auto pt-24 sm:pt-48 px-4`}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 20 }}
transition={{ duration: 0.5 }}
style={{
zIndex: 100,
}}
style={{ zIndex: 100 }}
>
{screen === "landing" && <Landing setScreen={setScreen} />}
{screen === "projects" && <Projects setScreen={setScreen} />}
Expand All @@ -62,56 +50,6 @@ const Home: NextPage = () => {
</AnimatePresence>
</>
);
// return (
// <footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center">
// <a
// className="flex items-center gap-2 hover:underline hover:underline-offset-4"
// href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
// target="_blank"
// rel="noopener noreferrer"
// >
// <Image
// aria-hidden
// src="/file.svg"
// alt="File icon"
// width={16}
// height={16}
// />
// Learn
// </a>
// <a
// className="flex items-center gap-2 hover:underline hover:underline-offset-4"
// href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
// target="_blank"
// rel="noopener noreferrer"
// >
// <Image
// aria-hidden
// src="/window.svg"
// alt="Window icon"
// width={16}
// height={16}
// />
// Examples
// </a>
// <a
// className="flex items-center gap-2 hover:underline hover:underline-offset-4"
// href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
// target="_blank"
// rel="noopener noreferrer"
// >
// <Image
// aria-hidden
// src="/globe.svg"
// alt="Globe icon"
// width={16}
// height={16}
// />
// Go to nextjs.org →
// </a>
// </footer>
// </div>
// );
};

export default Home;
21 changes: 11 additions & 10 deletions src/lib/components/Landing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ export const Landing: React.FC<{
setScreen: (screen: "landing" | "projects") => void;
}> = ({ setScreen }) => {
return (
<motion.div className="w-2/3 ml-auto mr-auto">
<motion.div className="relative p-8 pb-2 opacity-90 border-2 bg-[#1e1e1e] border-[#323232] flex flex-col items-start justify-start overflow-hidden rounded-xl shadow-md">
<span className="text-2xl font-semibold text-white mb-4">
<motion.div className="lg:w-full sm:w-2/3 mx-auto px-4">
<motion.div className="relative p-4 sm:p-8 pb-2 opacity-90 border-2 bg-[#1e1e1e] border-[#323232] flex flex-col items-start justify-start overflow-hidden rounded-xl shadow-md">
<span className="text-xl sm:text-2xl font-semibold text-white mb-4">
Hi, I{"'"}m Dylan
</span>
<motion.div>
<motion.div className="text-sm sm:text-base">
I’m a software engineer with hands-on experience building digital
products since I was a teenager. My early work led me to tech roles at
an e-commerce company that later sold and then into a YC-backed
Expand All @@ -27,27 +27,28 @@ export const Landing: React.FC<{
allowing teams to focus on delivering real value efficiently and adapt
to evolving challenges.
</motion.div>
{/* <Image
{/* Uncomment and adjust if needed:
<Image
src="/me-irl.png"
alt="me-irl"
width={200}
height={200}
className="rounded-full mr-auto ml-auto"
className="rounded-full mx-auto"
/> */}
<motion.div className="flex items-center gap-4 ml-auto mr-0 mt-8">
<motion.div className="flex items-center gap-4 mt-8 self-end">
<SocialLinks />
</motion.div>
</motion.div>
<motion.div className="flex items-center justify-center mt-4 z-100">
<motion.div className="flex flex-row items-center justify-center mt-4 z-10 gap-4">
<button
className="bg-black/60 border-2 border-black/10 text-white p-2 rounded-md mr-4"
className="bg-black/60 border-2 border-black/10 text-white p-2 rounded-md"
onClick={() => {
setScreen("projects");
}}
>
Resume
</button>
<a href={CALENDLY_LINK} target="_blank">
<a href={CALENDLY_LINK} target="_blank" rel="noopener noreferrer">
<button className="bg-black/60 border-2 border-black/10 text-white p-2 rounded-md">
Book a call
</button>
Expand Down
71 changes: 60 additions & 11 deletions src/lib/components/Projects.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { motion } from "framer-motion";
import { useState } from "react";
import { useEffect, useState } from "react";
import {
ATVsNetWeb,
DigiBuild,
PolitechAI,
SouffleClub,
TrustedFor,
} from "./ProjectDescriptions";
import { AiOutlineClose, AiOutlineMenu } from "react-icons/ai";
// import Image from "next/image";

const projects: Record<string, React.FC | React.ReactElement> = {
Expand All @@ -17,50 +18,98 @@ const projects: Record<string, React.FC | React.ReactElement> = {
"Politech.ai": PolitechAI,
};

const menuVariants = {
open: {
opacity: 1,
height: "auto",
transition: { duration: 0.3, ease: "easeInOut" },
},
closed: {
opacity: 0,
height: 0,
transition: { duration: 0.3, ease: "easeInOut" },
},
};

export const Projects: React.FC<{
setScreen: (screen: "landing" | "projects") => void;
}> = ({ setScreen }) => {
const [selectedProject, setSelectedProject] = useState<string>("Politech.ai");
const [menuOpen, setMenuOpen] = useState<boolean>(false);
const [isDesktop, setIsDesktop] = useState<boolean>(false);
const ProjectDescription = projects[selectedProject];

useEffect(() => {
const handleResize = () => {
setIsDesktop(window.innerWidth >= 640);
};

handleResize();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);

return (
<>
<motion.div className="flex mt-4 w-3/4 justify-end ml-auto mr-auto mb-4">
<motion.div className="flex mt-4 w-full sm:w-3/4 mx-auto mb-4 px-4 justify-between items-center">
<div className="sm:hidden">
<button
className="bg-black/60 border-2 border-black/10 text-white p-2 rounded-md flex items-center justify-center"
onClick={() => setMenuOpen(!menuOpen)}
>
{menuOpen ? (
<AiOutlineClose size={24} />
) : (
<AiOutlineMenu size={24} />
)}
</button>
</div>
<button
className="bg-black/60 border-2 border-black/10 text-white p-2 rounded-md"
onClick={() => setScreen("landing")}
>
Go Back
</button>
</motion.div>

<motion.div
key="projects-internal-container"
className="flex w-3/4 ml-auto mr-auto"
className="flex flex-col sm:flex-row w-full sm:w-3/4 mx-auto px-4"
>
<motion.div className="w-1/3 mr-4 mt-2">
<motion.div
variants={menuVariants}
initial="closed"
animate={isDesktop ? "open" : menuOpen ? "open" : "closed"}
className="overflow-hidden w-full sm:w-1/3 mr-0 sm:mr-4 mt-2 mb-4 sm:mb-0"
>
{Object.keys(projects)
.reverse()
.map((project, idx) => (
<button
key={`project-${idx}`}
className="opacity-90 border-2 bg-[#1e1e1e] border-[#323232] w-full mb-2 hover:opacity-100 transition-opacity duration-300 rounded-md"
onClick={() => setSelectedProject(project)}
className="opacity-90 border-2 bg-[#1e1e1e] border-[#323232] w-full mb-2 hover:opacity-100 transition-opacity duration-300 rounded-md p-2"
onClick={() => {
setSelectedProject(project);
setMenuOpen(false);
}}
>
{project}
</button>
))}
</motion.div>

<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 0.9, y: 0 }}
exit={{ opacity: 0, y: 20 }}
transition={{ duration: 0.3 }}
key={`project-description-${selectedProject}`}
className="w-2/3 relative p-8 opacity-90 border-2 bg-[#1e1e1e] border-[#323232] flex flex-col items-start justify-start overflow-y-scroll overflow-x-hidden rounded-xl shadow-md"
style={{
maxHeight: "60vh",
}}
className="w-full sm:w-2/3 relative p-4 sm:p-8 opacity-90 border-2 bg-[#1e1e1e] border-[#323232] flex flex-col items-start justify-start overflow-y-scroll overflow-x-hidden rounded-xl shadow-md"
style={{ maxHeight: "60vh" }}
>
<h1 className="text-2xl font-bold mb-4">{selectedProject}</h1>
<h1 className="text-xl sm:text-2xl font-bold mb-4">
{selectedProject}
</h1>
{/* @ts-expect-error ProjectDescription is a React.FC or React.ReactElement but TS doesn't care and doesn't want to render it */}
<ProjectDescription />
</motion.div>
Expand Down
26 changes: 23 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2939,6 +2939,11 @@ react-dom@19.0.0-rc-02c0e824-20241028:
dependencies:
scheduler "0.25.0-rc-02c0e824-20241028"

react-icons@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.5.0.tgz#8aa25d3543ff84231685d3331164c00299cdfaf2"
integrity sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==

react-is@^16.13.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
Expand Down Expand Up @@ -3194,8 +3199,16 @@ string-convert@^0.2.0:
resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97"
integrity sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==

"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
name string-width-cjs
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"

string-width@^4.1.0:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
Expand Down Expand Up @@ -3276,7 +3289,14 @@ string.prototype.trimstart@^1.0.8:
define-properties "^1.2.1"
es-object-atoms "^1.0.0"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"

strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
Expand Down