This commit is contained in:
Benjamin Toby 2023-10-24 18:59:00 +01:00
parent d163438f7b
commit b9364a702c
68 changed files with 4701 additions and 4697 deletions

8
.gitignore vendored
View File

@ -1,5 +1,5 @@
node_modules node_modules
.next .next
node_shell node_shell
.env .env
/dump /dump

View File

@ -1,20 +1,20 @@
# Set Node.js version # Set Node.js version
FROM node:16 FROM node:16
# Set working directory # Set working directory
WORKDIR /usr/src/app WORKDIR /usr/src/app
# Copy package.json and package-lock.json # Copy package.json and package-lock.json
COPY package*.json ./ COPY package*.json ./
# Install dependencies # Install dependencies
RUN npm install RUN npm install
# Copy source code # Copy source code
COPY . . COPY . .
# Expose port 3000 # Expose port 3000
EXPOSE 3000 EXPOSE 3000
# Run the app # Run the app
CMD ["npm", "run", "build", "&&", "npm", "start"] CMD ["npm", "run", "build", "&&", "npm", "start"]

View File

@ -1,2 +1,2 @@
# personal_site # personal_site
My personal site My personal site

View File

@ -1,61 +1,61 @@
/** # MODULE TRACE /** # MODULE TRACE
====================================================================== ======================================================================
* Detected 1 files that call this module. The files are listed below: * Detected 1 files that call this module. The files are listed below:
====================================================================== ======================================================================
* `import` Statement Found in [HomepageComponent.tsx] => file:///d:\GitHub\personal_site\app\(components)\HomepageComponent.tsx * `import` Statement Found in [HomepageComponent.tsx] => file:///d:\GitHub\personal_site\app\(components)\HomepageComponent.tsx
==== MODULE TRACE END ==== */ ==== MODULE TRACE END ==== */
"use client"; "use client";
import React from "react"; import React from "react";
export default function AboutSection() { export default function AboutSection() {
return ( return (
<div <div
className="max-w-6xl w-full flex flex-col items-center pb-40 generic-scroll page-section" className="max-w-6xl w-full flex flex-col items-center pb-40 generic-scroll page-section"
id="about-section" id="about-section"
> >
<div className="h-44"></div> <div className="h-44"></div>
<div className="flex flex-col xl:flex-row w-full gap-8"> <div className="flex flex-col xl:flex-row w-full gap-8">
<div className="w-full xl:w-[40%]"></div> <div className="w-full xl:w-[40%]"></div>
<div className="w-full xl:w-[60%] px-4 md:px-6 py-2"> <div className="w-full xl:w-[60%] px-4 md:px-6 py-2">
<section className="flex flex-col items-start gap-4"> <section className="flex flex-col items-start gap-4">
<h2 className="mb-0">About Me</h2> <h2 className="mb-0">About Me</h2>
<span className="text-[24px]">Quick learner, adaptable, problem solver, curious. I strive to know the system, rather than the status quo. I thrive in difficult situations and complex hurdles: problem solving is now second nature to me.</span> <span className="text-[24px]">Quick learner, adaptable, problem solver, curious. I strive to know the system, rather than the status quo. I thrive in difficult situations and complex hurdles: problem solving is now second nature to me.</span>
<hr className="w-full my-8" /> <hr className="w-full my-8" />
<h3 className="m-0">_ Code Ben</h3> <h3 className="m-0">_ Code Ben</h3>
<span className="text-[24px]">In the last two years I've developed from a complete designer to pro software engineer. After countless days of writing code, debugging, testing, building projects, server administration, deployment, CI/CD, etc, I've developed the most vital skill of all: adaptability. The ability to asimilate new knowledge at record pace: the tech industry moves really fast: you either keepup, or fall behind.</span> <span className="text-[24px]">In the last two years I've developed from a complete designer to pro software engineer. After countless days of writing code, debugging, testing, building projects, server administration, deployment, CI/CD, etc, I've developed the most vital skill of all: adaptability. The ability to asimilate new knowledge at record pace: the tech industry moves really fast: you either keepup, or fall behind.</span>
<hr className="w-full my-8" /> <hr className="w-full my-8" />
<h3 className="m-0">Graphic Design</h3> <h3 className="m-0">Graphic Design</h3>
<span className="text-[24px]"> <span className="text-[24px]">
After spending about 5 years in the design industry, I've picked up a few vital concepts about UI/UX design. My design path still sips into my developer life: and I must say, it's the perfect harmony of modern tech. Some of my designs can be found on my{" "} After spending about 5 years in the design industry, I've picked up a few vital concepts about UI/UX design. My design path still sips into my developer life: and I must say, it's the perfect harmony of modern tech. Some of my designs can be found on my{" "}
<a <a
href="https://99designs.com/profiles/tben" href="https://99designs.com/profiles/tben"
target="_blank" target="_blank"
> >
99designs 99designs
</a>{" "} </a>{" "}
profile. profile.
</span> </span>
<hr className="w-full my-8" /> <hr className="w-full my-8" />
<a <a
href="/about" href="/about"
className="button outlined" className="button outlined"
> >
Learn More About Me Learn More About Me
</a> </a>
</section> </section>
</div> </div>
</div> </div>
</div> </div>
); );
} }

View File

@ -1,65 +1,65 @@
"use client"; "use client";
import React from "react"; import React from "react";
import submitContactForm from "../../functions/frontend/submitContactForm"; import submitContactForm from "../../functions/frontend/submitContactForm";
export default function ContactForm() { export default function ContactForm() {
let [success, setSuccess] = React.useState<string | null>(null); let [success, setSuccess] = React.useState<string | null>(null);
let [loading, setLoading] = React.useState<boolean>(false); let [loading, setLoading] = React.useState<boolean>(false);
return ( return (
<form <form
autoComplete="on" autoComplete="on"
onSubmit={(e: any) => { onSubmit={(e: any) => {
submitContactForm(e, setSuccess, setLoading); submitContactForm(e, setSuccess, setLoading);
}} }}
> >
{loading && <div className="flex items-center justify-center w-full h-full absolute top-0 left-0 bg-[black]/90">Sending Mail...</div>} {loading && <div className="flex items-center justify-center w-full h-full absolute top-0 left-0 bg-[black]/90">Sending Mail...</div>}
<input <input
type="text" type="text"
placeholder="Your Name" placeholder="Your Name"
autoComplete="name" autoComplete="name"
required required
/> />
<input <input
type="email" type="email"
placeholder="Your Email Address" placeholder="Your Email Address"
autoComplete="email" autoComplete="email"
required required
/> />
<textarea <textarea
name="message" name="message"
id="contact-form-message" id="contact-form-message"
cols={30} cols={30}
rows={10} rows={10}
placeholder="Message" placeholder="Message"
></textarea> ></textarea>
<button type="submit">Submit</button> <button type="submit">Submit</button>
{success === "Success" && ( {success === "Success" && (
<div className="message-response"> <div className="message-response">
Success!!!{" "} Success!!!{" "}
<button <button
onClick={() => { onClick={() => {
window.location.reload(); window.location.reload();
}} }}
> >
Reload Reload
</button> </button>
</div> </div>
)} )}
{success === "Failed" && ( {success === "Failed" && (
<div className="message-response failed"> <div className="message-response failed">
Failed{" "} Failed{" "}
<button <button
onClick={() => { onClick={() => {
window.location.reload(); window.location.reload();
}} }}
> >
Reload Reload
</button> </button>
</div> </div>
)} )}
</form> </form>
); );
} }

View File

@ -1,24 +1,24 @@
"use client"; "use client";
import React from "react"; import React from "react";
import ContactForm from "./ContactForm"; import ContactForm from "./ContactForm";
export default function ContactMeSection() { export default function ContactMeSection() {
return ( return (
<div className="max-w-6xl w-full flex items-start page-section"> <div className="max-w-6xl w-full flex items-start page-section">
<div className="flex flex-col items-start gap-6 w-full xl:w-[50%]"> <div className="flex flex-col items-start gap-6 w-full xl:w-[50%]">
<div className="h-[150px]"></div> <div className="h-[150px]"></div>
<h2 className="m-0">Why So Serious?</h2> <h2 className="m-0">Why So Serious?</h2>
<div className="flex flex-col-reverse xl:flex-col items-start gap-4"> <div className="flex flex-col-reverse xl:flex-col items-start gap-4">
<span className="text-[24px]">Let's talk.</span> <span className="text-[24px]">Let's talk.</span>
</div> </div>
<div className="flex flex-col items-start w-full"> <div className="flex flex-col items-start w-full">
<ContactForm /> <ContactForm />
</div> </div>
</div> </div>
</div> </div>
); );
} }

View File

@ -1,124 +1,124 @@
"use client"; "use client";
import React from "react"; import React from "react";
import Image from "next/image"; import Image from "next/image";
import { gsap } from "gsap"; import { gsap } from "gsap";
import { TextPlugin } from "gsap/all"; import { TextPlugin } from "gsap/all";
gsap.registerPlugin(TextPlugin); gsap.registerPlugin(TextPlugin);
export default function Hero() { export default function Hero() {
/** /**
* Handle animations on page load * Handle animations on page load
*/ */
React.useEffect(() => { React.useEffect(() => {
const tl = gsap.timeline(); const tl = gsap.timeline();
gsap.fromTo( gsap.fromTo(
"#hero-sub-text", "#hero-sub-text",
{ {
opacity: 0, opacity: 0,
}, },
{ {
opacity: 1, opacity: 1,
delay: 0.5, delay: 0.5,
duration: 1, duration: 1,
} }
); );
gsap.to("#hero-text", { gsap.to("#hero-text", {
text: "I'm Benjamin Toby, a Software Engineer and UI/UX expert.", text: "I'm Benjamin Toby, a Software Engineer and UI/UX expert.",
delay: 1, delay: 1,
duration: 2, duration: 2,
ease: "none", ease: "none",
}); });
gsap.fromTo( gsap.fromTo(
".hero-button-link", ".hero-button-link",
{ {
opacity: 0, opacity: 0,
}, },
{ {
opacity: 1, opacity: 1,
delay: 3, delay: 3,
duration: 1, duration: 1,
stagger: 0.5, stagger: 0.5,
} }
); );
}, []); }, []);
/** /**
* Render component * Render component
*/ */
return ( return (
<div <div
className="flex flex-col xl:flex-row items-center gap-0 justify-center -mt-[80px] xl:-mt-[160px] w-full relative pt-[500px] xl:pt-0 page-section" className="flex flex-col xl:flex-row items-center gap-0 justify-center -mt-[80px] xl:-mt-[160px] w-full relative pt-[500px] xl:pt-0 page-section"
id="hero-content-wrapper" id="hero-content-wrapper"
> >
<div <div
className="rounded-full max-w-[450px] absolute md:relative flex items-center md:items-start justify-center mr-0 xl:-mr-14 bg-[#3e3f9c] overflow-hidden" className="rounded-full max-w-[450px] absolute md:relative flex items-center md:items-start justify-center mr-0 xl:-mr-14 bg-[#3e3f9c] overflow-hidden"
id="main-image" id="main-image"
style={{ style={{
transform: "scale(1.2)", transform: "scale(1.2)",
}} }}
> >
<img <img
src="/images/my-photo-stroked.png" src="/images/my-photo-stroked.png"
width={500} width={500}
height={562} height={562}
alt="Benjamin Toby Image" alt="Benjamin Toby Image"
className="contrast-[140%] grayscale mt-20 flex items-center justify-center object-contain" className="contrast-[140%] grayscale mt-20 flex items-center justify-center object-contain"
/> />
</div> </div>
<div <div
className="max-w-2xl relative z-10 mt-10 w-full" className="max-w-2xl relative z-10 mt-10 w-full"
id="hero-text-section" id="hero-text-section"
> >
<span <span
id="hero-sub-text" id="hero-sub-text"
className="uppercase bg-primary_light text-[black]/80 font-bold px-3 py-1 tracking-wide" className="uppercase bg-primary_light text-[black]/80 font-bold px-3 py-1 tracking-wide"
> >
Howdy Tech Enthusiasts Howdy Tech Enthusiasts
</span> </span>
<div className="h-4"></div> <div className="h-4"></div>
<h1 <h1
className="text-5xl md:text-[58px] leading-[1.1] gsap-text h-auto xl:h-[220px]" className="text-5xl md:text-[58px] leading-[1.1] gsap-text h-auto xl:h-[220px]"
id="hero-text" id="hero-text"
></h1> ></h1>
<div className="h-10 flex xl:hidden"></div> <div className="h-10 flex xl:hidden"></div>
<div className="gap-4 flex items-center flex-wrap"> <div className="gap-4 flex items-center flex-wrap">
<a <a
href="https://www.linkedin.com/in/benjamin-toby/" href="https://www.linkedin.com/in/benjamin-toby/"
target="_blank" target="_blank"
className="button grow hero-button-link" className="button grow hero-button-link"
> >
Linkedin Linkedin
</a> </a>
<a <a
href="/contact" href="/contact"
style={{ style={{
backgroundColor: "transparent", backgroundColor: "transparent",
color: "white", color: "white",
border: "2px solid white", border: "2px solid white",
}} }}
className="button grow hero-button-link" className="button grow hero-button-link"
> >
Contact Me Contact Me
</a> </a>
<a <a
href="/documents/Resume-Benjamin-Toby-Linkedin.pdf" href="/documents/Resume-Benjamin-Toby-Linkedin.pdf"
download={true} download={true}
className="button grow hero-button-link" className="button grow hero-button-link"
style={{ style={{
backgroundColor: "transparent", backgroundColor: "transparent",
color: "white", color: "white",
border: "2px solid white", border: "2px solid white",
}} }}
> >
See my resume See my resume
</a> </a>
</div> </div>
</div> </div>
</div> </div>
); );
} }

View File

@ -1,56 +1,56 @@
"use client"; "use client";
import React from "react"; import React from "react";
import Hero from "./Hero"; import Hero from "./Hero";
import AboutSection from "./AboutSection"; import AboutSection from "./AboutSection";
import { gsap } from "gsap"; import { gsap } from "gsap";
import MyWorkSection from "./MyWorkSection"; import MyWorkSection from "./MyWorkSection";
import MySkillsSection from "./MySkillsSection"; import MySkillsSection from "./MySkillsSection";
import homepageTimeline from "../(utils)/homepage-timeline"; import homepageTimeline from "../(utils)/homepage-timeline";
import { SiteContext } from "../../layouts/general_layout/GeneralLayout"; import { SiteContext } from "../../layouts/general_layout/GeneralLayout";
import ContactMeSection from "./ContactMeSection"; import ContactMeSection from "./ContactMeSection";
export type Project = { export type Project = {
id: number; id: number;
title: string; title: string;
description: string; description: string;
image?: string | null; image?: string | null;
url?: string | null; url?: string | null;
full_description?: string; full_description?: string;
}; };
type ChildProps = { type ChildProps = {
projects: Project[]; projects: Project[];
}; };
export default function HomepageComponent({ projects }: ChildProps) { export default function HomepageComponent({ projects }: ChildProps) {
const layoutContext: any = React.useContext(SiteContext); const layoutContext: any = React.useContext(SiteContext);
if (layoutContext) layoutContext.projects = projects; if (layoutContext) layoutContext.projects = projects;
const comp = React.useRef<HTMLDivElement>(null); const comp = React.useRef<HTMLDivElement>(null);
React.useLayoutEffect(() => { React.useLayoutEffect(() => {
let ctx = gsap.context(() => { let ctx = gsap.context(() => {
homepageTimeline({ componentRef: comp }); homepageTimeline({ componentRef: comp });
}, comp); }, comp);
return () => ctx.revert(); return () => ctx.revert();
}, []); }, []);
return ( return (
<React.Fragment> <React.Fragment>
<div <div
id="homepage-content-wrapper" id="homepage-content-wrapper"
ref={comp} ref={comp}
className="z-0 xl:z-50 mb-32" className="z-0 xl:z-50 mb-32"
> >
<Hero /> <Hero />
<AboutSection /> <AboutSection />
<MySkillsSection /> <MySkillsSection />
<MyWorkSection /> <MyWorkSection />
<ContactMeSection /> <ContactMeSection />
</div> </div>
</React.Fragment> </React.Fragment>
); );
} }

View File

@ -1,91 +1,91 @@
"use client"; "use client";
import React from "react"; import React from "react";
export default function MySkillsSection() { export default function MySkillsSection() {
const webDevStack = require("../(utils)/web-dev-stack.json"); const webDevStack = require("../(utils)/web-dev-stack.json");
const uiStack = require("../(utils)/ui-ux-stack.json"); const uiStack = require("../(utils)/ui-ux-stack.json");
const [targetStack, setTargetStack] = React.useState("dev"); const [targetStack, setTargetStack] = React.useState("dev");
return ( return (
<div className="max-w-6xl w-full flex flex-col items-start pb-40 page-section"> <div className="max-w-6xl w-full flex flex-col items-start pb-40 page-section">
<div className="h-[200px]"></div> <div className="h-[200px]"></div>
<div className="flex flex-col items-start gap-6 w-full xl:w-[50%]"> <div className="flex flex-col items-start gap-6 w-full xl:w-[50%]">
<h2 className="mb-0">My Skills</h2> <h2 className="mb-0">My Skills</h2>
<span className="text-[24px]">I am well-versed in the full spectrum of design and development. While I started out as a designer, I have focused more on development in the last few years.</span> <span className="text-[24px]">I am well-versed in the full spectrum of design and development. While I started out as a designer, I have focused more on development in the last few years.</span>
<hr className="w-full" /> <hr className="w-full" />
<h3 className="m-0">{targetStack?.match(/dev/i) ? "Web Dev Tech Stack" : "UI/UX tech stack"}</h3> <h3 className="m-0">{targetStack?.match(/dev/i) ? "Web Dev Tech Stack" : "UI/UX tech stack"}</h3>
<div className="flex flex-col xl:flex-col items-start gap-4 w-full"> <div className="flex flex-col xl:flex-col items-start gap-4 w-full">
{/* <h3>My Tech Stack</h3> */} {/* <h3>My Tech Stack</h3> */}
<div className="flex flex-wrap w-full gap-2"> <div className="flex flex-wrap w-full gap-2">
<div <div
className={"p-4 text-lg cursor-pointer grow" + (targetStack.match(/dev/i) ? " bg-[white] text-[black] font-bold" : " border border-solid border-white/10 hover:opacity-60 ")} className={"p-4 text-lg cursor-pointer grow" + (targetStack.match(/dev/i) ? " bg-[white] text-[black] font-bold" : " border border-solid border-white/10 hover:opacity-60 ")}
onClick={() => { onClick={() => {
setTargetStack("dev"); setTargetStack("dev");
}} }}
> >
<div>Web Dev Stack</div> <div>Web Dev Stack</div>
</div> </div>
<div <div
className={"p-4 text-lg cursor-pointer grow" + (targetStack.match(/design/i) ? " bg-[white] text-[black] font-bold" : " border border-solid border-white/10 hover:opacity-60 ")} className={"p-4 text-lg cursor-pointer grow" + (targetStack.match(/design/i) ? " bg-[white] text-[black] font-bold" : " border border-solid border-white/10 hover:opacity-60 ")}
onClick={() => { onClick={() => {
setTargetStack("design"); setTargetStack("design");
}} }}
> >
<div>UI/UX Stack</div> <div>UI/UX Stack</div>
</div> </div>
</div> </div>
</div> </div>
<ul <ul
style={{ maxWidth: "800px" }} style={{ maxWidth: "800px" }}
className="pl-6" className="pl-6"
> >
{targetStack?.match(/dev/i) ? ( {targetStack?.match(/dev/i) ? (
<React.Fragment> <React.Fragment>
{webDevStack.map((item: { title: string; description: string }, index: number) => ( {webDevStack.map((item: { title: string; description: string }, index: number) => (
<li <li
key={index} key={index}
className="mb-4" className="mb-4"
> >
<h4 className="m-0 text-[#BBE572]"> <h4 className="m-0 text-[#BBE572]">
{item.title} {item.title}
{/* <TextShuffler textInput={item.title} /> */} {/* <TextShuffler textInput={item.title} /> */}
</h4> </h4>
<span className="opacity-80"> <span className="opacity-80">
{item.description} {item.description}
{/* <TextShuffler textInput={item.description} /> */} {/* <TextShuffler textInput={item.description} /> */}
</span> </span>
</li> </li>
))} ))}
</React.Fragment> </React.Fragment>
) : ( ) : (
<React.Fragment> <React.Fragment>
{uiStack.map((item: { title: string; description: string }, index: number) => ( {uiStack.map((item: { title: string; description: string }, index: number) => (
<li <li
key={index} key={index}
className="mb-4" className="mb-4"
> >
<h4 className="m-0 text-[#BBE572]"> <h4 className="m-0 text-[#BBE572]">
{item.title} {item.title}
{/* <TextShuffler textInput={item.title} /> */} {/* <TextShuffler textInput={item.title} /> */}
</h4> </h4>
<span className="opacity-80"> <span className="opacity-80">
{item.description} {item.description}
{/* <TextShuffler textInput={item.description} /> */} {/* <TextShuffler textInput={item.description} /> */}
</span> </span>
</li> </li>
))} ))}
</React.Fragment> </React.Fragment>
)} )}
</ul> </ul>
</div> </div>
</div> </div>
); );
} }

View File

@ -1,36 +1,36 @@
"use client"; "use client";
import React from "react"; import React from "react";
import { Project } from "./HomepageComponent"; import { Project } from "./HomepageComponent";
import Image from "next/image"; import Image from "next/image";
export default function MyWorkCard({ project }: { project: Project }) { export default function MyWorkCard({ project }: { project: Project }) {
return ( return (
<div className="bg-primary/10 w-full shadow-2xl shadow-[black] relative"> <div className="bg-primary/10 w-full shadow-2xl shadow-[black] relative">
<Image <Image
src={project.image || ""} src={project.image || ""}
alt={project.title} alt={project.title}
width={600} width={600}
height={300} height={300}
className="object-cover object-top w-full" className="object-cover object-top w-full"
/> />
<div className="p-10"> <div className="p-10">
<h3 className="m-0">{project.title}</h3> <h3 className="m-0">{project.title}</h3>
<p className="m-0">{project.description}</p> <p className="m-0">{project.description}</p>
</div> </div>
<a <a
href={project.url || "#"} href={project.url || "#"}
className="absolute z-10 top-[340px] right-6 w-10 h-10 p-2 flex items-center justify-center rounded-full bg-[white]" className="absolute z-10 top-[340px] right-6 w-10 h-10 p-2 flex items-center justify-center rounded-full bg-[white]"
target="_blank" target="_blank"
> >
<img <img
src="/images/external-link-dark.png" src="/images/external-link-dark.png"
alt="External Link Icon" alt="External Link Icon"
width={20} width={20}
height={20} height={20}
/> />
</a> </a>
</div> </div>
); );
} }

View File

@ -1,43 +1,43 @@
"use client"; "use client";
import React from "react"; import React from "react";
import { SiteContext } from "../../layouts/general_layout/GeneralLayout"; import { SiteContext } from "../../layouts/general_layout/GeneralLayout";
import { Project } from "./HomepageComponent"; import { Project } from "./HomepageComponent";
import MyWorkCard from "./MyWorkCard"; import MyWorkCard from "./MyWorkCard";
export default function MyWorkSection() { export default function MyWorkSection() {
const layoutContext: { projects: Project[] } = React.useContext(SiteContext); const layoutContext: { projects: Project[] } = React.useContext(SiteContext);
const projects = layoutContext.projects; const projects = layoutContext.projects;
return ( return (
<div className="max-w-6xl w-full flex flex-col xl:flex-row items-start pb-40 page-section"> <div className="max-w-6xl w-full flex flex-col xl:flex-row items-start pb-40 page-section">
<div className="flex flex-col items-start gap-6 w-full xl:w-[50%]"></div> <div className="flex flex-col items-start gap-6 w-full xl:w-[50%]"></div>
<div className="flex flex-col items-start gap-6 w-full xl:w-[50%]"> <div className="flex flex-col items-start gap-6 w-full xl:w-[50%]">
<div className="h-[150px]"></div> <div className="h-[150px]"></div>
<h2 className="m-0">Some of my work</h2> <h2 className="m-0">Some of my work</h2>
<div className="flex flex-col-reverse xl:flex-col items-start gap-4"> <div className="flex flex-col-reverse xl:flex-col items-start gap-4">
<span className="text-[24px]">I've been creating and building awesome designs and applications since 2016. Here are a few picks:</span> <span className="text-[24px]">I've been creating and building awesome designs and applications since 2016. Here are a few picks:</span>
</div> </div>
<div className="flex flex-col items-start gap-44 mt-10"> <div className="flex flex-col items-start gap-44 mt-10">
{projects && {projects &&
projects.slice(0, 4).map((project, index) => ( projects.slice(0, 4).map((project, index) => (
<MyWorkCard <MyWorkCard
key={index} key={index}
project={project} project={project}
/> />
))} ))}
</div> </div>
<a <a
href="/work" href="/work"
className="button outlined mt-10" className="button outlined mt-10"
> >
See More See More
</a> </a>
</div> </div>
</div> </div>
); );
} }

