From ff553187db23e81d0a18264e0a13550737e3377e Mon Sep 17 00:00:00 2001 From: HangerThem Date: Tue, 4 Aug 2026 08:21:11 +0200 Subject: [PATCH] Added about page --- app/about/page.tsx | 45 ++++++++++++++++++++++++++++++++++++++++++ content/pages/about.md | 16 +++++++++++++++ lib/posts.tsx | 4 ++-- 3 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 app/about/page.tsx create mode 100644 content/pages/about.md diff --git a/app/about/page.tsx b/app/about/page.tsx new file mode 100644 index 0000000..296587b --- /dev/null +++ b/app/about/page.tsx @@ -0,0 +1,45 @@ +import { metadata } from '@/app/metadata' +import { ImageWrapper } from '@/components/content/ImageWrapper' +import { TableOfContents } from '@/components/post/TableOfContents' +import { getPostBySlug } from '@/lib/posts' +import { slugify } from '@/utils/slug' +import { Pencil, SendHorizonal } from 'lucide-react' +import type { Metadata } from 'next' +import Link from 'next/link' + +export async function generateStaticParams() { + return await getPostBySlug('about', 'content/pages') +} + +export const dynamicParams = false + +export async function generateMetadata(): Promise { + const { meta } = await getPostBySlug('about', 'content/pages') + return { + title: `${meta.title} | ${metadata.title!.toString()}`, + description: meta.description, + openGraph: { + type: 'website', + title: `${meta.title} | ${metadata.title!.toString()}`, + description: meta.description, + url: process.env.SITE_URL + `/about`, + siteName: metadata.title!.toString(), + }, + } +} + +export default async function Post() { + const { meta, content } = await getPostBySlug('about', 'content/pages') + + return ( +
+
+

{meta.title}

+

{meta.description}

+
{content}
+
+ +
+
+ ) +} diff --git a/content/pages/about.md b/content/pages/about.md new file mode 100644 index 0000000..ac8cc7b --- /dev/null +++ b/content/pages/about.md @@ -0,0 +1,16 @@ +--- +title: About +description: Learn more about me, my background, and my passions. Discover what drives me as a software developer, IT instructor, and lifelong learner. Get to know the person behind the code and the projects. +--- + +Hey, I'm Frank (František Borisjuk) — a freelance full-stack developer and IT instructor based in Czechia. + +By day, I build things with Next.js, TypeScript, Supabase, and Prisma — mostly full-stack web projects for clients, ranging from B2B platforms to niche tools that solve one very specific problem well. I also run my own self-hosted infrastructure stack (Coolify, Traefik, Authentik, Forgejo, and the rest) on a Hetzner VPS, because I like understanding — and controlling — every layer of what I ship. + +I also teach. At my old high school, I run a web development and cybersecurity curriculum for teenagers, which somehow keeps me both humble and sharp — nothing forces you to actually understand something like explaining it to a room of sixteen-year-olds. + +Outside of client work, I tinker on my own projects: an open-source cookie consent library built on an anti-dark-pattern philosophy, a branching narrative RPG engine, and the occasional deep dive into things that have nothing to do with code — Czech constitutional law, obscure mythology, grimdark fiction, Linux package conflicts at 2am. + +I run Arch (btw), care a lot about privacy and self-hosting, and generally believe most software problems are actually just under-specified problems in disguise. + +This site is where I write about what I'm building, what I'm learning, and occasionally what's breaking. Feel free to look around, or reach out at [f.borisjuk@hangerthem.com](mailto:f.borisjuk@hangerthem.com). \ No newline at end of file diff --git a/lib/posts.tsx b/lib/posts.tsx index c2cd0e3..34eb11c 100644 --- a/lib/posts.tsx +++ b/lib/posts.tsx @@ -62,8 +62,8 @@ export function getNextAndPreviousPosts(slug: string): { return { next, previous } } -export async function getPostBySlug(slug: string) { - const fullPath = path.join(postsDirectory, `${slug}.md`) +export async function getPostBySlug(slug: string, postDirectory: string = postsDirectory) { + const fullPath = path.join(postDirectory, `${slug}.md`) const { data, content } = matter(fs.readFileSync(fullPath, 'utf8')) let processor = remark().use(remarkParse).use(remarkGfm)