diff --git a/README.md b/README.md index 7474a09..eee7646 100644 --- a/README.md +++ b/README.md @@ -13,15 +13,17 @@ A minimal CMS where articles are Markdown files rendered in the browser. No buil ## Features - **Dark mode** — automatically follows the OS `prefers-color-scheme` setting; no toggle needed. -- **Client-side search** — the search box in the header filters all articles by title, description, author, and category in-memory. Navigates to `#search/query` so results are bookmarkable. +- **Client-side search** — the search box in the header filters all articles by title, description, author, category, and tags in-memory. Navigates to `#search/query` so results are bookmarkable. - **Reading time** — estimated from the article word count (200 wpm) and shown on list cards and in article headers. Computed automatically; no frontmatter field needed. - **Table of contents** — auto-generated from `h2`/`h3` headings and inserted at the top of the article body. Only appears when the article has three or more headings. - **Back link** — a "← Back to articles" link above every article for one-click navigation back to the list. - **Pagination** — article list paginates at 20 articles per page; page state is encoded in the hash so browser history works. -- **Author and category filtering** — clicking an author name or category badge shows a filtered list. Both support pagination. +- **Author, category, and tag filtering** — clicking an author name, category badge, or tag pill shows a filtered list. All three support pagination. - **Responsive layout** — layout, cards, images, and pagination all adapt to narrow screens (breakpoint at 640 px). - **Keyboard navigation** — all interactive elements have visible `:focus-visible` outlines for keyboard users. - **Author profiles** — a profile card with bio and social links is shown at the top of each author's article list. Created by adding `articles/{author}/{author}.md`. +- **Offline-friendly caching** — discovered articles are cached in IndexedDB, so repeat visits skip re-fetching content that hasn't changed. +- **Translatable UI** — every UI string is looked up from a locale JSON file (English, Czech, and Slovak ship by default); adding a language needs no code changes. ## Project structure @@ -38,11 +40,12 @@ cmjs/ └── cmjs/ # App content — articles, templates, component styles ├── css/ │ └── components/ - │ ├── card.css # Article list cards and filter heading - │ ├── article.css # Single article view, back link, hero image - │ ├── content.css # Rendered markdown styles (.content *) - │ ├── pagination.css # Prev/next page navigation - │ └── toc.css # Auto-generated table of contents + │ ├── card.css # Article list cards and filter heading + │ ├── article.css # Single article view, back link, hero image + │ ├── content.css # Rendered markdown styles (.content *) + │ ├── pagination.css # Prev/next page navigation + │ ├── toc.css # Auto-generated table of contents + │ └── author-profile.css # Author profile card (avatar, bio, social links) ├── js/ │ ├── config.js # BASE_URL, MARKED_URL, PICTURES_URL (all via import.meta.url) │ ├── frontmatter.js # parseFrontmatter() — pure YAML-front parser @@ -58,8 +61,11 @@ cmjs/ │ ├── cs.json # Czech translation │ └── sk.json # Slovak translation ├── templates/ - │ ├── card.html # Article list card layout - │ └── article.html # Full article view layout + │ ├── card.html # Article list card layout + │ ├── article.html # Full article view layout + │ └── author-profile.html # Author profile card layout + ├── blog-config/ + │ └── tags.json # Tag id → human-readable label registry — see "Tag labels" below ├── articles/ │ └── author/ # One directory per author │ ├── author.md # Author profile (optional) @@ -87,6 +93,24 @@ cmjs/ `author` is derived from the directory path — no frontmatter field needed for it. Publish date, tags, and category are derived from the `.date`/`.tag` marker files, not frontmatter. +### Tag labels + +A `.tag` marker's filename is just an id (e.g. `kometa`) — the human-readable label shown in +the sidebar and on tag pills comes from `cmjs/blog-config/tags.json`: + +```json +{ + "schemaVersion": 1, + "tags": [ + { "id": "kometa", "label": "Comet", "description": "", "aliases": [], "active": true } + ] +} +``` + +Registering an id here is optional — an unregistered tag id still works, it just displays as +its raw id instead of a friendly label. `expa-YYYY` year ids don't need to be registered here; +they're recognised automatically by pattern and don't use this label registry. + ### Frontmatter format ```yaml @@ -163,10 +187,12 @@ Author names and category tags on each card and article are clickable links to t ## Customising the layout -The HTML structure for the article list card and the full article view live in `cmjs/templates/`: +The HTML structure for the article list card, the full article view, and the author profile +card live in `cmjs/templates/`: - `cmjs/templates/card.html` — the card shown in the article list - `cmjs/templates/article.html` — the full article view (header, hero image, content) +- `cmjs/templates/author-profile.html` — the profile card (avatar, bio, social links) Edit these files directly to change layout — no JS changes needed. Elements are identified by `data-field` attributes, which is how the JS modules find and populate them. Keep existing `data-field` values when rearranging; add new ones if you add new fields. @@ -214,9 +240,10 @@ To add cmjs to any HTML page, three things are needed: the CSS, the two mount-po + ``` -The site-level CSS files (`reset.css`, `header.css`, `layout.css`) are optional — they style the shell around the CMS. If your page already has a layout and reset, you can skip them and only load the component stylesheets. Note that `reset.css` also defines the CSS custom properties (colours, radius) used throughout — if you skip it, define the variables yourself. +The site-level CSS files (`reset.css`, `header.css`, `layout.css`) are optional — they style the shell around the CMS. If your page already has a layout and reset, you can skip them and only load the component stylesheets. Note that `reset.css` also defines the CSS custom properties (colours, radius) used throughout — if you skip it, define the variables yourself. `author-profile.css` is only needed if any of your authors have a profile file (see "Author profiles" above) — safe to skip otherwise. ### 2. Mount points — in ``