View File

@ -1,6 +1,6 @@
header { header {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 10px; gap: 10px;
} }

View File

@ -1,149 +1,149 @@
import { gsap } from "gsap"; import { gsap } from "gsap";
import ScrollTrigger from "gsap/ScrollTrigger"; import ScrollTrigger from "gsap/ScrollTrigger";
import TextPlugin from "gsap/TextPlugin"; import TextPlugin from "gsap/TextPlugin";
/** /**
* Register plugins * Register plugins
*/ */
gsap.registerPlugin(ScrollTrigger); gsap.registerPlugin(ScrollTrigger);
gsap.registerPlugin(TextPlugin); gsap.registerPlugin(TextPlugin);
/** /**
* Animates the hero section * Animates the hero section
*/ */
export function hero() { export function hero() {
/** /**
* Animate hero section * Animate hero section
*/ */
gsap.fromTo( gsap.fromTo(
"#main-image", "#main-image",
{ {
z: -100, z: -100,
scale: 1.2, scale: 1.2,
}, },
{ {
z: 0, z: 0,
duration: 1.5, duration: 1.5,
scale: 1, scale: 1,
} }
); );
gsap.fromTo( gsap.fromTo(
"#hero-text-section", "#hero-text-section",
{ {
z: -100, z: -100,
scale: 1.2, scale: 1.2,
}, },
{ {
z: 0, z: 0,
duration: 2.5, duration: 2.5,
scale: 1, scale: 1,
} }
); );
gsap.fromTo( gsap.fromTo(
"#main-image", "#main-image",
{ {
y: 0, y: 0,
// scale: 1, // scale: 1,
}, },
{ {
scrollTrigger: { scrollTrigger: {
scrub: 1, scrub: 1,
}, },
y: 150, y: 150,
// scale: 0.8, // scale: 0.8,
} }
); );
gsap.fromTo( gsap.fromTo(
"#hero-text-section", "#hero-text-section",
{ {
y: 0, y: 0,
// scale: 1, // scale: 1,
}, },
{ {
scrollTrigger: { scrollTrigger: {
scrub: 2, scrub: 2,
}, },
y: 100, y: 100,
// scale: 0.8, // scale: 0.8,
} }
); );
} }
/** /**
* Animates the about section * Animates the about section
*/ */
export function about() { export function about() {
gsap.fromTo( gsap.fromTo(
"#about-section", "#about-section",
{ {
y: 40, y: 40,
scale: 0.8, scale: 0.8,
}, },
{ {
scrollTrigger: { scrollTrigger: {
scrub: 4, scrub: 4,
}, },
y: 0, y: 0,
scale: 1.1, scale: 1.1,
} }
); );
gsap.to("#about-me-label", { gsap.to("#about-me-label", {
scrollTrigger: { scrollTrigger: {
scrub: 2, scrub: 2,
}, },
y: 300, y: 300,
scale: 0.8, scale: 0.8,
}); });
} }
/** /**
* Animates the about section * Animates the about section
*/ */
export function genericScroll() { export function genericScroll() {
gsap.fromTo( gsap.fromTo(
".generic-scroll", ".generic-scroll",
{ {
y: 0, y: 0,
scale: 0.9, scale: 0.9,
}, },
{ {
scrollTrigger: { scrollTrigger: {
scrub: 3, scrub: 3,
}, },
y: 100, y: 100,
scale: 1, scale: 1,
} }
); );
} }
/** /**
* Animates the about section * Animates the about section
*/ */
export function appear() { export function appear() {
gsap.fromTo( gsap.fromTo(
".appear", ".appear",
{ {
y: 40, y: 40,
scale: 0.8, scale: 0.8,
opacity: 0, opacity: 0,
}, },
{ {
y: 0, y: 0,
scale: 1, scale: 1,
opacity: 1, opacity: 1,
duration: 2, duration: 2,
delay: (i, target) => { delay: (i, target) => {
const datasetDelay = target?.dataset?.delay; const datasetDelay = target?.dataset?.delay;
if (datasetDelay) { if (datasetDelay) {
return datasetDelay; return datasetDelay;
} }
return 0; return 0;
}, },
} }
); );
} }

View File

@ -1,208 +1,208 @@
import { gsap } from "gsap"; import { gsap } from "gsap";
import { ScrollTrigger, Observer } from "gsap/all"; import { ScrollTrigger, Observer } from "gsap/all";
gsap.registerPlugin(ScrollTrigger, Observer); gsap.registerPlugin(ScrollTrigger, Observer);
export default function homepageTimeline({ componentRef }: { componentRef: { current: HTMLDivElement | null } }) { export default function homepageTimeline({ componentRef }: { componentRef: { current: HTMLDivElement | null } }) {
const mm = gsap.matchMedia(); const mm = gsap.matchMedia();
const compHeight = componentRef.current?.clientHeight; const compHeight = componentRef.current?.clientHeight;
const isMobile = window.innerWidth <= 1200; const isMobile = window.innerWidth <= 1200;
// mm.add("(min-width: 1200px)", () => { // mm.add("(min-width: 1200px)", () => {
ScrollTrigger.create({ ScrollTrigger.create({
trigger: "#homepage-content-wrapper", trigger: "#homepage-content-wrapper",
start: "200px 200px", start: "200px 200px",
end: "bottom 90%", end: "bottom 90%",
pin: isMobile ? null : "#main-image", pin: isMobile ? null : "#main-image",
scrub: 1, scrub: 1,
onUpdate: (self) => { onUpdate: (self) => {
const scrollTop = compHeight ? self.progress * compHeight : 0; const scrollTop = compHeight ? self.progress * compHeight : 0;
/** /**
* Origin * Origin
*/ */
if (!isMobile) { if (!isMobile) {
if (scrollTop < 300) { if (scrollTop < 300) {
gsap.to("nav", { gsap.to("nav", {
opacity: 1, opacity: 1,
pointerEvents: "visible", pointerEvents: "visible",
}); });
gsap.to("header", { gsap.to("header", {
zIndex: 2000, zIndex: 2000,
}); });
} else { } else {
gsap.to("nav", { gsap.to("nav", {
opacity: 0, opacity: 0,
pointerEvents: "none", pointerEvents: "none",
}); });
gsap.to("header", { gsap.to("header", {
zIndex: 0, zIndex: 0,
}); });
} }
} }
/** /**
* Handle Mobile * Handle Mobile
*/ */
if (isMobile && scrollTop > 100) { if (isMobile && scrollTop > 100) {
gsap.to("#main-image", { gsap.to("#main-image", {
opacity: 0.1, opacity: 0.1,
duration: 1, duration: 1,
}); });
} else { } else {
gsap.to("#main-image", { gsap.to("#main-image", {
opacity: 1, opacity: 1,
duration: 1, duration: 1,
}); });
} }
}, },
onEnter: (self) => {}, onEnter: (self) => {},
}); });
/** /**
* Position color map * Position color map
*/ */
const positionColorMap: { const positionColorMap: {
x: number; x: number;
imgBg: string; imgBg: string;
bodyBg: string; bodyBg: string;
duration: number; duration: number;
imgSrc?: string; imgSrc?: string;
}[] = [ }[] = [
{ {
x: 0, x: 0,
imgBg: "#3e3f9c", imgBg: "#3e3f9c",
bodyBg: "#181515", bodyBg: "#181515",
duration: 1, duration: 1,
imgSrc: "/images/my-photo-stroked.png", imgSrc: "/images/my-photo-stroked.png",
}, },
{ {
x: -50, x: -50,
imgBg: "#FE6847", imgBg: "#FE6847",
bodyBg: "#292a6b", bodyBg: "#292a6b",
duration: 1, duration: 1,
imgSrc: "/images/my-photo-3.png", imgSrc: "/images/my-photo-3.png",
}, },
{ {
x: 600, x: 600,
imgBg: "#688e26", imgBg: "#688e26",
bodyBg: "#181515", bodyBg: "#181515",
duration: 1.2, duration: 1.2,
imgSrc: "/images/programming-laptop.png", imgSrc: "/images/programming-laptop.png",
}, },
{ {
x: -50, x: -50,
imgBg: "#1B2CC1", imgBg: "#1B2CC1",
bodyBg: "#091540", bodyBg: "#091540",
duration: 1.2, duration: 1.2,
imgSrc: "/images/projects-section-image.png", imgSrc: "/images/projects-section-image.png",
}, },
{ {
x: 600, x: 600,
imgBg: "#ffd87d", imgBg: "#ffd87d",
bodyBg: "#3e3f9c", bodyBg: "#3e3f9c",
duration: 1.2, duration: 1.2,
imgSrc: "/images/why-so-serious.png", imgSrc: "/images/why-so-serious.png",
}, },
]; ];
/** /**
* Activate section based on scroll position * Activate section based on scroll position
*/ */
const sections = document.querySelectorAll(".page-section"); const sections = document.querySelectorAll(".page-section");
function activateSection(index: number) { function activateSection(index: number) {
const targetPositionMap = positionColorMap[index]; const targetPositionMap = positionColorMap[index];
if (!targetPositionMap) { if (!targetPositionMap) {
return; return;
} }
gsap.to("#main-image", { gsap.to("#main-image", {
backgroundColor: targetPositionMap.imgBg, backgroundColor: targetPositionMap.imgBg,
x: isMobile ? 0 : targetPositionMap.x, x: isMobile ? 0 : targetPositionMap.x,
duration: targetPositionMap.duration, duration: targetPositionMap.duration,
}); });
gsap.to("body", { gsap.to("body", {
backgroundColor: targetPositionMap.bodyBg, backgroundColor: targetPositionMap.bodyBg,
}); });
if (targetPositionMap?.imgSrc) { if (targetPositionMap?.imgSrc) {
changeMainImage(targetPositionMap.imgSrc); changeMainImage(targetPositionMap.imgSrc);
} }
if (index >= 2) { if (index >= 2) {
gsap.to("#main-image img", { gsap.to("#main-image img", {
filter: "none", filter: "none",
duration: 1, duration: 1,
}); });
} else { } else {
gsap.to("#main-image img", { gsap.to("#main-image img", {
filter: "grayscale(100%) contrast(140%)", filter: "grayscale(100%) contrast(140%)",
duration: 1, duration: 1,
}); });
} }
} }
sections.forEach((section, index) => { sections.forEach((section, index) => {
ScrollTrigger.create({ ScrollTrigger.create({
trigger: section, trigger: section,
start: "top 50%", start: "top 50%",
end: "bottom 50%", end: "bottom 50%",
onEnter: (self) => { onEnter: (self) => {
activateSection(index); activateSection(index);
}, },
onEnterBack: (self) => { onEnterBack: (self) => {
activateSection(index); activateSection(index);
}, },
}); });
}); });
/** /**
* Entry animation timeline * Entry animation timeline
*/ */
const entryTimeline = gsap.timeline(); const entryTimeline = gsap.timeline();
entryTimeline entryTimeline
.from("#main-image", { .from("#main-image", {
clipPath: "circle(0)", clipPath: "circle(0)",
}) })
.to("#main-image", { .to("#main-image", {
clipPath: "circle(100%)", clipPath: "circle(100%)",
scale: 1, scale: 1,
duration: 1, duration: 1,
}); });
gsap.to("#main-image", { gsap.to("#main-image", {
y: 20, y: 20,
repeat: -1, repeat: -1,
duration: 2, duration: 2,
yoyo: true, yoyo: true,
ease: "sine.inOut", ease: "sine.inOut",
}); });
// }); // });
} }
async function changeMainImage(src: string) { async function changeMainImage(src: string) {
const mainImage: HTMLImageElement | null = document.querySelector("#main-image img"); const mainImage: HTMLImageElement | null = document.querySelector("#main-image img");
if (mainImage) { if (mainImage) {
await gsap.to(mainImage, { await gsap.to(mainImage, {
opacity: 0, opacity: 0,
duration: 0.5, duration: 0.5,
}); });
if (mainImage) { if (mainImage) {
mainImage.setAttribute("src", src); mainImage.setAttribute("src", src);
mainImage.onload = () => { mainImage.onload = () => {
gsap.to(mainImage, { gsap.to(mainImage, {
opacity: 1, opacity: 1,
duration: 0.5, duration: 0.5,
delay: 0.5, delay: 0.5,
}); });
}; };
} }
} }
} }

View File

@ -1,30 +1,30 @@
[ [
{ {
"title": "Adobe Photoshop", "title": "Adobe Photoshop",
"description": "Web design, image manipulation, image compositing, and more." "description": "Web design, image manipulation, image compositing, and more."
}, },
{ {
"title": "Adobe Illustrator", "title": "Adobe Illustrator",
"description": "Vector graphic of all types" "description": "Vector graphic of all types"
}, },
{ {
"title": "Figma", "title": "Figma",
"description": "Web, UI, UX design." "description": "Web, UI, UX design."
}, },
{ {
"title": "Affinity Designer", "title": "Affinity Designer",
"description": "Vector graphics." "description": "Vector graphics."
}, },
{ {
"title": "After Effects", "title": "After Effects",
"description": "Motion graphics and animation" "description": "Motion graphics and animation"
}, },
{ {
"title": "Adobe XD", "title": "Adobe XD",
"description": "UI/UX design" "description": "UI/UX design"
}, },
{ {
"title": "Webflow", "title": "Webflow",
"description": "Visual Web coding" "description": "Visual Web coding"
} }
] ]

View File

@ -1,38 +1,38 @@
[ [
{ {
"title": "HTML, CSS, Javascript", "title": "HTML, CSS, Javascript",
"description": "The basics, the bedrock of all websites." "description": "The basics, the bedrock of all websites."
}, },
{ {
"title": "React JS", "title": "React JS",
"description": "JavaScript library for high-performance web applications" "description": "JavaScript library for high-performance web applications"
}, },
{ {
"title": "Next JS", "title": "Next JS",
"description": "High performance React and Node js web framework for building blazing flast and performant web applications" "description": "High performance React and Node js web framework for building blazing flast and performant web applications"
}, },
{ {
"title": "Tailwind CSS", "title": "Tailwind CSS",
"description": "Lighting fast mobile first styling" "description": "Lighting fast mobile first styling"
}, },
{ {
"title": "Node JS", "title": "Node JS",
"description": "JavaScript runtime for the server. For creating backend architectures and APIs" "description": "JavaScript runtime for the server. For creating backend architectures and APIs"
}, },
{ {
"title": "Ubuntu Linux", "title": "Ubuntu Linux",
"description": "Secure server management with ubuntu and Linux" "description": "Secure server management with ubuntu and Linux"
}, },
{ {
"title": "Nginx", "title": "Nginx",
"description": "Super secure web server, reverse proxy and load balancer" "description": "Super secure web server, reverse proxy and load balancer"
}, },
{ {
"title": "MySQL", "title": "MySQL",
"description": "Tried and tested data storage, querying, and management." "description": "Tried and tested data storage, querying, and management."
}, },
{ {
"title": "Git and Github", "title": "Git and Github",
"description": "Version control" "description": "Version control"
} }
] ]

View File

@ -1,23 +1,27 @@
"use client"; "use client";
import React from "react"; import React from "react";
export default function Hero() { export default function Hero() {
return ( return (
<div className="-mt-10 appear"> <div className="-mt-10 appear">
<div <div
className="flex flex-col items-start gap-0 max-w-6xl w-full relative generic-scroll" className="flex flex-col items-start gap-0 max-w-6xl w-full relative generic-scroll"
// id="hero-text-section" // id="hero-text-section"
> >
<span className="text-primary-light text-lg">About Me</span> <span className="text-primary-light text-lg">About Me</span>
<h1 <h1 className="text-5xl leading-snug" id="hero-text">
className="text-5xl leading-snug" I live on the bleeding edge of technology
id="hero-text" </h1>
> <span className="hero-sub-text">
Ben of All Trades, Master of All Quick learner, adaptable, problem solver, curious. I strive
</h1> to know the system, rather than the status quo. My credo is:
<span className="hero-sub-text">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.</span> no problem too great, no knowledge too vast, no logic too
</div> complex. I thrive in difficult situations and complex
</div> hurdles: problem solving is now second nature to me: if you
); can think it, it can be done.
} </span>
</div>
</div>
);
}

View File

@ -1,98 +1,98 @@
"use client"; "use client";
import React from "react"; import React from "react";
export default function MoreAboutMe() { export default function MoreAboutMe() {
const webDevStack = require("../../(utils)/web-dev-stack.json"); const webDevStack = require("../../(utils)/web-dev-stack.json");
const uiStack = require("../../(utils)/ui-ux-stack.json"); const uiStack = require("../../(utils)/ui-ux-stack.json");
const [targetStack, setTargetStack] = React.useState("dev"); const [targetStack, setTargetStack] = React.useState("dev");
return ( return (
<div className="max-w-6xl w-full flex flex-col items-center pb-40 generic-scroll"> <div className="max-w-6xl w-full flex flex-col items-center pb-40 generic-scroll">
<div className="h-20"></div> <div className="h-20"></div>
<div <div
className="flex flex-col w-full gap-8 appear" className="flex flex-col w-full gap-8 appear"
data-delay={2} data-delay={2}
> >
<div className="w-full"> <div className="w-full">
<h2> <h2>
More About Me More About Me
{/* <TextShuffler textInput="More About Me" /> */} {/* <TextShuffler textInput="More About Me" /> */}
</h2> </h2>
<div className="flex flex-col items-start gap-4"> <div className="flex flex-col items-start gap-4">
<div className="flex w-full gap-4"> <div className="flex w-full gap-4">
<div <div
className={"p-4 cursor-pointer hover:opacity-60 grow" + (targetStack.match(/dev/i) ? " bg-[#343680]" : " border border-solid border-white/10")} className={"p-4 cursor-pointer hover:opacity-60 grow" + (targetStack.match(/dev/i) ? " bg-[#343680]" : " border border-solid border-white/10")}
onClick={() => { onClick={() => {
setTargetStack("dev"); setTargetStack("dev");
}} }}
> >
<div>Web Dev Stack</div> <div>Web Dev Stack</div>
</div> </div>
<div <div
className={"p-4 cursor-pointer hover:opacity-60 grow" + (targetStack.match(/design/i) ? " bg-[#343680]" : " border border-solid border-white/10")} className={"p-4 cursor-pointer hover:opacity-60 grow" + (targetStack.match(/design/i) ? " bg-[#343680]" : " border border-solid border-white/10")}
onClick={() => { onClick={() => {
setTargetStack("design"); setTargetStack("design");
}} }}
> >
<div>UI/UX Stack</div> <div>UI/UX Stack</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div className="w-full bg-[#343680] px-4 md:px-6 py-2"> <div className="w-full bg-[#343680] px-4 md:px-6 py-2">
<section> <section>
<h3> <h3>
{targetStack?.match(/dev/i) ? "Web Dev Tech Stack" : "UI/UX tech stack"} {targetStack?.match(/dev/i) ? "Web Dev Tech Stack" : "UI/UX tech stack"}
{/* <TextShuffler textInput={targetStack?.match(/dev/i) ? "Web Dev Tech Stack" : "UI/UX tech stack"} /> */} {/* <TextShuffler textInput={targetStack?.match(/dev/i) ? "Web Dev Tech Stack" : "UI/UX tech stack"} /> */}
</h3> </h3>
<hr /> <hr />
<ul style={{ maxWidth: "800px" }}> <ul style={{ maxWidth: "800px" }}>
{targetStack?.match(/dev/i) ? ( {targetStack?.match(/dev/i) ? (
<React.Fragment> <React.Fragment>
{webDevStack.map((item: { title: string; description: string }, index: number) => ( {webDevStack.map((item: { title: string; description: string }, index: number) => (
<li <li
key={index} key={index}
className="mb-4" className="mb-4"
> >
<h4 className="m-0"> <h4 className="m-0">
{item.title} {item.title}
{/* <TextShuffler textInput={item.title} /> */} {/* <TextShuffler textInput={item.title} /> */}
</h4> </h4>
<span className="opacity-80"> <span className="opacity-80">
{item.description} {item.description}
{/* <TextShuffler textInput={item.description} /> */} {/* <TextShuffler textInput={item.description} /> */}
</span> </span>
</li> </li>
))} ))}
</React.Fragment> </React.Fragment>
) : ( ) : (
<React.Fragment> <React.Fragment>
{uiStack.map((item: { title: string; description: string }, index: number) => ( {uiStack.map((item: { title: string; description: string }, index: number) => (
<li <li
key={index} key={index}
className="mb-4" className="mb-4"
> >
<h4 className="m-0"> <h4 className="m-0">
{item.title} {item.title}
{/* <TextShuffler textInput={item.title} /> */} {/* <TextShuffler textInput={item.title} /> */}
</h4> </h4>
<span className="opacity-80"> <span className="opacity-80">
{item.description} {item.description}
{/* <TextShuffler textInput={item.description} /> */} {/* <TextShuffler textInput={item.description} /> */}
</span> </span>
</li> </li>
))} ))}
</React.Fragment> </React.Fragment>
)} )}
</ul> </ul>
</section> </section>
</div> </div>
</div> </div>
</div> </div>
); );
} }

View File

@ -1,12 +1,12 @@
import React from "react"; import React from "react";
import MoreAboutMe from "./(components)/MoreAboutMe"; import MoreAboutMe from "./(components)/MoreAboutMe";
import Hero from "./(components)/Hero"; import Hero from "./(components)/Hero";
export default function AboutPage() { export default function AboutPage() {
return ( return (
<React.Fragment> <React.Fragment>
<Hero /> <Hero />
<MoreAboutMe /> <MoreAboutMe />
</React.Fragment> </React.Fragment>
); );
} }

View File

@ -1,17 +1,17 @@
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
// export async function GET(request: Request, context?: {}) { // export async function GET(request: Request, context?: {}) {
// console.log(request.headers); // console.log(request.headers);
// return NextResponse.json({ name: "Benjamin Toby" }); // return NextResponse.json({ name: "Benjamin Toby" });
// } // }
export async function GET(request: Request) { export async function GET(request: Request) {
return new Response(JSON.stringify({ name: "Benjamin Toby" }), { return new Response(JSON.stringify({ name: "Benjamin Toby" }), {
status: 200, status: 200,
headers: { headers: {
"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization", "Access-Control-Allow-Headers": "Content-Type, Authorization",
}, },
}); });
} }

View File

