- {post.frontmatter.title} -
- {post.frontmatter.excerpt && ( -{post.frontmatter.excerpt}
- )} - {post.frontmatter.icon && ( -diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..5911a689
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,19 @@
+# Git
+.git
+.gitignore
+
+# Docker
+Dockerfile
+.dockerignore
+
+# Dependencies
+node_modules
+
+# Build output
+.next
+
+# Local environment variables
+.env.local
+
+# PNPM specific
+# pnpm-lock.yaml
\ No newline at end of file
diff --git a/AGENTS.md b/AGENTS.md
index a25a535a..784923cc 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -4,7 +4,7 @@ This document provides context for AI agents working on this project.
## Project Overview
-This is a personal website and portfolio built with Next.js and Tailwind CSS. The site is statically generated, with content sourced from local `.mdx` files. The primary purpose is to showcase research, projects, and blog posts.
+This is a personal website and portfolio built with Next.js and Tailwind CSS. The site is statically generated, with content sourced from local `.mdx` files. The primary purpose is to showcase experience, and publications posts.
## Tech Stack
@@ -24,7 +24,7 @@ This is a personal website and portfolio built with Next.js and Tailwind CSS. Th
## Project Structure
-- `content/`: Root directory for all MDX content, organized into subdirectories by category (e.g., `research`, `projects`, `blog`).
+- `content/`: Root directory for all MDX content, organized into subdirectories by category (e.g., `research`, `experience`).
- `src/app/`: Next.js App Router structure. Pages are dynamically generated based on the content in the `content/` directory.
- `src/lib/mdx.ts`: Core logic for finding, parsing, and serializing MDX files. It reads the file contents, separates frontmatter using `gray-matter`, and prepares it for rendering.
- `src/components/`: Contains all reusable React components.
diff --git a/Dockerfile b/Dockerfile
index 12da4aa9..ee45b45e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,3 +1,39 @@
-FROM nginx:latest
-COPY ./_site/. /usr/share/nginx/html/.
-COPY ./nginx_default.conf /etc/nginx/conf.d/default.conf
\ No newline at end of file
+# Stage 1: Builder
+FROM node:20-alpine AS builder
+
+# Enable pnpm
+RUN corepack enable
+
+WORKDIR /app
+
+# Copy dependency files and install dependencies
+COPY package.json pnpm-lock.yaml ./
+RUN pnpm install --frozen-lockfile
+
+# Copy the rest of the application source code
+COPY . .
+
+# Run the build command
+RUN pnpm run build
+
+# ---
+
+# Stage 2: Runner
+FROM node:20-alpine AS runner
+WORKDIR /app
+
+# Create a non-root user for security
+RUN addgroup --system --gid 1001 nodejs
+RUN adduser --system --uid 1001 nextjs
+USER nextjs
+
+# Copy the standalone output from the builder stage
+COPY --from=builder /app/public ./public
+COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
+COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
+
+EXPOSE 3000
+ENV PORT 3000
+
+# The standalone output creates a server.js file that is the entrypoint
+CMD ["node", "server.js"]
\ No newline at end of file
diff --git a/README.md b/README.md
index d25feabe..4e65c769 100644
--- a/README.md
+++ b/README.md
@@ -9,8 +9,7 @@ Built with next.js, [shadcn/ui](https://ui.shadcn.com/), and [magic ui](https://
# Features
- Setup only takes a few minutes by editing the [single config file](./src/data/resume.tsx)
-- Built using Next.js 14, React, Typescript, Shadcn/UI, TailwindCSS, Framer Motion, Magic UI
-- Includes a blog
+- Built using Next.js 15, React, Typescript, Shadcn/UI, TailwindCSS, React/Motion, Magic UI
- Responsive for different devices
- Optimized for Next.js and Vercel
diff --git a/app/blog/[slug]/page.tsx b/app/blog/[slug]/page.tsx
deleted file mode 100644
index 7d278272..00000000
--- a/app/blog/[slug]/page.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import { getPostBySlug, getPostSlugs } from '@/lib/mdx';
-import { CitationProvider } from '@/components/context-citation';
-import { ReferencesContainer } from '@/components/container-references';
-import { notFound } from 'next/navigation';
-import Image from 'next/image';
-import { DATA } from '@/app/resume';
-import { getPublicationsData } from '@/lib/publications';
-import { CustomMDX } from '@/components/mdx-custom';
-import Link from 'next/link';
-
-export async function generateStaticParams() {
- const slugs = getPostSlugs('blog');
- return slugs.map((slug) => ({ slug }));
-}
-
-export async function generateMetadata({ params: { slug } }: { params: { slug: string } }) {
- const post = await getPostBySlug('blog', slug);
- if (!post) {
- return {};
- }
- return {
- title: post.frontmatter.title,
- description: post.frontmatter.description || DATA.description,
- };
- }
-
-export default async function BlogPage({ params: { slug } }: { params: { slug: string } }) {
- const post = await getPostBySlug('blog', slug);
- const publications = getPublicationsData();
-
- if (!post) {
- return notFound();
- }
-
- return (
- {post.frontmatter.excerpt}
- Musings on technology, research, and life.
-
- My professional experience encompasses both hands-on systems engineering and academic instruction. I've worked at the intersection of machine learning and complex systems, with projects ranging from exploring emergent behavior in AI to managing cluster infrastructure. In my role at LMU Munich, I further developed this experience by mentoring students, contributing to lectures, and leading practical seminars.
+ It seems the page you are looking for does not exist, has been moved,
+ or is currently unavailable.
+
- {post.frontmatter.title}
-
- {post.frontmatter.excerpt && (
-
- Blog
-
-
+ My professional experience encompasses both hands-on systems engineering and academic instruction. I've worked at the intersection of machine learning and complex systems, with projects ranging from exploring emergent behavior in AI to managing cluster infrastructure. In my role at LMU Munich, I further developed this experience by mentoring students, contributing to lectures, and leading practical seminars.
-
+ Lost in the Digital Sands
+
+
- I've worked on a variety of projects, from scientific research to managing projects. Here are a few of my - latest. + I've worked on a variety of projects, from scientific research to managing projects. Here are a few of my latest.
diff --git a/app/projects/[slug]/page.tsx b/app/projects/[slug]/page.tsx deleted file mode 100644 index 6836327d..00000000 --- a/app/projects/[slug]/page.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { getPostBySlug, getPostSlugs } from '@/lib/mdx'; -import { notFound } from 'next/navigation'; - -import { getPublicationsData } from '@/lib/publications'; -import { Article } from '@/components/page-article'; -import { DATA } from '@/app/resume'; - -export async function generateStaticParams() { - const slugs = getPostSlugs('projects'); - return slugs.map((slug) => ({ slug })); -} - -export async function generateMetadata({ params }: { params: { slug: string } }) { - // FIX: Await params to get slug for Next.js 15 - const { slug } = await params; - - const post = await getPostBySlug('projects', slug); - if (!post) { return {}; } - return { - title: post.frontmatter.title, - description: post.frontmatter.teaser || DATA.description, - }; -} - -export default async function ProjectPage({ params }: { params: { slug: string } }) { - // FIX: Await params to get slug for Next.js 15 - const { slug } = await params; - - const post = await getPostBySlug('projects', slug); - const publications = getPublicationsData(); - - if (!post) { - notFound(); - } - - // --- Navigation Logic --- - const allSlugs = getPostSlugs('projects'); - const currentIndex = allSlugs.findIndex((s) => s === slug); - const prevSlug = currentIndex > 0 ? allSlugs[currentIndex - 1] : null; - const nextSlug = currentIndex < allSlugs.length - 1 ? allSlugs[currentIndex + 1] : null; - const prevPost = prevSlug ? await getPostBySlug('projects', prevSlug) : null; - const nextPost = nextSlug ? await getPostBySlug('projects', nextSlug) : null; - const navigation = { - prev: prevPost ? { slug: prevSlug, title: prevPost.frontmatter.title } : null, - next: nextPost ? { slug: nextSlug, title: nextPost.frontmatter.title } : null, - }; - - return ; -} \ No newline at end of file diff --git a/app/projects/page.tsx b/app/projects/page.tsx deleted file mode 100644 index 10fd179b..00000000 --- a/app/projects/page.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { getSortedPostsData } from "@/lib/posts"; -import { BlurFade } from "@/components/magicui/blur-fade"; -import { ExperienceCard } from "@/components/list-item"; - -const BLUR_FADE_DELAY = 0.04; - -export default function ProjectsPage() { - const posts = getSortedPostsData("projects"); - - return ( -- My work sits at the intersection of machine learning and systems engineering. I have experience in everything from exploring emergent behavior in AI agents to managing robust, automated infrastructure with Kubernetes. Here are some highlights. -
-+
This section details my scientific publications, primarily focused - on advancing machine learning and deep neural networks. - My involvement has spanned, from conceptualizing the ideas - and developing machine learning models, to providing support - to my colleagues. + on advancing machine learning and deep neural networks. My + involvement has spanned, from conceptualizing the ideas and + developing machine learning models, to providing support to my + colleagues.
Filter by Topic:
+ {tags.map((tag) => ( ++ No publications found with the tag "{activeTag}". +
+ )} +Filter by Topic:
+ {tags.map((tag) => ( ++ No publications found with the tag "{activeTag}". +
+ )} +