mirror of
https://github.com/andwati/andwati.com.git
synced 2026-10-27 05:12:16 +00:00
References: pixperk.tech (dark, warm off-white text, serif-italic + mono mixed typography, personal dashboard modules) and mcyoung.xyz (meta line with reading time, subtle accent underline on titles). - src/styles/tokens.css: dark-first color palette with a warm-paper light mode (data-theme override + prefers-color-scheme, toggle wins either direction), fluid clamp() type scale, spacing/radius scale. - Fonts: Fraunces (display/headings, italic), Newsreader (body, long-form readability), JetBrains Mono (nav/meta/code) — all self-hosted via @fontsource, continuing the mono choice already used in the legacy OG-image pipeline. - Base.astro rewritten: real header/nav with active-link state, a theme toggle (persisted to localStorage, no-flash inline script), footer with social links (ported from zola.toml), replacing the scaffold placeholder. - Reading time: toml-content-loader.ts computes wordCount/ readingMinutes from the raw body at load time, surfaced in the writings list and detail meta line. - Bug fix: the marked heading renderer was using raw token.text for both the visible heading and the TOC, so a heading like "**Registers**" rendered literal asterisks instead of bold — now renders inline tokens properly and strips markdown for the plain-text TOC label/slug. Verified in-browser (light + dark) across home, a migrated writing with TOC/headings, bookshelf, and 404.
80 lines
2.2 KiB
TypeScript
80 lines
2.2 KiB
TypeScript
import { defineCollection } from "astro:content";
|
|
import { z } from "astro/zod";
|
|
import { tomlContentLoader } from "./lib/toml-content-loader";
|
|
|
|
const taxonomies = z
|
|
.object({
|
|
tags: z.array(z.string()).default([]),
|
|
})
|
|
.optional();
|
|
|
|
const writings = defineCollection({
|
|
loader: tomlContentLoader("../../content/writings/"),
|
|
schema: z.object({
|
|
title: z.string(),
|
|
description: z.string().optional(),
|
|
author: z.string().optional(),
|
|
date: z.coerce.date(),
|
|
updated: z.coerce.date().optional(),
|
|
draft: z.boolean().default(false),
|
|
canonical_url: z.string().optional(),
|
|
wordCount: z.number().optional(),
|
|
readingMinutes: z.number().optional(),
|
|
taxonomies,
|
|
extra: z
|
|
.object({
|
|
series: z.string().optional(),
|
|
series_index: z.number().optional(),
|
|
llms_description: z.string().optional(),
|
|
})
|
|
.optional(),
|
|
}),
|
|
});
|
|
|
|
const portfolio = defineCollection({
|
|
loader: tomlContentLoader("../../content/portfolio/"),
|
|
schema: z.object({
|
|
title: z.string(),
|
|
description: z.string().optional(),
|
|
role: z.string().optional(),
|
|
date_start: z.coerce.date().optional(),
|
|
date_end: z.coerce.date().optional(),
|
|
outcome: z.string().optional(),
|
|
draft: z.boolean().default(false),
|
|
links: z
|
|
.array(z.object({ label: z.string(), url: z.string() }))
|
|
.default([]),
|
|
taxonomies,
|
|
}),
|
|
});
|
|
|
|
const bookshelf = defineCollection({
|
|
loader: tomlContentLoader("../../content/bookshelf/"),
|
|
schema: z.object({
|
|
title: z.string(),
|
|
kind: z.enum(["book", "paper"]),
|
|
authors: z.array(z.string()).default([]),
|
|
isbn: z.string().optional(),
|
|
doi: z.string().optional(),
|
|
arxiv_id: z.string().optional(),
|
|
url: z.string().optional(),
|
|
cover_image: z.string().optional(),
|
|
rating: z.number().optional(),
|
|
read_status: z.enum(["reading", "read", "abandoned"]).optional(),
|
|
date_started: z.coerce.date().optional(),
|
|
date_finished: z.coerce.date().optional(),
|
|
taxonomies,
|
|
}),
|
|
});
|
|
|
|
const blogs = defineCollection({
|
|
loader: tomlContentLoader("../../content/blogs/"),
|
|
schema: z.object({
|
|
title: z.string(),
|
|
url: z.string(),
|
|
feed_url: z.string().optional(),
|
|
}),
|
|
});
|
|
|
|
export const collections = { writings, portfolio, bookshelf, blogs };
|