@ -1,178 +1,178 @@
/** /**
* ============================================================================== * ==============================================================================
* Imports * Imports
* ============================================================================== * ==============================================================================
*/ */
import React from "react"; import React from "react";
import Head from "next/head"; import Head from "next/head";
import type { InferGetStaticPropsType, GetStaticProps, GetStaticPaths } from "next"; import type { InferGetStaticPropsType, GetStaticProps, GetStaticPaths } from "next";
const datasquirel = require("datasquirel"); const datasquirel = require("datasquirel");
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
import GeneralLayout from "../../layouts/general_layout/GeneralLayout"; import GeneralLayout from "../../layouts/general_layout/GeneralLayout";
import TextShuffler from "../../components/actions/TextShuffler"; import TextShuffler from "../../components/actions/TextShuffler";
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** /**
* ============================================================================== * ==============================================================================
* Main Component { Functional } * Main Component { Functional }
* ============================================================================== * ==============================================================================
* @param {Object} props - Server props * @param {Object} props - Server props
*/ */
export default function BlogIndex({ blogPost }: InferGetStaticPropsType<typeof getStaticProps>) { export default function BlogIndex({ blogPost }: InferGetStaticPropsType<typeof getStaticProps>) {
// ## Get Contexts // ## Get Contexts
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## Javascript Variables // ## Javascript Variables
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## React Hooks { useState, useEffect, useRef, etc ... } // ## React Hooks { useState, useEffect, useRef, etc ... }
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## Function Return // ## Function Return
return ( return (
<React.Fragment> <React.Fragment>
<Head> <Head>
<title>{blogPost.title} | Tben.me Blog</title> <title>{blogPost.title} | Tben.me Blog</title>
<meta <meta
name="description" name="description"
content={blogPost.excerpt} content={blogPost.excerpt}
/> />
</Head> </Head>
<GeneralLayout> <GeneralLayout>
<div className="flex flex-col items-start gap-2 mb-8 max-w-6xl w-full"> <div className="flex flex-col items-start gap-2 mb-8 max-w-6xl w-full">
<button <button
className="bg-transparent text-white/50 border-2 border-solid border-white/20" className="bg-transparent text-white/50 border-2 border-solid border-white/20"
onClick={(e) => { onClick={(e) => {
window.history.back(); window.history.back();
}} }}
> >
Back Back
</button> </button>
<h1 className="m-0"> <h1 className="m-0">
<TextShuffler textInput={blogPost.title} /> <TextShuffler textInput={blogPost.title} />
</h1> </h1>
<span className="text-lg"> <span className="text-lg">
<TextShuffler textInput={blogPost.excerpt} /> <TextShuffler textInput={blogPost.excerpt} />
</span> </span>
<span className="text-base opacity-50"> <span className="text-base opacity-50">
<TextShuffler textInput={blogPost.date_created.substring(0, 24)} /> <TextShuffler textInput={blogPost.date_created.substring(0, 24)} />
</span> </span>
</div> </div>
<span <span
className="flex flex-col items-start max-w-6xl w-full gap-4 text-xl" className="flex flex-col items-start max-w-6xl w-full gap-4 text-xl"
dangerouslySetInnerHTML={{ __html: blogPost.body }} dangerouslySetInnerHTML={{ __html: blogPost.body }}
></span> ></span>
</GeneralLayout> </GeneralLayout>
</React.Fragment> </React.Fragment>
); );
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
} }
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** /**
* Server Side Props or Static Props * Server Side Props or Static Props
* ============================================================================== * ==============================================================================
*/ */
export const getStaticProps: GetStaticProps = async ({ params }) => { export const getStaticProps: GetStaticProps = async ({ params }) => {
// ## Environment processes // ## Environment processes
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## User Authentication // ## User Authentication
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## Page/Site Data Data Fetching // ## Page/Site Data Data Fetching
const postsResponse = await datasquirel.get({ const postsResponse = await datasquirel.get({
key: process.env.DATASQUIREL_API_KEY, key: process.env.DATASQUIREL_API_KEY,
db: "tbenme", db: "tbenme",
query: `select * from blog_posts WHERE slug='${params?.single}'`, query: `select * from blog_posts WHERE slug='${params?.single}'`,
}); });
const post = postsResponse.payload[0]; const post = postsResponse.payload[0];
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## Server Props Return // ## Server Props Return
return { return {
props: { props: {
blogPost: post, blogPost: post,
}, },
revalidate: 3600, revalidate: 3600,
}; };
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
}; };
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** /**
* Server Side Props or Static Props * Server Side Props or Static Props
* ============================================================================== * ==============================================================================
*/ */
export const getStaticPaths: GetStaticPaths = async () => { export const getStaticPaths: GetStaticPaths = async () => {
/** /**
* Data fetching * Data fetching
* *
* @abstract fetch date from the server or externnal source * @abstract fetch date from the server or externnal source
*/ */
const postsResponse = await datasquirel.get({ const postsResponse = await datasquirel.get({
key: process.env.DATASQUIREL_API_KEY, key: process.env.DATASQUIREL_API_KEY,
db: "tbenme", db: "tbenme",
query: `select slug from blog_posts`, query: `select slug from blog_posts`,
}); });
const posts: { slug: string }[] | null = postsResponse.payload; const posts: { slug: string }[] | null = postsResponse.payload;
const paths = posts?.map((entry) => { const paths = posts?.map((entry) => {
return { return {
params: { single: entry.slug }, params: { single: entry.slug },
}; };
}); });
return { return {
paths: paths ? paths : [], paths: paths ? paths : [],
fallback: "blocking", fallback: "blocking",
}; };
}; };

View File

@ -1,72 +1,72 @@
///////////////////////////////////////////// /////////////////////////////////////////////
//* IMPORTS //* IMPORTS
///////////////////////////////////////////// /////////////////////////////////////////////
import React from "react"; import React from "react";
import { Metadata } from "next"; import { Metadata } from "next";
const datasquirel = require("datasquirel"); const datasquirel = require("datasquirel");
import { headers, cookies } from "next/headers"; import { headers, cookies } from "next/headers";
///////////////////////////////////////////// /////////////////////////////////////////////
//* Metadata //* Metadata
///////////////////////////////////////////// /////////////////////////////////////////////
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Blog posts | Tben.me", title: "Blog posts | Tben.me",
description: "Tech talks and tutorials by Tben", description: "Tech talks and tutorials by Tben",
}; };
///////////////////////////////////////////// /////////////////////////////////////////////
//* Main Function //* Main Function
///////////////////////////////////////////// /////////////////////////////////////////////
/** /**
* Blog page index * Blog page index
* ============================================================================== * ==============================================================================
*/ */
export default async function BlogIndex() { export default async function BlogIndex() {
//* Data fetching //* Data fetching
///////////////////////////////////////////// /////////////////////////////////////////////
const postsResponse = await datasquirel.get({ const postsResponse = await datasquirel.get({
key: process.env.DATASQUIREL_API_KEY, key: process.env.DATASQUIREL_API_KEY,
db: process.env.DB_NAME, db: process.env.DB_NAME,
query: "select title,slug,excerpt,date_created from blog_posts limit 10", query: "select title,slug,excerpt,date_created from blog_posts limit 10",
}); });
const posts = postsResponse?.success ? postsResponse.payload : []; const posts = postsResponse?.success ? postsResponse.payload : [];
try { try {
const test = await fetch("http://localhost:5000/api/test"); const test = await fetch("http://localhost:5000/api/test");
const result = await test.json(); const result = await test.json();
console.log(result); console.log(result);
} catch (error: any) { } catch (error: any) {
console.log(error.message); console.log(error.message);
} }
console.log("Referer:", headers().get("referer")); console.log("Referer:", headers().get("referer"));
console.log("Host:", headers().get("host")); console.log("Host:", headers().get("host"));
// console.log(nextHeaders.cookies()); // console.log(nextHeaders.cookies());
//* Main Function Return //* Main Function Return
///////////////////////////////////////////// /////////////////////////////////////////////
return ( return (
<React.Fragment> <React.Fragment>
<div className="flex flex-col items-start max-w-6xl w-full"> <div className="flex flex-col items-start max-w-6xl w-full">
<h1 className="mb-8">My Blog</h1> <h1 className="mb-8">My Blog</h1>
<div className="flex flex-col items-start w-full gap-4"> <div className="flex flex-col items-start w-full gap-4">
{posts.map((post: { slug: string; title: string; excerpt: string; date_created: string }, index: number) => ( {posts.map((post: { slug: string; title: string; excerpt: string; date_created: string }, index: number) => (
<a <a
key={index} key={index}
href={`/blog/${post.slug}`} href={`/blog/${post.slug}`}
className="flex flex-col items-start gap-2 w-full hover:bg-blue-600 border border-solid border-white/20 p-8 transition-all bg-primary/10" className="flex flex-col items-start gap-2 w-full hover:bg-blue-600 border border-solid border-white/20 p-8 transition-all bg-primary/10"
> >
<h2 className="m-0">{post.title}</h2> <h2 className="m-0">{post.title}</h2>
<span className="opacity-80">{post.excerpt}</span> <span className="opacity-80">{post.excerpt}</span>
<span className="text-sm opacity-50">{post.date_created.substring(0, 24)}</span> <span className="text-sm opacity-50">{post.date_created.substring(0, 24)}</span>
</a> </a>
))} ))}
</div> </div>
</div> </div>
</React.Fragment> </React.Fragment>
); );
/** ********************************************** */ /** ********************************************** */
} }

View File

@ -1,51 +1,51 @@
/** # MODULE TRACE /** # MODULE TRACE
====================================================================== ======================================================================
* No imports found for this Module * No imports found for this Module
==== MODULE TRACE END ==== */ ==== MODULE TRACE END ==== */
// General imports // General imports
import { Metadata } from "next"; import { Metadata } from "next";
import GeneralLayout from "../layouts/general_layout/GeneralLayout"; import GeneralLayout from "../layouts/general_layout/GeneralLayout";
// Styles imports // Styles imports
import "../styles/main.css"; import "../styles/main.css";
import "../styles/tw_main.css"; import "../styles/tw_main.css";
// Metadata // Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Homepage", 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", 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", 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 // Main Layout Component
export default function RootLayout({ children }: { children: React.ReactNode }) { export default function RootLayout({ children }: { children: React.ReactNode }) {
return ( return (
<html lang="en"> <html lang="en">
<head> <head>
{/* <script {/* <script
defer defer
src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js" src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"
></script> ></script>
<script <script
defer defer
src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js" src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js"
></script> ></script>
<script <script
defer defer
src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/TextPlugin.min.js" src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/TextPlugin.min.js"
></script> */} ></script> */}
<script src="https://cdn.jsdelivr.net/gh/studio-freight/lenis@1/bundled/lenis.min.js"></script> <script src="https://cdn.jsdelivr.net/gh/studio-freight/lenis@1/bundled/lenis.min.js"></script>
<script <script
src="/scripts/main.js" src="/scripts/main.js"
defer defer
></script> ></script>
</head> </head>
<body> <body>
<GeneralLayout>{children}</GeneralLayout> <GeneralLayout>{children}</GeneralLayout>
</body> </body>
</html> </html>
); );
} }

View File

@ -1,21 +1,21 @@
import React from "react"; import React from "react";
import HomepageComponent from "./(components)/HomepageComponent"; import HomepageComponent from "./(components)/HomepageComponent";
const datasquirel = require("datasquirel"); const datasquirel = require("datasquirel");
export const revalidate = 3600; export const revalidate = 3600;
type DsqlResponse = { type DsqlResponse = {
success: boolean; success: boolean;
payload: any; payload: any;
}; };
export default async function Homepage() { export default async function Homepage() {
const projects: DsqlResponse = await datasquirel.get({ const projects: DsqlResponse = await datasquirel.get({
db: process.env.DB_NAME, db: process.env.DB_NAME,
key: process.env.DATASQUIREL_API_KEY, key: process.env.DATASQUIREL_API_KEY,
query: "SELECT * FROM portfolio ORDER BY project_order ASC", query: "SELECT * FROM portfolio ORDER BY project_order ASC",
}); });
return <HomepageComponent projects={projects.payload} />; return <HomepageComponent projects={projects.payload} />;
} }

View File

@ -1,54 +1,54 @@
/** /**
* *
* *
* Imports * Imports
* ------------------------------------------------------------------------------ * ------------------------------------------------------------------------------
* *
*/ */
/** ********************* React/Next Imports */ /** ********************* React/Next Imports */
import React from "react"; import React from "react";
import TextShuffler from "./actions/TextShuffler"; import TextShuffler from "./actions/TextShuffler";
/** ~ End React/Next Imports *************** */ /** ~ End React/Next Imports *************** */
/** ********************* Functions and Other Page Imports */ /** ********************* Functions and Other Page Imports */
/** ~ End Functions and Other Page Imports *************** */ /** ~ End Functions and Other Page Imports *************** */
/** /**
* *
* *
* Main Component { Functional } * Main Component { Functional }
* ------------------------------------------------------------------------------ * ------------------------------------------------------------------------------
* @param {Object} props - React component props including { children } * @param {Object} props - React component props including { children }
* *
*/ */
/** ********************* Page Main Component */ /** ********************* Page Main Component */
export default function PortfolioEntry({ title, description, url, image }) { export default function PortfolioEntry({ title, description, url, image }) {
// ## Get Contexts // ## Get Contexts
// ----------------------- // -----------------------
// ## Javascript Variables // ## Javascript Variables
// ----------------------- // -----------------------
// ## React Hooks { useState, useEffect, useRef, etc ... } // ## React Hooks { useState, useEffect, useRef, etc ... }
// ----------------------- // -----------------------
// ## Function Return // ## Function Return
return ( return (
<div className="portfolio-entry-block"> <div className="portfolio-entry-block">
<h2 style={ { marginTop: "0" } }><TextShuffler textInput={ title } /></h2> <h2 style={ { marginTop: "0" } }><TextShuffler textInput={ title } /></h2>
<div className="portfolio-image-wrapper"> <div className="portfolio-image-wrapper">
<img src={ image } alt="" className="portfolio-image" /> <img src={ image } alt="" className="portfolio-image" />
</div> </div>
<span> <span>
<TextShuffler textInput={ description } /> <TextShuffler textInput={ description } />
</span> </span>
<div className="hero-ctas-section"> <div className="hero-ctas-section">
<a href={ url } target="_blank">Visit Site</a> <a href={ url } target="_blank">Visit Site</a>
</div> </div>
</div> </div>
); );
// ----------------------- // -----------------------
}; };
/** ~ End Page Main Component *************** */ /** ~ End Page Main Component *************** */
// export default Header; // export default Header;

View File

@ -1,98 +1,98 @@
"use client"; "use client";
import React, { FC, useEffect, useState, ReactElement } from "react"; import React, { FC, useEffect, useState, ReactElement } from "react";
import { gsap } from "gsap"; import { gsap } from "gsap";
type ChildProps = { type ChildProps = {
textInput: string; textInput: string;
delay?: number; delay?: number;
}; };
const TextShuffler: FC<ChildProps> = ({ textInput, delay }): ReactElement => { const TextShuffler: FC<ChildProps> = ({ textInput, delay }): ReactElement => {
let [readyState, setReadyState] = useState(false); let [readyState, setReadyState] = useState(false);
const spanRef = React.useRef<HTMLElement>(null); const spanRef = React.useRef<HTMLElement>(null);
useEffect(() => { useEffect(() => {
const spanObserver = new IntersectionObserver( const spanObserver = new IntersectionObserver(
(entries, observer) => { (entries, observer) => {
if (entries[0].isIntersecting) { if (entries[0].isIntersecting) {
if (delay) { if (delay) {
setTimeout(() => { setTimeout(() => {
setReadyState(true); setReadyState(true);
}, delay); }, delay);
} else { } else {
setReadyState(true); setReadyState(true);
} }
if (spanRef.current) observer.unobserve(spanRef.current); if (spanRef.current) observer.unobserve(spanRef.current);
} }
}, },
{ {
rootMargin: "0px 0px 0px 0px", rootMargin: "0px 0px 0px 0px",
} }
); );
if (spanRef.current) spanObserver.observe(spanRef.current); if (spanRef.current) spanObserver.observe(spanRef.current);
}, []); }, []);
useEffect(() => { useEffect(() => {
if (!readyState) return; if (!readyState) return;
let chars = textInput.split(""); let chars = textInput.split("");
let charsSpans = chars.map((char) => `<span style="opacity:0">${char}</span>`); let charsSpans = chars.map((char) => `<span style="opacity:0">${char}</span>`);
if (spanRef?.current?.innerHTML) spanRef.current.innerHTML = charsSpans.join(""); if (spanRef?.current?.innerHTML) spanRef.current.innerHTML = charsSpans.join("");
if (spanRef.current) { if (spanRef.current) {
gsap.to(spanRef.current, { gsap.to(spanRef.current, {
opacity: 1, opacity: 1,
duration: 1, duration: 1,
}); });
} }
let textSpans: NodeList | null = spanRef.current ? spanRef.current.querySelectorAll("span") : null; let textSpans: NodeList | null = spanRef.current ? spanRef.current.querySelectorAll("span") : null;
requestAnimationFrame(() => { requestAnimationFrame(() => {
if (textSpans) { if (textSpans) {
textSpans.forEach((span) => { textSpans.forEach((span) => {
gsap.to(span, { gsap.to(span, {
opacity: 1, opacity: 1,
duration: Math.random() * 1.5, duration: Math.random() * 1.5,
}); });
}); });
textSpans.forEach((span) => { textSpans.forEach((span) => {
gsap.killTweensOf(span, "opacity"); gsap.killTweensOf(span, "opacity");
gsap.to(span, { gsap.to(span, {
opacity: 0, opacity: 0,
duration: Math.random() * 1.5, duration: Math.random() * 1.5,
delay: Math.random() * 0.5, delay: Math.random() * 0.5,
}); });
}); });
textSpans.forEach((span) => { textSpans.forEach((span) => {
gsap.killTweensOf(span, "opacity"); gsap.killTweensOf(span, "opacity");
gsap.to(span, { gsap.to(span, {
opacity: 1, opacity: 1,
duration: Math.random() * 1.5, duration: Math.random() * 1.5,
delay: Math.random(), delay: Math.random(),
}); });
}); });
} }
}); });
}, [readyState]); }, [readyState]);
return ( return (
<span <span
className="shuffled-text-span" className="shuffled-text-span"
ref={spanRef} ref={spanRef}
style={{ opacity: 0 }} style={{ opacity: 0 }}
> >
{textInput} {textInput}
</span> </span>
); );
}; };
export default TextShuffler; export default TextShuffler;

View File

@ -1,129 +1,129 @@
/** /**
* ============================================================================== * ==============================================================================
* Imports * Imports
* ============================================================================== * ==============================================================================
*/ */
import React from "react"; import React from "react";
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** /**
* ============================================================================== * ==============================================================================
* Main Component { Functional } * Main Component { Functional }
* ============================================================================== * ==============================================================================
* @param {Object} props - Server props * @param {Object} props - Server props
*/ */
export default function Homepage(props) { export default function Homepage(props) {
// ## Get Contexts // ## Get Contexts
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## Javascript Variables // ## Javascript Variables
/** ********************* Head Items */ /** ********************* Head Items */
let head = ( let head = (
<React.Fragment> <React.Fragment>
<title>Showmerebates | Home</title> <title>Showmerebates | Home</title>
<meta name="description" content="Find great property rebates" /> <meta name="description" content="Find great property rebates" />
</React.Fragment> </React.Fragment>
); );
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## React Hooks { useState, useEffect, useRef, etc ... } // ## React Hooks { useState, useEffect, useRef, etc ... }
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## Function Return // ## Function Return
return ( return (
<React.Fragment> <React.Fragment>
<GeneralLayout head={ head } user={ props.user }> <GeneralLayout head={ head } user={ props.user }>
<main> <main>
<Hero /> <Hero />
<HowItWorks /> <HowItWorks />
<FeaturedProperties data={ props.data } user={ props.user } /> <FeaturedProperties data={ props.data } user={ props.user } />
<AboutUsSection /> <AboutUsSection />
{ !props.user && <LoginPromptPopup user={ props.user } /> } { !props.user && <LoginPromptPopup user={ props.user } /> }
</main> </main>
</GeneralLayout> </GeneralLayout>
</React.Fragment> </React.Fragment>
); );
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
}; };
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** /**
* ============================================================================== * ==============================================================================
* Server Side Props or Static Props * Server Side Props or Static Props
* ============================================================================== * ==============================================================================
* @param {Object} req - http incoming request object * @param {Object} req - http incoming request object
* @param {Object} res - http response object * @param {Object} res - http response object
* @param {Object} query - queries attached to the url * @param {Object} query - queries attached to the url
*/ */
export async function getServerSideProps({ req, res, query }) { export async function getServerSideProps({ req, res, query }) {
// ## Environment processes // ## Environment processes
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## User Authentication // ## User Authentication
const user = await userAuth(req, res); const user = await userAuth(req, res);
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## Page/Site Data Data Fetching // ## Page/Site Data Data Fetching
let properties = await dbHandler(` let properties = await dbHandler(`
SELECT SELECT
ListingKeyNumeric,City,RoomsTotal,BathroomsFull,BathroomsTotalInteger,BedroomsTotal,UnparsedAddress,BuildingAreaTotal,ListPrice,PostalCode ListingKeyNumeric,City,RoomsTotal,BathroomsFull,BathroomsTotalInteger,BedroomsTotal,UnparsedAddress,BuildingAreaTotal,ListPrice,PostalCode
FROM FROM
utahapidata utahapidata
WHERE WHERE
PhotosCount > 0 AND ListPrice > 0 AND BedroomsTotal > 0 LIMIT 3 PhotosCount > 0 AND ListPrice > 0 AND BedroomsTotal > 0 LIMIT 3
`); `);
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## Server Props Return // ## Server Props Return
return { return {
props: { props: {
user: user, user: user,
data: properties, data: properties,
}, },
}; };
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
} }

View File

@ -1,73 +1,73 @@
/** /**
* ============================================================================== * ==============================================================================
* Imports * Imports
* ============================================================================== * ==============================================================================
*/ */
import React from "react"; import React from "react";
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** /**
* ============================================================================== * ==============================================================================
* Main Component { Functional } * Main Component { Functional }
* ============================================================================== * ==============================================================================
* @param {Object} props - Server props * @param {Object} props - Server props
*/ */
export default function SingleBlogPostPreset(props) { export default function SingleBlogPostPreset(props) {
// ## Get Contexts // ## Get Contexts
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## Javascript Variables // ## Javascript Variables
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## React Hooks { useState, useEffect, useRef, etc ... } // ## React Hooks { useState, useEffect, useRef, etc ... }
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## Function Return // ## Function Return
return ( return (
<React.Fragment> <React.Fragment>
<GeneralLayout head={ head } user={ props.user }> <GeneralLayout head={ head } user={ props.user }>
<main> <main>
<Hero /> <Hero />
<HowItWorks /> <HowItWorks />
<FeaturedProperties data={ props.data } user={ props.user } /> <FeaturedProperties data={ props.data } user={ props.user } />
<AboutUsSection /> <AboutUsSection />
{ !props.user && <LoginPromptPopup user={ props.user } /> } { !props.user && <LoginPromptPopup user={ props.user } /> }
</main> </main>
</GeneralLayout> </GeneralLayout>
</React.Fragment> </React.Fragment>
); );
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
}; };
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */

View File

@ -1,6 +1,6 @@
[ [
{ {
"title": "", "title": "",
"id": 1 "id": 1
} }
] ]

View File

@ -1,26 +1,26 @@
[ [
{ {
"title": "Showme Rebates", "title": "Showme Rebates",
"description": "Showmerebates curates agents' rebates/cashback on properties in Utah, Texas, Florida, and Kansas states", "description": "Showmerebates curates agents' rebates/cashback on properties in Utah, Texas, Florida, and Kansas states",
"url": "https://showmerebates.com/", "url": "https://showmerebates.com/",
"image": "/images/showmerebates.jpg" "image": "/images/showmerebates.jpg"
}, },
{ {
"title": "Summit Lending", "title": "Summit Lending",
"description": "Summit Lending is a mortgage broker offering competitive rates for home loans of all sorts", "description": "Summit Lending is a mortgage broker offering competitive rates for home loans of all sorts",
"url": "https://summitlending.com", "url": "https://summitlending.com",
"image": "/images/summit-lending.jpg" "image": "/images/summit-lending.jpg"
}, },
{ {
"title": "Datasquirel", "title": "Datasquirel",
"description": "Datasquirel is a fast and efficient cloud-based SQL data management system", "description": "Datasquirel is a fast and efficient cloud-based SQL data management system",
"url": "https://datasquirel.com", "url": "https://datasquirel.com",
"image": "/images/datasquirel-img.jpg" "image": "/images/datasquirel-img.jpg"
}, },
{ {
"title": "Homeruntoken", "title": "Homeruntoken",
"description": "Real Estate Investing Made Easy", "description": "Real Estate Investing Made Easy",
"url": "https://homeruntoken.vercel.app/", "url": "https://homeruntoken.vercel.app/",
"image": "/images/Homeruntoken-graphic.jpg" "image": "/images/Homeruntoken-graphic.jpg"
} }
] ]

View File

