Use 8px radius for inline code + embedded images; Gruvbox figure captions; add AGENTS.md with system requirements

This commit is contained in:
trilium-share-gruvbox
2026-08-28 14:55:08 +02:00
parent 302e48391c
commit a8d9c83ae7
2 changed files with 116 additions and 4 deletions
+103
View File
@@ -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).
+13 -4
View File
@@ -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 {