Compare commits

..

No commits in common. '107c60e592139ae19c9fa44f028d890188a22037' and '16cc67c4152c390b21fd017f0ca3eb7799ebb2a6' have entirely different histories.

@ -28,6 +28,10 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }} password: ${{ secrets.DOCKER_TOKEN }}
- name: Set Short SHA
id: short_sha
run: echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Build/Push Image - name: Build/Push Image
uses: docker/build-push-action@v4 uses: docker/build-push-action@v4
with: with:
@ -35,6 +39,11 @@ jobs:
push: true push: true
build-args: | build-args: |
NEXT_PUBLIC_IS_PREVIEW=1 NEXT_PUBLIC_IS_PREVIEW=1
NEXT_PUBLIC_BUILD_SHA=${{ steps.short_sha.outputs.short_sha }}
NEXT_PUBLIC_BUILD_ID=${{ github.run_id }}
NEXT_PUBLIC_BUILD_NUM=${{ github.run_number }}
secrets: |
REPOS_READ_ONLY=${{ secrets.REPOS_READ_ONLY }}
tags: ${{ secrets.DOCKER_USERNAME }}/website:preview tags: ${{ secrets.DOCKER_USERNAME }}/website:preview
cache-from: type=gha cache-from: type=gha
cache-to: type=gha,mode=max cache-to: type=gha,mode=max

@ -22,9 +22,19 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }} password: ${{ secrets.DOCKER_TOKEN }}
- name: Set Short SHA
id: short_sha
run: echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Build/Push Image - name: Build/Push Image
uses: docker/build-push-action@v4 uses: docker/build-push-action@v4
with: with:
context: . context: .
push: true push: true
build-args: |
NEXT_PUBLIC_BUILD_SHA=${{ steps.short_sha.outputs.short_sha }}
NEXT_PUBLIC_BUILD_ID=${{ github.run_id }}
NEXT_PUBLIC_BUILD_NUM=${{ github.run_number }}
secrets: |
REPOS_READ_ONLY=${{ secrets.REPOS_READ_ONLY }}
tags: ${{ secrets.DOCKER_USERNAME }}/website:${{ github.ref_name }} tags: ${{ secrets.DOCKER_USERNAME }}/website:${{ github.ref_name }}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,7 +1,3 @@
compressionLevel: mixed
enableGlobalCache: false
nodeLinker: node-modules nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.5.1.cjs yarnPath: .yarn/releases/yarn-3.6.1.cjs

@ -21,8 +21,16 @@ ENV NEXT_TELEMETRY_DISABLED 1
# Keep as empty string as Typescript parses empty strings as false # Keep as empty string as Typescript parses empty strings as false
ARG NEXT_PUBLIC_IS_PREVIEW="" ARG NEXT_PUBLIC_IS_PREVIEW=""
ENV NEXT_PUBLIC_IS_PREVIEW=$NEXT_PUBLIC_IS_PREVIEW ENV NEXT_PUBLIC_IS_PREVIEW=$NEXT_PUBLIC_IS_PREVIEW
ARG NEXT_PUBLIC_BUILD_SHA
RUN yarn build ENV NEXT_PUBLIC_BUILD_SHA=$NEXT_PUBLIC_BUILD_SHA
ARG NEXT_PUBLIC_BUILD_ID
ENV NEXT_PUBLIC_BUILD_ID=$NEXT_PUBLIC_BUILD_ID
ARG NEXT_PUBLIC_BUILD_NUM
ENV NEXT_PUBLIC_BUILD_NUM=$NEXT_PUBLIC_BUILD_NUM
RUN --mount=type=secret,id=REPOS_READ_ONLY \
REPOS_READ_ONLY=$(cat /run/secrets/REPOS_READ_ONLY) \
yarn build
# Production Image # Production Image
FROM node:20-alpine AS runner FROM node:20-alpine AS runner

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 49 KiB

@ -0,0 +1,27 @@
import { FancyUnderline, GroupedText, Text } from "./utils/Text";
export const About = () => {
return (
<GroupedText className="text-center">
<Text>
I am a{" "}
<FancyUnderline className="font-semibold" decoration="decoration-green">
software engineer
</FancyUnderline>{" "}
at the BBC and a{" "}
<FancyUnderline className="font-semibold" decoration="decoration-red">student</FancyUnderline>,
currently pursuing a BSc in Software Engineering at the University of
Glasgow.
</Text>
<Text>
You&apos;ll usually find me nerding out about technology and playing
video games. I also really enjoy contributing to open source projects,
mainly{" "}
<FancyUnderline className="font-semibold" decoration="decoration-peach">
Catppuccin
</FancyUnderline>
.
</Text>
</GroupedText>
);
};