@ -1,32 +1,32 @@
[ [
{ {
"title": "Showme Rebates", "title": "Showme Rebates",
"description": "Property rebates in Utah", "description": "Property rebates in Utah",
"url": "https://dev.showmerebates.com/", "url": "https://dev.showmerebates.com/",
"image": "/images/showmerebates.jpg" "image": "/images/showmerebates.jpg"
}, },
{ {
"title": "Guaranteed software", "title": "Guaranteed software",
"description": "software development agency", "description": "software development agency",
"url": "https://guaranteed.software/", "url": "https://guaranteed.software/",
"image": "/images/guaranteed.jpg" "image": "/images/guaranteed.jpg"
}, },
{ {
"title": "Renition", "title": "Renition",
"description": "Curated top quality Apparel", "description": "Curated top quality Apparel",
"url": "https://renition.com", "url": "https://renition.com",
"image": "/images/renition-graphic.jpg" "image": "/images/renition-graphic.jpg"
}, },
{ {
"title": "Castcord", "title": "Castcord",
"description": "Social Media web app", "description": "Social Media web app",
"url": "https://cast-cord.com", "url": "https://cast-cord.com",
"image": "/images/castcord-graphic.jpg" "image": "/images/castcord-graphic.jpg"
}, },
{ {
"title": "Next 7 Web Engine", "title": "Next 7 Web Engine",
"description": "Next 7 is an all-in-one web engine featuring a web page builder and a content management system", "description": "Next 7 is an all-in-one web engine featuring a web page builder and a content management system",
"url": "https://next7.io", "url": "https://next7.io",
"image": "/images/next-7-graphic-min.jpg" "image": "/images/next-7-graphic-min.jpg"
} }
] ]

View File

@ -1,135 +1,135 @@
/** /**
* ============================================================================== * ==============================================================================
* Imports * Imports
* ============================================================================== * ==============================================================================
*/ */
const http = require("http"); const http = require("http");
const https = require("https"); const https = require("https");
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** /**
* ============================================================================== * ==============================================================================
* Main Function * Main Function
* ============================================================================== * ==============================================================================
* @param {Object} mailObject - foundUser if any * @param {Object} mailObject - foundUser if any
*/ */
/** ********************* Main API Handler */ /** ********************* Main API Handler */
module.exports = async function httpFetch({ protocol, options, paradigm }) { module.exports = async function httpFetch({ protocol, options, paradigm }) {
if (!protocol) protocol = "http"; if (!protocol) protocol = "http";
/** /**
* Http(s) Response function * Http(s) Response function
* *
* @description handle http and https protocols differently * @description handle http and https protocols differently
* @param {object} response => response object * @param {object} response => response object
* @param {Function} resolve => promise resolve method * @param {Function} resolve => promise resolve method
* @param {Function} reject => promise reject method * @param {Function} reject => promise reject method
*/ */
function httpResponse(response, resolve, reject) { function httpResponse(response, resolve, reject) {
var str = ""; var str = "";
/** * Append data chunks to "str" variable /** * Append data chunks to "str" variable
*/ */
response.on("data", function (chunk) { response.on("data", function (chunk) {
str += chunk; str += chunk;
}); });
/** * the whole response has been received, so we just print it out here /** * the whole response has been received, so we just print it out here
*/ */
response.on("end", function () { response.on("end", function () {
resolve(JSON.parse(str)); resolve(JSON.parse(str));
}); });
/** * Handle errors /** * Handle errors
*/ */
response.on("error", (err) => { response.on("error", (err) => {
console.log(err); console.log(err);
reject("Fetch Failed"); reject("Fetch Failed");
}); });
} }
/** /**
* Switch protocols * Switch protocols
* *
* @description handle http and https protocols differently * @description handle http and https protocols differently
*/ */
switch (protocol) { switch (protocol) {
case "http": case "http":
/** /**
* Handle http protocol * Handle http protocol
* *
* @description handles fetch requests with http protocol * @description handles fetch requests with http protocol
* @see => handles strapi api calls only for now * @see => handles strapi api calls only for now
*/ */
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {
http.request( http.request(
/** * Make Request /** * Make Request
* @abstract Make Request * @abstract Make Request
*/ */
{ {
...options, ...options,
host: "localhost", host: "localhost",
port: "1337", port: "1337",
// path: "/api/blog-posts", // path: "/api/blog-posts",
// href: "http://localhost:1337/api/blog-posts", // href: "http://localhost:1337/api/blog-posts",
headers: { headers: {
Authorization: `bearer ${process.env.STRAPI_API_KEY_DEV}`, Authorization: `bearer ${process.env.STRAPI_API_KEY_DEV}`,
}, },
}, },
/** * Handle Response /** * Handle Response
* @abstract Handle response * @abstract Handle response
*/ */
(response) => { (response) => {
httpResponse(response, resolve, reject); httpResponse(response, resolve, reject);
} }
).end(); ).end();
}); });
break; break;
case "https": case "https":
/** /**
* Handle http protocol * Handle http protocol
* *
* @description handles fetch requests with http protocol * @description handles fetch requests with http protocol
* @see => handles strapi api calls only for now * @see => handles strapi api calls only for now
*/ */
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {
https.request( https.request(
/** * Make Request /** * Make Request
* @abstract Make Request * @abstract Make Request
*/ */
{ {
...options, ...options,
host: "cms.showmerebates.com", host: "cms.showmerebates.com",
headers: { headers: {
Authorization: `bearer ${process.env.STRAPI_API_KEY}`, Authorization: `bearer ${process.env.STRAPI_API_KEY}`,
}, },
}, },
/** * Handle Response /** * Handle Response
* @abstract Handle response * @abstract Handle response
*/ */
(response) => { (response) => {
httpResponse(response, resolve, reject); httpResponse(response, resolve, reject);
} }
).end(); ).end();
}); });
break; break;
default: default:
break; break;
} }
}; };
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */

View File

@ -1,10 +1,10 @@
const sanitizeHtmlOptions: object = { const sanitizeHtmlOptions: object = {
allowedTags: ["b", "i", "em", "strong", "a", "p", "span", "ul", "ol", "li", "h1", "h2", "h3", "h4", "h5", "h6", "img", "div", "button", "pre", "code", "br"], allowedTags: ["b", "i", "em", "strong", "a", "p", "span", "ul", "ol", "li", "h1", "h2", "h3", "h4", "h5", "h6", "img", "div", "button", "pre", "code", "br"],
allowedAttributes: { allowedAttributes: {
a: ["href"], a: ["href"],
img: ["src", "alt", "width", "height", "class", "style"], img: ["src", "alt", "width", "height", "class", "style"],
"*": ["style", "class"], "*": ["style", "class"],
}, },
}; };
export default sanitizeHtmlOptions; export default sanitizeHtmlOptions;

View File

@ -1,40 +1,40 @@
import { Dispatch, SetStateAction } from "react"; import { Dispatch, SetStateAction } from "react";
export default async function submitContactForm(e: any, setSuccess: Dispatch<SetStateAction<string | null>>, setLoading: Dispatch<SetStateAction<boolean>>) { export default async function submitContactForm(e: any, setSuccess: Dispatch<SetStateAction<string | null>>, setLoading: Dispatch<SetStateAction<boolean>>) {
e.preventDefault(); e.preventDefault();
setLoading(true); setLoading(true);
let name = e.target[0].value; let name = e.target[0].value;
let email = e.target[1].value; let email = e.target[1].value;
let message = e.target[2].value; let message = e.target[2].value;
let body = { let body = {
name: name, name: name,
email: email, email: email,
message: message, message: message,
}; };
let res = await fetch("/api/contactForm", { let res = await fetch("/api/contactForm", {
method: "post", method: "post",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify(body), body: JSON.stringify(body),
}); });
let data = await res.json(); let data = await res.json();
console.log(data); console.log(data);
if (data.msg === "Success") { if (data.msg === "Success") {
setSuccess("Success"); setSuccess("Success");
setTimeout(() => { setTimeout(() => {
window.location.reload(); window.location.reload();
}, 1000); }, 1000);
} else { } else {
setSuccess("Failed"); setSuccess("Failed");
} }
setLoading(false); setLoading(false);
} }

View File

@ -1,13 +1,13 @@
export const textSHuffle = (text, dispatch) => { export const textSHuffle = (text, dispatch) => {
let shuffleTimer = 0; let shuffleTimer = 0;
let startText = text; let startText = text;
let shuffledtext let shuffledtext
setInterval(()=>{ setInterval(()=>{
shuffleTimer++ shuffleTimer++
shuffledtext = startText + "whatever"; shuffledtext = startText + "whatever";
}, 200); }, 200);
return shuffledtext return shuffledtext
} }

View File

@ -1,132 +1,132 @@
import * as THREE from "three"; import * as THREE from "three";
export default function threeJsAnimations() { export default function threeJsAnimations() {
const animationWrapper = document.getElementById("homepage-animation-wrapper"); const animationWrapper = document.getElementById("homepage-animation-wrapper");
const scene = new THREE.Scene(); const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, animationWrapper.clientWidth / animationWrapper.clientHeight, 0.1, 1000); const camera = new THREE.PerspectiveCamera(75, animationWrapper.clientWidth / animationWrapper.clientHeight, 0.1, 1000);
const light = new THREE.PointLight(0xff0000, 1, 200); const light = new THREE.PointLight(0xff0000, 1, 200);
light.position.set(-1, -1, 5); light.position.set(-1, -1, 5);
const ambientLight = new THREE.AmbientLight("#adb2d3"); const ambientLight = new THREE.AmbientLight("#adb2d3");
const pointLight = new THREE.PointLight(0xffffff, 1, 100); const pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(10, 10, 10); pointLight.position.set(10, 10, 10);
const sphereSize = 1; const sphereSize = 1;
const pointLightHelper = new THREE.PointLightHelper(pointLight, sphereSize); const pointLightHelper = new THREE.PointLightHelper(pointLight, sphereSize);
const renderer = new THREE.WebGLRenderer(); const renderer = new THREE.WebGLRenderer();
renderer.setSize(animationWrapper.clientWidth, animationWrapper.clientHeight); renderer.setSize(animationWrapper.clientWidth, animationWrapper.clientHeight);
animationWrapper.appendChild(renderer.domElement); animationWrapper.appendChild(renderer.domElement);
const geometry = new THREE.BoxGeometry(); const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshPhongMaterial({ const material = new THREE.MeshPhongMaterial({
// light // light
// specular: "rgb(30, 33, 68)", // specular: "rgb(30, 33, 68)",
// intermediate // intermediate
color: "rgb(30, 33, 68)", color: "rgb(30, 33, 68)",
// dark // dark
// emissive: "rgb(30, 33, 68)", // emissive: "rgb(30, 33, 68)",
shininess: 50, shininess: 50,
wireframe: true, wireframe: true,
// map: THREE.ImageUtils.loadTexture("http://i.imgur.com/xCE2Br4.jpg?1"), // map: THREE.ImageUtils.loadTexture("http://i.imgur.com/xCE2Br4.jpg?1"),
}); });
const cube = new THREE.Mesh(geometry, material); const cube = new THREE.Mesh(geometry, material);
const material2 = new THREE.MeshPhongMaterial({ const material2 = new THREE.MeshPhongMaterial({
// light // light
// specular: "rgb(30, 33, 68)", // specular: "rgb(30, 33, 68)",
// intermediate // intermediate
color: "#1668e4", color: "#1668e4",
// dark // dark
// emissive: "rgb(30, 33, 68)", // emissive: "rgb(30, 33, 68)",
shininess: 50, shininess: 50,
wireframe: false, wireframe: false,
// map: THREE.ImageUtils.loadTexture("http://i.imgur.com/xCE2Br4.jpg?1"), // map: THREE.ImageUtils.loadTexture("http://i.imgur.com/xCE2Br4.jpg?1"),
}); });
const cube2 = new THREE.Mesh(geometry, material2); const cube2 = new THREE.Mesh(geometry, material2);
cube2.position.x = window.innerWidth > 500 ? 1.5 : -0.5; cube2.position.x = window.innerWidth > 500 ? 1.5 : -0.5;
cube2.position.y = window.innerWidth > 500 ? 1.5 : 1.8; cube2.position.y = window.innerWidth > 500 ? 1.5 : 1.8;
cube2.position.z = -1; cube2.position.z = -1;
cube2.scale.x = 0.3; cube2.scale.x = 0.3;
cube2.scale.y = 0.3; cube2.scale.y = 0.3;
cube2.scale.z = 0.3; cube2.scale.z = 0.3;
const material3 = new THREE.MeshPhongMaterial({ const material3 = new THREE.MeshPhongMaterial({
// light // light
// specular: "rgb(30, 33, 68)", // specular: "rgb(30, 33, 68)",
// intermediate // intermediate
color: "rgb(53, 65, 194)", color: "rgb(53, 65, 194)",
// dark // dark
// emissive: "rgb(30, 33, 68)", // emissive: "rgb(30, 33, 68)",
shininess: 50, shininess: 50,
wireframe: false, wireframe: false,
// map: THREE.ImageUtils.loadTexture("http://i.imgur.com/xCE2Br4.jpg?1"), // map: THREE.ImageUtils.loadTexture("http://i.imgur.com/xCE2Br4.jpg?1"),
}); });
const cube3 = new THREE.Mesh(geometry, material3); const cube3 = new THREE.Mesh(geometry, material3);
scene.add(cube); scene.add(cube);
scene.add(cube2); scene.add(cube2);
scene.add(cube3); scene.add(cube3);
scene.add(ambientLight); scene.add(ambientLight);
scene.add(light); scene.add(light);
scene.add(pointLight); scene.add(pointLight);
scene.add(pointLightHelper); scene.add(pointLightHelper);
cube3.position.x = -1.5; cube3.position.x = -1.5;
cube3.position.y = -1.5; cube3.position.y = -1.5;
cube3.position.z = -1; cube3.position.z = -1;
cube3.scale.x = 0.2; cube3.scale.x = 0.2;
cube3.scale.y = 0.2; cube3.scale.y = 0.2;
cube3.scale.z = 0.2; cube3.scale.z = 0.2;
camera.position.z = 2; camera.position.z = 2;
function animate() { function animate() {
requestAnimationFrame(animate); requestAnimationFrame(animate);
renderer.render(scene, camera); renderer.render(scene, camera);
cube.rotation.x += 0.002; cube.rotation.x += 0.002;
cube.rotation.y += 0.002; cube.rotation.y += 0.002;
cube2.rotation.x += 0.005; cube2.rotation.x += 0.005;
cube2.rotation.y += 0.005; cube2.rotation.y += 0.005;
cube3.rotation.x += 0.01; cube3.rotation.x += 0.01;
cube3.rotation.y += 0.01; cube3.rotation.y += 0.01;
scene.rotation.z += 0.0003; scene.rotation.z += 0.0003;
} }
animate(); animate();
window.addEventListener("mousemove", (e) => { window.addEventListener("mousemove", (e) => {
let relMouseX = e.x - window.innerWidth / 2; let relMouseX = e.x - window.innerWidth / 2;
let relMouseY = e.y - window.innerHeight / 2; let relMouseY = e.y - window.innerHeight / 2;
// console.log("X pos: ", relMouseX); // console.log("X pos: ", relMouseX);
// console.log("Y pos: ", relMouseY); // console.log("Y pos: ", relMouseY);
// console.log(e.y); // console.log(e.y);
relMouseX < 0 ? (cube.rotation.x += 0.003) : (cube.rotation.x += 0.003); relMouseX < 0 ? (cube.rotation.x += 0.003) : (cube.rotation.x += 0.003);
relMouseY > 0 ? (cube.rotation.y += 0.003) : (cube.rotation.y += 0.003); relMouseY > 0 ? (cube.rotation.y += 0.003) : (cube.rotation.y += 0.003);
relMouseX < 0 ? (cube2.position.x += 0.001) : (cube2.position.x -= 0.001); relMouseX < 0 ? (cube2.position.x += 0.001) : (cube2.position.x -= 0.001);
relMouseY > 0 ? (cube2.position.y += 0.001) : (cube2.position.y -= 0.001); relMouseY > 0 ? (cube2.position.y += 0.001) : (cube2.position.y -= 0.001);
relMouseX < 0 ? (cube3.position.x += 0.0007) : (cube3.position.x -= 0.0007); relMouseX < 0 ? (cube3.position.x += 0.0007) : (cube3.position.x -= 0.0007);
relMouseY > 0 ? (cube3.position.y += 0.0007) : (cube3.position.y -= 0.0007); relMouseY > 0 ? (cube3.position.y += 0.0007) : (cube3.position.y -= 0.0007);
}); });
window.addEventListener("resize", (e) => { window.addEventListener("resize", (e) => {
renderer.setSize(animationWrapper.clientWidth, window.innerHeight); renderer.setSize(animationWrapper.clientWidth, window.innerHeight);
}); });
window.addEventListener("scroll", (e) => { window.addEventListener("scroll", (e) => {
if (window.scrollY > 100) { if (window.scrollY > 100) {
scene.remove(cube2); scene.remove(cube2);
scene.remove(cube3); scene.remove(cube3);
} else { } else {
scene.add(cube2); scene.add(cube2);
scene.add(cube3); scene.add(cube3);
} }
}); });
} }

