blog.hangerthem.com/content/pages/projects.md
HangerThem 30ef0d611e Bug fixes, SEO, performance and accessibility pass (#1)
## Summary

A cleanup pass across the blog: route and feed bugs fixed, SEO basics added, smaller and lazier images, accessibility fixes, and a real README. No content or design changes beyond small fixes.

## Bug fixes

- **Tag/category pages**: static params now use slugs, so pre-rendered pages match the links (before, `/tags/standard-model` was only rendered on demand and the pre-built pages said "Tag not found"). Unknown slugs now return a real 404, and there's a new not-found page.
- **Recently updated**: sorts by last modification *before* taking the top 5, so older posts that were updated recently now show up.
- **Atom feed**: `rel="self"` now points to `/feed.xml` (was `/feed`); `<updated>` uses the `updated` frontmatter field.
- **No-JS flash**: the `no-js` → `js` class swap runs in an inline `<head>` script before first paint, not after hydration.
- **Markdown links**: only internal paths go through `next/link`; `#anchors`, `mailto:` and links without an `href` no longer break.
- **Invalid HTML**: images in a paragraph together with text (e.g. "**Screenshots:**" followed by images on the Projects page) produced `<p><figure>` and a hydration error. Those paragraphs are now split.
- **Dates**: frontmatter dates are normalized to ISO, so `<time datetime>` values are valid. Formatting is pinned to Europe/Prague so a UTC build server can't shift a date by a day.

## SEO

- `sitemap.xml` and `robots.txt`
- Canonical URLs, Twitter cards and a feed link on every page, built by a shared `pageMetadata()` helper
- Generated Open Graph images: a site card, and for each post its cover image or a branded title card (pre-rendered at build time)
- `BlogPosting` JSON-LD on post pages

## Performance

- Only the post cover and the latest-post image are preloaded (was: every image)
- In-post image quality 100 → 90, plus responsive `sizes`
- Screenshots downscaled to 1800px wide; `linkboard-old.png` converted to WebP (3.1 MB → 60 KB)
- `CodeWrapper` is now a server component; only the copy button ships to the client
- Mermaid CDN script pinned to `11.17.2` for reproducible builds

## Accessibility

- Accessible names for icon-only links (share, social, mobile nav) and `aria-current` on active nav items
- Copy button: uses React state instead of mutating `innerHTML`, handles clipboard errors, announces the result to screen readers, and is no longer inside an `aria-hidden` header
- Code-block line numbers hidden from screen readers
- Image captions: the Markdown `"title"` becomes the caption; captions that only repeat the alt text are hidden from screen readers

## Content & maintenance

- **Frontmatter validation**: a missing or malformed field fails the build and names the file, instead of rendering a broken post
- **`draft: true` support**: drafts only render in development
- About/Projects/Setup pages share one `MarkdownPage` component; tag/category lists share `PostList`
- Markdown rendering is cached, so metadata and page share one render
- New README covering features, env vars, frontmatter schema, Markdown extensions and deployment
- Removed unused ESLint setup and the unrelated `hast` package; `oxlint`, `oxfmt` and `puppeteer` moved to devDependencies (locked versions unchanged)
- Typo fix in the Tessera cover alt text; removed unused `math`/`mermaid` flags from two posts

## Deployment notes

- **`SITE_URL` is now required**: the build fails with a clear error if it's missing.
- **Puppeteer is a devDependency now**: Nixpacks installs dev dependencies for the build by default, but check that Mermaid diagrams render on the first deploy (the Standard Model post has one).

## Testing

- `tsc --noEmit` and `bun run lint` pass
- `bun run build` passes; all 81 pages are generated statically
- Smoke-tested `next start`: posts, tags, categories, feed, sitemap and OG images return 200; unknown tags and routes return 404
- No block elements nested inside `<p>` in any built page

Reviewed-on: #1
2026-10-19 12:41:40 +00:00

161 lines
5.8 KiB
Markdown

---
title: Projects
description: A collection of my personal and professional projects, showcasing my skills, creativity, and problem-solving abilities. Explore the diverse range of work I've done, from software development to design, and see how I approach challenges and deliver innovative solutions.
---
## Tessera
Simple PWA for managing loyalty and membership cards. No account, no ads, no data leaving your device. A privacy-first approach to digital card storage.
Read more about it in the [blog post](/posts/tessera-privacy-first-card-wallet).
**Tech Stack:** Preact + Vite, TypeScript, ZXing, BWIP-JS, IDB-Keyval
**Status**: Maintained
**Screenshots:**
![Screenshot of Tessera's homepage showing a list of saved loyalty cards with their barcodes.](tessera-homepage.png)
![Screenshot of opened card detail](tessera-active_card.png)
![Screenshot of Tessera's form for adding a new card](tessera-new_card_form.png)
## Bitez
**Confidentiality Note:** This project is built under NDA. Details shared here reflect publicly sharable information only.
B2B social media management platform designed for restaurants and cafes. Streamlines content creation, scheduling, and analytics for food service businesses managing multiple locations.
It included real-time chat and media processing job queues, allowing users to upload images and videos, which were then processed asynchronously for optimal performance.
Alongside the core platform, I developed a companion mobile app for iOS and Android, later gravitating towards a Progressive Web App (PWA) approach for broader accessibility and ease of updates.
**Tech Stack:** Next.js, TypeScript, Supabase, Prisma, PostgreSQL, Redis, BullMQ
**Status:** Maintained
**Screenshots:**
![Bitez Dashboard (Some parts were redacted to comply with confidentiality)](bitez-dashboard.png)
---
## Linkboard
Self-hosted alternative to Linktree, a centralized link management and sharing solution you can deploy on your own infrastructure.
The first build of this project was a learning exercise for me and thus was not production-ready. I am currently working on a complete rewrite of the project, focusing on ease of deployment, user experience, and maintainability. The new version will be open-source and available on GitHub.
The new version has focus on ease of use for not tech-savvy users, with a simple and intuitive interface for managing links, analytics, and customization options.
**Tech Stack:** Next.js, TypeScript, Prisma, SQLite
**GitHub:** [HangerThem/linkboard](https://github.com/HangerThem/linkboard)
**Live (old version):** [socials.hangerthem.com](https://socials.hangerthem.com)
**Status:** Active / Maintained
**Screenshots:**
![Linkboard UI (Old Version)](linkboard-old.webp)
![Linkboard UI (New Version)](linkboard-new.png)
![Linkboard Editor](linkboard-editor.png)
---
## LRC Audio Player
NPM package that synchronizes LRC (lyrics file format) display with audio playback. Useful for music apps, karaoke platforms, and lyric-synced UIs.
It also has React wrapper support, allowing developers to easily integrate it into React applications.
**Tech Stack:** TypeScript, Audio API, NPM
**GitHub:** [HangerThem/lrc-audio-player](https://github.com/HangerThem/lrc-audio-player)
**NPM Package:** [lrc-audio-player](https://www.npmjs.com/package/lrc-audio-player)
**Status:** Maintained
**Features:**
- Real-time lyric synchronization
- Customizable UI
- Flexible timing formats
- React wrapper for easy integration
---
## Social Network
Personal learning project building a full-stack social network from scratch. It includes user authentication, profile management, post creation, and a basic feed system.
**Tech Stack:** Next.js, TypeScript, Supabase, Prisma, PostgreSQL, better-auth
**GitHub:** [HangerThem/socials-example](https://github.com/HangerThem/socials-example)
**Status:** Active Development / Learning Project
---
## Venia
Open-source cookie consent library with a strong anti-dark-pattern philosophy. Provides accessible, user-friendly consent management without manipulative UX patterns.
It is designed to be framework-agnostic, with implementations for React and Vue, and a core library that can be integrated into any web application.
For developers, it offers a CLI tool for easy setup and configuration, along with customizable components to fit various design needs.
**Tech Stack:** TypeScript, React, Vue, Node.js
**GitHub:** [HangerThem/venia](https://github.com/HangerThem/venia)
**NPM Package (core):** [venia/core](https://www.npmjs.com/package/@venia-consent/core)
**NPM Package (React):** [venia/react](https://www.npmjs.com/package/@venia-consent/react)
**NPM Package (Vue):** [venia/vue](https://www.npmjs.com/package/@venia-consent/vue)
**NPM Package (CLI):** [venia/cli](https://www.npmjs.com/package/@venia-consent/cli)
**Status:** Maintained
**Key Features:**
- GDPR/CCPA compliant
- No dark patterns
- Accessible by default
- Lightweight and customizable
---
## lighthouse-report-svg
Converts Lighthouse audit results into SVG visualizations. Useful for CI/CD pipelines, performance dashboards, and automated reporting.
**Tech Stack:** TypeScript, Node.js, SVG
**GitHub:** [HangerThem/lighthouse-report-svg](https://github.com/HangerThem/lighthouse-report-svg)
**Live Demo:** [lighthouse-report-svg.vercel.app](https://lighthouse-report-svg.vercel.app)
**Status:** Maintained
**Use Cases:**
- Performance monitoring in CI/CD
- Automated performance reports
- Visual audit dashboards
---
## This blog
This very blog is a personal project where I share my thoughts, tutorials, and insights on web development, programming, and technology trends.
**Tech Stack:** Next.js, TypeScript, Tailwind CSS
**Source Code:** [HangerThem/blog.hangerthem.com](https://git.hangerthem.com/HangerThem/blog.hangerthem.com)
---
## Summary
All source code is available on [GitHub](https://github.com/HangerThem).