updates
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import TextShuffler from "../../components/actions/TextShuffler";
|
||||
import { about } from "../(utils)/animate";
|
||||
|
||||
export default function AboutSection() {
|
||||
React.useEffect(about, []);
|
||||
|
||||
const webDevStack = require("../(utils)/web-dev-stack.json");
|
||||
const uiStack = require("../(utils)/ui-ux-stack.json");
|
||||
|
||||
const [targetStack, setTargetStack] = React.useState("dev");
|
||||
|
||||
return (
|
||||
<div
|
||||
className="max-w-6xl w-full flex flex-col items-center pb-40"
|
||||
id="about-section"
|
||||
>
|
||||
{/* <span
|
||||
className="text-[300px] uppercase absolute whitespace-nowrap opacity-5 -mt-64 z-[-1]"
|
||||
id="about-me-label"
|
||||
>
|
||||
About Me
|
||||
</span> */}
|
||||
<div className="h-44"></div>
|
||||
|
||||
<div className="flex flex-col xl:flex-row w-full gap-8">
|
||||
<div className="w-full xl:w-[40%]">
|
||||
<h2>
|
||||
<TextShuffler textInput="About Me" />
|
||||
</h2>
|
||||
|
||||
<div className="flex flex-col-reverse xl:flex-col items-start gap-4">
|
||||
<div className="flex flex-col w-full gap-2">
|
||||
<div
|
||||
className={"p-4 cursor-pointer hover:opacity-60" + (targetStack.match(/dev/i) ? " bg-[#343680] w-full xl:w-[120%]" : " w-full border border-solid border-white/10")}
|
||||
onClick={() => {
|
||||
setTargetStack("dev");
|
||||
}}
|
||||
>
|
||||
<div>Web Dev Stack</div>
|
||||
</div>
|
||||
<div
|
||||
className={"p-4 cursor-pointer hover:opacity-60" + (targetStack.match(/design/i) ? " bg-[#343680] w-full xl:w-[120%]" : " w-full border border-solid border-white/10")}
|
||||
onClick={() => {
|
||||
setTargetStack("design");
|
||||
}}
|
||||
>
|
||||
<div>UI/UX Stack</div>
|
||||
</div>
|
||||
</div>
|
||||
<span className="hero-sub-text">
|
||||
<TextShuffler
|
||||
textInput="Quick learner, adaptable, problem solver, curious. I strive to know the system, rather than the status quo. My credo is: no problem too great, no knowledge too vast, no logic too complex. I thrive in difficult situations and complex hurdles: problem solving is now second nature to me: if you can think it, it can be done."
|
||||
delay={500}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<a
|
||||
href="/about"
|
||||
className="button"
|
||||
>
|
||||
Learn More About Me
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full xl:w-[60%] bg-[#343680] px-4 md:px-6 py-2">
|
||||
<section>
|
||||
<h3>
|
||||
<TextShuffler textInput={targetStack?.match(/dev/i) ? "Web Dev Tech Stack" : "UI/UX tech stack"} />
|
||||
</h3>
|
||||
<hr />
|
||||
<ul style={{ maxWidth: "800px" }}>
|
||||
{targetStack?.match(/dev/i) ? (
|
||||
<React.Fragment>
|
||||
{webDevStack.map((item: { title: string; description: string }, index: number) => (
|
||||
<li
|
||||
key={index}
|
||||
className="mb-4"
|
||||
>
|
||||
<h4 className="m-0">
|
||||
<TextShuffler textInput={item.title} />
|
||||
</h4>
|
||||
<span className="opacity-80">
|
||||
<TextShuffler textInput={item.description} />
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
{uiStack.map((item: { title: string; description: string }, index: number) => (
|
||||
<li
|
||||
key={index}
|
||||
className="mb-4"
|
||||
>
|
||||
<h4 className="m-0">
|
||||
<TextShuffler textInput={item.title} />
|
||||
</h4>
|
||||
<span className="opacity-80">
|
||||
<TextShuffler textInput={item.description} />
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</React.Fragment>
|
||||
)}
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import TextShuffler from "../../components/actions/TextShuffler";
|
||||
import { hero } from "../(utils)/animate";
|
||||
|
||||
export default function Hero() {
|
||||
React.useEffect(hero, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex flex-col xl:flex-row items-center gap-0 justify-center -mt-[120px] xl:-mt-[160px] w-full relative pt-[450px] md:pt-0">
|
||||
<div
|
||||
className="rounded-full max-w-[450px] absolute md:relative top-0 flex items-center md:items-start justify-center mr-0 xl:-mr-14 bg-[#3e3f9c] overflow-hidden"
|
||||
id="main-image"
|
||||
>
|
||||
<Image
|
||||
src="/images/my-photo.png"
|
||||
// fill
|
||||
width={500}
|
||||
height={562}
|
||||
objectFit="contain"
|
||||
alt="Benjamin Toby Image"
|
||||
className="contrast-[140%] grayscale mt-20 flex items-center justify-center"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="max-w-2xl relative z-10 mt-10 w-full"
|
||||
id="hero-text-section"
|
||||
>
|
||||
<h1
|
||||
className="text-5xl leading-snug"
|
||||
id="hero-text"
|
||||
>
|
||||
{/* Hi */}
|
||||
{/* Fullstack developer, UI/UX designer, Software Engineer, welcome */}
|
||||
<TextShuffler
|
||||
textInput="I'm Benjamin Toby, a Software Engineer and UI/UX expert"
|
||||
delay={500}
|
||||
/>
|
||||
</h1>
|
||||
|
||||
<div className="gap-4 flex items-center">
|
||||
<a
|
||||
href="/documents/Resume-Benjamin-Toby-Linkedin.pdf"
|
||||
download={true}
|
||||
className="button"
|
||||
>
|
||||
See my resume
|
||||
</a>
|
||||
<a
|
||||
href="https://www.linkedin.com/in/benjamin-toby/"
|
||||
target="_blank"
|
||||
className="button"
|
||||
>
|
||||
Linkedin
|
||||
</a>
|
||||
<a
|
||||
href="/contact"
|
||||
style={{
|
||||
backgroundColor: "transparent",
|
||||
color: "white",
|
||||
border: "2px solid white",
|
||||
}}
|
||||
className="button"
|
||||
>
|
||||
Contact Me
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
import { gsap } from "gsap";
|
||||
import ScrollTrigger from "gsap/ScrollTrigger";
|
||||
import TextPlugin from "gsap/TextPlugin";
|
||||
|
||||
/**
|
||||
* Register plugins
|
||||
*/
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
gsap.registerPlugin(TextPlugin);
|
||||
|
||||
/**
|
||||
* Animates the hero section
|
||||
*/
|
||||
export function hero() {
|
||||
/**
|
||||
* Animate hero section
|
||||
*/
|
||||
gsap.fromTo(
|
||||
"#main-image",
|
||||
{
|
||||
z: -100,
|
||||
scale: 1.2,
|
||||
},
|
||||
{
|
||||
z: 0,
|
||||
duration: 1.5,
|
||||
scale: 1,
|
||||
}
|
||||
);
|
||||
|
||||
gsap.fromTo(
|
||||
"#hero-text-section",
|
||||
{
|
||||
z: -100,
|
||||
scale: 1.2,
|
||||
},
|
||||
{
|
||||
z: 0,
|
||||
duration: 2.5,
|
||||
scale: 1,
|
||||
}
|
||||
);
|
||||
|
||||
gsap.fromTo(
|
||||
"#main-image",
|
||||
{
|
||||
y: 0,
|
||||
// scale: 1,
|
||||
},
|
||||
{
|
||||
scrollTrigger: {
|
||||
scrub: 1,
|
||||
},
|
||||
y: 150,
|
||||
// scale: 0.8,
|
||||
}
|
||||
);
|
||||
|
||||
gsap.fromTo(
|
||||
"#hero-text-section",
|
||||
{
|
||||
y: 0,
|
||||
// scale: 1,
|
||||
},
|
||||
{
|
||||
scrollTrigger: {
|
||||
scrub: 2,
|
||||
},
|
||||
y: 100,
|
||||
// scale: 0.8,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the about section
|
||||
*/
|
||||
export function about() {
|
||||
gsap.fromTo(
|
||||
"#about-section",
|
||||
{
|
||||
y: 40,
|
||||
scale: 0.8,
|
||||
},
|
||||
{
|
||||
scrollTrigger: {
|
||||
scrub: 4,
|
||||
},
|
||||
y: 0,
|
||||
scale: 1.1,
|
||||
}
|
||||
);
|
||||
|
||||
gsap.to("#about-me-label", {
|
||||
scrollTrigger: {
|
||||
scrub: 2,
|
||||
},
|
||||
y: 300,
|
||||
scale: 0.8,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the about section
|
||||
*/
|
||||
export function genericScroll() {
|
||||
gsap.fromTo(
|
||||
".generic-scroll",
|
||||
{
|
||||
y: 0,
|
||||
scale: 0.9,
|
||||
},
|
||||
{
|
||||
scrollTrigger: {
|
||||
scrub: 3,
|
||||
},
|
||||
y: 100,
|
||||
scale: 1,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the about section
|
||||
*/
|
||||
export function appear() {
|
||||
gsap.fromTo(
|
||||
".appear",
|
||||
{
|
||||
y: 40,
|
||||
scale: 0.8,
|
||||
opacity: 0,
|
||||
},
|
||||
{
|
||||
y: 0,
|
||||
scale: 1,
|
||||
opacity: 1,
|
||||
duration: 2,
|
||||
delay: (i, target) => {
|
||||
const datasetDelay = target?.dataset?.delay;
|
||||
|
||||
if (datasetDelay) {
|
||||
return datasetDelay;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
[
|
||||
{
|
||||
"title": "Adobe Photoshop",
|
||||
"description": "Web design, image manipulation, image compositing, and more."
|
||||
},
|
||||
{
|
||||
"title": "Adobe Illustrator",
|
||||
"description": "Vector graphic of all types"
|
||||
},
|
||||
{
|
||||
"title": "Figma",
|
||||
"description": "Web, UI, UX design."
|
||||
},
|
||||
{
|
||||
"title": "Affinity Designer",
|
||||
"description": "Vector graphics."
|
||||
},
|
||||
{
|
||||
"title": "After Effects",
|
||||
"description": "Motion graphics and animation"
|
||||
},
|
||||
{
|
||||
"title": "Adobe XD",
|
||||
"description": "UI/UX design"
|
||||
},
|
||||
{
|
||||
"title": "Webflow",
|
||||
"description": "Visual Web coding"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,42 @@
|
||||
[
|
||||
{
|
||||
"title": "HTML, CSS, Javascript",
|
||||
"description": "The basics, the bedrock of all websites."
|
||||
},
|
||||
{
|
||||
"title": "HTML, CSS, Javascript",
|
||||
"description": "The basics, the bedrock of all websites."
|
||||
},
|
||||
{
|
||||
"title": "React JS",
|
||||
"description": "JavaScript library for high-performance web applications"
|
||||
},
|
||||
{
|
||||
"title": "Next JS",
|
||||
"description": "High performance React and Node js web framework for building blazing flast and performant web applications"
|
||||
},
|
||||
{
|
||||
"title": "Tailwind CSS",
|
||||
"description": "Lighting fast mobile first styling"
|
||||
},
|
||||
{
|
||||
"title": "Node JS",
|
||||
"description": "JavaScript runtime for the server. For creating backend architectures and APIs"
|
||||
},
|
||||
{
|
||||
"title": "Ubuntu Linux",
|
||||
"description": "Secure server management with ubuntu and Linux"
|
||||
},
|
||||
{
|
||||
"title": "Nginx",
|
||||
"description": "Super secure web server, reverse proxy and load balancer"
|
||||
},
|
||||
{
|
||||
"title": "MySQL",
|
||||
"description": "Tried and tested data storage, querying, and management."
|
||||
},
|
||||
{
|
||||
"title": "Git and Github",
|
||||
"description": "Version control"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,35 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import TextShuffler from "../../../components/actions/TextShuffler";
|
||||
import { appear, genericScroll } from "../../(utils)/animate";
|
||||
|
||||
export default function Hero() {
|
||||
React.useEffect(genericScroll, []);
|
||||
React.useEffect(appear, []);
|
||||
|
||||
return (
|
||||
<div className="-mt-10 appear">
|
||||
<div
|
||||
className="flex flex-col items-start gap-0 max-w-6xl w-full relative generic-scroll"
|
||||
// id="hero-text-section"
|
||||
>
|
||||
<span className="text-primary-light text-lg">
|
||||
<TextShuffler textInput="About Me" />
|
||||
</span>
|
||||
<h1
|
||||
className="text-5xl leading-snug"
|
||||
id="hero-text"
|
||||
>
|
||||
<TextShuffler textInput="Ben of All Trade, Master of All" />
|
||||
</h1>
|
||||
<span className="hero-sub-text">
|
||||
<TextShuffler
|
||||
textInput="Quick learner, adaptable, problem solver, curious. I strive to know the system, rather than the status quo. My credo is: no problem too great, no knowledge too vast, no logic too complex. I thrive in difficult situations and complex hurdles: problem solving is now second nature to me: if you can think it, it can be done."
|
||||
delay={1000}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import TextShuffler from "../../../components/actions/TextShuffler";
|
||||
import { appear, genericScroll } from "../../(utils)/animate";
|
||||
|
||||
export default function MoreAboutMe() {
|
||||
React.useEffect(genericScroll, []);
|
||||
React.useEffect(appear, []);
|
||||
|
||||
const webDevStack = require("../../(utils)/web-dev-stack.json");
|
||||
const uiStack = require("../../(utils)/ui-ux-stack.json");
|
||||
|
||||
const [targetStack, setTargetStack] = React.useState("dev");
|
||||
|
||||
return (
|
||||
<div className="max-w-6xl w-full flex flex-col items-center pb-40 generic-scroll">
|
||||
<div className="h-20"></div>
|
||||
|
||||
<div
|
||||
className="flex flex-col w-full gap-8 appear"
|
||||
data-delay={2}
|
||||
>
|
||||
<div className="w-full">
|
||||
<h2>
|
||||
<TextShuffler textInput="More About Me" />
|
||||
</h2>
|
||||
|
||||
<div className="flex flex-col items-start gap-4">
|
||||
<div className="flex w-full gap-4">
|
||||
<div
|
||||
className={"p-4 cursor-pointer hover:opacity-60 grow" + (targetStack.match(/dev/i) ? " bg-[#343680]" : " border border-solid border-white/10")}
|
||||
onClick={() => {
|
||||
setTargetStack("dev");
|
||||
}}
|
||||
>
|
||||
<div>Web Dev Stack</div>
|
||||
</div>
|
||||
<div
|
||||
className={"p-4 cursor-pointer hover:opacity-60 grow" + (targetStack.match(/design/i) ? " bg-[#343680]" : " border border-solid border-white/10")}
|
||||
onClick={() => {
|
||||
setTargetStack("design");
|
||||
}}
|
||||
>
|
||||
<div>UI/UX Stack</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full bg-[#343680] px-4 md:px-6 py-2">
|
||||
<section>
|
||||
<h3>
|
||||
<TextShuffler textInput={targetStack?.match(/dev/i) ? "Web Dev Tech Stack" : "UI/UX tech stack"} />
|
||||
</h3>
|
||||
<hr />
|
||||
<ul style={{ maxWidth: "800px" }}>
|
||||
{targetStack?.match(/dev/i) ? (
|
||||
<React.Fragment>
|
||||
{webDevStack.map((item: { title: string; description: string }, index: number) => (
|
||||
<li
|
||||
key={index}
|
||||
className="mb-4"
|
||||
>
|
||||
<h4 className="m-0">
|
||||
<TextShuffler textInput={item.title} />
|
||||
</h4>
|
||||
<span className="opacity-80">
|
||||
<TextShuffler textInput={item.description} />
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
{uiStack.map((item: { title: string; description: string }, index: number) => (
|
||||
<li
|
||||
key={index}
|
||||
className="mb-4"
|
||||
>
|
||||
<h4 className="m-0">
|
||||
<TextShuffler textInput={item.title} />
|
||||
</h4>
|
||||
<span className="opacity-80">
|
||||
<TextShuffler textInput={item.description} />
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</React.Fragment>
|
||||
)}
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
import MoreAboutMe from "./(components)/MoreAboutMe";
|
||||
import Hero from "./(components)/Hero";
|
||||
|
||||
export default function AboutPage() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Hero />
|
||||
<MoreAboutMe />
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// General imports
|
||||
import { Metadata } from "next";
|
||||
import GeneralLayout from "../layouts/general_layout/GeneralLayout";
|
||||
|
||||
// Styles imports
|
||||
import "../styles/main.css";
|
||||
import "../styles/tw_main.css";
|
||||
|
||||
// Metadata
|
||||
export const metadata: Metadata = {
|
||||
title: "Homepage",
|
||||
description: "Software engineer, UI/UX designer, Full Stack Web Developer, Web/graphic/motion designer, React Developer, Next JS developer, Node JS developer, Javascript Developer, Linux Ubuntu, DevOps, Nginx, MySQL developer, Freelancer",
|
||||
keywords: "UI/UX designer, Full Stack Web Developer, Web/graphic/motion designer, React Developer, NextJS developer, Node JS developer, Javascript Developer, Linux Ubuntu, DevOps, Nginx, MySQL developer, Freelancer",
|
||||
};
|
||||
|
||||
// Main Layout Component
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script
|
||||
src="/scripts/main.js"
|
||||
defer
|
||||
></script>
|
||||
</head>
|
||||
<body>
|
||||
<GeneralLayout>{children}</GeneralLayout>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
import Hero from "./(components)/Hero";
|
||||
import AboutSection from "./(components)/AboutSection";
|
||||
|
||||
export default function Homepage() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Hero />
|
||||
<AboutSection />
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user