View File

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1766.7 2003.6" style="enable-background:new 0 0 1766.7 2003.6;" xml:space="preserve"> viewBox="0 0 1766.7 2003.6" style="enable-background:new 0 0 1766.7 2003.6;" xml:space="preserve">
<style type="text/css"> <style type="text/css">
.st0{opacity:0.1;fill:#1730C6;enable-background:new ;} .st0{opacity:0.1;fill:#1730C6;enable-background:new ;}
.st1{fill:#FFFFFF;} .st1{fill:#FFFFFF;}
</style> </style>
<g id="Layer_2_1_"> <g id="Layer_2_1_">
<g id="Layer_1-2"> <g id="Layer_1-2">
<path class="st0" d="M1468,1688.2l137.5-1540.8H883.3v1702.9L1468,1688.2z"/> <path class="st0" d="M1468,1688.2l137.5-1540.8H883.3v1702.9L1468,1688.2z"/>
<path class="st1" d="M0,0l160.8,1803.3l721.5,200.3l0,0l723.5-200.6l161-1803L0,0z M1396.7,816.3L1396.7,816.3l-5.4,59.4 <path class="st1" d="M0,0l160.8,1803.3l721.5,200.3l0,0l723.5-200.6l161-1803L0,0z M1396.7,816.3L1396.7,816.3l-5.4,59.4
l-52,582.3l-3.3,37.4l-452.6,125.4l0,0l-1,0.3l-453.1-125.7l-31-347.3h222l15.8,176.4l246.4,66.5h0.2l0,0l246.7-66.6l25.7-286.9 l-52,582.3l-3.3,37.4l-452.6,125.4l0,0l-1,0.3l-453.1-125.7l-31-347.3h222l15.8,176.4l246.4,66.5h0.2l0,0l246.7-66.6l25.7-286.9
H388.4l-19.8-221.2h805.5l20.1-226.5H348.9l-20.1-221.2h1107.9L1396.7,816.3z"/> H388.4l-19.8-221.2h805.5l20.1-226.5H348.9l-20.1-221.2h1107.9L1396.7,816.3z"/>
</g> </g>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 938 B

After

Width:  |  Height:  |  Size: 955 B

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve"> viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
<style type="text/css"> <style type="text/css">
.st0{fill:#1C3766;} .st0{fill:#1C3766;}
</style> </style>
<g> <g>
<path class="st0" d="M28.6,13.4l-11,9.4c-0.7,0.6-1.7,0.9-2.6,0.9c-0.9,0-1.8-0.3-2.6-0.9l-11-9.4C-0.3,12-0.5,9.4,1,7.7 <path class="st0" d="M28.6,13.4l-11,9.4c-0.7,0.6-1.7,0.9-2.6,0.9c-0.9,0-1.8-0.3-2.6-0.9l-11-9.4C-0.3,12-0.5,9.4,1,7.7
C2.4,6,5,5.8,6.6,7.2l8.4,7.2l8.4-7.2C25.1,5.8,27.6,6,29,7.7C30.5,9.4,30.3,12,28.6,13.4z"/> C2.4,6,5,5.8,6.6,7.2l8.4,7.2l8.4-7.2C25.1,5.8,27.6,6,29,7.7C30.5,9.4,30.3,12,28.6,13.4z"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 638 B

View File

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 433.6 491.7" style="enable-background:new 0 0 433.6 491.7;" xml:space="preserve"> viewBox="0 0 433.6 491.7" style="enable-background:new 0 0 433.6 491.7;" xml:space="preserve">
<style type="text/css"> <style type="text/css">
.st0{opacity:0.1;fill:#2236C6;enable-background:new ;} .st0{opacity:0.1;fill:#2236C6;enable-background:new ;}
.st1{fill:#FFFFFF;} .st1{fill:#FFFFFF;}
</style> </style>
<g id="Layer_2_1_"> <g id="Layer_2_1_">
<g id="Layer_1-2"> <g id="Layer_1-2">
<polygon class="st0" points="216.8,454.1 360.3,414.3 394,36.2 216.8,36.2 "/> <polygon class="st0" points="216.8,454.1 360.3,414.3 394,36.2 216.8,36.2 "/>
<path class="st1" d="M0,0l39.5,442.6l177.1,49.2l177.6-49.2L433.6,0L0,0z M351.3,105l-2.5,27.5l-1.1,12.2H140l5,55.6h197.8 <path class="st1" d="M0,0l39.5,442.6l177.1,49.2l177.6-49.2L433.6,0L0,0z M351.3,105l-2.5,27.5l-1.1,12.2H140l5,55.6h197.8
l-1.3,14.6l-12.8,142.9l-0.8,9.2l-111.1,30.8l0,0l-0.2,0.1L105.3,367l-7.6-85.2h54.5l3.9,43.3l60.4,16.3l0,0l0,0l60.5-16.3 l-1.3,14.6l-12.8,142.9l-0.8,9.2l-111.1,30.8l0,0l-0.2,0.1L105.3,367l-7.6-85.2h54.5l3.9,43.3l60.4,16.3l0,0l0,0l60.5-16.3
l6.3-70.4H95.3L82,105l-1.3-14.6h271.9L351.3,105z"/> l6.3-70.4H95.3L82,105l-1.3-14.6h271.9L351.3,105z"/>
</g> </g>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 908 B

After

Width:  |  Height:  |  Size: 925 B

View File

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 310 310" style="enable-background:new 0 0 310 310;" xml:space="preserve"> viewBox="0 0 310 310" style="enable-background:new 0 0 310 310;" xml:space="preserve">
<style type="text/css"> <style type="text/css">
.st0{fill:#FFFFFF;} .st0{fill:#FFFFFF;}
</style> </style>
<g id="XMLID_801_"> <g id="XMLID_801_">
<path id="XMLID_802_" class="st0" d="M72.2,99.7H9.9c-2.8,0-5,2.2-5,5v199.9c0,2.8,2.2,5,5,5h62.2c2.8,0,5-2.2,5-5V104.7 <path id="XMLID_802_" class="st0" d="M72.2,99.7H9.9c-2.8,0-5,2.2-5,5v199.9c0,2.8,2.2,5,5,5h62.2c2.8,0,5-2.2,5-5V104.7
C77.2,102,74.9,99.7,72.2,99.7z"/> C77.2,102,74.9,99.7,72.2,99.7z"/>
<path id="XMLID_803_" class="st0" d="M41.1,0.3C18.4,0.3,0,18.7,0,41.4c0,22.6,18.4,41,41.1,41c22.6,0,41-18.4,41-41 <path id="XMLID_803_" class="st0" d="M41.1,0.3C18.4,0.3,0,18.7,0,41.4c0,22.6,18.4,41,41.1,41c22.6,0,41-18.4,41-41
C82.1,18.7,63.7,0.3,41.1,0.3z"/> C82.1,18.7,63.7,0.3,41.1,0.3z"/>
<path id="XMLID_804_" class="st0" d="M230.5,94.8c-25,0-43.5,10.7-54.7,23v-13c0-2.8-2.2-5-5-5h-59.6c-2.8,0-5,2.2-5,5v199.9 <path id="XMLID_804_" class="st0" d="M230.5,94.8c-25,0-43.5,10.7-54.7,23v-13c0-2.8-2.2-5-5-5h-59.6c-2.8,0-5,2.2-5,5v199.9
c0,2.8,2.2,5,5,5h62.1c2.8,0,5-2.2,5-5v-98.9c0-33.3,9.1-46.3,32.3-46.3c25.3,0,27.3,20.8,27.3,48v97.2c0,2.8,2.2,5,5,5H305 c0,2.8,2.2,5,5,5h62.1c2.8,0,5-2.2,5-5v-98.9c0-33.3,9.1-46.3,32.3-46.3c25.3,0,27.3,20.8,27.3,48v97.2c0,2.8,2.2,5,5,5H305
c2.8,0,5-2.2,5-5V195C310,145.4,300.5,94.8,230.5,94.8z"/> c2.8,0,5-2.2,5-5V195C310,145.4,300.5,94.8,230.5,94.8z"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve"> viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
<style type="text/css"> <style type="text/css">
.st0{fill:#FFFFFF;} .st0{fill:#FFFFFF;}
</style> </style>
<g> <g>
<path class="st0" d="M28.6,13.4l-11,9.4c-0.7,0.6-1.7,0.9-2.6,0.9c-0.9,0-1.8-0.3-2.6-0.9l-11-9.4C-0.3,12-0.5,9.4,1,7.7 <path class="st0" d="M28.6,13.4l-11,9.4c-0.7,0.6-1.7,0.9-2.6,0.9c-0.9,0-1.8-0.3-2.6-0.9l-11-9.4C-0.3,12-0.5,9.4,1,7.7
C2.4,6,5,5.8,6.6,7.2l8.4,7.2l8.4-7.2C25.1,5.8,27.6,6,29,7.7C30.5,9.4,30.3,12,28.6,13.4z"/> C2.4,6,5,5.8,6.6,7.2l8.4,7.2l8.4-7.2C25.1,5.8,27.6,6,29,7.7C30.5,9.4,30.3,12,28.6,13.4z"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 638 B

View File

@ -1,394 +1,394 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<!-- ...................................................................................................................... Head --> <!-- ...................................................................................................................... Head -->
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Tben Web Designer</title> <title>Tben Web Designer</title>
<meta name="description" content="Web/Graphic/Motion Designer, UI UX Designer, Frontend Web Developer"> <meta name="description" content="Web/Graphic/Motion Designer, UI UX Designer, Frontend Web Developer">
<link rel="shortcut icon" href="https://benjamintoby.github.io/personal_site/images/favicon4.ico" <link rel="shortcut icon" href="https://benjamintoby.github.io/personal_site/images/favicon4.ico"
type="image/x-icon"> type="image/x-icon">
<link href="https://fonts.googleapis.com/css?family=Titillium+Web:400,500,600,700,800|Material+Icons" <link href="https://fonts.googleapis.com/css?family=Titillium+Web:400,500,600,700,800|Material+Icons"
rel="stylesheet"> rel="stylesheet">
<link rel="stylesheet" href="main.css"> <link rel="stylesheet" href="main.css">
</head> </head>
<body> <body>
<!-- #################################################################################-- Preloader --> <!-- #################################################################################-- Preloader -->
<div class="preloader-init" id="preloader"></div> <div class="preloader-init" id="preloader"></div>
<!-- #################################################################################-- Header --> <!-- #################################################################################-- Header -->
<header> <header>
<a href="#"> <a href="#">
<img src="images/logo-v3.svg" alt=""> <img src="images/logo-v3.svg" alt="">
<div>Tben.<br>Design</div> <div>Tben.<br>Design</div>
</a> </a>
<div> <div>
<nav> <nav>
<a href="#my-work" id="my-work-link" class="nav-link">My Work</a> <a href="#my-work" id="my-work-link" class="nav-link">My Work</a>
<a href="#about-me" id="about-me-link" class="nav-link">About Me</a> <a href="#about-me" id="about-me-link" class="nav-link">About Me</a>
<a href="#my-specialties" id="resume-link" class="nav-link footer-special">Resume</a> <a href="#my-specialties" id="resume-link" class="nav-link footer-special">Resume</a>
<a href="#contact-me" id="contact-me-link" class="nav-link footer-special">Contact Me</a> <a href="#contact-me" id="contact-me-link" class="nav-link footer-special">Contact Me</a>
</nav> </nav>
</div> </div>
<div style="display: flex;align-items: center;"> <div style="display: flex;align-items: center;">
<a href="mailto:benoti.san@gmail.com" class="social-media-links material-icons" id="mail">mail</a> <a href="mailto:benoti.san@gmail.com" class="social-media-links material-icons" id="mail">mail</a>
<a href="https://linkedin.com/in/benjamin-toby" class="social-media-links material-icons" id="linkedin" <a href="https://linkedin.com/in/benjamin-toby" class="social-media-links material-icons" id="linkedin"
target="_blank"><img src="images/linkedin.svg" alt=""></a> target="_blank"><img src="images/linkedin.svg" alt=""></a>
</div> </div>
<button class="hamburger-button"> <button class="hamburger-button">
<div></div> <div></div>
<div></div> <div></div>
<div></div> <div></div>
</button> </button>
</header> </header>
<div id="header-controller"></div> <div id="header-controller"></div>
<!-- #################################################################################-- Preloader --> <!-- #################################################################################-- Preloader -->
<div id="preloader-container"> <div id="preloader-container">
<img src="images/clouds.jpg" alt=""> <img src="images/clouds.jpg" alt="">
<img src="images/logo-v3.svg" alt=""> <img src="images/logo-v3.svg" alt="">
</div> </div>
<!-- #################################################################################-- Hero --> <!-- #################################################################################-- Hero -->
<section class="hero-section"> <section class="hero-section">
<div></div> <div></div>
<div> <div>
<div class="main-text-block"> <div class="main-text-block">
Hi. Im a Hi. Im a
<h1 class="main-hero-text"> <h1 class="main-hero-text">
<a href="#" class="uiux-designer-link">UI UX Designer</a>, <a href="#" class="uiux-designer-link">UI UX Designer</a>,
<a href="#" class="web-designer-link">Web Designer</a>, <a href="#" class="web-designer-link">Web Designer</a>,
<a href="#" class="frontend-designer-link">Frontend Web Developer</a>, <a href="#" class="frontend-designer-link">Frontend Web Developer</a>,
<a href="#" class="graphic-motion-designer-link">Graphic and motion Designer</a>. <a href="#" class="graphic-motion-designer-link">Graphic and motion Designer</a>.
</h1> <br> </h1> <br>
<button class="main-cta-button"><a href="#contact-me">Let's Talk</a></button> <button class="main-cta-button"><a href="#contact-me">Let's Talk</a></button>
</div> </div>
<!-- <div class="hero-scroll-down-block"> <!-- <div class="hero-scroll-down-block">
<a href="#my-work"> <a href="#my-work">
<div>&lsaquo;</div> <div>&lsaquo;</div>
</a> </a>
<img src="images/rotating-text.svg" alt="" class="rotating-text-image"> <img src="images/rotating-text.svg" alt="" class="rotating-text-image">
</div> --> </div> -->
<div class="hero-text-section-graphic"> <div class="hero-text-section-graphic">
<a href="#my-work"> <a href="#my-work">
<img src="images/down-arrow.svg" alt=""> <img src="images/down-arrow.svg" alt="">
</a> </a>
<div></div> <div></div>
<div></div> <div></div>
<div></div> <div></div>
</div> </div>
</div> </div>
<img src="images/clouds.jpg" alt="" id="clouds"> <img src="images/clouds.jpg" alt="" id="clouds">
<img src="images/mountains.png" alt="" id="mountains"> <img src="images/mountains.png" alt="" id="mountains">
<div class="benjamin-image-block-wrapper"> <div class="benjamin-image-block-wrapper">
<div class="benjamin-image-block"> <div class="benjamin-image-block">
<div class="benjamin-image-block-overlay"></div> <div class="benjamin-image-block-overlay"></div>
</div> </div>
<div class="service-display-block"> <div class="service-display-block">
</div> </div>
</div> </div>
<div class="benjamin-big-text-block">Benjamin<br>Toby</div> <div class="benjamin-big-text-block">Benjamin<br>Toby</div>
</section> </section>
<!-- #################################################################################-- My Work --> <!-- #################################################################################-- My Work -->
<section class="my-work-section" id="my-work"> <section class="my-work-section" id="my-work">
<div> <div>
<h2 class="scroll-into-view-content" data-delay="200">Some of My Work</h2> <h2 class="scroll-into-view-content" data-delay="200">Some of My Work</h2>
<p class="scroll-into-view-content" data-delay="400">Here are a few of my works: you can find more of my <p class="scroll-into-view-content" data-delay="400">Here are a few of my works: you can find more of my
work on my <a href="https://99designs.com/profiles/2220588" target="_blank">99designs</a> profile.</p> work on my <a href="https://99designs.com/profiles/2220588" target="_blank">99designs</a> profile.</p>
<div class="portfolio-buttons-container"> <div class="portfolio-buttons-container">
<button class="portfolio-left-button"><img src="images/white-arrow.svg" alt=""></button> <button class="portfolio-left-button"><img src="images/white-arrow.svg" alt=""></button>
<button class="portfolio-right-button"><img src="images/white-arrow.svg" alt=""></button> <button class="portfolio-right-button"><img src="images/white-arrow.svg" alt=""></button>
</div> </div>
</div> </div>
<div class="scroll-into-view"> <div class="scroll-into-view">
<div class="portfolio-items-container scroll-into-view-content" data-delay="800"> <div class="portfolio-items-container scroll-into-view-content" data-delay="800">
<!-- Porfolio entry --> <!-- Porfolio entry -->
<div class="portfolio-entry" id="transcend-barriers"> <div class="portfolio-entry" id="transcend-barriers">
<!-- <img src="images/my-image-large.jpg" alt=""> --> <!-- <img src="images/my-image-large.jpg" alt=""> -->
<div> <div>
<h3>Transcend Barriers Animation</h3> <h3>Transcend Barriers Animation</h3>
<p>This animation was made for web view. I used aftereffects and bodymoving to accomplish this: <p>This animation was made for web view. I used aftereffects and bodymoving to accomplish this:
the result? High definition svg anmimation that looks crisp on any resolution and maintains the result? High definition svg anmimation that looks crisp on any resolution and maintains
a relatively light weight</p> a relatively light weight</p>
</div> </div>
<div> <div>
<div class="specialty-skill"> <div class="specialty-skill">
<div>Adobe Illustrator</div><img src="images/illustrator.svg" alt=""> <div>Adobe Illustrator</div><img src="images/illustrator.svg" alt="">
</div> </div>
<div class="specialty-skill"> <div class="specialty-skill">
<div>Adobe After Effects</div><img src="images/aftereffects.svg" alt=""> <div>Adobe After Effects</div><img src="images/aftereffects.svg" alt="">
</div> </div>
<div class="specialty-skill"> <div class="specialty-skill">
<div>javascript</div><img src="images/javascript.svg" alt=""> <div>javascript</div><img src="images/javascript.svg" alt="">
</div> </div>
</div> </div>
</div> </div>
<!-- Porfolio entry --> <!-- Porfolio entry -->
<div class="portfolio-entry" id="github-to-asana"> <div class="portfolio-entry" id="github-to-asana">
<!-- <img src="images/mountains.png" alt=""> --> <!-- <img src="images/mountains.png" alt=""> -->
<div> <div>
<h3>Github to Asana</h3> <h3>Github to Asana</h3>
<p>This project is an ongoing webapp that connects github to asana. In this project I'm focusing <p>This project is an ongoing webapp that connects github to asana. In this project I'm focusing
on the UI/UX, together with frontend functionality.</p> on the UI/UX, together with frontend functionality.</p>
</div> </div>
<div> <div>
<div class="specialty-skill"> <div class="specialty-skill">
<div>Adobe Photoshop</div><img src="images/photoshop.svg" alt=""> <div>Adobe Photoshop</div><img src="images/photoshop.svg" alt="">
</div> </div>
<div class="specialty-skill"> <div class="specialty-skill">
<div>Adobe Illustrator</div><img src="images/illustrator.svg" alt=""> <div>Adobe Illustrator</div><img src="images/illustrator.svg" alt="">
</div> </div>
<div class="specialty-skill"> <div class="specialty-skill">
<div>Adobe After Effects</div><img src="images/aftereffects.svg" alt=""> <div>Adobe After Effects</div><img src="images/aftereffects.svg" alt="">
</div> </div>
<div class="specialty-skill"> <div class="specialty-skill">
<div>HTML5</div><img src="images/html5.svg" alt=""> <div>HTML5</div><img src="images/html5.svg" alt="">
</div> </div>
<div class="specialty-skill"> <div class="specialty-skill">
<div>CSS3</div><img src="images/css3.svg" alt=""> <div>CSS3</div><img src="images/css3.svg" alt="">
</div> </div>
<div class="specialty-skill"> <div class="specialty-skill">
<div>javascript</div><img src="images/javascript.svg" alt=""> <div>javascript</div><img src="images/javascript.svg" alt="">
</div> </div>
<div class="specialty-skill"> <div class="specialty-skill">
<div>Git version control</div><img src="images/git-version-control.svg" alt=""> <div>Git version control</div><img src="images/git-version-control.svg" alt="">
</div> </div>
</div> </div>
<img src="images/Project_GitToAsana_LandingPage_002.jpg" alt=""> <img src="images/Project_GitToAsana_LandingPage_002.jpg" alt="">
<div id="github-to-asana-animation"></div> <div id="github-to-asana-animation"></div>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
<!-- #################################################################################-- About Me --> <!-- #################################################################################-- About Me -->
<section class="about-me-section" id="about-me"> <section class="about-me-section" id="about-me">
<div class="scroll-into-view"> <div class="scroll-into-view">
<img src="images/my-image-large.jpg" alt=""> <img src="images/my-image-large.jpg" alt="">
</div> </div>
<div> <div>
<h2 class="scroll-into-view-content">About Me</h2> <h2 class="scroll-into-view-content">About Me</h2>
<p class="scroll-into-view-content">I've traversed multiple fields over the past decade: from engineering <p class="scroll-into-view-content">I've traversed multiple fields over the past decade: from engineering
studies, to solar power constructions, to web design, graphic design, 2d animations, and code. Over the studies, to solar power constructions, to web design, graphic design, 2d animations, and code. Over the
years I've learnt the best skill: which is learnability and adaptability: hence I aim to cut across many years I've learnt the best skill: which is learnability and adaptability: hence I aim to cut across many
different fields: the world changes fast, and I think this is the only skill that matters.</p> different fields: the world changes fast, and I think this is the only skill that matters.</p>
</div> </div>
</section> </section>
<!-- #################################################################################-- My Specialties --> <!-- #################################################################################-- My Specialties -->
<section class="my-specialties-section" id="my-specialties"> <section class="my-specialties-section" id="my-specialties">
<h2 class="scroll-into-view-content">My Tools For Creating Awesomeness</h2> <h2 class="scroll-into-view-content">My Tools For Creating Awesomeness</h2>
<p class="scroll-into-view-content">Ever expanding and ever improving, I have proffesional grade understanding <p class="scroll-into-view-content">Ever expanding and ever improving, I have proffesional grade understanding
of the tools below. But I don't plan to stop here.</p> of the tools below. But I don't plan to stop here.</p>
<div> <div>
<div class="specialty-skill scroll-into-view-content" data-delay="0"> <div class="specialty-skill scroll-into-view-content" data-delay="0">
<div>Adobe Photoshop</div><img src="images/photoshop.svg" alt=""> <div>Adobe Photoshop</div><img src="images/photoshop.svg" alt="">
</div> </div>
<div class="specialty-skill scroll-into-view-content" data-delay="100"> <div class="specialty-skill scroll-into-view-content" data-delay="100">
<div>Adobe Illustrator</div><img src="images/illustrator.svg" alt=""> <div>Adobe Illustrator</div><img src="images/illustrator.svg" alt="">
</div> </div>
<div class="specialty-skill scroll-into-view-content" data-delay="200"> <div class="specialty-skill scroll-into-view-content" data-delay="200">
<div>Adobe After Effects</div><img src="images/aftereffects.svg" alt=""> <div>Adobe After Effects</div><img src="images/aftereffects.svg" alt="">
</div> </div>
<div class="specialty-skill scroll-into-view-content" data-delay="300"> <div class="specialty-skill scroll-into-view-content" data-delay="300">
<div>HTML 5</div><img src="images/html5.svg" alt=""> <div>HTML 5</div><img src="images/html5.svg" alt="">
</div> </div>
<div class="specialty-skill scroll-into-view-content" data-delay="400"> <div class="specialty-skill scroll-into-view-content" data-delay="400">
<div>CSS3</div><img src="images/css3.svg" alt=""> <div>CSS3</div><img src="images/css3.svg" alt="">
</div> </div>
<div class="specialty-skill scroll-into-view-content" data-delay="500"> <div class="specialty-skill scroll-into-view-content" data-delay="500">
<div>javascript</div><img src="images/javascript.svg" alt=""> <div>javascript</div><img src="images/javascript.svg" alt="">
</div> </div>
<div class="specialty-skill scroll-into-view-content" data-delay="600"> <div class="specialty-skill scroll-into-view-content" data-delay="600">
<div>Git Version Control</div><img src="images/git-version-control.svg" alt=""> <div>Git Version Control</div><img src="images/git-version-control.svg" alt="">
</div> </div>
<div class="specialty-skill scroll-into-view-content" data-delay="700"> <div class="specialty-skill scroll-into-view-content" data-delay="700">
<div>Figma</div><img src="images/figma.svg" alt=""> <div>Figma</div><img src="images/figma.svg" alt="">
</div> </div>
<div class="specialty-skill scroll-into-view-content" data-delay="800"> <div class="specialty-skill scroll-into-view-content" data-delay="800">
<div>Wordpress</div><img src="images/wordpress.svg" alt=""> <div>Wordpress</div><img src="images/wordpress.svg" alt="">
</div> </div>
<div class="specialty-skill scroll-into-view-content-2" data-delay="900"> <div class="specialty-skill scroll-into-view-content-2" data-delay="900">
<div>Webflow</div><img src="images/webflow.svg" alt=""> <div>Webflow</div><img src="images/webflow.svg" alt="">
</div> </div>
<div class="specialty-skill scroll-into-view-content-2" data-delay="1000"> <div class="specialty-skill scroll-into-view-content-2" data-delay="1000">
<div>Adobe XD</div><img src="images/adobe-xd.svg" alt=""> <div>Adobe XD</div><img src="images/adobe-xd.svg" alt="">
</div> </div>
<div class="specialty-skill scroll-into-view-content-2" data-delay="1100"> <div class="specialty-skill scroll-into-view-content-2" data-delay="1100">
<div>Visual Studio Code</div><img src="images/vs-code.svg" alt=""> <div>Visual Studio Code</div><img src="images/vs-code.svg" alt="">
</div> </div>
<div class="specialty-skill scroll-into-view-content-2" data-delay="1200"> <div class="specialty-skill scroll-into-view-content-2" data-delay="1200">
<div>Dreamweaver</div><img src="images/dreamweaver.svg" alt=""> <div>Dreamweaver</div><img src="images/dreamweaver.svg" alt="">
</div> </div>
<div class="specialty-skill scroll-into-view-content-2" data-delay="1300"> <div class="specialty-skill scroll-into-view-content-2" data-delay="1300">
<div>Adobe Animate</div><img src="images/adobe animate.svg" alt=""> <div>Adobe Animate</div><img src="images/adobe animate.svg" alt="">
</div> </div>
<div class="specialty-skill scroll-into-view-content-2" data-delay="1400"> <div class="specialty-skill scroll-into-view-content-2" data-delay="1400">
<div>Affinity Photo and Affinity Designer</div><img src="images/affinity.svg" alt=""> <div>Affinity Photo and Affinity Designer</div><img src="images/affinity.svg" alt="">
</div> </div>
</div> </div>
<button class="scroll-into-view-content-2" data-delay="500">Download My Resume</button> <button class="scroll-into-view-content-2" data-delay="500">Download My Resume</button>
</section> </section>
<!-- #################################################################################-- Contact Me --> <!-- #################################################################################-- Contact Me -->
<section class="contact-section" id="contact-me"> <section class="contact-section" id="contact-me">
<div> <div>
<h2 class="scroll-into-view-content">So. Let's talk</h2> <h2 class="scroll-into-view-content">So. Let's talk</h2>
<p class="scroll-into-view-content">Your business is my business as soon as you hit that contact button. I'm <p class="scroll-into-view-content">Your business is my business as soon as you hit that contact button. I'm
ready ready
to attend to your needs as soon as possible. Just drop a line.</p> to attend to your needs as soon as possible. Just drop a line.</p>
<a href="mailto:benoti.san@gmail.com" class="scroll-into-view-content-2" data-delay="500"> <a href="mailto:benoti.san@gmail.com" class="scroll-into-view-content-2" data-delay="500">
Email Address&nbsp;<span class="material-icons">mail</span> Email Address&nbsp;<span class="material-icons">mail</span>
</a> </a>
<div class="scroll-into-view-content-2" data-delay="700"> <div class="scroll-into-view-content-2" data-delay="700">
<div>Copyright 2021 Tben.Design</div> <div>Copyright 2021 Tben.Design</div>
</div> </div>
</div> </div>
<div class="scroll-into-view" id="footer-right-section"> <div class="scroll-into-view" id="footer-right-section">
<div class="scroll-into-view-content" data-delay="800"> <div class="scroll-into-view-content" data-delay="800">
<form id="contact-form" class="main-cta-form" method="post" action="contact-form-process.php" <form id="contact-form" class="main-cta-form" method="post" action="contact-form-process.php"
autocomplete="on"> autocomplete="on">
<input type="text" required placeholder="Enter Full Name"> <input type="text" required placeholder="Enter Full Name">
<input type="email" required placeholder="Enter Email Address"> <input type="email" required placeholder="Enter Email Address">
<textarea name="Message" rows="3" maxlength="3000" required placeholder="Enter Message"></textarea> <textarea name="Message" rows="3" maxlength="3000" required placeholder="Enter Message"></textarea>
<button type="submit">Send Message</button> <button type="submit">Send Message</button>
</form> </form>
</div> </div>
</div> </div>
<div class="contact-section-controller"></div> <div class="contact-section-controller"></div>
<div class="footer-bar"> <div class="footer-bar">
</div> </div>
</section> </section>
<!-- #################################################################################-- Scripts --> <!-- #################################################################################-- Scripts -->
<script src="scripts/anime.min.js"></script> <script src="scripts/anime.min.js"></script>
<script src="scripts/lottie.min.js"></script> <script src="scripts/lottie.min.js"></script>
<script src="scripts/main.js"></script> <script src="scripts/main.js"></script>
</body> </body>
</html> </html>

View File

@ -1,79 +1,79 @@
[ [
{ {
"id": 1, "id": 1,
"title": "Choosing your stack", "title": "Choosing your stack",
"slug": "choosing-your-tech-stack", "slug": "choosing-your-tech-stack",
"description": "So many technologies, so little time to vet all", "description": "So many technologies, so little time to vet all",
"date": "Fri Jun 10 2022 06:34:08 GMT+0100 (West Africa Standard Time)", "date": "Fri Jun 10 2022 06:34:08 GMT+0100 (West Africa Standard Time)",
"body": [ "body": [
{ {
"tag": "p", "tag": "p",
"content": "The tech pool is an ever growing trojan horse. JavaScript libraries alone are getting out of hand: we seem to be getting a new one every 6 months. Hell even I have a javascript library of my own. Trying to pick from this pool can easily turn into mission impossible: understandably so: there's just too many of them" "content": "The tech pool is an ever growing trojan horse. JavaScript libraries alone are getting out of hand: we seem to be getting a new one every 6 months. Hell even I have a javascript library of my own. Trying to pick from this pool can easily turn into mission impossible: understandably so: there's just too many of them"
}, },
{ {
"tag": "p", "tag": "p",
"content": "The thing is, each of these libraries and frameworks end up doing essentially the same thing in thier respective categories: react creates reuseable javascript components: same with vue, same with angular, svelte. And for the most part, you won't be using every single feature provided by these libraries: just the ones that suit your project." "content": "The thing is, each of these libraries and frameworks end up doing essentially the same thing in thier respective categories: react creates reuseable javascript components: same with vue, same with angular, svelte. And for the most part, you won't be using every single feature provided by these libraries: just the ones that suit your project."
}, },
{ {
"tag": "p", "tag": "p",
"content": "In truth, the tech stack you choose doesn't mean much: you can get 10 different options which achieve the same goal. Really, all that matters is the developer you pick: because a masterful developer can create great products using any stack of his/her choosing." "content": "In truth, the tech stack you choose doesn't mean much: you can get 10 different options which achieve the same goal. Really, all that matters is the developer you pick: because a masterful developer can create great products using any stack of his/her choosing."
}, },
{ {
"tag": "p", "tag": "p",
"children": [ "children": [
{ {
"tag": "span", "tag": "span",
"content": "If you're just starting off, perhaps the best step is to evaluate the stacks and get a recommendation from an expert in the field: you may be surprised to find out you don't need as many technologies as you think: you may even be surprised that using a traditional framework like ruby on rails is actually a lot easier than wordpress. " "content": "If you're just starting off, perhaps the best step is to evaluate the stacks and get a recommendation from an expert in the field: you may be surprised to find out you don't need as many technologies as you think: you may even be surprised that using a traditional framework like ruby on rails is actually a lot easier than wordpress. "
}, },
{ {
"tag": "a", "tag": "a",
"href": "/contact", "href": "/contact",
"class": "text-blue-300", "class": "text-blue-300",
"content": "Reach out" "content": "Reach out"
}, },
{ {
"tag": "span", "tag": "span",
"content": " to find out more." "content": " to find out more."
} }
] ]
} }
] ]
}, },
{ {
"id": 2, "id": 2,
"title": "Find your perfect framework", "title": "Find your perfect framework",
"slug": "find-your-perfect-framework", "slug": "find-your-perfect-framework",
"description": "How much can a web framework affect your project?", "description": "How much can a web framework affect your project?",
"date": "Fri Jun 10 2022 06:34:08 GMT+0100 (West Africa Standard Time)", "date": "Fri Jun 10 2022 06:34:08 GMT+0100 (West Africa Standard Time)",
"body": [ "body": [
{ {
"tag": "p", "tag": "p",
"content": "Web frameworks are a great way to get the best out of multiple technologies while keeping your development time short and reliability high. But just like it is with every aspect of web development, there's a dilemma of \"Which framework should I go with\"." "content": "Web frameworks are a great way to get the best out of multiple technologies while keeping your development time short and reliability high. But just like it is with every aspect of web development, there's a dilemma of \"Which framework should I go with\"."
}, },
{ {
"tag": "p", "tag": "p",
"content": "Different frameworks come with different structures and different selections of languages and packages. In truth, you don't necessarily need a framework: nearly all major programming languages can handle applications on thier own: but as you build more projects, you keep encountering more repetitions, and you end up abstracting those repetitions into reuseable components: you now have a framework of your own. Now this isn't bad at all: infact, this is the end goal of a truly performant app: frameworks often come with a lot of packages you may not need: which end up bugging down your application: if you can develop a framework of your own, you can eliminate this downside: but, you have to be prepared to spend a lot of time on your project: if you have the time, then go for it: else, go for a framework." "content": "Different frameworks come with different structures and different selections of languages and packages. In truth, you don't necessarily need a framework: nearly all major programming languages can handle applications on thier own: but as you build more projects, you keep encountering more repetitions, and you end up abstracting those repetitions into reuseable components: you now have a framework of your own. Now this isn't bad at all: infact, this is the end goal of a truly performant app: frameworks often come with a lot of packages you may not need: which end up bugging down your application: if you can develop a framework of your own, you can eliminate this downside: but, you have to be prepared to spend a lot of time on your project: if you have the time, then go for it: else, go for a framework."
}, },
{ {
"tag": "p", "tag": "p",
"content": "Haven said this, there are lots of frameworks you can choose from: depending on your time and budget: here are some great picks you should consider:" "content": "Haven said this, there are lots of frameworks you can choose from: depending on your time and budget: here are some great picks you should consider:"
}, },
{ {
"tag": "h2", "tag": "h2",
"content": "1. Next JS" "content": "1. Next JS"
}, },
{ {
"tag": "img", "tag": "img",
"src": "https://miro.medium.com/max/1400/1*htbUdWgFQ3a94PMEvBr_hQ.png", "src": "https://miro.medium.com/max/1400/1*htbUdWgFQ3a94PMEvBr_hQ.png",
"class": "w-full", "class": "w-full",
"style": { "style": {
"border": "1px solid #ffffff40" "border": "1px solid #ffffff40"
} }
}, },
{ {
"tag": "p", "tag": "p",
"content": "Next JS is slowly becoming the household name for web development frameworks: it features an immensely powerful and efficient structure, based on React JS: which enables server side rendering of pages: as opposed to the traditional SPA(single page application) model React was created for. Next JS handles the heavilifting of routing, apis, frontend and backend components, module bundling, and linting, leaving you with a relatively easy platform to integrate your project. Next JS is growing very quick and in no time, it will become the most used framework for enterprise applications" "content": "Next JS is slowly becoming the household name for web development frameworks: it features an immensely powerful and efficient structure, based on React JS: which enables server side rendering of pages: as opposed to the traditional SPA(single page application) model React was created for. Next JS handles the heavilifting of routing, apis, frontend and backend components, module bundling, and linting, leaving you with a relatively easy platform to integrate your project. Next JS is growing very quick and in no time, it will become the most used framework for enterprise applications"
} }
] ]
} }
] ]

View File

@ -1,46 +1,46 @@
"use client"; "use client";
import React from "react"; import React from "react";
import { gsap } from "gsap"; import { gsap } from "gsap";
// import scrollTrigger from "gsap/ScrollTrigger"; // import scrollTrigger from "gsap/ScrollTrigger";
const BG = () => { const BG = () => {
React.useEffect(() => { React.useEffect(() => {
// gsap.registerPlugin(scrollTrigger); // gsap.registerPlugin(scrollTrigger);
gsap.to("#bg-blurred-image", { gsap.to("#bg-blurred-image", {
scrollTrigger: { scrollTrigger: {
scrub: 5, scrub: 5,
}, },
y: 50, y: 50,
scale: 0.8, scale: 0.8,
}); });
gsap.to("#bg-image", { gsap.to("#bg-image", {
scrollTrigger: { scrollTrigger: {
scrub: 2, scrub: 2,
}, },
y: 50, y: 50,
opacity: 0, opacity: 0,
}); });
}, []); }, []);
return ( return (
<React.Fragment> <React.Fragment>
<img <img
src="/images/rm378-07c-min.png" src="/images/rm378-07c-min.png"
alt="bg-image" alt="bg-image"
className="fixed top-0 left-0 w-full h-full object-cover z-[-2] p-[100px] opacity-20 blur-sm" className="fixed top-0 left-0 w-full h-full object-cover z-[-2] p-[100px] opacity-20 blur-sm"
id="bg-blurred-image" id="bg-blurred-image"
/> />
<img <img
src="/images/rm378-07c-min.png" src="/images/rm378-07c-min.png"
alt="bg-image" alt="bg-image"
className="fixed top-0 left-0 w-full h-full object-cover z-[-1] p-[150px] opacity-5" className="fixed top-0 left-0 w-full h-full object-cover z-[-1] p-[150px] opacity-5"
id="bg-image" id="bg-image"
/> />
</React.Fragment> </React.Fragment>
); );
}; };
export default BG; export default BG;

View File

@ -1,53 +1,53 @@
import React from "react"; import React from "react";
import Image from "next/image"; import Image from "next/image";
const GeneralFooter = () => { const GeneralFooter = () => {
const date = new Date(); const date = new Date();
return ( return (
<footer <footer
className="mt-10 w-full flex flex-col items-center py-20" className="mt-10 w-full flex flex-col items-center py-20"
style={{ style={{
borderTop: "1px solid rgba(255,255,255,0.2)", borderTop: "1px solid rgba(255,255,255,0.2)",
}} }}
> >
<div className="max-w-6xl w-full flex flex-wrap items-stretch gap-10"> <div className="max-w-6xl w-full flex flex-wrap items-stretch gap-10">
<a <a
href="/" href="/"
data-href="/" data-href="/"
className="logo-link-block -mb-4" className="logo-link-block -mb-4"
> >
<Image <Image
src="/images/logo-white.svg" src="/images/logo-white.svg"
width={50} width={50}
height={100} height={100}
alt="Logo" alt="Logo"
/> />
</a> </a>
<div className="flex flex-col items-start justify-between"> <div className="flex flex-col items-start justify-between">
<div className="flex-col flex items-start gap-1"> <div className="flex-col flex items-start gap-1">
<span className="opacity-50">Contact Me</span> <span className="opacity-50">Contact Me</span>
<div className="flex gap-4"> <div className="flex gap-4">
<a <a
href="https://www.linkedin.com/in/benjamin-toby/" href="https://www.linkedin.com/in/benjamin-toby/"
target="_blank" target="_blank"
> >
LinkedIn LinkedIn
</a> </a>
<a <a
href="https://github.com/BenjaminToby" href="https://github.com/BenjaminToby"
target="_blank" target="_blank"
> >
Github Github
</a> </a>
<a href="mailto:benoti.san@gmail.com">Mail</a> <a href="mailto:benoti.san@gmail.com">Mail</a>
<a href="tel:+2348123682346">Phone</a> <a href="tel:+2348123682346">Phone</a>
</div> </div>
</div> </div>
<span className="text-sm opacity-40">Copyright © {date.getFullYear()} Tben.me. All Rights Reserved.</span> <span className="text-sm opacity-40">Copyright © {date.getFullYear()} Tben.me. All Rights Reserved.</span>
</div> </div>
</div> </div>
</footer> </footer>
); );
}; };
export default GeneralFooter; export default GeneralFooter;

View File

@ -1,101 +1,101 @@
"use client"; "use client";
import React from "react"; import React from "react";
import Image from "next/image"; import Image from "next/image";
import { gsap } from "gsap"; import { gsap } from "gsap";
import HeaderNav from "./HeaderNav"; import HeaderNav from "./HeaderNav";
/** /**
* General Header for all pages * General Header for all pages
*/ */
const GeneralHeader = (): React.ReactElement => { const GeneralHeader = (): React.ReactElement => {
const links: { title: string; url: string }[] = require("./links.json"); const links: { title: string; url: string }[] = require("./links.json");
const [mobileNavOpen, setMobileNavOpen] = React.useState<boolean>(false); const [mobileNavOpen, setMobileNavOpen] = React.useState<boolean>(false);
/** /**
* Animate the header on mount * Animate the header on mount
*/ */
React.useEffect(() => { React.useEffect(() => {
gsap.fromTo( gsap.fromTo(
"#main-header", "#main-header",
{ {
y: -20, y: -20,
filter: "blur(100px)", filter: "blur(100px)",
webkitFilter: "blur(100px)", webkitFilter: "blur(100px)",
opacity: 0, opacity: 0,
}, },
{ {
y: 0, y: 0,
opacity: 1, opacity: 1,
duration: 1, duration: 1,
filter: "none", filter: "none",
webkitFilter: "none", webkitFilter: "none",
delay: 0.5, delay: 0.5,
} }
); );
}, []); }, []);
React.useEffect(() => { React.useEffect(() => {
if (mobileNavOpen) { if (mobileNavOpen) {
gsap.to("#mobile-nave-drawer", { gsap.to("#mobile-nave-drawer", {
opacity: 1, opacity: 1,
pointerEvents: "all", pointerEvents: "all",
duration: 0.5, duration: 0.5,
}); });
} else { } else {
gsap.to("#mobile-nave-drawer", { gsap.to("#mobile-nave-drawer", {
opacity: 0, opacity: 0,
pointerEvents: "none", pointerEvents: "none",
duration: 0.5, duration: 0.5,
}); });
} }
}, [mobileNavOpen]); }, [mobileNavOpen]);
return ( return (
<header <header
id="main-header" id="main-header"
className="flex items-start justify-between gap-10 w-full py-4 md:py-10 z-10 fixed xl:sticky top-0" className="flex items-start justify-between gap-10 w-full py-4 md:py-10 z-10 fixed xl:sticky top-0"
> >
<a <a
href="/" href="/"
data-href="/" data-href="/"
className="logo-link-block scale-90 sm:scale-100" className="logo-link-block scale-90 sm:scale-100"
> >
<Image <Image
src="/images/logo-white.svg" src="/images/logo-white.svg"
width={50} width={50}
height={100} height={100}
alt="Logo" alt="Logo"
/> />
</a> </a>
<HeaderNav /> <HeaderNav />
<button <button
className="p-2 w-14 h-14 rounded-full flex flex-col items-center justify-center gap-2 hover:bg-[white]/90 xl:hidden fixed top-[35px] right-10 z-10 -rotate-45" className="p-2 w-14 h-14 rounded-full flex flex-col items-center justify-center gap-2 hover:bg-[white]/90 xl:hidden fixed top-[35px] right-10 z-10 -rotate-45"
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
setMobileNavOpen(!mobileNavOpen); setMobileNavOpen(!mobileNavOpen);
}} }}
> >
<div className="w-8 h-1 rounded-full bg-[black]"></div> <div className="w-8 h-1 rounded-full bg-[black]"></div>
<div className="w-8 h-1 rounded-full bg-[black]"></div> <div className="w-8 h-1 rounded-full bg-[black]"></div>
</button> </button>
<div <div
id="mobile-nave-drawer" id="mobile-nave-drawer"
className="flex xl:hidden flex-col fixed top-0 right-0 w-screen max-w-[400px] h-screen overflow-auto bg-[black] p-8" className="flex xl:hidden flex-col fixed top-0 right-0 w-screen max-w-[400px] h-screen overflow-auto bg-[black] p-8"
style={{ style={{
opacity: 0, opacity: 0,
pointerEvents: "none", pointerEvents: "none",
}} }}
> >
<HeaderNav mobile={true} /> <HeaderNav mobile={true} />
</div> </div>
</header> </header>
); );
}; };
export default GeneralHeader; export default GeneralHeader;

View File

@ -1,62 +1,62 @@
"use client"; "use client";
import React, { ReactElement } from "react"; import React, { ReactElement } from "react";
import GeneralHeader from "./GeneralHeader"; import GeneralHeader from "./GeneralHeader";
import GeneralFooter from "./GeneralFooter"; import GeneralFooter from "./GeneralFooter";
import { gsap } from "gsap"; import { gsap } from "gsap";
import BG from "./BG"; import BG from "./BG";
export const SiteContext: any = React.createContext({}); export const SiteContext: any = React.createContext({});
type GeneralLayoutProps = { type GeneralLayoutProps = {
children: React.ReactNode; children: React.ReactNode;
}; };
const GeneralLayout = ({ children }: GeneralLayoutProps): ReactElement => { const GeneralLayout = ({ children }: GeneralLayoutProps): ReactElement => {
const [readyState, setReadyState] = React.useState(false); const [readyState, setReadyState] = React.useState(false);
React.useEffect(() => { React.useEffect(() => {
const links: NodeListOf<HTMLAnchorElement> | null = document.querySelectorAll("nav a"); const links: NodeListOf<HTMLAnchorElement> | null = document.querySelectorAll("nav a");
links?.forEach((link) => { links?.forEach((link) => {
if (link.dataset.href === window.location.pathname) { if (link.dataset.href === window.location.pathname) {
link.classList.add("active-page"); link.classList.add("active-page");
} }
if (window.location.pathname.match(new RegExp(`${link.dataset.href}\\/.*`))) { if (window.location.pathname.match(new RegExp(`${link.dataset.href}\\/.*`))) {
link.classList.add("active-page"); link.classList.add("active-page");
} }
}); });
gsap.to("#main-content-wrapper", { gsap.to("#main-content-wrapper", {
opacity: 1, opacity: 1,
duration: 2, duration: 2,
}); });
}, []); }, []);
return ( return (
<SiteContext.Provider value={{ readyState, setReadyState }}> <SiteContext.Provider value={{ readyState, setReadyState }}>
<div <div
id="main-content-wrapper" id="main-content-wrapper"
style={{ style={{
opacity: 0, opacity: 0,
}} }}
className="px-4 md:px-10" className="px-4 md:px-10"
> >
<GeneralHeader /> <GeneralHeader />
<main <main
className="flex items-center flex-col w-full" className="flex items-center flex-col w-full"
// style={{ // style={{
// perspective: "800px", // perspective: "800px",
// }} // }}
> >
{children} {children}
</main> </main>
<GeneralFooter /> <GeneralFooter />
</div> </div>
<BG /> <BG />
</SiteContext.Provider> </SiteContext.Provider>
); );
}; };
export default GeneralLayout; export default GeneralLayout;

View File

@ -1,60 +1,60 @@
"use client"; "use client";
import React from "react"; import React from "react";
import { gsap } from "gsap"; import { gsap } from "gsap";
/** /**
* General Header for all pages * General Header for all pages
*/ */
const HeaderNav = ({ mobile }: { mobile?: boolean }): React.ReactElement => { const HeaderNav = ({ mobile }: { mobile?: boolean }): React.ReactElement => {
const links: { title: string; url: string }[] = require("./links.json"); const links: { title: string; url: string }[] = require("./links.json");
return ( return (
<nav className={"items-start xl:items-center gap-x-6 gap-y-2 xl:flex-row" + (mobile ? " flex-col" : " hidden xl:flex")}> <nav className={"items-start xl:items-center gap-x-6 gap-y-2 xl:flex-row" + (mobile ? " flex-col" : " hidden xl:flex")}>
{links.map((link: { title: string; url: string; download?: boolean }, index) => { {links.map((link: { title: string; url: string; download?: boolean }, index) => {
return ( return (
<a <a
key={index} key={index}
href={link.url} href={link.url}
data-href={link.url} data-href={link.url}
className="text-lg" className="text-lg"
download={link.download} download={link.download}
> >
{link.title} {link.title}
</a> </a>
); );
})} })}
<span className="opacity-20">|</span> <span className="opacity-20">|</span>
<div className="flex items-start xl:items-center gap-4 flex-col xl:flex-row"> <div className="flex items-start xl:items-center gap-4 flex-col xl:flex-row">
<a <a
href="https://github.com/BenjaminToby" href="https://github.com/BenjaminToby"
target="_blank" target="_blank"
> >
<img <img
src="/images/github-white.png" src="/images/github-white.png"
alt="Benjamin Toby Github" alt="Benjamin Toby Github"
width={20} width={20}
height={20} height={20}
className="flex items-center" className="flex items-center"
/> />
</a> </a>
<a <a
href="https://www.linkedin.com/in/benjamin-toby/" href="https://www.linkedin.com/in/benjamin-toby/"
target="_blank" target="_blank"
> >
<img <img
src="/images/linkedin-white.png" src="/images/linkedin-white.png"
alt="Benjamin Toby Github" alt="Benjamin Toby Github"
width={20} width={20}
height={20} height={20}
className="flex items-center" className="flex items-center"
/> />
</a> </a>
</div> </div>
</nav> </nav>
); );
}; };
export default HeaderNav; export default HeaderNav;

View File

@ -1,27 +1,27 @@
[ [
{ {
"title": "Home", "title": "Home",
"url": "/" "url": "/"
}, },
{ {
"title": "About Me", "title": "About Me",
"url": "/about" "url": "/about"
}, },
{ {
"title": "My Work", "title": "My Work",
"url": "/work" "url": "/work"
}, },
{ {
"title": "My Resume", "title": "My Resume",
"url": "/documents/Resume-Benjamin-Toby-Linkedin.pdf", "url": "/documents/Resume-Benjamin-Toby-Linkedin.pdf",
"download": true "download": true
}, },
{ {
"title": "Blog", "title": "Blog",
"url": "/blog" "url": "/blog"
}, },
{ {
"title": " Contact Me", "title": " Contact Me",
"url": "/contact" "url": "/contact"
} }
] ]

12
next-env.d.ts vendored
View File

@ -1,6 +1,6 @@
/// <reference types="next" /> /// <reference types="next" />
/// <reference types="next/image-types/global" /> /// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" /> /// <reference types="next/navigation-types/compat/navigation" />
// NOTE: This file should not be edited // NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information. // see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@ -1,15 +1,15 @@
import "../styles/main.css"; import "../styles/main.css";
import "../styles/tw_main.css"; import "../styles/tw_main.css";
import { Fragment } from "react"; import { Fragment } from "react";
import type { AppProps } from "next/app"; import type { AppProps } from "next/app";
function MyApp({ Component, pageProps }: AppProps) { function MyApp({ Component, pageProps }: AppProps) {
return ( return (
<Fragment> <Fragment>
<Component {...pageProps} /> <Component {...pageProps} />
</Fragment> </Fragment>
); );
} }
export default MyApp; export default MyApp;

View File

@ -1,19 +1,19 @@
import React from "react"; import React from "react";
import { Html, Head, Main, NextScript } from "next/document"; import { Html, Head, Main, NextScript } from "next/document";
export default function Document() { export default function Document() {
return ( return (
<Html> <Html>
<Head> <Head>
<script <script
src="/scripts/main.js" src="/scripts/main.js"
defer defer
></script> ></script>
</Head> </Head>
<body className="w-full"> <body className="w-full">
<Main /> <Main />
<NextScript /> <NextScript />
</body> </body>
</Html> </Html>
); );
} }

View File

@ -1,49 +1,49 @@
/** /**
* Imports * Imports
*/ */
const fs = require("fs"); const fs = require("fs");
const sanitizeHtml = require("sanitize-html"); const sanitizeHtml = require("sanitize-html");
const nodemailer = require("nodemailer"); const nodemailer = require("nodemailer");
import sanitizeHtmlOptions from "../../functions/backend/sanitizeHtmlOptions"; import sanitizeHtmlOptions from "../../functions/backend/sanitizeHtmlOptions";
import { NextApiRequest, NextApiResponse } from "next"; import { NextApiRequest, NextApiResponse } from "next";
let transporter = nodemailer.createTransport({ let transporter = nodemailer.createTransport({
host: process.env.TBENMAIL_HOST, host: process.env.TBENMAIL_HOST,
port: 587, port: 587,
auth: { auth: {
user: process.env.TBENMAIL_EMAIL, user: process.env.TBENMAIL_EMAIL,
pass: process.env.TBENMAIL_EMAIL_PASSWORD, pass: process.env.TBENMAIL_EMAIL_PASSWORD,
}, },
}); });
/** /**
* API handler * API handler
* *
*/ */
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "POST") { if (req.method === "POST") {
let name = req.body.name; let name = req.body.name;
let email = req.body.email; let email = req.body.email;
let message = req.body.message; let message = req.body.message;
const html = `<h1>Message from ${name} | ${email}</h1><h4>Name:</h4><p>${name}</p><h4>Email:</h4><p>${email}</p><h4>Message:</h4><p>${message}</p>`; const html = `<h1>Message from ${name} | ${email}</h1><h4>Name:</h4><p>${name}</p><h4>Email:</h4><p>${email}</p><h4>Message:</h4><p>${message}</p>`;
const sanitizedHtml = sanitizeHtml(html, sanitizeHtmlOptions); const sanitizedHtml = sanitizeHtml(html, sanitizeHtmlOptions);
try { try {
let info = await transporter.sendMail({ let info = await transporter.sendMail({
from: `"Tben.me" <${process.env.TBENMAIL_EMAIL}>`, from: `"Tben.me" <${process.env.TBENMAIL_EMAIL}>`,
to: "benoti.san@gmail.com, benoti.sanchez@gmail.com", to: "benoti.san@gmail.com, benoti.sanchez@gmail.com",
subject: "Tben.me | Client Message", subject: "Tben.me | Client Message",
text: "Hello from tben", text: "Hello from tben",
html: sanitizedHtml, html: sanitizedHtml,
}); });
console.log("Message sent: %s", info.messageId); console.log("Message sent: %s", info.messageId);
res.json({ msg: "Success", info: info }); res.json({ msg: "Success", info: info });
} catch (error) { } catch (error) {
console.log(error); console.log(error);
res.json({ msg: "Failed" }); res.json({ msg: "Failed" });
} }
} }
} }

