This commit is contained in:
Tben
2023-07-19 15:49:15 +01:00
parent b18cbba53d
commit 550d54fdd7
67 changed files with 3098 additions and 2397 deletions
+115
View File
@@ -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>
);
}
+76
View File
@@ -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>
);
}
+6
View File
@@ -0,0 +1,6 @@
header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
+149
View File
@@ -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;
},
}
);
}
+30
View File
@@ -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"
}
]
+42
View File
@@ -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"
}
]
+35
View File
@@ -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>
);
}
+97
View File
@@ -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>
);
}
+12
View File
@@ -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>
);
}
+31
View File
@@ -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>
);
}
+12
View File
@@ -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>
);
}