site: rename "finds" superpost collection to "bundles"

Disambiguates the one-letter `find` (item) vs `finds` (roundup) split that
kept causing confusion. Audience-facing now: `/bundles/<slug>/`, "Bundle"
labels in home/footer/search.

Internals: `getCollection('finds')` → `('bundles')`, `Entry.type 'finds'`
→ `'bundle'`, `OgFallback 'finds'` → `'bundles'`, `findListMosaic` →
`bundleMosaic`, `FindsPost` → `Bundle`, `findsReferencing` →
`bundlesReferencing`. Build script + generated mosaic dir follow
(`scripts/build-bundle-mosaics.mjs`, `src/generated/bundle-mosaics/`).

Skills `build-finds` → `build-bundle`, `cluster-finds` →
`cluster-bundles`. The `find` collection (individual items) is unchanged.

No URL redirects: low external-link surface area.
This commit is contained in:
2026-05-06 20:43:22 -04:00
parent c2e1df222d
commit 049c6c5377
36 changed files with 503 additions and 255 deletions
+3 -3
View File
@@ -1,9 +1,9 @@
import { getCollection, type CollectionEntry } from 'astro:content';
export type FindsPost = CollectionEntry<'finds'>;
export type Bundle = CollectionEntry<'bundles'>;
export async function findsReferencing(slug: string): Promise<FindsPost[]> {
const all = await getCollection('finds');
export async function bundlesReferencing(slug: string): Promise<Bundle[]> {
const all = await getCollection('bundles');
return all
.filter((p) => p.data.items.includes(slug))
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
@@ -1,16 +1,16 @@
import type { ImageMetadata } from 'astro';
const modules = import.meta.glob<{ default: ImageMetadata }>(
'../generated/list-mosaics/*.jpg',
'../generated/bundle-mosaics/*.jpg',
{ eager: true }
);
const mosaics = new Map<string, ImageMetadata>();
for (const [path, mod] of Object.entries(modules)) {
const match = path.match(/list-mosaics\/([^/]+)\.jpg$/);
const match = path.match(/bundle-mosaics\/([^/]+)\.jpg$/);
if (match) mosaics.set(match[1], mod.default);
}
export function findListMosaic(slug: string): ImageMetadata | undefined {
export function bundleMosaic(slug: string): ImageMetadata | undefined {
return mosaics.get(slug);
}
+10 -10
View File
@@ -1,7 +1,7 @@
import { getCollection } from 'astro:content';
export type Entry = {
type: 'review' | 'post' | 'finds';
type: 'review' | 'post' | 'bundle';
id: string;
href: string;
date: Date;
@@ -14,7 +14,7 @@ export type Entry = {
export async function getAllEntries(): Promise<Entry[]> {
const reviews = await getCollection('reviews');
const posts = await getCollection('posts');
const findsPosts = await getCollection('finds');
const bundles = await getCollection('bundles');
const r: Entry[] = reviews.map((e) => ({
type: 'review',
@@ -37,10 +37,10 @@ export async function getAllEntries(): Promise<Entry[]> {
primary: e.data.title,
}));
const f: Entry[] = findsPosts.map((e) => ({
type: 'finds',
const b: Entry[] = bundles.map((e) => ({
type: 'bundle',
id: e.id,
href: `/finds/${e.id}/`,
href: `/bundles/${e.id}/`,
date: e.data.date,
category: e.data.category,
tags: e.data.tags,
@@ -48,7 +48,7 @@ export async function getAllEntries(): Promise<Entry[]> {
secondary: e.data.blurb,
}));
return [...r, ...p, ...f].sort((a, b) => b.date.valueOf() - a.date.valueOf());
return [...r, ...p, ...b].sort((a, b) => b.date.valueOf() - a.date.valueOf());
}
export type SiteStats = {
@@ -57,7 +57,7 @@ export type SiteStats = {
reviews: number;
finds: number;
posts: number;
lists: number;
bundles: number;
};
let statsCache: Promise<SiteStats> | null = null;
@@ -73,17 +73,17 @@ async function computeSiteStats(): Promise<SiteStats> {
const reviews = entries.filter((e) => e.type === 'review').length;
const finds = findItems.length;
const posts = entries.filter((e) => e.type === 'post').length;
const lists = entries.filter((e) => e.type === 'finds').length;
const bundles = entries.filter((e) => e.type === 'bundle').length;
const allDates = [
...entries.map((e) => e.date),
...findItems.map((f) => f.data.date),
].sort((a, b) => b.valueOf() - a.valueOf());
return {
total: reviews + finds + posts + lists,
total: reviews + finds + posts + bundles,
lastUpdated: allDates[0] ?? null,
reviews,
finds,
posts,
lists,
bundles,
};
}
+2 -2
View File
@@ -1,13 +1,13 @@
import { heroes } from './hero';
import type { OgImage } from '../components/SEO.astro';
export type OgFallback = 'reviews' | 'finds' | 'posts' | 'site';
export type OgFallback = 'reviews' | 'bundles' | 'posts' | 'site';
const SITE_URL = 'https://unique.rzen.dev';
const FALLBACK_PATHS: Record<OgFallback, string> = {
reviews: '/og/reviews.png',
finds: '/og/finds.png',
bundles: '/og/bundles.png',
posts: '/og/posts.png',
site: '/og/default.png',
};