import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
import { z } from 'astro/zod';
import { baseEntry, themeOverride } from '@eratic/core';
/**
* io.eratic.ro — one issue a week.
*
* src/content/issues/2026/32.mdx → /2026/32/
*
* The links are frontmatter rather than prose because a list of links is
* structured data: it wants to be rendered consistently, grouped by kind, and
* carried whole into the feed. The MDX body is for whatever you want to say
* around them, and it can be empty.
*
* `title` is optional here and nowhere else. A weekly thing that demands a
* clever title every week becomes a weekly thing you stop doing; leave it out
* and the issue is simply "Issue 32".
*/
export const LINK_KINDS = ['read', 'watched', 'listened', 'other'] as const;
export type LinkKind = (typeof LINK_KINDS)[number];
export const LINK_KIND_LABEL: Record<LinkKind, string> = {
read: 'Read',
watched: 'Watched',
listened: 'Listened',
other: 'Elsewhere',
};
const issues = defineCollection({
loader: glob({ pattern: '**/[^_]*.{md,mdx}', base: './src/content/issues' }),
schema: () =>
baseEntry.extend({
title: z.string().optional(),
issue: z.number().int().positive(),
links: z
.array(
z.object({
title: z.string().min(1),
url: z.url(),
kind: z.enum(LINK_KINDS).default('read'),
/** Who or what led you to it. Credit costs nothing. */
via: z.string().optional(),
/** One or two sentences on why it is here. */
note: z.string().optional(),
}),
)
.min(1, 'An issue with no links is not an issue.'),
canvas: z.enum(['article', 'wide', 'bare']).default('article'),
theme: themeOverride,
}),
});
export const collections = { issues };