View File

@ -1,45 +1,45 @@
import { NextApiHandler, NextApiRequest, NextApiResponse } from "next"; import { NextApiHandler, NextApiRequest, NextApiResponse } from "next";
import Cors from "cors"; import Cors from "cors";
const cors = Cors({ const cors = Cors({
methods: ["GET"], methods: ["GET"],
origin: "*", origin: "*",
}); });
// Helper method to wait for a middleware to execute before continuing // Helper method to wait for a middleware to execute before continuing
// And to throw an error when an error happens in a middleware // And to throw an error when an error happens in a middleware
function runMiddleware(req: NextApiRequest, res: NextApiResponse, fn: Function) { function runMiddleware(req: NextApiRequest, res: NextApiResponse, fn: Function) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fn(req, res, (result: any) => { fn(req, res, (result: any) => {
if (result instanceof Error) { if (result instanceof Error) {
return reject(result); return reject(result);
} }
return resolve(result); return resolve(result);
}); });
}); });
} }
/** /**
* @type {NextApiHandler} * @type {NextApiHandler}
*/ */
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
// res.setHeader("Access-Control-Allow-Credentials", "true"); // res.setHeader("Access-Control-Allow-Credentials", "true");
// res.setHeader("Access-Control-Allow-Origin", "*"); // res.setHeader("Access-Control-Allow-Origin", "*");
// res.setHeader("Access-Control-Allow-Methods", "*"); // res.setHeader("Access-Control-Allow-Methods", "*");
// res.setHeader("Access-Control-Allow-Headers", "*"); // res.setHeader("Access-Control-Allow-Headers", "*");
res.setHeader("Access-Control-Allow-Credentials", "true"); res.setHeader("Access-Control-Allow-Credentials", "true");
res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader("Access-Control-Allow-Origin", "*");
// another common pattern // another common pattern
// res.setHeader('Access-Control-Allow-Origin', req.headers.origin); // res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
res.setHeader("Access-Control-Allow-Methods", "GET,OPTIONS,PATCH,DELETE,POST,PUT"); res.setHeader("Access-Control-Allow-Methods", "GET,OPTIONS,PATCH,DELETE,POST,PUT");
res.setHeader("Access-Control-Allow-Headers", "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version"); res.setHeader("Access-Control-Allow-Headers", "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version");
// await runMiddleware(req, res, cors); // await runMiddleware(req, res, cors);
res.json({ res.json({
title: "Hello There", title: "Hello There",
message: "General Kenobi", message: "General Kenobi",
}); });
} }