@ -7,20 +7,60 @@ import {
Twitter, Twitter,
Twitch, Twitch,
} from "./icons/SocialMedia"; } from "./icons/SocialMedia";
import Link from "next/link";
import { Heart } from "./icons/Heart";
import { ExternalLink } from "./icons/ExternalLink";
export const Footer = () => { export const Footer = () => {
return ( return (
<footer className="w-full text-subtext1"> <footer className="border-t-2 border-surface1 w-full text-subtext1">
<div className="flex flex-col justify-center items-center space-y-2"> <div className="flex flex-col justify-center items-center space-y-6 pt-10 pb-20">
<div className="text-center"> <div className="text-center">
<p className="text-lg lg:text-xl xl:text-2xl">
Designed With <Heart />
</p>
<Text>&copy; {new Date().getFullYear()} Goudham Suresh</Text> <Text>&copy; {new Date().getFullYear()} Goudham Suresh</Text>
</div> </div>
<BuildInfo />
<SocialMediaRow /> <SocialMediaRow />
</div> </div>
</footer> </footer>
); );
}; };
const BuildInfo = () => {
return (
<div className="text-center text-md lg:text-lg xl:text-xl">
<p>{process.env.NEXT_PUBLIC_IS_PREVIEW ? "Preview" : "Release"} Build</p>
<p>
GitHub SHA:{" "}
<Link
rel="noopener noreferrer"
target="_blank"
className="hocus:underline hocus:decoration-solid hocus:underline-offset-1"
href={`https://github.com/sgoudham/website/commit/${process.env.NEXT_PUBLIC_BUILD_SHA}`}
>
{process.env.NEXT_PUBLIC_BUILD_SHA}&#8201;
<ExternalLink />
</Link>
</p>
<p>
Build ID:{" "}
<Link
rel="noopener noreferrer"
target="_blank"
className="hocus:underline hocus:decoration-solid hocus:underline-offset-1"
href={`https://github.com/sgoudham/website/actions/runs/${process.env.NEXT_PUBLIC_BUILD_ID}`}
>
{process.env.NEXT_PUBLIC_BUILD_ID}&#8201;
<ExternalLink />
</Link>
</p>
<p>Build Num: #{process.env.NEXT_PUBLIC_BUILD_NUM}</p>
</div>
);
};
const SocialMediaRow = () => { const SocialMediaRow = () => {
return ( return (
<div className="flex gap-3 items-center"> <div className="flex gap-3 items-center">

@ -1,13 +1,14 @@
import { Wave } from "./icons/Wave"; import { Wave } from "./icons/Wave";
import { H1 } from "./utils/Titles";
export const Header = () => { export const Header = () => {
return ( return (
<h1 className="text-2xl lg:text-3xl xl:text-4xl 2xl:text-5xl font-bold tracking-tight text-center"> <H1>
Hiya{" "} Hiya{" "}
<div className="inline-block motion-safe:animate-waving-hand"> <div className="inline-block motion-safe:animate-waving-hand">
<Wave /> <Wave />
</div> </div>
, I&#39;m Goudham , I&#39;m Goudham
</h1> </H1>
); );
}; };

@ -0,0 +1,69 @@
import { fetchUserRepositories } from "@/app/lib/api";
import { Star } from "./icons/Star";
import Link from "next/link";
import { H2 } from "./utils/Titles";
import { ExternalLink } from "./icons/ExternalLink";
import { Archived } from "./icons/Archived";
export const Projects = async () => {
const projects = await fetchUserRepositories().then((res) =>
res
.filter(
(data) =>
!data.fork &&
data.name !== "uwuifyy" &&
data.name !== "Enso-Bot" &&
!data.archived
)
.sort((a, b) => (b.stargazers_count ?? 0) - (a.stargazers_count ?? 0))
.slice(0, 6)
);
return (
<section className="flex flex-col items-center space-y-3 px-5">
<H2>Favourite Projects</H2>
<div className="rounded-lg text-md lg:text-lg xl:text-xl">
<div className="flex flex-col space-y-4">
{projects.map((project) => (
<Project key={project.name} project={project} />
))}
</div>
</div>
</section>
);
};
export const Project = ({ project }: { project: RepositoryData }) => {
return (
<Link
rel="noopener noreferrer"
target="_blank"
href={project.html_url}
className="bg-base w-full rounded-xl outline-2 outline-mantle focus:ring-2 focus:ring-blue ring-offset-0 shadow-lg hover:scale-105 motion-safe:duration-300 p-3"
>
<div className="flex flex-col space-y-1 h-full justify-between">
<div>
<span className="font-semibold hover:underline">
{project.name}&#8201;
<ExternalLink />
</span>
{project.description && (
<div className="text-sm lg:text-md xl:text-lg text-subtext1">
{project.description}
</div>
)}
</div>
<div className="self-end flex flex-row gap-x-1">
{project.archived && (
<p className="text-md font-medium bg-mantle rounded-xl px-3">
<Archived />
</p>
)}
<p className="text-md font-medium bg-mantle rounded-xl px-3">
{project.stargazers_count} <Star />
</p>
</div>
</div>
</Link>
);
};

@ -0,0 +1,13 @@
export const Archived = () => {
return (
<svg
className="h-5 w-5 xl:h-6 xl:w-6 inline align-text-bottom fill-yellow"
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 256 256"
>
<path d="M224,48H32A16,16,0,0,0,16,64V88a16,16,0,0,0,16,16v88a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V104a16,16,0,0,0,16-16V64A16,16,0,0,0,224,48ZM208,192H48V104H208ZM224,88H32V64H224V88ZM96,136a8,8,0,0,1,8-8h48a8,8,0,0,1,0,16H104A8,8,0,0,1,96,136Z"></path>
</svg>
);
};

@ -0,0 +1,13 @@
export const Close = () => {
return (
<svg
className="h-8 w-8 fill-overlay0 group-hover:bg-subtext1"
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 256 256"
>
<path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>
</svg>
);
};

@ -0,0 +1,13 @@
export const ExternalLink = () => {
return (
<svg
className="h-4 w-4 inline-block align-text-top fill-text opacity-50"
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 256 256"
>
<path d="M224,104a8,8,0,0,1-16,0V59.32l-66.33,66.34a8,8,0,0,1-11.32-11.32L196.68,48H152a8,8,0,0,1,0-16h64a8,8,0,0,1,8,8Zm-40,24a8,8,0,0,0-8,8v72H48V80h72a8,8,0,0,0,0-16H48A16,16,0,0,0,32,80V208a16,16,0,0,0,16,16H176a16,16,0,0,0,16-16V136A8,8,0,0,0,184,128Z"></path>
</svg>
);
};

@ -0,0 +1,18 @@
export const Heart = () => {
return (
<svg
className="h-5 w-5 lg:h-6 lg:w-6 xl:h-7 xl:w-7 inline-block align-text-bottom"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
>
<path
d="M128,216S24,160,24,94A54,54,0,0,1,78,40c22.59,0,41.94,12.31,50,32,8.06-19.69,27.41-32,50-32a54,54,0,0,1,54,54C232,160,128,216,128,216Z"
fill="red"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="0"
/>
</svg>
);
};

@ -0,0 +1,19 @@
export const Star = () => {
return (
<svg
className="h-5 w-5 xl:h-6 xl:w-6 inline align-text-bottom"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
>
<rect width="256" height="256" fill="none" />
<path
d="M135.34,28.9l23.23,55.36a8,8,0,0,0,6.67,4.88l59.46,5.14a8,8,0,0,1,4.54,14.07L184.13,147.7a8.08,8.08,0,0,0-2.54,7.89l13.52,58.54a8,8,0,0,1-11.89,8.69l-51.1-31a7.93,7.93,0,0,0-8.24,0l-51.1,31a8,8,0,0,1-11.89-8.69l13.52-58.54a8.08,8.08,0,0,0-2.54-7.89L26.76,108.35A8,8,0,0,1,31.3,94.28l59.46-5.14a8,8,0,0,0,6.67-4.88L120.66,28.9A8,8,0,0,1,135.34,28.9Z"
fill="orange"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="0"
/>
</svg>
);
};

@ -1,7 +1,7 @@
export const Wave = () => { export const Wave = () => {
return ( return (
<svg <svg
className="h-9 w-9 lg:h-10 lg:w-10 xl:h-11 xl:w-11 2xl:h-14 2xl:w-14 inline-block align-bottom text-peach" className="h-9 w-9 lg:h-10 lg:w-10 xl:h-12 xl:w-12 inline-block align-bottom text-peach"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256" viewBox="0 0 256 256"
> >

@ -4,10 +4,10 @@ export const ProfilePicture = ({ }) => {
return ( return (
<Image <Image
src="/profile-picture.png" src="/profile-picture.png"
width={128} width={64}
height={128} height={64}
alt="Goudham smiling at the camera" alt="Goudham smiling at the camera"
className="motion-safe:hover:animate-spin w-20 h-20 lg:w-24 lg:h-24 xl:w-28 xl:h-28 2xl:w-32 2xl:h-32" className="motion-safe:hover:animate-spin w-12 h-12 lg:w-14 lg:h-14 xl:w-16 xl:h-16"
quality={100} quality={100}
priority={true} priority={true}
/> />

@ -0,0 +1,9 @@
export const Hamburger = () => {
return (
<div className="space-y-2">
<span className="block w-8 h-0.5 bg-overlay0 group-hover:bg-subtext1"></span>
<span className="block w-8 h-0.5 bg-overlay0 group-hover:bg-subtext1"></span>
<span className="block w-8 h-0.5 bg-overlay0 group-hover:bg-subtext1"></span>
</div>
);
};

@ -0,0 +1,30 @@
import Link from "next/link";
export const Links = () => {
return (
<>
<LinkWithAnimatedUnderline href="/" text="&lt; Home /&gt;" />
<LinkWithAnimatedUnderline href="/projects" text="&lt; Projects /&gt;" />
</>
);
};
const LinkWithAnimatedUnderline = ({
href,
text,
}: {
href: string;
text: string;
}) => {
const animatedUnderline =
"md:block md:max-w-0 md:group-hover:max-w-full motion-safe:md:transition-all md:h-0.5 md:bg-blue motion-safe:md:duration-300";
return (
<Link href={href} className="motion-safe:md:transition motion-safe:md:duration-300 group focus:text-blue">
<span className="group-hover:text-blue motion-safe:md:transition-all motion-safe:md:duration-300">
{text}
</span>
<span className={`${animatedUnderline}`}></span>
</Link>
);
};

@ -0,0 +1,83 @@
"use client";
import { Dispatch, SetStateAction, useRef, useState } from "react";
import { ProfilePicture } from "../images/ProfilePicture";
import { Hamburger } from "./Hamburger";
import { Links } from "./Links";
import { Close } from "../icons/Close";
import Link from "next/link";
import { Dialog } from "@headlessui/react";
import { usePathname } from "next/navigation";
export const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<nav className="self-center w-full max-w-xl lg:max-w-3xl xl:max-w-6xl">
<div className="p-4 flex flex-row items-center justify-between text-md lg:text-lg xl:text-xl">
<ProfilePicture />
<div className="hidden md:flex flex-row gap-x-4 font-bold tracking-tight">
<Links />
</div>
<button
className="md:hidden px-4 py-2 hover:bg-crust dark:hover:bg-base rounded-lg"
aria-label="Open Menu"
onClick={() => setIsOpen((prev) => !prev)}
>
<Hamburger />
</button>
</div>
</nav>
<MobileMenu isOpen={isOpen} setIsOpen={setIsOpen} />
</>
);
};
export const MobileMenu = ({
isOpen,
setIsOpen,
}: {
isOpen: boolean;
setIsOpen: Dispatch<SetStateAction<boolean>>;
}) => {
const focusedRef = useRef(null);
const path = usePathname();
const checkPath = (href: string) => {
if (href === path) {
setIsOpen(false);
}
};
return (
<Dialog
className={
isOpen
? "block w-full h-screen absolute overflow-hidden inset-0 bg-base dark:bg-crust z-10 flex-col items-center"
: "hidden"
}
open={isOpen}
onClose={() => setIsOpen(false)}
>
<div className="max-w-xl mx-auto">
<div className="p-4 w-full flex flex-row items-center justify-between">
<ProfilePicture />
<button
className="px-4 py-1 hover:bg-crust dark:hover:bg-base rounded-lg focus:bg-crust dark:focus:bg-base"
onClick={() => setIsOpen((prev) => !prev)}
ref={focusedRef}
>
<Close />
</button>
</div>
<ul className="flex flex-col space-y-6 items-center text-2xl font-semibold justify-center">
<Link href="/" onClick={() => checkPath("/")}>
&lt; Home /&gt;
</Link>
<Link href="/projects" onClick={() => checkPath("/projects")}>
&lt; Projects /&gt;
</Link>
</ul>
</div>
</Dialog>
);
};

@ -12,7 +12,8 @@ export const StyledLink = ({
return ( return (
<Link <Link
href={href} href={href}
className={`font-medium text-blue underline focus:ring-1 focus:ring-blue ${className ?? "" className={`font-medium text-blue underline text-lg lg:text-xl xl:text-2xl focus:ring-1 focus:ring-blue ${
className ?? ""
}`} }`}
> >
{children} {children}

@ -15,7 +15,7 @@ export const FancyUnderline = ({
}; };
export const Text = ({ className, children }: { className?: string, children: React.ReactNode }) => { export const Text = ({ className, children }: { className?: string, children: React.ReactNode }) => {
return <p className={`text-md lg:text-lg xl:text-xl 2xl:text-2xl ${className ?? ""}`}>{children}</p>; return <p className={`text-md lg:text-lg xl:text-xl ${className ?? ""}`}>{children}</p>;
}; };
export const GroupedText = ({ export const GroupedText = ({
@ -26,6 +26,6 @@ export const GroupedText = ({
children: React.ReactNode; children: React.ReactNode;
}) => { }) => {
return ( return (
<div className={`flex flex-col mx-2 gap-4 ${className}`}>{children}</div> <div className={`flex flex-col mx-3 gap-3 ${className}`}>{children}</div>
); );
}; };

@ -0,0 +1,16 @@
export const H1 = ({ children }: { children: React.ReactNode | string }) => {
return (
<h1 className="text-3xl lg:text-4xl xl:text-5xl font-bold tracking-tight text-center">
{children}
</h1>
);
};
export const H2 = ({ children }: { children: React.ReactNode | string }) => {
return (
<h2 className="text-2xl lg:text-3xl xl:text-4xl font-bold">
{children}
</h2>
);
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1000 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

@ -1,6 +1,7 @@
import "./globals.css"; import "./globals.css";
import type { Metadata } from "next"; import type { Metadata } from "next";
import { Raleway } from "next/font/google"; import { Raleway } from "next/font/google";
import { Footer } from "./components/Footer";
const raleway = Raleway({ const raleway = Raleway({
subsets: ["latin"], subsets: ["latin"],
@ -9,7 +10,7 @@ const raleway = Raleway({
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Goudham Suresh", title: "Goudham Suresh",
description: description:
"Software Engineer at the BBC, Core Maintainer for Catppuccin. Ultimately trying to write code that I don't hate and take photos that I'm proud of.", "I am a software engineer by day, and an open source enthusiast by night. Welcome to my corner of the internet where I write about my experiences, projects, and more.",
keywords: ["Next.js", "React", "Typescript", "Catppuccin", "Goudham"], keywords: ["Next.js", "React", "Typescript", "Catppuccin", "Goudham"],
colorScheme: "light dark", colorScheme: "light dark",
metadataBase: new URL( metadataBase: new URL(
@ -21,10 +22,11 @@ export const metadata: Metadata = {
url: process.env.NEXT_PUBLIC_IS_PREVIEW url: process.env.NEXT_PUBLIC_IS_PREVIEW
? "https://preview.goudham.com" ? "https://preview.goudham.com"
: "https://goudham.com", : "https://goudham.com",
title: `Goudham Suresh${process.env.NEXT_PUBLIC_IS_PREVIEW ? " (Preview)" : "" title: `Goudham Suresh${
process.env.NEXT_PUBLIC_IS_PREVIEW ? " (Preview)" : ""
}`, }`,
description: description:
"Software Engineer at the BBC, Core Maintainer for Catppuccin. Ultimately trying to write code that I don't hate and take photos that I'm proud of.", "I am a software engineer by day, and an open source enthusiast by night. Welcome to my corner of the internet where I write about my experiences, projects, and more.",
locale: "en_GB", locale: "en_GB",
}, },
twitter: { twitter: {
@ -45,9 +47,10 @@ export default function RootLayout({
return ( return (
<html lang="en"> <html lang="en">
<body <body
className={`${raleway.className} latte dark:mocha bg-base dark:bg-crust text-text flex flex-col h-screen pt-12`} className={`${raleway.className} latte dark:mocha bg-base dark:bg-crust text-text flex flex-col h-screen overflow-auto space-y-10 pb-10`}
> >
{children} {children}
<Footer />
</body> </body>
</html> </html>
); );

@ -0,0 +1,36 @@
import { Octokit } from "octokit";
if (!process.env.REPOS_READ_ONLY) {
throw new Error("GITHUB TOKEN 'REPOS_READ_ONLY' is missing");
}
const octokit = new Octokit({
auth: process.env.REPOS_READ_ONLY,
});
export const fetchUserRepositories = async (): Promise<RepositoryData[]> => {
return await octokit.paginate(
octokit.rest.repos.listForAuthenticatedUser,
{
per_page: 100,
visibility: "public",
affiliation: "owner",
},
(response) =>
response.data.map((data) => {
return {
name: data.name,
description: data.description,
html_url: data.html_url,
size: data.size,
archived: data.archived,
fork: data.fork,
stargazers_count: data.stargazers_count,
open_issues_count: data.open_issues,
created_at: data.created_at,
updated_at: data.updated_at,
topics: data.topics,
};
})
);
};

13
app/lib/types.d.ts vendored

@ -0,0 +1,13 @@
type RepositoryData = {
name: string;
description: string | null;
html_url: string;
size?: number;
archived?: boolean;
fork: boolean;
stargazers_count?: number;
open_issues_count?: number;
created_at: string | null | undefined;
updated_at: string | null | undefined;
topics?: string[];
};

@ -1,49 +1,18 @@
import { Header } from "./components/Header"; import { Header } from "./components/Header";
import { StyledLink } from "./components/utils/StyledLink"; import { About } from "./components/About";
import { Text } from "./components/utils/Text"; import { Projects } from "./components/Projects";
import { GroupedText, FancyUnderline } from "./components/utils/Text"; import { Navbar } from "./components/nav/Navbar";
import { ProfilePicture } from "./components/images/ProfilePicture";
import { Footer } from "./components/Footer";
export default function Home() { export default function Home() {
return ( return (
<div className="flex flex-col gap-4"> /* Inherits from the RootLayout */
<div className="self-center"> <div className="flex flex-col">
<ProfilePicture /> <Navbar />
</div> <div className="self-center max-w-md lg:max-w-lg xl:max-w-xl flex flex-col space-y-10 grow">
<div className="self-center max-w-lg lg:max-w-xl xl:max-w-2xl flex flex-col space-y-10">
<Header /> <Header />
<GroupedText className="text-center"> <About />
<Text> <Projects />
I am a{" "}
<FancyUnderline className="font-semibold" decoration="decoration-peach">
Software Engineer at the BBC
</FancyUnderline>.{" "}
I obtained my degree while working full-time, you can learn
more about that by visiting{" \""}
<StyledLink
href={"https://www.gla.ac.uk/schools/computing/undergraduate/graduateapprenticeships/"}>
Graduate Apprenticeships - University of Glasgow
</StyledLink>.&quot;
</Text>
<Text>
You&apos;ll usually find me nerding out about technology and playing
video games. Contributing to open-source is a big passion of mine and
I&apos;m grateful to be a{" "}
<FancyUnderline className="font-semibold" decoration="decoration-peach">
Core Maintainer for Catppuccin
</FancyUnderline>
. When I&apos;m not staring at a screen, I love taking my Canon EOS R50 out for a spin and capturing my friends and the world around me.
</Text>
<Text>
Eventually, I&apos;d like to turn this website into a place where I can share my thoughts, projects, and photographs with everyone. Hopefully sometime soon<span className="text-blue font-bold">™</span>
</Text>
<Text>
<span className="text-red font-bold">~~~</span>
</Text>
</GroupedText>
</div> </div>
<Footer />
</div> </div>
); );
} }

@ -0,0 +1,25 @@
import { Metadata } from "next";
export const metadata: Metadata = {
title: "Projects by Goudham Suresh",
description:
"I am a software engineer by day, and an open source enthusiast by night. Welcome to my corner of the internet where I write about my experiences, projects, and more.",
openGraph: {
url: process.env.NEXT_PUBLIC_IS_PREVIEW
? "https://preview.goudham.com/projects"
: "https://goudham.com/projects",
title: `Projects by Goudham Suresh${
process.env.NEXT_PUBLIC_IS_PREVIEW ? " (Preview)" : ""
}`,
description:
"I am a software engineer by day, and an open source enthusiast by night. Welcome to my corner of the internet where I write about my experiences, projects, and more.",
},
};
export default function ProjectsLayout({
children,
}: {
children: React.ReactNode;
}) {
return <section>{children}</section>;
}

@ -0,0 +1,45 @@
import { fetchUserRepositories } from "../lib/api";
import { Project } from "../components/Projects";
import { Text } from "../components/utils/Text";
import { H1 } from "../components/utils/Titles";
import { Navbar } from "../components/nav/Navbar";
export default async function Projects() {
const projects = await fetchUserRepositories().then((res) =>
res
.filter((data) => !data.fork)
.sort((a, b) => (b.stargazers_count ?? 0) - (a.stargazers_count ?? 0))
);
return (
/* Inherits from the RootLayout */
<div className="flex flex-col">
<Navbar />
<div className="self-center max-w-md lg:max-w-lg xl:max-w-xl 2xl:max-w-4xl flex flex-col space-y-10 grow">
<H1>All Projects</H1>
<div className="flex flex-col mx-3 gap-3 text-center">
<Text>
Here&apos;s a list of all my public projects, they are sorted by
most starred. Note that some projects are still under development
and/or unfinished, but I&apos;d like to get around to finishing them
at some point in the future!
</Text>
<Text>
I promise I&apos;ll implement sorting options soon
<span className="text-blue font-bold">™</span>
</Text>
</div>
<div className="grid grid-cols-1 2xl:grid-cols-2 gap-y-4 gap-x-6 px-5">
{projects.map((project) => (
<div
key={project.name}
className="rounded-lg text-md lg:text-lg xl:text-xl flex justify-center"
>
<Project key={project.name} project={project} />
</div>
))}
</div>
</div>
</div>
);
}

@ -1,11 +1,9 @@
import { MetadataRoute } from "next"; import { MetadataRoute } from "next";
export default function sitemap(): MetadataRoute.Sitemap { export default function sitemap(): MetadataRoute.Sitemap {
return ["goudham.com"].map((url) => { return ["goudham.com", "goudham.com/projects"].map((url) => {
return { return {
url: process.env.NEXT_PUBLIC_IS_PREVIEW url: process.env.NEXT_PUBLIC_IS_PREVIEW ? `https://preview.${url}` : `https://${url}`,
? `https://preview.${url}`
: `https://${url}`,
lastModified: new Date(), lastModified: new Date(),
}; };
}); });

@ -7,9 +7,9 @@
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint", "lint": "next lint",
"docker:preview:build": "docker build --build-arg='NEXT_PUBLIC_IS_PREVIEW=1' --build-arg='NEXT_PUBLIC_BUILD_NUM=1' -t website-preview .", "docker:preview:build": "docker build --secret id=REPOS_READ_ONLY --build-arg='NEXT_PUBLIC_IS_PREVIEW=1' --build-arg='NEXT_PUBLIC_BUILD_SHA=5266152' --build-arg='NEXT_PUBLIC_BUILD_ID=4716419565' --build-arg='NEXT_PUBLIC_BUILD_NUM=1' -t website-preview .",
"docker:preview": "yarn docker:preview:build && docker run --rm -it -p 3000:3000 --name website website-preview:latest", "docker:preview": "yarn docker:preview:build && docker run --rm -it -p 3000:3000 --name website website-preview:latest",
"docker:release:build": "docker build -t website-release .", "docker:release:build": "docker build --secret id=REPOS_READ_ONLY --build-arg='NEXT_PUBLIC_BUILD_SHA=5266152' --build-arg='NEXT_PUBLIC_BUILD_ID=4716419565' --build-arg='NEXT_PUBLIC_BUILD_NUM=1' -t website-release .",
"docker:release": "yarn docker:release:build && docker run --rm -it -p 3000:3000 --name website website-release:latest" "docker:release": "yarn docker:release:build && docker run --rm -it -p 3000:3000 --name website website-release:latest"
}, },
"dependencies": { "dependencies": {
@ -31,5 +31,5 @@
"devDependencies": { "devDependencies": {
"@catppuccin/tailwindcss": "^0.1.6" "@catppuccin/tailwindcss": "^0.1.6"
}, },
"packageManager": "yarn@4.5.1" "packageManager": "yarn@3.6.1"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 282 KiB

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save