feat: implement dynamic Eleventy tiling blog, modular CSS, and agent customizations

- Add project foundation README.md and root AGENTS.md for pair programming
- Configure .agents/ rules and skills for Eleventy tiling and Obsidian publishing
- Decompose monolithic styles into modular tokens, reset, layout, and component CSS
- Implement Nunjucks layout inheritance (base.njk, post.njk, page.njk) and reusable partials
- Configure Eleventy 3 with markdown-it-anchor, syntax highlighting, and dynamic collections
- Migrate sample prototypes into dynamic dispatches lander, gateway, and Markdown posts
- Add multi-stage Dockerfile and clean-URL nginx.conf for production serving
This commit is contained in:
venus
2026-09-13 00:49:27 -05:00
parent c0f67e75a3
commit d8fb8a3699
37 changed files with 4361 additions and 7 deletions
+56
View File
@@ -0,0 +1,56 @@
# Technical Blog System Rules & Architecture Directives
## 1. Pedagogical Explanations (Interactive Learning)
1. **Explain the Code:** Whenever creating or refactoring code (Eleventy configuration, Nunjucks templates, CSS modules, build scripts), provide a clear, educational breakdown.
2. **Break Down Key Concepts:** Explain *why* a particular Eleventy filter, Nunjucks tag, or CSS variable structure was used so the user learns the foundational concepts.
3. **No Magic:** Avoid opaque or overly clever abstractions; prioritize readable, idiomatic code with commentary explaining tricky points.
---
## 2. CSS Architecture & Isolation
1. **Zero Monolithic Inlines:** Do not inject raw `<style>` blocks into HTML templates.
2. **Modular File Structure:**
- Put global tokens in `src/assets/css/tokens.css`.
- Put reset and base typography in `src/assets/css/reset.css`.
- Put layout structures (tiling layout, split grids) in `src/assets/css/layout.css`.
- Put scoped component styles in `src/assets/css/components/<component-name>.css`.
3. **Design System Token Integrity:** Always use CSS custom properties defined in `tokens.css`:
- Canvas: `var(--bg-canvas)` (`#0d0f12`)
- Surface: `var(--bg-surface)` (`#121417`)
- Elevated: `var(--bg-elevated)` (`#1c1f26`)
- Borders: `var(--border-color)` (`#2b303b`)
- Text: `var(--text-primary)` (`#e0e6f0`), `var(--text-muted)` (`#8a95a5`)
- Accents: `var(--accent-cyan)` (`#00f0ff`), `var(--accent-green)` (`#00e676`), `var(--accent-amber)` (`#ffb700`)
4. **Hard Aesthetic Constraints:**
- No glassmorphism (`backdrop-filter`).
- No box-shadows or glows.
- No linear/radial gradients.
- Border radius strictly bounded between `0px` and `4px`.
- Transition durations set to `none` or `0s` for instant snap responses on hover.
---
## 3. Templating Guidelines (Eleventy + Nunjucks)
1. **Layout Hierarchy:**
- Root template: `src/_includes/layouts/base.njk` (contains HTML structure, `<head>`, metadata, scripts, stylesheets).
- Content layouts: `src/_includes/layouts/post.njk` (for articles), `src/_includes/layouts/page.njk` (for landing/catalog).
2. **Component Partials:**
- Isolated partials in `src/_includes/partials/` (`global-bar.njk`, `hero-tile.njk`, `post-card.njk`, `stats-sidebar.njk`, `code-box.njk`, `footer.njk`).
- Pass dynamic data via Nunjucks macros or contextual variables.
---
## 4. Obsidian Content Pipeline
1. **Frontmatter Specification:** Every post ingested from Obsidian must adhere to:
```yaml
title: "Article Title"
date: YYYY-MM-DD
tags: ["#tag1", "#tag2"]
excerpt: "Single paragraph summary"
readingTime: "X MIN READ"
draft: false
```
2. **Obsidian Normalization:**
- Wikilinks `[[slug]]` or `[[slug|Label]]` must be transformed into standard web URLs (`/posts/slug/`).
- Callout blocks (`> [!NOTE]`, `> [!WARNING]`, etc.) must render as terminal-style alert callouts.
- Images must be processed into `src/assets/images/posts/` and linked via standard `<img>` or Markdown image syntax.
@@ -0,0 +1,109 @@
---
name: eleventy-tiling-blog
description: >-
Use this skill when developing, refactoring, or building the River Rooks Eleventy blog, modularizing CSS into tokens and components, creating Nunjucks layouts and partials from sample designs, or configuring Eleventy build pipelines.
---
# Eleventy Tiling Blog Development Skill
This skill guides the agent in modularizing templates and CSS from `sample-designs/` into a clean, DRY Eleventy (11ty) static publication site.
---
## 1. CSS Modularization Workflow
When extracting CSS from `sample-designs/*.html` into `src/assets/css/`:
1. **Tokens (`src/assets/css/tokens.css`):**
Extract all `:root` custom properties:
```css
:root {
--bg-canvas: #0d0f12;
--bg-surface: #121417;
--bg-elevated: #1c1f26;
--border-color: #2b303b;
--text-primary: #e0e6f0;
--text-muted: #8a95a5;
--accent-cyan: #00f0ff;
--accent-green: #00e676;
--accent-amber: #ffb700;
--accent-red: #ff5252;
--font-mono: 'IBM Plex Mono', monospace;
--font-code: 'JetBrains Mono', monospace;
--font-prose: 'Inter', sans-serif;
}
```
2. **Reset & Base (`src/assets/css/reset.css`):**
- Universal box-sizing reset (`box-sizing: border-box; margin: 0; padding: 0;`).
- Body font defaults, base line-height (`1.6`), instant hover transitions (`transition: none;`).
- Explicit 1px/2px focus ring styling for keyboard accessibility.
3. **Layout Grid (`src/assets/css/layout.css`):**
- `.tiling-layout`: Centered flex column, `max-width: 1120px` to `1160px`.
- `.split-grid`: 2-column or multi-tile layout with rigid gaps (`16px`).
- `.article-workspace-grid`: Left sticky sidebar (`290px`) + main article reading view (`1fr`).
4. **Component Modules (`src/assets/css/components/`):**
- `global-bar.css`: `.global-bar`, `.brand-group`, `.status-indicator`, `.bar-nav`, `.bar-link`.
- `tiles.css`: `.tile`, `.tile-header`, `.tile-title`, `.tile-meta`, `.hero-tile`.
- `code-box.css`: `.terminal-code-box`, `.code-titlebar`, `.code-content`.
- `article.css`: Prose typography capped at `65ch`, inline `<kbd>`, tables, callouts.
---
## 2. Nunjucks (`.njk`) Component Architecture
1. **Layout Inheritance:**
- `src/_includes/layouts/base.njk`:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }} | River Rooks</title>
<link rel="stylesheet" href="/assets/css/main.css">
</head>
<body>
<main class="tiling-layout">
{% include "partials/global-bar.njk" %}
{{ content | safe }}
{% include "partials/footer.njk" %}
</main>
</body>
</html>
```
- `src/_includes/layouts/post.njk`:
Extends `layouts/base.njk`, injecting the `.article-workspace-grid` with the table of contents sidebar and article body.
2. **Reusable Partials:**
- `src/_includes/partials/global-bar.njk`
- `src/_includes/partials/hero-tile.njk`
- `src/_includes/partials/post-card.njk`
- `src/_includes/partials/stats-sidebar.njk`
- `src/_includes/partials/code-box.njk`
---
## 3. Explaining Changes to the User
When writing or modifying Eleventy files:
- Explain **how Nunjucks blocks and layout inheritance prevent template duplication**.
- Explain **how CSS custom properties cascade and ensure dark-mode consistency**.
- Point out how the resulting build outputs raw static HTML in `_site/` with zero runtime JavaScript overhead.
---
## 4. Validation & Verification
Run these commands to test Eleventy builds:
```bash
# Validate Eleventy configuration and build static output
npx @11ty/eleventy --dryrun
# Build to _site directory
npx @11ty/eleventy
# Launch local dev server with auto-refresh
npx @11ty/eleventy --serve
```
+99
View File
@@ -0,0 +1,99 @@
---
name: obsidian-sync
description: >-
Use this skill when designing, building, or troubleshooting the Obsidian vault publishing integration, the server upload API, note normalization (wikilinks, callouts, frontmatter), or the custom Obsidian plugin.
---
# Obsidian Vault Publishing & Sync Skill
This skill guides the agent in implementing the custom Obsidian plugin and server-side ingestion workflow for publishing blog posts directly from an Obsidian vault.
---
## 1. System Architecture
```text
+-------------------+ +-----------------------+
| Obsidian Vault | | Blog Server |
| | | |
| [Active Markdown] | POST /api/posts | /api/posts Endpoint |
| + | -------------------> | + |
| Custom Plugin | (Payload: JSON/MD) | Frontmatter Validator |
+-------------------+ | + |
| Wikilink Normalizer |
| + |
+-------------------+ | Write to `src/posts/` |
| Self-Hosted | CouchDB Sync | + |
| LiveSync Server | ===================> | 11ty Build Trigger |
+-------------------+ +-----------------------+
```
---
## 2. Ingestion API Specification
### Endpoint: `POST /api/posts`
- **Headers:**
- `Content-Type: application/json`
- `Authorization: Bearer <API_SECRET>`
- **Request Body:**
```json
{
"slug": "reverse-engineering-iot-firmware",
"content": "---\ntitle: \"Reverse Engineering IoT Firmware\"\ndate: 2026-09-12\ntags: [\"#firmware\"]\n---\n\n## Content...",
"assets": [
{
"filename": "diagram.png",
"data": "<base64-encoded-image>"
}
]
}
```
- **Response:**
- `200 OK`: `{"status": "published", "path": "/posts/reverse-engineering-iot-firmware/"}`
- `400 Bad Request`: `{"error": "Missing required frontmatter: title, date"}`
---
## 3. Obsidian Markdown Normalization Rules
1. **Frontmatter Invariants:**
- Must contain `title`, `date`, `tags` (array), and optional `excerpt`, `readingTime`, `draft`.
2. **Wikilinks Translation:**
- `[[article-slug]]` $\rightarrow$ `[article-slug](/posts/article-slug/)`
- `[[article-slug|Custom Label]]` $\rightarrow$ `[Custom Label](/posts/article-slug/)`
3. **Callout Translation:**
- Obsidian callouts:
```markdown
> [!NOTE]
> Informational notice
```
Must be rendered with corresponding terminal alert styling.
4. **Internal Attachments:**
- `![[screenshot.png]]` $\rightarrow$ translated to `![screenshot](/assets/images/posts/screenshot.png)` and written to `src/assets/images/posts/`.
---
## 4. Custom Obsidian Plugin Development
The Obsidian plugin runs inside Obsidian desktop/mobile and interacts with the Obsidian API:
1. Registers a ribbon icon (e.g. `send` or `terminal`) and a command: `Publish Current Note to River Rooks Blog`.
2. Reads the active file:
```typescript
const activeFile = this.app.workspace.getActiveFile();
const content = await this.app.vault.read(activeFile);
```
3. Parses frontmatter using Obsidian's metadata cache:
```typescript
const cache = this.app.metadataCache.getFileCache(activeFile);
```
4. Sends the HTTP payload to the configured blog server URL with the Bearer token.
5. Displays an Obsidian `Notice('Published successfully to River Rooks Blog!')`.
---
## 5. Self-Hosted LiveSync Compatibility
If using CouchDB-based self-hosted LiveSync:
- A local watcher or CouchDB change listener daemon can be configured to detect updates to notes marked with `published: true` or in a dedicated `Blog/` folder.
- When an update event fires, the daemon pulls the latest revision from the CouchDB database, runs the normalization pipeline, and saves it to `src/posts/`.