Skip to content

Repository files navigation

yseeger.me

Personal site. Astro static site, markdown-authored.

Pages

Route What it is
/ Bio, combined GitHub + GitLab contribution graph, recent posts and projects
/blog/ All posts
/blog/<slug>/ A single post
/projects/ Curated project list from src/data/projects.ts
/cv/ Career timeline from src/data/cv.ts, plus the portrait
/rss.xml Feed
/sitemap-index.xml Sitemap, generated by @astrojs/sitemap

Writing a post

Create a new file in src/content/posts/<slug>.md:

---
title: Your post title
pubDate: 2026-05-14
description: One sentence for search results, social cards and the feed.
---

Body content in markdown.

The filename becomes the URL slug. pubDate is required; description is optional but worth writing, since it fills the meta description, the Open Graph and Twitter cards, the JSON-LD, and the RSS item summary.

Links in a post that point off-site get target="_blank" and rel="noopener noreferrer" automatically.

To draft without publishing, add draft: true to the frontmatter. Drafts are hidden in production builds and visible in pnpm dev.

Projects

Edit src/data/projects.ts. The list renders in the order it is written; the first three also appear on the home page.

Contribution graph

The home page merges a trailing year of GitHub and self-hosted GitLab activity into one calendar. Both are fetched at build time, so the graph is as fresh as the last deploy.

Copy .env.example to .env and fill in what you have:

  • GITHUB_TOKEN: any token with read:user. Locally you can skip it; the build falls back to gh auth token from the GitHub CLI.
  • GITLAB_TOKEN: a token from git.cloo-gmbh.de with the read_api scope. GitLab has no calendar API, so the numbers are derived from the event stream: a push counts for its commits, everything else counts once.

Neither token is required for the build to succeed. A source without a token is skipped, a source that fails is logged and skipped, and if nothing is reachable the last successful fetch in .cache/contributions.json is used. With no data at all the section is simply left off the page.

To keep the graph current without pushing, redeploy on a schedule.

Icons

The favicon is the lowercase y from Inter at weight 600, pulled straight out of the font file so the mark matches the type on the page. favicon.svg carries its own prefers-color-scheme rule and flips to light in a dark browser theme; favicon.ico is the legacy fallback at 16, 32 and 48. The Apple touch icon and the two manifest icons sit on the site background, because iOS fills alpha with black and a maskable icon gets cropped to a circle.

Regenerating them means re-running the extraction against the Inter file Astro downloads into node_modules/.astro/fonts/, so the script is not wired into the build. src/pages/site.webmanifest.js is generated, so the name and description follow src/consts.ts.

Portrait

src/components/Portrait.astro owns the photo on the cv page. Clicking it opens a native <dialog>, which brings the focus trap and Escape handling with it, and the picture is animated from the thumbnail to full size with a FLIP pass over the Web Animations API. Escape, the close button, the backdrop and the picture itself all close it, and under prefers-reduced-motion the dialog just appears.

The social card is a separate crop, see below.

SEO

Handled in src/layouts/BaseLayout.astro: canonical URL, meta description, Open Graph and Twitter card tags, and JSON-LD (Person on regular pages, BlogPosting on posts). @astrojs/sitemap writes the sitemap, which public/robots.txt points at.

The social card is public/og.jpg, a 1200x630 crop of the portrait. It is a plain file, not generated at build time, so replacing the photo means re-cropping it by hand.

Posts used to live under /posts/<slug>/. redirects in astro.config.mjs keeps those URLs working.

Development

pnpm install
pnpm dev       # http://localhost:4321
pnpm build     # output: dist/
pnpm preview   # serve the production build locally

Deployment

Coolify Static Site application.

  • Build command: pnpm install --frozen-lockfile && pnpm build
  • Publish directory: dist
  • Environment: set GITHUB_TOKEN and GITLAB_TOKEN as build-time variables.
  • Auto-deploy on push to main.

Stack

  • Astro 7 (static output)
  • Content Collections (markdown + Zod schema), rendered by Sätteri with one small hast plugin for external links
  • @astrojs/rss for the feed, @astrojs/sitemap for the sitemap
  • Inter and Geist Mono, self-hosted by Astro's font pipeline, so there are no third-party font requests, which also keeps the site clean under GDPR
  • Plain CSS. UI labels are lowercase throughout; motion uses one shared easing curve and is disabled under prefers-reduced-motion
  • <ClientRouter /> for crossfaded page navigation (the only client script)

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages