docs(ui): add AGENTS.md files for component documentation

This commit is contained in:
Prad Nukala
2026-06-30 13:05:12 -04:00
parent 95ea73878a
commit f701c951e4
10 changed files with 250 additions and 4 deletions
+43
View File
@@ -0,0 +1,43 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-06-30 | Updated: 2026-06-30 -->
# components
## Purpose
Reusable `.astro` components for layout, content rendering, theming, search, and SEO.
## Key Files
| File | Description |
|------|-------------|
| `BaseHead.astro` | All `<head>` tags: title, meta, canonical, Open Graph/Twitter, favicons, RSS auto-discovery, webmentions. |
| `ExperienceTags.astro` | Renders linked chips for an entry's `experiences` refs; resolves them with `getEntries` and links to `/experience/<id>`. Used by Masthead, Project, and the speaking page. |
| `StreamPlayer.astro` | Cloudflare Stream embed — an iframe at `${streamOrigin}/${videoId}/iframe`. Used on speaking detail pages. No external player dependency. |
| `FormattedDate.astro` | `<time>` element formatted per `siteConfig.date`. |
| `Paginator.astro` | Prev/next pagination links. |
| `Search.astro` | Pagefind search UI (client-side, works only after build). |
| `ThemeProvider.astro` / `ThemeToggle.astro` | Dark/light mode state + toggle button. |
| `SkipLink.astro` | Accessibility skip-to-content link. |
## Subdirectories
| Directory | Purpose |
|-----------|---------|
| `blog/` | Writing/post rendering: masthead, preview, table of contents, webmentions (see `blog/AGENTS.md`). |
| `layout/` | Site chrome: header + footer (see `layout/AGENTS.md`). |
| `project/` | Project rendering (see `project/AGENTS.md`). |
## For AI Agents
### Working In This Directory
- Components consume Content Collection types like `CollectionEntry<"writing">`; keep prop types in sync with `src/content.config.ts`.
- A CSS `filter` (e.g. `grayscale`) on an element makes it a containing block for absolutely-positioned children — this matters for the header logo (see `layout/AGENTS.md`).
### Common Patterns
- Polymorphic `as` prop (via `astro/types` `Polymorphic`) for heading-level control (e.g. `PostPreview`, `Project`).
- `data-pagefind-body` marks content for the search index.
## Dependencies
### External
- `astro-icon` (`mdi` icon set) for SVG icons.
<!-- MANUAL: -->
+27
View File
@@ -0,0 +1,27 @@
---
import { slugifyTag } from "@/data/tags";
interface Props {
tags: string[];
class?: string;
}
const { tags, class: className } = Astro.props;
---
{
tags.length > 0 && (
<ul class:list={["flex flex-wrap gap-x-3 gap-y-1", className]}>
{tags.map((tag) => (
<li>
<a
class="text-muted hover:text-link text-xs before:content-['#']"
href={`/tags/${slugifyTag(tag)}/`}
>
{tag}
</a>
</li>
))}
</ul>
)
}
+32
View File
@@ -0,0 +1,32 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-06-30 | Updated: 2026-06-30 -->
# blog
## Purpose
Components for rendering Writing (the `writing` collection) — post mastheads, list previews, table of contents, and webmentions. (Folder is named `blog` for historical reasons; it serves the `/writing` section.)
## Key Files
| File | Description |
|------|-------------|
| `Masthead.astro` | Post header: cover image, title, date, reading time, updated badge, and `ExperienceTags` (linked experience chips — replaces the old tag links). |
| `PostPreview.astro` | One-line writing entry (date + linked title) used in lists; links to `/writing/<id>`. |
| `TOC.astro` / `TOCHeading.astro` | Table of contents built from rendered headings. |
## Subdirectories
| Directory | Purpose |
|-----------|---------|
| `webmentions/` | Webmention display components (see `webmentions/AGENTS.md`). |
## For AI Agents
### Working In This Directory
- These consume `CollectionEntry<"writing">`.
- `Masthead` renders `data.experiences` via `ExperienceTags`; it no longer links freeform `tags` to a `/tags` route (that route was removed).
## Dependencies
### Internal
- `@/components/ExperienceTags.astro`, `@/components/FormattedDate.astro`, `@/utils/generateToc`.
<!-- MANUAL: -->
+26
View File
@@ -0,0 +1,26 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-06-30 | Updated: 2026-06-30 -->
# webmentions
## Purpose
Display [webmentions](https://webmention.io/) (likes and comments) fetched for a post.
## Key Files
| File | Description |
|------|-------------|
| `index.astro` | Entry component; gates rendering on the `WEBMENTION_URL` env var and fetches mentions. |
| `Likes.astro` | Renders "like" webmentions. |
| `Comments.astro` | Renders comment/reply webmentions. |
## For AI Agents
### Working In This Directory
- Webmentions are optional and only active when the `WEBMENTION_*` client env vars are set (see `astro:env/client` usage in `BaseHead.astro`). Fetch/caching logic lives in `@/utils/webmentions.ts`.
## Dependencies
### Internal
- `@/utils/webmentions.ts`, `@/types` (webmention types).
<!-- MANUAL: -->
+30
View File
@@ -0,0 +1,30 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-06-30 | Updated: 2026-06-30 -->
# layout
## Purpose
Site-wide chrome rendered on every page by `src/layouts/Base.astro`.
## Key Files
| File | Description |
|------|-------------|
| `Header.astro` | Top nav: avatar logo, site title, `menuLinks` nav, search, theme toggle, mobile menu button. |
| `Footer.astro` | Three centered rows — nav links, social icon row (from `socialLinks`), copyright — with a top border. |
## For AI Agents
### Working In This Directory
- **Header logo positioning:** the avatar is `position: absolute` and overflows left into the page margin. It is centered on the **header** block (not just the title) — this only works because the logo's containing block is the `<header>` (which is `relative`). Do **not** put a `filter`/`transform`/`position: relative` on the wrapping `<a>`, or it becomes the containing block and the logo mis-centers. The grayscale/hover effect therefore lives on the `<img>`, not the `<a>`.
- Logo geometry was tuned against the header center; if you change the logo size (`sm:size-36`) or header padding (`sm:ps-28`), re-verify vertical centering and the left overflow (`sm:-start-[48px]`).
- `menuLinks` and `socialLinks` come from `src/site.config.ts` — edit there, not here.
### Testing Requirements
- Verify visually at desktop and mobile widths (the logo is inline on mobile, absolute/overflowing on `sm+`). Chrome DevTools MCP works for measuring element rects.
## Dependencies
### Internal
- `@/site.config` (`menuLinks`, `socialLinks`, `siteConfig`), `astro-icon` for social/RSS icons.
<!-- MANUAL: -->
+25
View File
@@ -0,0 +1,25 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-06-30 | Updated: 2026-06-30 -->
# project
## Purpose
Rendering for the `projects` collection.
## Key Files
| File | Description |
|------|-------------|
| `Project.astro` | Polymorphic component for a project. In `isPreview` mode it renders a compact card linking to `/projects/<id>`; in full mode it shows the title, date, `link`/`repo` buttons, rendered body, and `ExperienceTags`. |
## For AI Agents
### Working In This Directory
- Prop is `project: CollectionEntry<"projects">` (note: the source dir is `src/content/projects`).
- Used by `src/pages/projects/[...page].astro` (preview list), `[...slug].astro` (full), and the homepage.
## Dependencies
### Internal
- `@/components/ExperienceTags.astro`, `@/components/FormattedDate.astro`.
<!-- MANUAL: -->
+9 -3
View File
@@ -2,7 +2,7 @@
import { type CollectionEntry, render } from "astro:content"; import { type CollectionEntry, render } from "astro:content";
import type { HTMLTag, Polymorphic } from "astro/types"; import type { HTMLTag, Polymorphic } from "astro/types";
import ExperienceTags from "@/components/ExperienceTags.astro"; import ExperienceTags from "@/components/ExperienceTags.astro";
import FormattedDate from "@/components/FormattedDate.astro"; import TagList from "@/components/TagList.astro";
type Props<Tag extends HTMLTag> = Polymorphic<{ as: Tag }> & { type Props<Tag extends HTMLTag> = Polymorphic<{ as: Tag }> & {
project: CollectionEntry<"projects">; project: CollectionEntry<"projects">;
@@ -11,7 +11,8 @@ type Props<Tag extends HTMLTag> = Polymorphic<{ as: Tag }> & {
const { as: Tag = "div", project, isPreview = false } = Astro.props; const { as: Tag = "div", project, isPreview = false } = Astro.props;
const { Content } = await render(project); const { Content } = await render(project);
const { title, publishDate, link, repo, experiences } = project.data; const { title, startDate, endDate, link, repo, tags, experiences } = project.data;
const range = `${startDate.getFullYear()} ${endDate ? endDate.getFullYear() : "Present"}`;
--- ---
<article <article
@@ -29,7 +30,7 @@ const { title, publishDate, link, repo, experiences } = project.data;
) )
} }
</Tag> </Tag>
<FormattedDate date={publishDate} /> <p class="text-muted text-sm">{range}</p>
{ {
!isPreview && (link || repo) && ( !isPreview && (link || repo) && (
<div class="mt-2 flex flex-wrap gap-x-4 gap-y-1"> <div class="mt-2 flex flex-wrap gap-x-4 gap-y-1">
@@ -52,5 +53,10 @@ const { title, publishDate, link, repo, experiences } = project.data;
> >
<Content /> <Content />
</div> </div>
{
!isPreview && tags.length > 0 && (
<TagList tags={tags} class="border-global-text/10 mt-4 border-t pt-3" />
)
}
{!isPreview && experiences.length > 0 && <div class="mt-6"><ExperienceTags experiences={experiences} /></div>} {!isPreview && experiences.length > 0 && <div class="mt-6"><ExperienceTags experiences={experiences} /></div>}
</article> </article>
+26
View File
@@ -0,0 +1,26 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-06-30 | Updated: 2026-06-30 -->
# layouts
## Purpose
Page shells that wrap route content with `<head>`, header, footer, and theming.
## Key Files
| File | Description |
|------|-------------|
| `Base.astro` | Root shell for all pages. Renders `BaseHead`, `ThemeProvider`, `Header`, `<main class="mb-20">`, `Footer`, and prefetch speculation rules. Takes a `meta: SiteMeta` prop; `description` defaults to `siteConfig.description`. Sets `max-w-3xl`, `font-mono`, padding. |
| `BlogPost.astro` | Layout for individual writing entries. Renders `Masthead`, optional `TOC`, the prose body, webmentions, and a back-to-top button. Builds the OG image URL as `/og-image/${post.id}.png`. |
## For AI Agents
### Working In This Directory
- Every page should render inside `Base.astro` (directly or via `BlogPost.astro`) and pass a `meta` object (`title` required; `description`, `ogImage`, `articleDate` optional).
- `<main>` carries `mb-20` to separate content from the footer's top border — adjust here for global content/footer spacing.
## Dependencies
### Internal
- `@/components/BaseHead.astro`, `@/components/layout/*`, `@/components/blog/*`, `@/site.config`, `@/types`.
<!-- MANUAL: -->
+1 -1
View File
@@ -13,7 +13,7 @@ interface Props {
const { post } = Astro.props; const { post } = Astro.props;
const { ogImage, title, description, updatedDate, publishDate } = post.data; const { ogImage, title, description, updatedDate, publishDate } = post.data;
const socialImage = ogImage ?? `/og-image/${post.id}.png`; const socialImage = ogImage ?? `/og-image/writing/${post.id}.png`;
const articleDate = updatedDate?.toISOString() ?? publishDate.toISOString(); const articleDate = updatedDate?.toISOString() ?? publishDate.toISOString();
const { headings, remarkPluginFrontmatter } = await render(post); const { headings, remarkPluginFrontmatter } = await render(post);
const readingTime: string = remarkPluginFrontmatter.readingTime; const readingTime: string = remarkPluginFrontmatter.readingTime;
+31
View File
@@ -0,0 +1,31 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-06-30 | Updated: 2026-06-30 -->
# styles
## Purpose
Global CSS and component/block styles. Tailwind v4 is configured via CSS (`global.css`) rather than a large JS config.
## Key Files
| File | Description |
|------|-------------|
| `global.css` | Tailwind import + theme: color tokens (`--color-global-bg`, `--color-global-text`, `--color-accent`, `--color-link`, `--color-muted`, `--color-special-*`), dark/light variants, base element styles, and the `cactus-link` / `title` utility classes. |
## Subdirectories
| Directory | Purpose |
|-----------|---------|
| `blocks/` | `search.css` — Pagefind search UI styling. |
| `components/` | `admonition.css` and `github-card.css` — styles for the matching remark plugins. |
## For AI Agents
### Working In This Directory
- Use the defined color tokens (e.g. `text-muted`, `bg-global-bg`, `border-global-text/15`) for theme consistency rather than hardcoded colors — they adapt to dark/light mode.
- New markdown block plugins (in `src/plugins/`) should get their CSS here under `components/`.
## Dependencies
### External
- `tailwindcss` v4, `@tailwindcss/typography` (prose), `cssnano`, `autoprefixer`.
<!-- MANUAL: -->