potluck: README sells and gets to TADA; CONTRIBUTING has the rest
The README was EmDash's template blurb. Now it says what potluck is and its first block runs from a fresh clone to /issues, using a new `pnpm seed:issues` script that applies seed/issues.json to the local D1 database. CONTRIBUTING covers how it's put together, seeds, checks, the EmDash rules, and deploying; the template's stale notes (Inter, three-column articles) are gone. AGENTS.md is now a symlink to it. Generated-by: Claude Opus 5.5
This commit is contained in:
1 parent
002f08b456
commit
8a812d76e3
4 files changed
+106
-168
No files matched your search
@@ -1,107 +0,0 @@
|
|||||||
This is an EmDash site -- a CMS built on Astro with a full admin UI.
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm dev # Start the Astro dev server
|
|
||||||
npx emdash types # Regenerate TypeScript types from a running site
|
|
||||||
```
|
|
||||||
|
|
||||||
The admin UI is at `http://localhost:4321/_emdash/admin`.
|
|
||||||
|
|
||||||
## Key Files
|
|
||||||
|
|
||||||
| File | Purpose |
|
|
||||||
| ------------------------ | ---------------------------------------------------------------------------------- |
|
|
||||||
| `astro.config.mjs` | Astro config with `emdash()` integration, database, and storage |
|
|
||||||
| `src/live.config.ts` | EmDash loader registration (boilerplate -- don't modify) |
|
|
||||||
| `seed/seed.json` | Schema definition + demo content (collections, fields, taxonomies, menus, widgets) |
|
|
||||||
| `emdash-env.d.ts` | Generated types for collections (auto-regenerated on dev server start) |
|
|
||||||
| `src/layouts/Base.astro` | Base layout with EmDash wiring (menus, search, page contributions) |
|
|
||||||
| `src/pages/` | Astro pages -- all server-rendered |
|
|
||||||
|
|
||||||
## Skills
|
|
||||||
|
|
||||||
Agent skills are in `.agents/skills/`. Load them when working on specific tasks:
|
|
||||||
|
|
||||||
- **building-emdash-site** -- Querying content, rendering Portable Text, schema design, seed files, site features (menus, widgets, search, SEO, comments, bylines). Start here.
|
|
||||||
- **creating-plugins** -- Building EmDash plugins with hooks, storage, admin UI, API routes, and Portable Text block types.
|
|
||||||
- **emdash-cli** -- CLI commands for content management, seeding, type generation, and visual editing flow.
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
The EmDash docs are available as an MCP server at `https://docs.emdashcms.com/mcp`. When you need to verify an API, hook, config option, field type, or pattern, call `search_docs` against the live documentation rather than relying on training-data recall. The docs reflect current behaviour; assumptions may not.
|
|
||||||
|
|
||||||
This template ships with `.mcp.json`, `.cursor/mcp.json`, and `.vscode/mcp.json` so Claude Code, Cursor, and VS Code auto-discover the docs server. Other tools (OpenCode, Windsurf, etc.) need a manual one-time setup -- see [docs.emdashcms.com/docs-mcp](https://docs.emdashcms.com/docs-mcp).
|
|
||||||
|
|
||||||
## Rules
|
|
||||||
|
|
||||||
- All content pages must be server-rendered (`output: "server"`). No `getStaticPaths()` for CMS content.
|
|
||||||
- Image fields are objects (`{ src, alt }`), not strings. Use `<Image image={...} />` from `"emdash/ui"`.
|
|
||||||
- `entry.id` is the slug (for URLs). `entry.data.id` is the database ULID (for API calls like `getEntryTerms`).
|
|
||||||
- When Astro's cache is enabled, pass content-query hints to `Astro.cache.set(cacheHint)`. Use the `WithCacheHint` variants for site settings, menus, taxonomies, and widget areas rendered by cached routes.
|
|
||||||
- Taxonomy names in queries must match the seed's `"name"` field exactly (e.g., `"category"` not `"categories"`).
|
|
||||||
|
|
||||||
## This Template
|
|
||||||
|
|
||||||
A blog with posts, pages, categories, tags, full-text search, and RSS. Designed for personal writing, technical writing, indie newsletters, and anything where the writing is the product. Editorial-tech aesthetic: confident sans-serif, restrained accent, real article structure with bylines and reading time.
|
|
||||||
|
|
||||||
## Pages
|
|
||||||
|
|
||||||
| Page | Path | What it shows |
|
|
||||||
| ----------- | ------------------ | ------------------------------------------------------------------------------------------------------ |
|
|
||||||
| Home | `/` | Featured post hero (large image + excerpt), latest posts grid |
|
|
||||||
| All posts | `/posts` | Article count, full post list with excerpts and tag chips |
|
|
||||||
| Post detail | `/posts/[slug]` | Featured image, title, body, left meta column (authors + date), right TOC + search + categories gutter |
|
|
||||||
| Search | `/search` | Full-text search UI |
|
|
||||||
| Page | `/pages/[slug]` | Static page content (Portable Text) |
|
|
||||||
| Category | `/category/[slug]` | Posts filtered by category |
|
|
||||||
| Tag | `/tag/[slug]` | Posts filtered by tag |
|
|
||||||
| RSS | `/rss.xml` | Generated feed |
|
|
||||||
|
|
||||||
## Schema
|
|
||||||
|
|
||||||
- `posts` collection: `title`, `featured_image`, `content` (Portable Text), `excerpt` (text).
|
|
||||||
- `pages` collection: `title`, `content` (Portable Text). Used for `/about` etc.
|
|
||||||
- Taxonomies: `category`, `tag`.
|
|
||||||
- Single `primary` menu (Home, About, Posts by default).
|
|
||||||
|
|
||||||
Site settings have `title` and `tagline` -- both render in the header / footer.
|
|
||||||
|
|
||||||
## Visual character
|
|
||||||
|
|
||||||
Single typeface: **Inter** on `--font-body`, used for everything including headings (`--font-heading` defaults to the body face; tighter letter-spacing on h1/h2). **JetBrains Mono** on `--font-mono` for inline code and code blocks. Body and headings share the same family; weight and size carry the hierarchy (`--font-weight-heading` 600, `--font-weight-display` 700 for h1/page titles).
|
|
||||||
|
|
||||||
The brand colour is `#0066cc` (`--color-brand`) -- used for links, the post-card title hover, and the search input focus ring. There's also a secondary text colour (`--color-text-secondary`) and a `--color-muted` for meta info. Don't add a second accent.
|
|
||||||
|
|
||||||
The article layout is the standout feature: a three-column reading view with a left meta column (author bylines, date), centred 680px body column, and a right gutter for search, table of contents, and categories. Don't flatten that into one column on desktop -- the layout signals "this is something to read".
|
|
||||||
|
|
||||||
## Customisation
|
|
||||||
|
|
||||||
Design tokens live in `src/styles/tokens.css` with their default values. To restyle the site, override tokens in `src/styles/theme.css` -- declarations there are unlayered, so they always beat the `@layer base` defaults. Don't edit `tokens.css` or `Base.astro` for visual changes.
|
|
||||||
|
|
||||||
Colours are defined with `light-dark(<light>, <dark>)`, so each token carries both modes. Overriding with a plain colour changes light and dark at once; use `light-dark()` in the override to keep them distinct. There is no separate dark palette to maintain.
|
|
||||||
|
|
||||||
Webfonts are configured in `astro.config.mjs` under `fonts:`. To swap the body face, change the `name:` for the entry bound to `cssVariable: "--font-body"`. Good alternatives: Geist, IBM Plex Sans, Söhne (if you have a licence), Public Sans. If you want a serif-bodied blog, swap to a humanist serif like Source Serif, Crimson Pro, or Lora -- but then also raise `--font-size-base` to `1.0625rem` for readability. To give headings their own face (or use a system font) without touching the font pipeline, override `--font-heading` or `--font-body` in `theme.css`.
|
|
||||||
|
|
||||||
CSS variables worth knowing (see `tokens.css` for the full list):
|
|
||||||
|
|
||||||
- `--color-brand`, `--color-brand-hover`, `--color-on-brand`, `--color-brand-ring`
|
|
||||||
- `--color-bg`, `--color-bg-subtle`, `--color-surface`, `--color-text`, `--color-text-secondary`, `--color-muted`, `--color-border`, `--color-border-subtle`
|
|
||||||
- `--font-body`, `--font-heading`, `--font-mono`
|
|
||||||
- `--font-weight-heading` (600) / `--font-weight-display` (700) -- heading weights; lower them if you switch to a serif
|
|
||||||
- `--tracking-tight` / `--tracking-snug` / `--tracking-wide` / `--tracking-wider` -- letter-spacing tokens used across headings and meta labels
|
|
||||||
- `--content-width` (680px) -- article body column
|
|
||||||
- `--wide-width` (1200px) -- max container
|
|
||||||
- `--gutter-width` (200px) -- right sidebar (TOC) on article pages
|
|
||||||
- `--meta-col-width` (180px) -- left meta column on article pages
|
|
||||||
- `--avatar-size-{xs,sm,md,lg}` -- byline avatar sizes at different scales
|
|
||||||
|
|
||||||
## What not to do
|
|
||||||
|
|
||||||
- Don't add a second accent colour or coloured section backgrounds. The page should be black, white, and one blue.
|
|
||||||
- Don't replace Inter with a display sans (Bebas, Anton, etc.). Headings rely on weight contrast, not novelty faces.
|
|
||||||
- Don't collapse the article gutter on desktop -- it's part of the reading experience.
|
|
||||||
- Don't use stock blog copy ("Welcome to my blog", "Stay tuned for more"). Write a real tagline that says what this blog is about.
|
|
||||||
- Don't seed the home page with three identical placeholder posts. If you only have one real post, show one real post.
|
|
||||||
- Comments are enabled on posts and rendered on the post detail page. Configure moderation before publishing the site, or remove `commentsEnabled` and the comments UI together.
|
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
CONTRIBUTING.md
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# Contributing to potluck
|
||||||
|
|
||||||
|
potluck started as EmDash's `cloudflare:blog` template
|
||||||
|
(`pnpm create emdash@latest`); it's part of
|
||||||
|
[the capsite goal tree](../capsite-checklist.md), where it is the site
|
||||||
|
that publishes the weekly roundup.
|
||||||
|
|
||||||
|
## How it's put together
|
||||||
|
|
||||||
|
- **Issues** are the `issues` collection
|
||||||
|
([seed/issues.json](seed/issues.json)): `title`, `week` (an ISO week,
|
||||||
|
`2026-W40`), `dek` (one-line summary), `body` (Portable Text). The
|
||||||
|
slug is the week, lowercased: `/issues/2026-w40`.
|
||||||
|
[issues-sketch.md](issues-sketch.md) is the dry run behind the three
|
||||||
|
sample issues: real public bookmarks, editorial lines marked *draft*.
|
||||||
|
- **Pages:** home and `/issues` list issues
|
||||||
|
([src/pages/issues/](src/pages/issues/)); `/tag/<tag>` lists issues
|
||||||
|
by diigo tag; search and `/rss.xml` cover issues. The `posts`
|
||||||
|
collection and its pages are the template's, still in place.
|
||||||
|
- **Microformats:** an issue list is an `h-feed` of `h-entry`s; an
|
||||||
|
issue is an `h-entry` (`p-name`, `dt-published`, `p-summary`,
|
||||||
|
`e-content`). In issue bodies,
|
||||||
|
[CiteLink.astro](src/components/CiteLink.astro) marks off-site links
|
||||||
|
as `h-cite` and `/tag/<tag>` links as rel-tag `p-category`.
|
||||||
|
- **Look:** plain HTML, after kmjn.org's
|
||||||
|
[Plain HTML with a few bureaucratic gestures](https://www.kmjn.org/notes/modern_plain_html.html):
|
||||||
|
system fonts (no webfonts), one ~800px column, links in the text
|
||||||
|
color with a dotted underline. Restyle in
|
||||||
|
[src/styles/theme.css](src/styles/theme.css), which overrides the
|
||||||
|
defaults in `tokens.css` (unlayered, so it always wins); don't edit
|
||||||
|
`tokens.css` or `Base.astro` for visual changes. Colors use
|
||||||
|
`light-dark(<light>, <dark>)`.
|
||||||
|
|
||||||
|
## Seeds
|
||||||
|
|
||||||
|
[seed/seed.json](seed/seed.json) (site settings, menus, widgets, the
|
||||||
|
template's collections) is applied on the first request to an empty
|
||||||
|
database. [seed/issues.json](seed/issues.json) is separate:
|
||||||
|
`pnpm seed:issues` applies it to the local D1 database, which exists
|
||||||
|
after the dev server's first request. Run it with the dev server
|
||||||
|
stopped.
|
||||||
|
|
||||||
|
## Checks
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm typecheck # astro check
|
||||||
|
pnpm build
|
||||||
|
```
|
||||||
|
|
||||||
|
## EmDash rules
|
||||||
|
|
||||||
|
- All content pages are server-rendered (`output: "server"`); no
|
||||||
|
`getStaticPaths()` for CMS content.
|
||||||
|
- Image fields are objects (`{ src, alt }`), not strings; render with
|
||||||
|
`<Image image={...} />` from `"emdash/ui"`.
|
||||||
|
- `entry.id` is the slug (for URLs); `entry.data.id` is the database
|
||||||
|
ULID (for API calls like `getEntryTerms`).
|
||||||
|
- When Astro's cache is enabled, pass query hints to
|
||||||
|
`Astro.cache.set(cacheHint)`.
|
||||||
|
- Taxonomy names in queries match the seed's `"name"` exactly (`"tag"`,
|
||||||
|
not `"tags"`).
|
||||||
|
- `npx emdash types` regenerates `emdash-env.d.ts` from a running site
|
||||||
|
(the dev server also regenerates it on start).
|
||||||
|
|
||||||
|
The EmDash docs are an MCP server at `https://docs.emdashcms.com/mcp`
|
||||||
|
(wired up in `.mcp.json`, `.cursor/mcp.json`, `.vscode/mcp.json`).
|
||||||
|
Check them rather than recalling APIs from memory.
|
||||||
|
|
||||||
|
## Deploying
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm wrangler login
|
||||||
|
pnpm deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
The first deploy provisions the D1 database and R2 bucket named in
|
||||||
|
[wrangler.jsonc](wrangler.jsonc). See
|
||||||
|
[Deploy to Cloudflare](https://docs.emdashcms.com/deployment/cloudflare/).
|
||||||
|
|
||||||
|
## For agents
|
||||||
|
|
||||||
|
`AGENTS.md` is a symlink to this file. capsite's
|
||||||
|
[working rules](../AGENTS.md) apply here too (the dev server is the
|
||||||
|
user's to start and stop). EmDash skills are in `.agents/skills/`:
|
||||||
|
`building-emdash-site` (start here), `creating-plugins`, `emdash-cli`.
|
||||||
+19
-61
@@ -1,68 +1,26 @@
|
|||||||
# EmDash Blog Template (Cloudflare)
|
# potluck
|
||||||
|
|
||||||
A clean, minimal blog built with [EmDash](https://github.com/emdash-cms/emdash) and deployed on Cloudflare Workers with D1 and R2.
|
A weekly zine of what you found elsewhere: each issue is one ISO week
|
||||||
|
(`/issues/2026-w40`) of bookmarks with a few words of editorial around
|
||||||
|
them. Everyone brings a dish. The bookmarks come from your own diigo
|
||||||
|
account, so the web you read becomes something you publish on your own
|
||||||
|
site ([PESOS](https://indieweb.org/PESOS)). For now issues are put
|
||||||
|
together by hand. Pulling a week from diigo-cache is next.
|
||||||
|
|
||||||
[](https://deploy.workers.cloudflare.com/?url=https://github.com/emdash-cms/templates/tree/main/blog-cloudflare)
|
Plain HTML that's easy to read, with
|
||||||
|
[microformats](https://microformats.org/wiki/h-entry) so feed readers
|
||||||
|
and IndieWeb tools see each issue as an `h-entry` and each bookmark as
|
||||||
|
an `h-cite`. It's an [EmDash](https://docs.emdashcms.com/) site, so you
|
||||||
|
edit issues in a real admin UI, and it runs on Cloudflare Workers.
|
||||||
|
|
||||||

|
## Getting started
|
||||||
|
|
||||||
## What's Included
|
```sh
|
||||||
|
|
||||||
- Featured post hero on the homepage
|
|
||||||
- Post archive with reading time estimates
|
|
||||||
- Category and tag archives
|
|
||||||
- Full-text search
|
|
||||||
- RSS feed
|
|
||||||
- SEO metadata and JSON-LD
|
|
||||||
- Dark/light mode
|
|
||||||
|
|
||||||
## Pages
|
|
||||||
|
|
||||||
| Page | Route |
|
|
||||||
|---|---|
|
|
||||||
| Homepage | `/` |
|
|
||||||
| All posts | `/posts` |
|
|
||||||
| Single post | `/posts/:slug` |
|
|
||||||
| Category archive | `/category/:slug` |
|
|
||||||
| Tag archive | `/tag/:slug` |
|
|
||||||
| Search | `/search` |
|
|
||||||
| Static pages | `/pages/:slug` |
|
|
||||||
| 404 | fallback |
|
|
||||||
|
|
||||||
## Screenshots
|
|
||||||
|
|
||||||
| | Desktop | Mobile |
|
|
||||||
|---|---|---|
|
|
||||||
| Light |  |  |
|
|
||||||
| Dark |  |  |
|
|
||||||
|
|
||||||
## Infrastructure
|
|
||||||
|
|
||||||
- **Runtime:** Cloudflare Workers
|
|
||||||
- **Database:** D1
|
|
||||||
- **Storage:** R2
|
|
||||||
- **Framework:** Astro with `@astrojs/cloudflare`
|
|
||||||
|
|
||||||
## Local Development
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm install
|
pnpm install
|
||||||
pnpm dev
|
pnpm dev # open http://localhost:4321/_emdash/admin, finish the setup wizard, then Ctrl-C
|
||||||
|
pnpm seed:issues # three sample issues, W38–W40 of 2026
|
||||||
|
pnpm dev # → http://localhost:4321/issues
|
||||||
```
|
```
|
||||||
|
|
||||||
Open http://localhost:4321/_emdash/admin and complete the setup wizard. EmDash runs database migrations and applies the blog seed during setup. The site is available at http://localhost:4321.
|
Next: [CONTRIBUTING](CONTRIBUTING.md) covers how it's put together,
|
||||||
|
checks, and deploying.
|
||||||
## Deploying
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm wrangler login
|
|
||||||
pnpm deploy
|
|
||||||
```
|
|
||||||
|
|
||||||
The first deployment provisions the named D1 database and R2 bucket from `wrangler.jsonc`. See [Deploy to Cloudflare](https://docs.emdashcms.com/deployment/cloudflare/) for production setup, or use the deploy button above.
|
|
||||||
|
|
||||||
## See Also
|
|
||||||
|
|
||||||
- [Node.js variant](../blog) -- same template using SQLite and local file storage
|
|
||||||
- [All templates](../)
|
|
||||||
- [EmDash documentation](https://docs.emdashcms.com/)
|
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev",
|
||||||
|
"seed:issues": "emdash seed seed/issues.json -d \"$(find .wrangler/state/v3/d1 -name '*.sqlite' ! -name metadata.sqlite)\"",
|
||||||
"build": "astro build",
|
"build": "astro build",
|
||||||
"preview": "astro preview",
|
"preview": "astro preview",
|
||||||
"deploy": "astro build && wrangler deploy",
|
"deploy": "astro build && wrangler deploy",
|
||||||
|
|||||||
Reference in new issue
Block a user