View File

@ -1,178 +1,178 @@
/** /**
* ============================================================================== * ==============================================================================
* Imports * Imports
* ============================================================================== * ==============================================================================
*/ */
import React from "react"; import React from "react";
import Head from "next/head"; import Head from "next/head";
import type { InferGetStaticPropsType, GetStaticProps, GetStaticPaths } from "next"; import type { InferGetStaticPropsType, GetStaticProps, GetStaticPaths } from "next";
const datasquirel = require("datasquirel"); const datasquirel = require("datasquirel");
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
import GeneralLayout from "../../layouts/general_layout/GeneralLayout"; import GeneralLayout from "../../layouts/general_layout/GeneralLayout";
import TextShuffler from "../../components/actions/TextShuffler"; import TextShuffler from "../../components/actions/TextShuffler";
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** /**
* ============================================================================== * ==============================================================================
* Main Component { Functional } * Main Component { Functional }
* ============================================================================== * ==============================================================================
* @param {Object} props - Server props * @param {Object} props - Server props
*/ */
export default function BlogIndex({ blogPost }: InferGetStaticPropsType<typeof getStaticProps>) { export default function BlogIndex({ blogPost }: InferGetStaticPropsType<typeof getStaticProps>) {
// ## Get Contexts // ## Get Contexts
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## Javascript Variables // ## Javascript Variables
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## React Hooks { useState, useEffect, useRef, etc ... } // ## React Hooks { useState, useEffect, useRef, etc ... }
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## Function Return // ## Function Return
return ( return (
<React.Fragment> <React.Fragment>
<Head> <Head>
<title>{blogPost.title} | Tben.me Blog</title> <title>{blogPost.title} | Tben.me Blog</title>
<meta <meta
name="description" name="description"
content={blogPost.excerpt} content={blogPost.excerpt}
/> />
</Head> </Head>
<GeneralLayout> <GeneralLayout>
<div className="flex flex-col items-start gap-2 mb-8 max-w-6xl w-full"> <div className="flex flex-col items-start gap-2 mb-8 max-w-6xl w-full">
<button <button
className="bg-transparent text-white/50 border-2 border-solid border-white/20" className="bg-transparent text-white/50 border-2 border-solid border-white/20"
onClick={(e) => { onClick={(e) => {
window.history.back(); window.history.back();
}} }}
> >
Back Back
</button> </button>
<h1 className="m-0"> <h1 className="m-0">
<TextShuffler textInput={blogPost.title} /> <TextShuffler textInput={blogPost.title} />
</h1> </h1>
<span className="text-lg"> <span className="text-lg">
<TextShuffler textInput={blogPost.excerpt} /> <TextShuffler textInput={blogPost.excerpt} />
</span> </span>
<span className="text-base opacity-50"> <span className="text-base opacity-50">
<TextShuffler textInput={blogPost.date_created.substring(0, 24)} /> <TextShuffler textInput={blogPost.date_created.substring(0, 24)} />
</span> </span>
</div> </div>
<span <span
className="flex flex-col items-start max-w-6xl w-full gap-4 text-xl" className="flex flex-col items-start max-w-6xl w-full gap-4 text-xl"
dangerouslySetInnerHTML={{ __html: blogPost.body }} dangerouslySetInnerHTML={{ __html: blogPost.body }}
></span> ></span>
</GeneralLayout> </GeneralLayout>
</React.Fragment> </React.Fragment>
); );
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
} }
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** /**
* Server Side Props or Static Props * Server Side Props or Static Props
* ============================================================================== * ==============================================================================
*/ */
export const getStaticProps: GetStaticProps = async ({ params }) => { export const getStaticProps: GetStaticProps = async ({ params }) => {
// ## Environment processes // ## Environment processes
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## User Authentication // ## User Authentication
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## Page/Site Data Data Fetching // ## Page/Site Data Data Fetching
const postsResponse = await datasquirel.get({ const postsResponse = await datasquirel.get({
key: process.env.DATASQUIREL_API_KEY, key: process.env.DATASQUIREL_API_KEY,
db: "tbenme", db: "tbenme",
query: `select * from blog_posts WHERE slug='${params?.single}'`, query: `select * from blog_posts WHERE slug='${params?.single}'`,
}); });
const post = postsResponse.payload[0]; const post = postsResponse.payload[0];
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
// ## Server Props Return // ## Server Props Return
return { return {
props: { props: {
blogPost: post, blogPost: post,
}, },
revalidate: 3600, revalidate: 3600,
}; };
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
/** ********************************************** */ /** ********************************************** */
}; };
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** ****************************************************************************** */ /** ****************************************************************************** */
/** /**
* Server Side Props or Static Props * Server Side Props or Static Props
* ============================================================================== * ==============================================================================
*/ */
export const getStaticPaths: GetStaticPaths = async () => { export const getStaticPaths: GetStaticPaths = async () => {
/** /**
* Data fetching * Data fetching
* *
* @abstract fetch date from the server or externnal source * @abstract fetch date from the server or externnal source
*/ */
const postsResponse = await datasquirel.get({ const postsResponse = await datasquirel.get({
key: process.env.DATASQUIREL_API_KEY, key: process.env.DATASQUIREL_API_KEY,
db: "tbenme", db: "tbenme",
query: `select slug from blog_posts`, query: `select slug from blog_posts`,
}); });
const posts: { slug: string }[] | null = postsResponse.payload; const posts: { slug: string }[] | null = postsResponse.payload;
const paths = posts?.map((entry) => { const paths = posts?.map((entry) => {
return { return {
params: { single: entry.slug }, params: { single: entry.slug },
}; };
}); });
return { return {
paths: paths ? paths : [], paths: paths ? paths : [],
fallback: "blocking", fallback: "blocking",
}; };
}; };

View File

@ -1,39 +1,39 @@
import React from "react"; import React from "react";
import Head from "next/head"; import Head from "next/head";
import TextShuffler from "../components/actions/TextShuffler"; import TextShuffler from "../components/actions/TextShuffler";
import submitContactForm from "../functions/frontend/submitContactForm"; import submitContactForm from "../functions/frontend/submitContactForm";
import GeneralLayout from "../layouts/general_layout/GeneralLayout"; import GeneralLayout from "../layouts/general_layout/GeneralLayout";
import threeJsAnimations from "../functions/frontend/threeJsAnimations"; import threeJsAnimations from "../functions/frontend/threeJsAnimations";
import ContactForm from "../app/(components)/ContactForm"; import ContactForm from "../app/(components)/ContactForm";
const contact = () => { const contact = () => {
let [success, setSuccess] = React.useState(false); let [success, setSuccess] = React.useState(false);
return ( return (
<GeneralLayout> <GeneralLayout>
<Head> <Head>
<title>Contact me</title> <title>Contact me</title>
<meta <meta
name="description" name="description"
content="Get in touch" content="Get in touch"
/> />
</Head> </Head>
<div className="flex flex-col items-start max-w-6xl w-full"> <div className="flex flex-col items-start max-w-6xl w-full">
<h1> <h1>
<TextShuffler textInput="Get in touch" /> <TextShuffler textInput="Get in touch" />
</h1> </h1>
<span className="hero-sub-text"> <span className="hero-sub-text">
<TextShuffler <TextShuffler
textInput="Have a question? Want to work together? Send me a message!" textInput="Have a question? Want to work together? Send me a message!"
delay={500} delay={500}
/> />
</span> </span>
<ContactForm /> <ContactForm />
</div> </div>
</GeneralLayout> </GeneralLayout>
); );
}; };
export default contact; export default contact;

View File

@ -1,54 +1,54 @@
import React from "react"; import React from "react";
import Head from "next/head"; import Head from "next/head";
import TextShuffler from "../components/actions/TextShuffler"; import TextShuffler from "../components/actions/TextShuffler";
import GeneralLayout from "../layouts/general_layout/GeneralLayout"; import GeneralLayout from "../layouts/general_layout/GeneralLayout";
import PortfolioEntry from "../components/PortfolioEntry"; import PortfolioEntry from "../components/PortfolioEntry";
const myWork = () => { const myWork = () => {
const portfolioEntries = require("../components/portfolioEntries.json"); const portfolioEntries = require("../components/portfolioEntries.json");
return ( return (
<GeneralLayout> <GeneralLayout>
<Head> <Head>
<title>My Work | Tben</title> <title>My Work | Tben</title>
<meta <meta
name="description" name="description"
content="Some of my Work" content="Some of my Work"
/> />
</Head> </Head>
<div className="flex flex-col items-start w-full max-w-6xl"> <div className="flex flex-col items-start w-full max-w-6xl">
<h1> <h1>
<TextShuffler textInput="My Work" /> <TextShuffler textInput="My Work" />
</h1> </h1>
<span className="hero-sub-text mb-2"> <span className="hero-sub-text mb-2">
<TextShuffler <TextShuffler
textInput="Some of the projects I've worked on" textInput="Some of the projects I've worked on"
delay={500} delay={500}
/> />
</span> </span>
<div className="portfolio-entries-block mt-4"> <div className="portfolio-entries-block mt-4">
{portfolioEntries.map((entry) => ( {portfolioEntries.map((entry) => (
<PortfolioEntry <PortfolioEntry
key={entry.title} key={entry.title}
title={entry.title} title={entry.title}
description={entry.description} description={entry.description}
url={entry.url} url={entry.url}
image={entry.image} image={entry.image}
/> />
))} ))}
</div> </div>
</div> </div>
</GeneralLayout> </GeneralLayout>
); );
}; };
export default myWork; export default myWork;
// { // {
// "title": "Stirrmedia Social webapp", // "title": "Stirrmedia Social webapp",
// "description": "A new social media experience without censorship", // "description": "A new social media experience without censorship",
// "url": "https://stirrmedia.com", // "url": "https://stirrmedia.com",
// "image": "/images/stirrmediascreenshot.png" // "image": "/images/stirrmediascreenshot.png"
// }, // },

View File

@ -1,3 +1,3 @@
User-agent: * User-agent: *
Sitemap: https://tben.me/sitemap.xml Sitemap: https://tben.me/sitemap.xml

View File

@ -1,169 +1,169 @@
/** /**
* Register plugins * Register plugins
*/ */
gsap.registerPlugin(ScrollTrigger); gsap.registerPlugin(ScrollTrigger);
const mm = gsap.matchMedia(); const mm = gsap.matchMedia();
mm.add("(min-width: 1200px)", () => { mm.add("(min-width: 1200px)", () => {
ScrollTrigger.create({ ScrollTrigger.create({
trigger: "#homepage-content-wrapper", trigger: "#homepage-content-wrapper",
// toggleActions: "play none none none", // toggleActions: "play none none none",
start: "top 200px", start: "top 200px",
end: "bottom 90%", end: "bottom 90%",
pin: "#main-image", pin: "#main-image",
// markers: true, // markers: true,
scrub: 1, scrub: 1,
onUpdate: (self) => { onUpdate: (self) => {
/** /**
* Origin * Origin
*/ */
if (self.progress < 0.4) { if (self.progress < 0.4) {
gsap.to("#main-image", { gsap.to("#main-image", {
backgroundColor: "#3e3f9c", backgroundColor: "#3e3f9c",
x: 0, x: 0,
duration: 1, duration: 1,
}); });
gsap.to("body", { gsap.to("body", {
backgroundColor: "#181515", backgroundColor: "#181515",
}); });
} }
/** /**
* Step 2 * Step 2
*/ */
if (self.progress > 0.4) { if (self.progress > 0.4) {
gsap.to("#main-image", { gsap.to("#main-image", {
backgroundColor: "#FE6847", backgroundColor: "#FE6847",
x: -50, x: -50,
duration: 1, duration: 1,
}); });
gsap.to("body", { gsap.to("body", {
backgroundColor: "#292a6b", backgroundColor: "#292a6b",
}); });
} }
// if (self.progress > 0 && self.progress < 1) { // if (self.progress > 0 && self.progress < 1) {
// gsap.to("#main-image", { // gsap.to("#main-image", {
// position: "fixed", // position: "fixed",
// top: 20, // top: 20,
// left: 20, // left: 20,
// }); // });
// } // }
}, },
onLeave: (self) => {}, onLeave: (self) => {},
}); });
// gsap.to("#main-image", { // gsap.to("#main-image", {
// scale: 1, // scale: 1,
// duration: 1, // duration: 1,
// }); // });
/** /**
* Entry animation timeline * Entry animation timeline
*/ */
const entryTimeline = gsap.timeline(); const entryTimeline = gsap.timeline();
entryTimeline.to("#main-image", { entryTimeline.to("#main-image", {
scale: 1, scale: 1,
duration: 1, duration: 1,
}); });
/** /**
* Scroll animation timeline * Scroll animation timeline
*/ */
// const scrollTimeline = gsap.timeline({ // const scrollTimeline = gsap.timeline({
// scrollTrigger: { // scrollTrigger: {
// trigger: "#homepage-content-wrapper", // trigger: "#homepage-content-wrapper",
// start: "top 200px", // start: "top 200px",
// end: "bottom 90%", // end: "bottom 90%",
// scrub: 1, // scrub: 1,
// }, // },
// }); // });
// scrollTimeline // scrollTimeline
// // .to("#main-image", { // // .to("#main-image", {
// // scale: 1, // // scale: 1,
// // duration: 1, // // duration: 1,
// // }) // // })
// .to("#main-image", { // .to("#main-image", {
// rotate: -10, // rotate: -10,
// }); // });
}); });
/** /**
* Animates the hero section * Animates the hero section
*/ */
// function homepageTimeline() { // function homepageTimeline() {
// /** // /**
// * Animate hero section // * Animate hero section
// */ // */
// tl.to("#main-image", { // tl.to("#main-image", {
// y: 100, // y: 100,
// }).to("#main-image", { // }).to("#main-image", {
// y: -100, // y: -100,
// }); // });
// tl.to("#main-image", { // tl.to("#main-image", {
// x: 300, // x: 300,
// scrollTrigger: { // scrollTrigger: {
// trigger: "#main-image", // trigger: "#main-image",
// // toggleActions: "play none none none", // // toggleActions: "play none none none",
// // start: "top center", // // start: "top center",
// // end: "bottom 500px", // // end: "bottom 500px",
// // pin: "#main-image", // // pin: "#main-image",
// markers: true, // markers: true,
// scrub: 1, // scrub: 1,
// }, // },
// }); // });
// } // }
// .to({ // .to({
// scrollTrigger: { // scrollTrigger: {
// trigger: "#homepage-content-wrapper", // trigger: "#homepage-content-wrapper",
// // toggleActions: "play none none none", // // toggleActions: "play none none none",
// start: "top top", // start: "top top",
// end: "bottom bottom", // end: "bottom bottom",
// pin: "#main-image", // pin: "#main-image",
// markers: true, // markers: true,
// scrub: 1, // scrub: 1,
// }, // },
// }); // });
// .to("#main-image", { // .to("#main-image", {
// y: 300, // y: 300,
// duration: 1, // duration: 1,
// scrollTrigger: { // scrollTrigger: {
// // trigger: "#homepage-content-wrapper", // // trigger: "#homepage-content-wrapper",
// // toggleActions: "play none none none", // // toggleActions: "play none none none",
// start: "top 100%", // start: "top 100%",
// end: "bottom 0%", // end: "bottom 0%",
// pin: "#main-image", // pin: "#main-image",
// markers: true, // markers: true,
// scrub: 1, // scrub: 1,
// }, // },
// }); // });
// requestAnimationFrame(async () => { // requestAnimationFrame(async () => {
// await tl.fromTo( // await tl.fromTo(
// "#main-image", // "#main-image",
// { // {
// scale: 1.2, // scale: 1.2,
// }, // },
// { // {
// scale: 1, // scale: 1,
// duration: 1, // duration: 1,
// } // }
// ); // );
// await tl.to("#main-image", { // await tl.to("#main-image", {
// y: 300, // y: 300,
// duration: 1, // duration: 1,
// scrollTrigger: { // scrollTrigger: {
// // trigger: "#main-image", // // trigger: "#main-image",
// // toggleActions: "play none none none", // // toggleActions: "play none none none",
// // start: "top center", // // start: "top center",
// // end: "bottom 500px", // // end: "bottom 500px",
// pin: true, // pin: true,
// markers: true, // markers: true,
// scrub: 1, // scrub: 1,
// }, // },
// }); // });
// }); // });

View File

@ -1,22 +1,22 @@
console.log("main js"); console.log("main js");
const lenis = new Lenis(); const lenis = new Lenis();
lenis.on("scroll", (e) => { lenis.on("scroll", (e) => {
// console.log(e); // console.log(e);
}); });
function raf(time) { function raf(time) {
lenis.raf(time); lenis.raf(time);
requestAnimationFrame(raf); requestAnimationFrame(raf);
} }
requestAnimationFrame(raf); requestAnimationFrame(raf);
/** /**
* GSAP globals * GSAP globals
*/ */
// gsap.to(".gsap-text", { // gsap.to(".gsap-text", {
// text: "Welcome", // text: "Welcome",
// }); // });

View File

@ -1,42 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url> <url>
<loc>https://tben.me/</loc> <loc>https://tben.me/</loc>
<lastmod>2022-07-16T17:30:45.214Z</lastmod> <lastmod>2022-07-16T17:30:45.214Z</lastmod>
</url> </url>
<url> <url>
<loc>https://tben.me/about</loc> <loc>https://tben.me/about</loc>
<lastmod>2022-07-16T17:30:45.214Z</lastmod> <lastmod>2022-07-16T17:30:45.214Z</lastmod>
</url> </url>
<url> <url>
<loc>https://tben.me/work</loc> <loc>https://tben.me/work</loc>
<lastmod>2022-07-16T17:30:45.214Z</lastmod> <lastmod>2022-07-16T17:30:45.214Z</lastmod>
</url> </url>
<url> <url>
<loc>https://tben.me/blog</loc> <loc>https://tben.me/blog</loc>
<lastmod>2022-07-16T17:30:45.214Z</lastmod> <lastmod>2022-07-16T17:30:45.214Z</lastmod>
</url> </url>
<url> <url>
<loc>https://tben.me/blog/choosing-your-tech-stack</loc> <loc>https://tben.me/blog/choosing-your-tech-stack</loc>
<lastmod>2022-07-16T17:30:45.214Z</lastmod> <lastmod>2022-07-16T17:30:45.214Z</lastmod>
</url> </url>
<url> <url>
<loc>https://tben.me/blog/find-your-perfect-framework</loc> <loc>https://tben.me/blog/find-your-perfect-framework</loc>
<lastmod>2022-07-16T17:30:45.214Z</lastmod> <lastmod>2022-07-16T17:30:45.214Z</lastmod>
</url> </url>
<url> <url>
<loc>https://tben.me/contact</loc> <loc>https://tben.me/contact</loc>
<lastmod>2022-07-16T17:30:45.214Z</lastmod> <lastmod>2022-07-16T17:30:45.214Z</lastmod>
</url> </url>
<url> <url>
<loc>https://tben.me/documents/Benjamin-Toby-CV-7-27-2022.pdf</loc> <loc>https://tben.me/documents/Benjamin-Toby-CV-7-27-2022.pdf</loc>
<lastmod>2022-07-16T17:30:45.214Z</lastmod> <lastmod>2022-07-16T17:30:45.214Z</lastmod>
</url> </url>
</urlset> </urlset>

View File

