Use 8px radius for inline code + embedded images; Gruvbox figure captions; add AGENTS.md with system requirements
This commit is contained in:
@@ -0,0 +1,103 @@
|
|||||||
|
# AGENTS.md – Trilium Share Gruvbox Blog System
|
||||||
|
|
||||||
|
Public repository for the **Gruvbox public-share theme + blog system** that runs on a
|
||||||
|
[TriliumNext](https://github.com/TriliumNext/Trilium) instance (`notes.familie-zink.org`,
|
||||||
|
live blog: `richard.familie-zink.org`). This file captures the requirements and design
|
||||||
|
decisions so future work stays consistent.
|
||||||
|
|
||||||
|
## What this is
|
||||||
|
|
||||||
|
A blog built on Trilium's Public Share: a backend **blog generator** builds index/category/tag
|
||||||
|
pages, an RSS feed, a sitemap, a search index and a garden-state map from notes that carry a
|
||||||
|
`publish=true` label. Frontend `shareHtml` scripts add search, prev/next, reading time,
|
||||||
|
widget rendering (Mermaid/Excalidraw/MindMap) and a themed footer. All styling lives in one
|
||||||
|
CSS file (Gruvbox, light + dark, theme toggle without reload).
|
||||||
|
|
||||||
|
## Repository layout
|
||||||
|
|
||||||
|
| Path | Note in Trilium | Purpose |
|
||||||
|
|---|---|---|
|
||||||
|
| `blog_generator.js` | `blog_generator` (backend script) | builds index, categories, tags, feed, sitemap, `blog_data`, `state_map` |
|
||||||
|
| `blog_publish_manager.js` | `blog_publish_manager` (backend script) | mirrors notes between `Unpublished` and the blog on `publish` label changes |
|
||||||
|
| `theme/blog_share_theme.css` | `blog_share_theme.css` (`shareCss`) | the entire Gruvbox theme |
|
||||||
|
| `theme/favicon.svg`, `theme/cookie.woff2` | `favicon`, `Cookie` | site icon + BMC font |
|
||||||
|
| `lib/highlight.js`, `lib/hljs_line_numbers.js` | `highlight.js`, `hljs line numbers plugin` | code highlighting |
|
||||||
|
| `scripts/*.js` | one code note each (`.blog`), attached via `~shareHtml` | frontend snippets (verbatim content incl. `<script>`) |
|
||||||
|
| `templates/blog_article.html` | `Blog Article` | article template with promoted labels |
|
||||||
|
| `examples/*` | ignis8 icons/script | sample category logo |
|
||||||
|
| `generated/*` | `feed.xml`, `sitemap.xml`, `blog_data`, `state_map` | regenerated by the generator (reference only) |
|
||||||
|
| `assets/palette.png` | – | Gruvbox palette (from morhetz/gruvbox, MIT) |
|
||||||
|
|
||||||
|
## How the generator works (keep this intact)
|
||||||
|
|
||||||
|
- Collects notes with `publish=true` under the blog root (skips `blogGarden` subtrees).
|
||||||
|
- **Index**: page 1 = blog root, further pages as notes under `.blog` named by
|
||||||
|
`blogPagedFor` + `blogPagedNumber` labels, `shareAlias = <alias>-<n>` (`blog-2`, …).
|
||||||
|
- **Categories**: any top-level note under the blog root that is not a system note
|
||||||
|
(`Tags`, `.blog`, `Impressum`, `About Me`, `Search`) is a category; `blogGarden`
|
||||||
|
marks a growth-state garden. Category pages are paginated the same way.
|
||||||
|
- **Sorting**: index, categories, tags and `blog_data` are all sorted by publication
|
||||||
|
date descending (`date` label, fallback `dateCreated`). Never change this.
|
||||||
|
- **Pagination**: `POSTS_PER_PAGE = 10`. Prev/next on index/category pages link only
|
||||||
|
between that section's pages (server-side `.blog-pagination`), not globally.
|
||||||
|
- **Article prev/next** (`scripts/prev_next.js`) is scoped to the article's category
|
||||||
|
(`blog_data.articles[].category`); falls back to the global list when uncategorized.
|
||||||
|
- **Thumbnails** (`thumbSrc()`): prefer a child note of the article titled `*_thumb.*`
|
||||||
|
(e.g. `ngc281_thumb.jpg`) → `api/notes/<id>/download`; otherwise use the first `<img>`
|
||||||
|
from the note content. Layout: image left, summary right (`.blog-post-inner`),
|
||||||
|
`max-height:256px`, lazy-loaded. **There is no server-side resizing** – see "Limitations".
|
||||||
|
- Regenerates `feed.xml`, `sitemap.xml`, `state_map` (garden states) and `blog_data`
|
||||||
|
(search index: id/title/url/summary/tags/category). Sets `shareDescription` from `summary`.
|
||||||
|
|
||||||
|
## Wiring / attributes (the ground truth)
|
||||||
|
|
||||||
|
- All inheritable relations live on the **blog root**: `~shareCss → blog_share_theme.css`,
|
||||||
|
`~shareFavicon → favicon`, `~shareHtml → <each script>`, `~runOnNoteContentChange/…
|
||||||
|
→ blog_generator`, `~runOnAttributeChange/Creation → blog_publish_manager`.
|
||||||
|
- Every script note carries `shareHtmlLocation` (`head:end`, `body:end`, `content:start`,
|
||||||
|
`body:start`) and `shareHiddenFromTree`.
|
||||||
|
- `feed.xml` → `shareAlias=feed` + `shareRaw`; `sitemap.xml` → `shareAlias=sitemap.xml` + `shareRaw`.
|
||||||
|
- Generator + publish manager are `application/javascript;env=backend`; generator has `run=daily`.
|
||||||
|
- Digital Garden category: `blogGarden`, `label:state` definition
|
||||||
|
(`promoted,alias=Growth Condition,single,select,options=Seed;Seedling;Sprout;Sprouting;Bud;Evergreen;Draft;Review`, inheritable), `~shareHtml → garden h1 green`.
|
||||||
|
- On import the note IDs differ → replace the `__X_ID__` tokens in scripts/generator (see README).
|
||||||
|
|
||||||
|
## Theme / design rules (keep consistent)
|
||||||
|
|
||||||
|
- **Gruvbox palette** only: bg `#282828`/`#1d2021`, fg `#ebdbb2`, red `#fb4934`,
|
||||||
|
green `#b8bb26`, yellow `#fabd2f`, blue `#83a598`, purple `#d3869b`, aqua `#8ec07c`,
|
||||||
|
orange `#fe8019`; light-mode fades from Gruvbox Light.
|
||||||
|
- **Radius system** (user decision, 2026-08-28): `8px` for code blocks/code notes,
|
||||||
|
inline code, embedded images, diagrams (mermaid/mindmap/excalidraw) and thumbnails;
|
||||||
|
`10px` for blog cards; `6px` for chips/tags/buttons/inputs; `4px` for tiny menu icons.
|
||||||
|
Embedded images and inline code use the **same 8px** radius.
|
||||||
|
- Inline code: `#content code { border-radius:8px; padding:.1em .35em }` (dark bg in both themes).
|
||||||
|
- Embedded images: `#content img:not(.blog-thumb) { border-radius:8px }`.
|
||||||
|
- **Figure captions**: `#content figcaption` is a Gruvbox chip (secondary bg, highlight
|
||||||
|
border, 8px radius, muted italic text, centered).
|
||||||
|
- Images in the share are served full-size only (no resize endpoint) → keep the
|
||||||
|
`_thumb` child-note convention for small thumbnails.
|
||||||
|
- Built-in share footer navigation and book children list are hidden
|
||||||
|
(`#content-footer .navigation`, `#index`).
|
||||||
|
|
||||||
|
## Limitations / gotchas
|
||||||
|
|
||||||
|
- **Backend script module whitelist is hardcoded** (`dayjs`, `marked`, `turndown`,
|
||||||
|
`cheerio`, `axios`, `xml2js`, `escape-html`, `sanitize-html`, `lodash`); `sharp`,
|
||||||
|
`fs`, `child_process`, `http` etc. are blocked. Therefore **image resizing inside a
|
||||||
|
backend script is impossible** without patching Trilium source. Do not attempt to add
|
||||||
|
sharp-based code to the generator.
|
||||||
|
- Triggering the generator via an attribute change on the **blog root itself** is ignored
|
||||||
|
by the self-trigger guard (`isGeneratedNoteId(BLOG_ROOT_ID) → true`). To force a full
|
||||||
|
regeneration, change an attribute/content on a **published article** instead.
|
||||||
|
- The share never resizes images; the `_thumb` child-note convention is the intended path
|
||||||
|
for bandwidth-friendly thumbnails.
|
||||||
|
- Comments/commits in the repo are English; communication with the owner is German.
|
||||||
|
|
||||||
|
## Releasing changes
|
||||||
|
|
||||||
|
Edit the corresponding Trilium note (live), verify on `richard.familie-zink.org`, then mirror
|
||||||
|
the anonymized file into this repo (replace `richard.familie-zink.org` → `https://YOUR-INSTANCE.example.com`,
|
||||||
|
`Richard's Blog` → `Your Blog`, and the note-ID tokens → `__…__`), update `README.md` if the
|
||||||
|
feature list changed, commit and push to `main`. Never commit real note IDs, the ETAPI token,
|
||||||
|
or personal data (name/domain are allowed in the README demo badge only).
|
||||||
@@ -780,7 +780,7 @@ html.theme-light {
|
|||||||
background-color: #3c3836;
|
background-color: #3c3836;
|
||||||
color: #ebdbb2;
|
color: #ebdbb2;
|
||||||
border-color: #504945;
|
border-color: #504945;
|
||||||
border-radius: 4px;
|
border-radius: 8px;
|
||||||
padding: 0.1em 0.35em;
|
padding: 0.1em 0.35em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -798,10 +798,14 @@ html.theme-light #content code {
|
|||||||
border-color: #bdae93;
|
border-color: #bdae93;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Eingebettete Bilder: Radius wie Inline-Code ---------- */
|
/* ---------- Eingebettete Bilder: Radius wie Code-Blöcke (8px) ---------- */
|
||||||
|
#content figure.image {
|
||||||
|
margin: 1.25em auto;
|
||||||
|
}
|
||||||
|
|
||||||
#content figure img,
|
#content figure img,
|
||||||
#content img:not(.blog-thumb) {
|
#content img:not(.blog-thumb) {
|
||||||
border-radius: 4px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Bildunterschriften (Gruvbox) ---------- */
|
/* ---------- Bildunterschriften (Gruvbox) ---------- */
|
||||||
@@ -810,7 +814,12 @@ html.theme-light #content code {
|
|||||||
font-style: italic;
|
font-style: italic;
|
||||||
color: var(--text-menu);
|
color: var(--text-menu);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 6px;
|
margin-top: 8px;
|
||||||
|
padding: 4px 12px;
|
||||||
|
background: var(--background-secondary);
|
||||||
|
border: 1px solid var(--background-highlight);
|
||||||
|
border-radius: 8px;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hljs {
|
.hljs {
|
||||||
|
|||||||
Reference in New Issue
Block a user