Switch the post-directory field separator from -- to ~ (AI)
A double-hyphen separator collides with an easy authoring typo: an accidental extra "-" in a kebab-case slug (e.g. "hello--world") silently misparses as slug "hello" + an invalid date, dropping the article from the index with no visible error. "~" isn't something anyone would type by accident while writing a normal slug, and (like "-") is in the URI "unreserved" set, so it never needs percent-encoding either. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AXSVPS3UmmASiiprPfcnUd
This commit is contained in:
1 parent
122593da24
commit
885178d1e7
2 files changed
+19
-13
No files matched your search
@@ -6,7 +6,7 @@ A minimal CMS where articles are Markdown files rendered in the browser. No buil
|
||||
|
||||
1. The browser traverses `cmjs/articles/` via a server directory index — discovering authors and their post directories; nginx JSON autoindex is preferred, with HTML autoindexes supported as a fallback.
|
||||
2. Sorting, filtering, and publish status all come from the post directory's own *name*
|
||||
(`slug--DDMMYYYY--tags`) — knowable straight from the listing that discovers it, with no
|
||||
(`slug~DDMMYYYY~tags`) — knowable straight from the listing that discovers it, with no
|
||||
further request per article. A `.md` file's actual content (title, description, image) is
|
||||
only fetched once that article is about to be shown — the current page's cards, a single
|
||||
article, or a search — not for the whole site up front. See "Adding an article" and "Article
|
||||
@@ -77,7 +77,7 @@ cmjs/
|
||||
└── author/ # One directory per author
|
||||
├── author.md # Author profile (optional)
|
||||
├── avatar.jpg # Optional — referenced by author.md's `avatar:` field
|
||||
└── slug--DDMMYYYY--tag1+tag2/ # One directory per post — see "Adding an article"
|
||||
└── slug~DDMMYYYY~tag1+tag2/ # One directory per post — see "Adding an article"
|
||||
├── slug.md # Article content + frontmatter
|
||||
└── cover.jpg # Optional — referenced by slug.md's `image:` field
|
||||
```
|
||||
@@ -88,7 +88,7 @@ An article's directory *name* is where its publish date, tags, category, and dra
|
||||
live — not in separate files, and not in frontmatter. The format is:
|
||||
|
||||
```
|
||||
<slug>--<DDMMYYYY>--<tag1>+<tag2>+…
|
||||
<slug>~<DDMMYYYY>~<tag1>+<tag2>+…
|
||||
```
|
||||
|
||||
- `<slug>` — the stable identifier used in the article's URL (`#post/author/slug`). Treat this
|
||||
@@ -98,9 +98,13 @@ live — not in separate files, and not in frontmatter. The format is:
|
||||
- `<tag1>+<tag2>+…` — zero or more tag ids, joined with `+`. A tag id matching `expa-YYYY` is
|
||||
treated as the article's "year"/category, shown as a badge linking to `#category/expa-YYYY`;
|
||||
every other tag id is a normal topic tag, shown as a pill linking to `#tag/tag-id`. Omit this
|
||||
whole segment (and its leading `--`) if the article has no tags.
|
||||
whole segment (and its leading `~`) if the article has no tags.
|
||||
|
||||
A leading underscore on the whole directory name — `_<slug>--...` — marks the article as a
|
||||
The separator is `~` (tilde), not a hyphen — deliberately, since a slug is expected to be plain
|
||||
kebab-case (single hyphens only) and `~` isn't something you'd type by accident while writing
|
||||
one, unlike an extra `-`.
|
||||
|
||||
A leading underscore on the whole directory name — `_<slug>~...` — marks the article as a
|
||||
**draft**: it's excluded from the list, search, and pagination, but still reachable directly by
|
||||
URL. Remove the underscore to publish it.
|
||||
|
||||
@@ -108,7 +112,7 @@ Steps:
|
||||
|
||||
1. Create the author directory if it doesn't exist: `cmjs/articles/author/`
|
||||
2. Create the post directory using the naming convention above, e.g.
|
||||
`cmjs/articles/author/my-article--16062026--kometa+expa-2026/`
|
||||
`cmjs/articles/author/my-article~16062026~kometa+expa-2026/`
|
||||
3. Create the Markdown file inside, named after the slug: `my-article.md`
|
||||
4. Optionally add a cover image beside it too, e.g. `photo.jpg`, and reference it from
|
||||
frontmatter with `image: photo.jpg`. Images live next to the article that uses them, not in a
|
||||
|
||||
@@ -151,16 +151,18 @@ function excerpt(content) {
|
||||
|
||||
// A post directory's own name is the sole authoritative source of its
|
||||
// slug, publish date, tags/category, and draft status — see the README's
|
||||
// "Adding an article" section. Format: `<slug>--<DDMMYYYY>[--tag1+tag2+…]`,
|
||||
// optionally prefixed with `_` for draft. Splitting on the whole name is
|
||||
// deliberate: a slug is expected not to contain "--" itself, the same way
|
||||
// it's already expected not to contain "/". Returns null for any directory
|
||||
// name that doesn't match — callers treat that as a silent skip, e.g. a
|
||||
// stray directory that isn't a post at all.
|
||||
// "Adding an article" section. Format: `<slug>~<DDMMYYYY>[~tag1+tag2+…]`,
|
||||
// optionally prefixed with `_` for draft. `~` (rather than e.g. "--") is
|
||||
// deliberate: a slug is expected to be plain kebab-case, and "~" isn't a
|
||||
// character anyone would type by accident while writing one — unlike a
|
||||
// double-hyphen separator, which collides with an easy slug typo (an extra
|
||||
// "-") and silently drops the whole article instead of erroring. Returns
|
||||
// null for any directory name that doesn't match — callers treat that as a
|
||||
// silent skip, e.g. a stray directory that isn't a post at all.
|
||||
function parseSlugDirName(name) {
|
||||
const draft = name.startsWith('_');
|
||||
const core = draft ? name.slice(1) : name;
|
||||
const [slug, dateSegment, tagsSegment] = core.split('--');
|
||||
const [slug, dateSegment, tagsSegment] = core.split('~');
|
||||
if (!slug || !dateSegment || !/^\d{8}$/.test(dateSegment)) return null;
|
||||
const day = dateSegment.slice(0, 2);
|
||||
const month = dateSegment.slice(2, 4);
|
||||
|
||||
Reference in new issue
Block a user