First Commit

This commit is contained in:
Benjamin Toby
2024-12-09 16:36:17 +01:00
parent f24b493566
commit b037cec100
128 changed files with 3281 additions and 193 deletions
+70
View File
@@ -0,0 +1,70 @@
import { GitBranch, Github, Linkedin, Mail, Users } from "lucide-react";
import { ReactNode } from "react";
export type HeaderLinkType = {
name: string;
href: string;
current?: boolean;
};
export const HeaderLinks: HeaderLinkType[] = [
{
name: "Home",
href: "/",
current: true,
},
{
name: "About",
href: "/about",
},
{
name: "Skills",
href: "/skills",
},
{
name: "Work",
href: "/work",
},
{
name: "Blog",
href: "/blog",
},
{
name: "Contact",
href: "/contact",
},
];
export type SocialLinksType = {
name?: string;
href: string;
icon: ReactNode;
};
export const SocialLinks: SocialLinksType[] = [
{
name: "Github",
href: "https://github.com/BenjaminToby",
icon: <Github size={17} />,
},
{
name: "Linkedin",
href: "https://www.linkedin.com/in/benjamin-toby/",
icon: <Linkedin size={17} />,
},
{
name: "Teams",
href: "https://team.tben.me/",
icon: <Users size={17} />,
},
{
name: "Git",
href: "https://git.tben.me",
icon: <GitBranch size={17} />,
},
{
name: "Mail",
href: "mailto:ben@tben.me",
icon: <Mail size={17} />,
},
];
+13
View File
@@ -0,0 +1,13 @@
import { HeaderLinkType } from "../(data)/links";
type Props = {
link: HeaderLinkType;
};
export default function HeaderLink({ link }: Props) {
return (
<a href={link.href} className="text-white hover:text-gray-300">
{link.name}
</a>
);
}
+18
View File
@@ -0,0 +1,18 @@
import { SocialLinksType } from "../(data)/links";
type Props = {
link: SocialLinksType;
};
export default function SocialLink({ link }: Props) {
return (
<a
href={link.href}
title={link.name}
className="text-white hover:text-gray-300"
target="_blank"
>
{link.icon}
</a>
);
}
+56
View File
@@ -0,0 +1,56 @@
import Logo from "@/components/general/Logo";
import Stack from "@/components/lib/layout/Stack";
import { twMerge } from "tailwind-merge";
import { HeaderLinks, SocialLinks } from "../(data)/links";
import HeaderLink from "../(partials)/HeaderLink";
import React from "react";
import Divider from "@/components/lib/layout/Divider";
import Button from "@/components/lib/layout/Button";
import { X } from "lucide-react";
import SocialLink from "../(partials)/SocialLink";
import Row from "@/components/lib/layout/Row";
type Props = {
menuOpen: boolean;
setMenuOpen: React.Dispatch<React.SetStateAction<boolean>>;
};
export default function MobileMenu({ menuOpen, setMenuOpen }: Props) {
return (
<div
className={twMerge(
"fixed top-0 bg-[var(--bg-color)] w-full h-full overflow-y-auto",
"z-[100] p-10",
menuOpen ? "right-0" : "right-[100vw]"
)}
>
<Button
variant="ghost"
className="absolute top-10 right-10"
onClick={() => setMenuOpen(false)}
>
<X />
</Button>
<Stack className="w-full h-full">
<Logo size={40} />
<Divider />
<Stack className="w-full items-stretch">
{HeaderLinks.map((link, index) => {
return (
<React.Fragment key={index}>
<HeaderLink key={index} link={link} />
{index < HeaderLinks.length - 1 && <Divider />}
</React.Fragment>
);
})}
</Stack>
<Divider />
<Row className="items-center w-full py-6 mt-auto gap-10 mt-auto">
{SocialLinks.map((link, index) => {
return <SocialLink key={index} link={link} />;
})}
</Row>
</Stack>
</div>
);
}
+40
View File
@@ -0,0 +1,40 @@
import Logo from "@/components/general/Logo";
import Stack from "@/components/lib/layout/Stack";
import { PropsWithChildren } from "react";
import { twMerge } from "tailwind-merge";
import { SocialLinks } from "./(data)/links";
import SocialLink from "./(partials)/SocialLink";
type Props = {};
export default function Aside({}: Props) {
return (
<aside
className={twMerge(
"max-w-[100px] border-0 border-r max-h-[100vh]",
"border-white/10 border-solid flex flex-col",
"items-start hidden md:flex sticky top-0"
)}
>
<div
className={twMerge(
"px-6 py-4 h-[var(--header-height)] border-0",
"border-b border-white/10"
)}
>
<Logo size={28} />
</div>
<Stack className="items-center w-full py-6 mt-auto">
{SocialLinks.map((link, index) => {
return <SocialLink key={index} link={link} />;
})}
</Stack>
<div
className={twMerge(
"px-6 py-4 h-[var(--header-height)] border-0",
"border-t border-white/10 w-full"
)}
></div>
</aside>
);
}
+22
View File
@@ -0,0 +1,22 @@
import Span from "@/components/lib/layout/Span";
import { PropsWithChildren } from "react";
import { twMerge } from "tailwind-merge";
type Props = {};
export default function Footer({}: Props) {
const date = new Date();
return (
<footer
className={twMerge(
"h-[var(--header-height)] border-0 border-t border-white/10",
"w-full flex flex-row items-center px-6 mt-auto"
)}
>
<Span className="text-sm opacity-40">
Copyright © {date.getFullYear()} Tben.me. All Rights Reserved.
</Span>
</footer>
);
}
+37
View File
@@ -0,0 +1,37 @@
import { twMerge } from "tailwind-merge";
import { HeaderLinks } from "./(data)/links";
import HeaderLink from "./(partials)/HeaderLink";
import Row from "@/components/lib/layout/Row";
import Logo from "@/components/general/Logo";
import { Menu } from "lucide-react";
import Button from "@/components/lib/layout/Button";
import React from "react";
type Props = {
menuOpen: boolean;
setMenuOpen: React.Dispatch<React.SetStateAction<boolean>>;
};
export default function Header({ menuOpen, setMenuOpen }: Props) {
return (
<header
className={twMerge(
"h-[var(--header-height)] border-0 border-b border-white/10",
"w-full flex flex-row items-center px-6 sticky top-0",
"bg-[var(--bg-color)] z-10"
)}
>
<Row className="gap-6 ml-auto hidden md:flex">
{HeaderLinks.map((link, index) => {
return <HeaderLink key={index} link={link} />;
})}
</Row>
<Row className="flex md:hidden w-full justify-between">
<Logo size={25} />
<Button variant="ghost" onClick={() => setMenuOpen(!menuOpen)}>
<Menu />
</Button>
</Row>
</header>
);
}
+30
View File
@@ -0,0 +1,30 @@
import Main from "@/components/lib/layout/Main";
import React, { PropsWithChildren } from "react";
import Aside from "./Aside";
import Header from "./Header";
import Footer from "./Footer";
import { twMerge } from "tailwind-merge";
import Stack from "@/components/lib/layout/Stack";
import { HeaderLinks } from "./(data)/links";
import HeaderLink from "./(partials)/HeaderLink";
import MobileMenu from "./(sections)/MobileMenu";
type Props = PropsWithChildren & {};
export default function Layout({ children }: Props) {
const [menuOpen, setMenuOpen] = React.useState(false);
return (
<div className="flex flex-row items-stretch w-full min-h-screen">
<Aside />
<div className={twMerge("flex flex-col items-start gap-0", "grow")}>
<Header {...{ menuOpen, setMenuOpen }} />
<main className="w-full items-start flex flex-col gap-0">
{children}
</main>
<Footer />
</div>
<MobileMenu {...{ menuOpen, setMenuOpen }} />
</div>
);
}