@ -1,441 +1,441 @@
@import url("https://fonts.googleapis.com/css?family=Source+Code+Pro&display=swap"); @import url("https://fonts.googleapis.com/css?family=Source+Code+Pro&display=swap");
html { html {
width: 100%; width: 100%;
/* overflow-x: hidden; */ /* overflow-x: hidden; */
scroll-behavior: smooth; scroll-behavior: smooth;
font-family: "Source Code Pro", Helvetica; font-family: "Source Code Pro", Helvetica;
font-size: 16px; font-size: 16px;
line-height: 1.5; line-height: 1.5;
color: #222; color: #222;
letter-spacing: -0.8px; letter-spacing: -0.8px;
} }
* { * {
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
} }
:root { :root {
--main-color: #1668e4; --main-color: #1668e4;
--main-color-lighter: #5698fc; --main-color-lighter: #5698fc;
--dark-color: #201e1e; --dark-color: #201e1e;
--sec-color-3: #688e26; --sec-color-3: #688e26;
--sec-color-4: #adb2d3; --sec-color-4: #adb2d3;
--sec-color-5: #c2a878; --sec-color-5: #c2a878;
--light-color-1: rgb(64, 37, 216); --light-color-1: rgb(64, 37, 216);
--test-color: rgb(113, 116, 255); --test-color: rgb(113, 116, 255);
--transparent-white: rgba(255, 255, 255, 0.2); --transparent-white: rgba(255, 255, 255, 0.2);
} }
body { body {
width: 100%; width: 100%;
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
top: 0; top: 0;
justify-content: center; justify-content: center;
background-color: var(--dark-color); background-color: var(--dark-color);
color: white; color: white;
} }
a { a {
text-decoration: none; text-decoration: none;
color: white; color: white;
border: 1px solid transparent; border: 1px solid transparent;
} }
a:hover { a:hover {
color: var(--sec-color-2); color: var(--sec-color-2);
} }
button { button {
padding: 10px 25px; padding: 10px 25px;
border: none; border: none;
cursor: pointer; cursor: pointer;
font-size: inherit; font-size: inherit;
border: 1px solid transparent; border: 1px solid transparent;
} }
hr { hr {
opacity: 0.3; opacity: 0.3;
} }
button:hover { button:hover {
background-color: var(--dark-color); background-color: var(--dark-color);
/* background-color: #c52532; */ /* background-color: #c52532; */
color: white; color: white;
border-color: var(--transparent-white); border-color: var(--transparent-white);
} }
form * { form * {
font-family: inherit; font-family: inherit;
font-size: inherit; font-size: inherit;
} }
header { header {
z-index: 1000000; z-index: 1000000;
margin-bottom: 40px; margin-bottom: 40px;
} }
h1 { h1 {
font-size: 52px; font-size: 52px;
margin-top: 0; margin-top: 0;
margin-bottom: 10px; margin-bottom: 10px;
} }
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
p a, p a,
span a { span a {
color: var(--main-color-lighter); color: var(--main-color-lighter);
/* border-bottom: 1px solid var(--main-color-lighter); */ /* border-bottom: 1px solid var(--main-color-lighter); */
} }
p a:hover, p a:hover,
span a:hover { span a:hover {
color: var(--main-color); color: var(--main-color);
} }
/* ################################################# -- Sliders */ /* ################################################# -- Sliders */
aside, aside,
.side-nav-block { .side-nav-block {
scrollbar-width: none; scrollbar-width: none;
} }
/* width */ /* width */
aside::-webkit-scrollbar, aside::-webkit-scrollbar,
.side-nav-block::-webkit-scrollbar { .side-nav-block::-webkit-scrollbar {
width: 5px; width: 5px;
} }
/* Track */ /* Track */
aside::-webkit-scrollbar-track, aside::-webkit-scrollbar-track,
.side-nav-block::-webkit-scrollbar-track { .side-nav-block::-webkit-scrollbar-track {
background: #f1f1f1; background: #f1f1f1;
} }
/* Handle */ /* Handle */
aside::-webkit-scrollbar-thumb, aside::-webkit-scrollbar-thumb,
.side-nav-block::-webkit-scrollbar-thumb { .side-nav-block::-webkit-scrollbar-thumb {
background: #dbe1eb; background: #dbe1eb;
border-radius: 10px; border-radius: 10px;
} }
/* Handle on hover */ /* Handle on hover */
aside::-webkit-scrollbar-thumb:hover, aside::-webkit-scrollbar-thumb:hover,
.side-nav-block::-webkit-scrollbar-thumb:hover { .side-nav-block::-webkit-scrollbar-thumb:hover {
background: #555; background: #555;
} }
/*############################################# -- Common Actions */ /*############################################# -- Common Actions */
.visible { .visible {
display: flex; display: flex;
} }
.hidden { .hidden {
display: none; display: none;
} }
.fixed { .fixed {
position: fixed; position: fixed;
} }
.absolute { .absolute {
position: absolute; position: absolute;
} }
.relative { .relative {
position: relative; position: relative;
} }
.no-pointer-events { .no-pointer-events {
pointer-events: none; pointer-events: none;
} }
.pointer-events { .pointer-events {
pointer-events: visible; pointer-events: visible;
} }
.spacer { .spacer {
display: block; display: block;
width: 100%; width: 100%;
height: 80px; height: 80px;
} }
/*############################################# -- Header */ /*############################################# -- Header */
header { header {
color: white; color: white;
} }
.logo-link-block h1 { .logo-link-block h1 {
font-size: 28px; font-size: 28px;
margin: 0; margin: 0;
margin-bottom: 5px; margin-bottom: 5px;
} }
nav { nav {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 20px; gap: 20px;
} }
nav a { nav a {
opacity: 0.5; opacity: 0.5;
cursor: pointer; cursor: pointer;
} }
nav a:hover { nav a:hover {
opacity: 1; opacity: 1;
} }
.active-page { .active-page {
opacity: 1; opacity: 1;
border-bottom: 2px solid white; border-bottom: 2px solid white;
} }
/*############################################# -- Shuffled Text */ /*############################################# -- Shuffled Text */
#__next { #__next {
max-width: 1200px; max-width: 1200px;
width: 100%; width: 100%;
height: 100%; height: 100%;
opacity: 0; opacity: 0;
animation-name: shuffle; animation-name: shuffle;
animation-timing-function: ease-out; animation-timing-function: ease-out;
animation-duration: 1s; animation-duration: 1s;
animation-fill-mode: forwards; animation-fill-mode: forwards;
} }
/* .shuffled-text-span span { /* .shuffled-text-span span {
animation-name: shuffle; animation-name: shuffle;
animation-timing-function: ease-out; animation-timing-function: ease-out;
animation-delay: 0.5s; animation-delay: 0.5s;
} */ } */
@keyframes shuffle { @keyframes shuffle {
0% { 0% {
opacity: 0; opacity: 0;
} }
100% { 100% {
opacity: 1; opacity: 1;
} }
} }
/*############################################# -- Hero Section */ /*############################################# -- Hero Section */
.hero-sub-text { .hero-sub-text {
font-size: 24px; font-size: 24px;
color: rgba(255, 255, 255, 0.7); color: rgba(255, 255, 255, 0.7);
} }
.hero-ctas-section { .hero-ctas-section {
display: flex; display: flex;
align-items: center; align-items: center;
margin-top: 40px; margin-top: 40px;
gap: 20px; gap: 20px;
} }
.hero-ctas-section a { .hero-ctas-section a {
padding: 10px 25px; padding: 10px 25px;
border: none; border: none;
cursor: pointer; cursor: pointer;
font-size: inherit; font-size: inherit;
color: var(--dark-color); color: var(--dark-color);
background-color: white; background-color: white;
font-size: 18px; font-size: 18px;
} }
.hero-ctas-section a:hover { .hero-ctas-section a:hover {
background-color: var(--dark-color); background-color: var(--dark-color);
color: white; color: white;
border-color: var(--transparent-white); border-color: var(--transparent-white);
} }
/*############################################# -- 404 page */ /*############################################# -- 404 page */
.not-found-page-wrapper { .not-found-page-wrapper {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
/*############################################# -- Portfolio page */ /*############################################# -- Portfolio page */
.portfolio-entries-block { .portfolio-entries-block {
display: grid; display: grid;
gap: 40px; gap: 40px;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
width: 100%; width: 100%;
} }
.portfolio-entry-block { .portfolio-entry-block {
max-width: 700px; max-width: 700px;
border: 1px solid rgba(255, 255, 255, 0.3); border: 1px solid rgba(255, 255, 255, 0.3);
padding: 20px; padding: 20px;
} }
/*############################################# -- Contact Forms */ /*############################################# -- Contact Forms */
form { form {
margin-top: 40px; margin-top: 40px;
max-width: 1000px; max-width: 1000px;
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 20px; gap: 20px;
position: relative; position: relative;
} }
input, input,
textarea { textarea {
padding: 15px 20px; padding: 15px 20px;
background-color: transparent; background-color: transparent;
color: white; color: white;
border: 1px solid rgba(255, 255, 255, 0.2); border: 1px solid rgba(255, 255, 255, 0.2);
width: 100%; width: 100%;
resize: none; resize: none;
} }
.message-response { .message-response {
position: absolute; position: absolute;
width: 100%; width: 100%;
height: 100%; height: 100%;
top: 0; top: 0;
left: 0; left: 0;
background-color: var(--dark-color); background-color: var(--dark-color);
border: 2px solid #688e26; border: 2px solid #688e26;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 24px; font-size: 24px;
gap: 10px; gap: 10px;
} }
.message-response.failed { .message-response.failed {
border: 2px solid #d42222; border: 2px solid #d42222;
} }
#homepage-animation-wrapper { #homepage-animation-wrapper {
width: 150%; width: 150%;
height: 100%; height: 100%;
background-color: var(--dark-color); background-color: var(--dark-color);
} }
.tech-stack-header { .tech-stack-header {
color: rgb(113, 116, 255); color: rgb(113, 116, 255);
margin-bottom: 3px; margin-bottom: 3px;
} }
.portfolio-image-wrapper { .portfolio-image-wrapper {
width: 100%; width: 100%;
height: 300px; height: 300px;
margin-bottom: 15px; margin-bottom: 15px;
overflow: hidden; overflow: hidden;
} }
.portfolio-image { .portfolio-image {
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: cover; object-fit: cover;
width: 100%; width: 100%;
height: 300px; height: 300px;
object-position: left top; object-position: left top;
margin-bottom: 20px; margin-bottom: 20px;
} }
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
span img { span img {
width: 100%; width: 100%;
height: auto; height: auto;
object-fit: contain; object-fit: contain;
} }
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* .transition-fade { /* .transition-fade {
transition: 0.4s; transition: 0.4s;
opacity: 1; opacity: 1;
} }
html.is-animating .transition-fade { html.is-animating .transition-fade {
opacity: 0; opacity: 0;
} */ } */
/* ############################################################################################### /* ###############################################################################################
################################################################################################## ##################################################################################################
################################################################################################## ##################################################################################################
################################################################################################## ##################################################################################################
##################################### -- Mobile Styles -- ######################################## ##################################### -- Mobile Styles -- ########################################
################################################################################################## ##################################################################################################
################################################################################################## ##################################################################################################
################################################################################################## ##################################################################################################
############################################################################################### */ ############################################################################################### */
@media (max-width: 1200px) { @media (max-width: 1200px) {
} }
@media (max-width: 990px) { @media (max-width: 990px) {
.portfolio-entries-block { .portfolio-entries-block {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
} }
@media (max-width: 800px) { @media (max-width: 800px) {
h1 { h1 {
font-size: 28px; font-size: 28px;
} }
nav { nav {
flex-wrap: wrap; flex-wrap: wrap;
gap: 15px; gap: 15px;
} }
body { body {
padding: 20px; padding: 20px;
padding-bottom: 80px; padding-bottom: 80px;
} }
.hero-ctas-section { .hero-ctas-section {
flex-wrap: wrap; flex-wrap: wrap;
} }
} }
@media (max-width: 600px) { @media (max-width: 600px) {
.portfolio-image-wrapper { .portfolio-image-wrapper {
height: auto; height: auto;
} }
.portfolio-image { .portfolio-image {
object-fit: contain; object-fit: contain;
height: auto; height: auto;
margin: 0; margin: 0;
} }
} }
@media (max-width: 450px) { @media (max-width: 450px) {
} }
@media (max-width: 350px) { @media (max-width: 350px) {
} }

28
scripts/lottie.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,479 +1,479 @@
@import url("https://fonts.googleapis.com/css?family=Cutive+Mono&display=swap"); @import url("https://fonts.googleapis.com/css?family=Cutive+Mono&display=swap");
html { html {
width: 100%; width: 100%;
/* scroll-behavior: smooth; */ /* scroll-behavior: smooth; */
font-family: "Cutive Mono", Helvetica; font-family: "Cutive Mono", Helvetica;
font-size: 16px; font-size: 16px;
line-height: 1.5; line-height: 1.5;
color: #222; color: #222;
letter-spacing: -0.8px; letter-spacing: -0.8px;
} }
* { * {
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
} }
:root { :root {
--main-color: #7174ff; --main-color: #7174ff;
--main-color-lighter: #9d9eff; --main-color-lighter: #9d9eff;
--main-color-darker: #7072c9; --main-color-darker: #7072c9;
--main-color-dark: #292a6b; --main-color-dark: #292a6b;
--dark-color: #181515; --dark-color: #181515;
--sec-color-3: #688e26; --sec-color-3: #688e26;
--sec-color-4: #adb2d3; --sec-color-4: #adb2d3;
--sec-color-5: #c2a878; --sec-color-5: #c2a878;
--light-color-1: rgb(64, 37, 216); --light-color-1: rgb(64, 37, 216);
--test-color: #7174ff; --test-color: #7174ff;
--transparent-white: rgba(255, 255, 255, 0.2); --transparent-white: rgba(255, 255, 255, 0.2);
} }
body { body {
width: 100%; width: 100%;
margin: 0px; margin: 0px;
top: 0; top: 0;
justify-content: center; justify-content: center;
background-color: var(--dark-color); background-color: var(--dark-color);
color: white; color: white;
} }
@media (max-width: 1200px) { @media (max-width: 1200px) {
main { main {
padding-top: 200px; padding-top: 200px;
} }
} }
@media (max-width: 600px) { @media (max-width: 600px) {
main { main {
padding-top: 150px; padding-top: 150px;
} }
} }
a { a {
text-decoration: none; text-decoration: none;
color: white; color: white;
border: 1px solid transparent; border: 1px solid transparent;
} }
a:hover { a:hover {
color: var(--sec-color-2); color: var(--sec-color-2);
} }
button, button,
.button { .button {
padding: 10px 25px; padding: 10px 25px;
border: none; border: none;
cursor: pointer; cursor: pointer;
font-size: inherit; font-size: inherit;
border: 1px solid transparent; border: 1px solid transparent;
color: var(--dark-color); color: var(--dark-color);
background-color: white; background-color: white;
font-size: 18px; font-size: 18px;
font-weight: 600; font-weight: 600;
} }
button.outlined, button.outlined,
.button.outlined { .button.outlined {
border: 1px solid white; border: 1px solid white;
background-color: transparent; background-color: transparent;
color: white; color: white;
} }
hr { hr {
opacity: 0.3; opacity: 0.3;
} }
button:hover, button:hover,
.button:hover { .button:hover {
background-color: var(--dark-color); background-color: var(--dark-color);
/* background-color: #c52532; */ /* background-color: #c52532; */
color: white; color: white;
border-color: var(--transparent-white); border-color: var(--transparent-white);
} }
form * { form * {
font-family: inherit; font-family: inherit;
font-size: inherit; font-size: inherit;
} }
header { header {
z-index: 1000000; z-index: 1000000;
} }
h1 { h1 {
font-size: 52px; font-size: 52px;
margin-top: 0; margin-top: 0;
margin-bottom: 10px; margin-bottom: 10px;
} }
h2 { h2 {
font-size: 44px; font-size: 44px;
} }
h3 { h3 {
font-size: 28px; font-size: 28px;
} }
h4 { h4 {
font-size: 22px; font-size: 22px;
} }
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
p a, p a,
span a { span a {
color: var(--main-color-lighter); color: var(--main-color-lighter);
/* border-bottom: 1px solid var(--main-color-lighter); */ /* border-bottom: 1px solid var(--main-color-lighter); */
} }
p a:hover, p a:hover,
span a:hover { span a:hover {
color: var(--main-color); color: var(--main-color);
} }
/* ################################################# -- Sliders */ /* ################################################# -- Sliders */
aside, aside,
.side-nav-block { .side-nav-block {
scrollbar-width: none; scrollbar-width: none;
} }
/* width */ /* width */
aside::-webkit-scrollbar, aside::-webkit-scrollbar,
.side-nav-block::-webkit-scrollbar { .side-nav-block::-webkit-scrollbar {
width: 5px; width: 5px;
} }
/* Track */ /* Track */
aside::-webkit-scrollbar-track, aside::-webkit-scrollbar-track,
.side-nav-block::-webkit-scrollbar-track { .side-nav-block::-webkit-scrollbar-track {
background: #f1f1f1; background: #f1f1f1;
} }
/* Handle */ /* Handle */
aside::-webkit-scrollbar-thumb, aside::-webkit-scrollbar-thumb,
.side-nav-block::-webkit-scrollbar-thumb { .side-nav-block::-webkit-scrollbar-thumb {
background: #dbe1eb; background: #dbe1eb;
border-radius: 10px; border-radius: 10px;
} }
/* Handle on hover */ /* Handle on hover */
aside::-webkit-scrollbar-thumb:hover, aside::-webkit-scrollbar-thumb:hover,
.side-nav-block::-webkit-scrollbar-thumb:hover { .side-nav-block::-webkit-scrollbar-thumb:hover {
background: #555; background: #555;
} }
/*############################################# -- Common Actions */ /*############################################# -- Common Actions */
.visible { .visible {
display: flex; display: flex;
} }
.hidden { .hidden {
display: none; display: none;
} }
.fixed { .fixed {
position: fixed; position: fixed;
} }
.absolute { .absolute {
position: absolute; position: absolute;
} }
.relative { .relative {
position: relative; position: relative;
} }
.no-pointer-events { .no-pointer-events {
pointer-events: none; pointer-events: none;
} }
.pointer-events { .pointer-events {
pointer-events: visible; pointer-events: visible;
} }
.spacer { .spacer {
display: block; display: block;
width: 100%; width: 100%;
height: 80px; height: 80px;
} }
/*############################################# -- Header */ /*############################################# -- Header */
header { header {
color: white; color: white;
} }
.logo-link-block h1 { .logo-link-block h1 {
font-size: 28px; font-size: 28px;
margin: 0; margin: 0;
margin-bottom: 5px; margin-bottom: 5px;
} }
nav { nav {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 20px; gap: 20px;
} }
nav a { nav a {
opacity: 0.5; opacity: 0.5;
cursor: pointer; cursor: pointer;
} }
nav a:hover { nav a:hover {
opacity: 1; opacity: 1;
} }
.active-page { .active-page {
opacity: 1; opacity: 1;
border-bottom: 2px solid white; border-bottom: 2px solid white;
} }
/*############################################# -- Shuffled Text */ /*############################################# -- Shuffled Text */
#__next { #__next {
width: 100%; width: 100%;
opacity: 0; opacity: 0;
animation-name: shuffle; animation-name: shuffle;
animation-timing-function: ease-out; animation-timing-function: ease-out;
animation-duration: 1s; animation-duration: 1s;
animation-fill-mode: forwards; animation-fill-mode: forwards;
} }
/* .shuffled-text-span span { /* .shuffled-text-span span {
animation-name: shuffle; animation-name: shuffle;
animation-timing-function: ease-out; animation-timing-function: ease-out;
animation-delay: 0.5s; animation-delay: 0.5s;
} */ } */
@keyframes shuffle { @keyframes shuffle {
0% { 0% {
opacity: 0; opacity: 0;
} }
100% { 100% {
opacity: 1; opacity: 1;
} }
} }
/*############################################# -- Hero Section */ /*############################################# -- Hero Section */
.hero-sub-text { .hero-sub-text {
font-size: 24px; font-size: 24px;
color: rgba(255, 255, 255, 0.7); color: rgba(255, 255, 255, 0.7);
} }
.hero-ctas-section { .hero-ctas-section {
display: flex; display: flex;
align-items: center; align-items: center;
margin-top: 40px; margin-top: 40px;
gap: 20px; gap: 20px;
} }
.hero-ctas-section a { .hero-ctas-section a {
padding: 10px 25px; padding: 10px 25px;
border: none; border: none;
cursor: pointer; cursor: pointer;
font-size: inherit; font-size: inherit;
color: var(--dark-color); color: var(--dark-color);
background-color: white; background-color: white;
font-size: 18px; font-size: 18px;
} }
.hero-ctas-section a:hover { .hero-ctas-section a:hover {
background-color: var(--dark-color); background-color: var(--dark-color);
color: white; color: white;
border-color: var(--transparent-white); border-color: var(--transparent-white);
} }
/*############################################# -- 404 page */ /*############################################# -- 404 page */
.not-found-page-wrapper { .not-found-page-wrapper {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
/*############################################# -- Portfolio page */ /*############################################# -- Portfolio page */
.portfolio-entries-block { .portfolio-entries-block {
display: grid; display: grid;
gap: 40px; gap: 40px;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
width: 100%; width: 100%;
} }
.portfolio-entry-block { .portfolio-entry-block {
max-width: 700px; max-width: 700px;
border: 1px solid rgba(255, 255, 255, 0.3); border: 1px solid rgba(255, 255, 255, 0.3);
padding: 20px; padding: 20px;
} }
/*############################################# -- Contact Forms */ /*############################################# -- Contact Forms */
form { form {
margin-top: 40px; margin-top: 40px;
max-width: 1000px; max-width: 1000px;
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 20px; gap: 20px;
position: relative; position: relative;
} }
input, input,
textarea { textarea {
padding: 15px 20px; padding: 15px 20px;
background-color: transparent; background-color: transparent;
color: white; color: white;
border: 1px solid rgba(255, 255, 255, 0.5); border: 1px solid rgba(255, 255, 255, 0.5);
width: 100%; width: 100%;
resize: none; resize: none;
font-size: 20px; font-size: 20px;
} }
input::placeholder, input::placeholder,
textarea::placeholder { textarea::placeholder {
color: rgba(255, 255, 255, 0.5); color: rgba(255, 255, 255, 0.5);
} }
.message-response { .message-response {
position: absolute; position: absolute;
width: 100%; width: 100%;
height: 100%; height: 100%;
top: 0; top: 0;
left: 0; left: 0;
background-color: var(--dark-color); background-color: var(--dark-color);
border: 2px solid #688e26; border: 2px solid #688e26;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 24px; font-size: 24px;
gap: 10px; gap: 10px;
} }
.message-response.failed { .message-response.failed {
border: 2px solid #d42222; border: 2px solid #d42222;
} }
#homepage-animation-wrapper { #homepage-animation-wrapper {
width: 150%; width: 150%;
height: 100%; height: 100%;
background-color: var(--dark-color); background-color: var(--dark-color);
} }
.tech-stack-header { .tech-stack-header {
color: #7174ff; color: #7174ff;
margin-bottom: 3px; margin-bottom: 3px;
} }
.portfolio-image-wrapper { .portfolio-image-wrapper {
width: 100%; width: 100%;
height: 300px; height: 300px;
margin-bottom: 15px; margin-bottom: 15px;
overflow: hidden; overflow: hidden;
} }
.portfolio-image { .portfolio-image {
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: cover; object-fit: cover;
width: 100%; width: 100%;
height: 300px; height: 300px;
object-position: left top; object-position: left top;
margin-bottom: 20px; margin-bottom: 20px;
} }
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
span img { span img {
width: 100%; width: 100%;
height: auto; height: auto;
object-fit: contain; object-fit: contain;
} }
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* * */ /* * */
/* .transition-fade { /* .transition-fade {
transition: 0.4s; transition: 0.4s;
opacity: 1; opacity: 1;
} }
html.is-animating .transition-fade { html.is-animating .transition-fade {
opacity: 0; opacity: 0;
} */ } */
/* ############################################################################################### /* ###############################################################################################
################################################################################################## ##################################################################################################
################################################################################################## ##################################################################################################
################################################################################################## ##################################################################################################
##################################### -- Mobile Styles -- ######################################## ##################################### -- Mobile Styles -- ########################################
################################################################################################## ##################################################################################################
################################################################################################## ##################################################################################################
################################################################################################## ##################################################################################################
############################################################################################### */ ############################################################################################### */
@media (max-width: 1200px) { @media (max-width: 1200px) {
#main-image { #main-image {
position: fixed; position: fixed;
top: 40px; top: 40px;
z-index: -1; z-index: -1;
} }
} }
@media (max-width: 990px) { @media (max-width: 990px) {
.portfolio-entries-block { .portfolio-entries-block {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
} }
@media (max-width: 800px) { @media (max-width: 800px) {
h1 { h1 {
font-size: 28px; font-size: 28px;
} }
nav { nav {
flex-wrap: wrap; flex-wrap: wrap;
gap: 15px; gap: 15px;
} }
.hero-ctas-section { .hero-ctas-section {
flex-wrap: wrap; flex-wrap: wrap;
} }
} }
@media (max-width: 600px) { @media (max-width: 600px) {
.portfolio-image-wrapper { .portfolio-image-wrapper {
height: auto; height: auto;
} }
.portfolio-image { .portfolio-image {
object-fit: contain; object-fit: contain;
height: auto; height: auto;
margin: 0; margin: 0;
} }
} }
@media (max-width: 450px) { @media (max-width: 450px) {
} }
@media (max-width: 350px) { @media (max-width: 350px) {
} }

View File

@ -762,4 +762,4 @@
.xl\:pt-0 { .xl\:pt-0 {
padding-top: 0px padding-top: 0px
} }
} }

View File

@ -1,35 +1,35 @@
module.exports = { module.exports = {
content: ["./components/**/*.{html,js,jsx}", "./pages/**/*.{jsx,tsx}", "./app/**/*.{html,js,jsx,tsx}", "./layouts/**/*.{jsx,tsx}"], content: ["./components/**/*.{html,js,jsx}", "./pages/**/*.{jsx,tsx}", "./app/**/*.{html,js,jsx,tsx}", "./layouts/**/*.{jsx,tsx}"],
theme: { theme: {
screens: { screens: {
xs: "350px", xs: "350px",
sm: "450px", sm: "450px",
md: "600px", md: "600px",
sl: "800px", sl: "800px",
lg: "976px", lg: "976px",
xl: "1200px", xl: "1200px",
}, },
colors: { colors: {
primary: "#7174ff", primary: "#7174ff",
primary_light: "#9d9eff", primary_light: "#9d9eff",
primary_dark: "#7072c9", primary_dark: "#7072c9",
}, },
fontFamily: { fontFamily: {
sans: ["Graphik", "sans-serif"], sans: ["Graphik", "sans-serif"],
serif: ["Merriweather", "serif"], serif: ["Merriweather", "serif"],
}, },
// extend: { // extend: {
// spacing: { // spacing: {
// 128: "32rem", // 128: "32rem",
// 144: "36rem", // 144: "36rem",
// }, // },
// borderRadius: { // borderRadius: {
// "4xl": "2rem", // "4xl": "2rem",
// }, // },
// }, // },
}, },
plugins: [], plugins: [],
corePlugins: { corePlugins: {
preflight: false, preflight: false,
}, },
}; };

View File

@ -1,3 +1,3 @@
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;

View File

@ -1,14 +1,14 @@
{ {
"rewrites": [ "rewrites": [
{ {
"source": "/api/:path*", "source": "/api/:path*",
"destination": "/api/:path*", "destination": "/api/:path*",
"headers": [ "headers": [
{ "key": "Access-Control-Allow-Credentials", "value": "true" }, { "key": "Access-Control-Allow-Credentials", "value": "true" },
{ "key": "Access-Control-Allow-Origin", "value": "*" }, { "key": "Access-Control-Allow-Origin", "value": "*" },
{ "key": "Access-Control-Allow-Methods", "value": "GET,OPTIONS,PATCH,DELETE,POST,PUT" }, { "key": "Access-Control-Allow-Methods", "value": "GET,OPTIONS,PATCH,DELETE,POST,PUT" },
{ "key": "Access-Control-Allow-Headers", "value": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" } { "key": "Access-Control-Allow-Headers", "value": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" }
] ]
} }
] ]
} }