code is licensed under MIT, text content, all markdown files, words, images are licensed under CC BY-NC-SA 4.0.
Lives in packages/index/src/pages/portfolio/index.astro. The project list is the single source of truth in packages/index/src/portfolio/projects.json, newest first. The markup (components/Project.astro) and the JSON-LD are rendered from it at build time, there is nothing to regenerate.
-
Add screenshots to
packages/index/src/portfolio/img/, 16:10, named after the projectid:<id>.jpgand<id>.webpat 1280x800,<id>-sm.webpat 640x400.
-
Add an entry to
projects.json(the order in the file is the order on the page):field meaning idslug, used for image names and the #anchornameproject name (the h2)hostaddress shown to visitors urllink target, or nullwhen there is nothing to link toyearonly the year is shown stacklist of technologies descriptionwhat it is and what we did noteoptional highlight line altfactual alt text for the screenshot internaloptional, truefor links to frsource.org itself (same tab, nonofollow)linksoptional extra links, [{ "label": "...", "url": "..." }], e.g. app storesnoImageoptional, truerenders a gradient placeholder instead of a screenshot -
Check it with
pnpm start(orpnpm build && pnpm preview), then open/portfolio/on desktop and mobile widths.
External links get rel="nofollow noopener" automatically. Each project also gets a "Build something like this" link that opens the contact form with a pre-filled message (a mailto: link without JS).
- Without JS (and on small screens) it is a plain list of
<details>elements, closed by default. src/portfolio/portfolio.tsupgrades it to the "Browser Deck" on landscape screens of 920px and wider.- The glitch sweep between
/and/portfolio/is progressive enhancement over a normal link click (data-glitchattribute,src/common/glitch.ts). It is skipped withprefers-reduced-motion.
An Astro static site styled with Tailwind CSS (v4, utilities only, no preflight) and plain CSS in src/styles/. The only client code is small vanilla TypeScript (src/index.ts, src/portfolio/portfolio.ts).
pnpm startruns the dev server (/blogis proxied to the blog's dev server).pnpm buildwrites the site to the repository'spublic/folder (the blog is added there by its own build), generates the favicons andsw.js(precaches the homepage, seebuild/serviceWorker.mjs).- Static files that must be copied as they are (
robots.txt,sitemap.xml,logo.*, ...) live inpackages/index/public/. - Theme tokens (colors, spacing, breakpoints) are in the
@themeblock ofsrc/styles/global.css. Thedark:variant followsprefers-color-schemeunless a visitor picked a theme (body.t-light/body.t-dark).