Something went wrong. Try again.
React blog kit backed by AT Protocol. Provides filtering UI, pagination, Bluesky comments/embeds, subscribe widget, and markdown rendering.
Something went wrong. Try again.
800 B · 20 lines
TypeScript
at main
123456789101112131415161718192021import type { Category } from "./types";
const WHITESPACE_RE = /\s+/g;
// Title → slug is stateless. Used in URL params and category filtering.export function getCategorySlug(title: string): string { return title.toLowerCase().replace(WHITESPACE_RE, "-");}
// Slug → title resolver. Bound at config time because the title map is// per-consumer (each blog has its own categories). Returns the slug// untouched when no match — keeps URLs deep-linkable to unknown slugs.export function makeCategoryTitleResolver( categories: Record<string, Category>,): (slug: string) => string { const slugToTitle: Record<string, string> = Object.fromEntries( Object.values(categories).map((cat) => [getCategorySlug(cat.title), cat.title]), ); return (slug) => slugToTitle[slug] ?? slug;}