Files
trilium_share_gruvbox/README.md
T

12 KiB
Raw Blame History

Trilium Share Gruvbox Blog System

A complete public-share blog system + Gruvbox theme for TriliumNext. It turns a normal Trilium note tree into a themed, searchable blog with categories, an RSS feed, a sitemap, a digital garden (growth states) and client-side rendering of Mermaid, Excalidraw and mind-map notes.

Everything is driven by Trilium's built-in Public Share feature plus a few frontend/backend scripts no external dependencies (except highlight.js, vendored in lib/).

Gruvbox palette

Features

  • Gruvbox light/dark theme for the share, with a theme toggle in the header.
  • Blog index, category pages, sub-categories, tags and tag overview.
  • Article metadata: date, category, summary, tags, prev/next navigation, reading time.
  • Digital Garden: state labels (Seed → Evergreen, Draft, Review) rendered as badges and colour-coded growth tables.
  • Search (client-side over a generated index), RSS feed and sitemap.xml.
  • Widget rendering for Mermaid, Excalidraw (canvas) and MindElixir (mind map) notes, with a collapsible, highlighted "Source" block and copy button.
  • Code highlighting (highlight.js + line numbers) and copy buttons on all code boxes.
  • Optional "Buy me a coffee" button with locally-hosted Cookie font.
  • blog_generator (backend) builds index/feed/sitemap/search-data; blog_publish_manager moves notes between an Unpublished staging area and the live blog.

Repository layout

Path Content Trilium note type / mime
blog_generator.js backend script that generates index, feed, sitemap, search data, category & tag pages code, application/javascript;env=backend
blog_publish_manager.js backend script that mirrors notes between Unpublished and the blog code, application/javascript;env=backend
theme/blog_share_theme.css the Gruvbox share theme code, text/css
theme/favicon.svg default site favicon code (SVG)
theme/cookie.woff2 "Cookie" font for the Buy me a coffee button file, font/woff2
lib/highlight.js vendored highlight.js code, application/javascript
lib/hljs_line_numbers.js highlight.js line-numbers plugin code
scripts/*.js frontend share snippets (content is pasted verbatim into a code note, including the <script>/<style> wrapper) code
templates/blog_article.html article template with promoted labels text
examples/* sample category logo + menu icon script (ignis8) code / SVG
generated/* reference output, regenerated automatically by blog_generator.js code / xml

The file content of a scripts/* note already contains the <script> / <style> tags. When you create the code note, paste the whole file into the note content.

Prerequisites

  • TriliumNext server with Public Share enabled (Options → Public access).
  • A public hostname (optional but recommended, e.g. for sitemap.xml / OG tags).
  • Basic familiarity with Trilium attributes (labels & relations).

Installation

1. Create the note structure

root
└── Blog                    (book)
    ├── Richard's Blog      (book)  ← blog root, the shared note
    │   ├── .blog           (book)  ← system notes (scripts, css, data)
    │   ├── Astrophotography (book) ← example category
    │   ├── Electronic      (book)
    │   ├── Leathercraft    (book)
    │   ├── Digital Garden  (book)  ← growth-state garden category
    │   ├── Tags            (text)  ← auto-filled tag overview
    │   ├── About Me        (text)
    │   └── Impressum       (text)
    ├── Unpublished         (book)  ← staging area
    ├── blog_generator      (code, backend)
    └── blog_publish_manager (code, backend)

You can use any titles; the generator finds notes by the constants at the top of blog_generator.js (BLOG_ROOT_NOTE_ID, BLOG_SYSTEM_NOTE_ID, TAGS_SECTION_TITLE).

2. Create the code notes

Under .blog create one code note per file, using the file name as the note title (optional, but matches the generator):

Note title File mime
blog_share_theme.css theme/blog_share_theme.css text/css
favicon theme/favicon.svg (SVG)
Cookie theme/cookie.woff2 font/woff2 (file note)
highlight.js lib/highlight.js application/javascript
hljs line numbers plugin lib/hljs_line_numbers.js text/javascript
hide home title scripts/hide_home_title.js text/html
garden h1 green scripts/garden_h1_green.js text/html
table column hover scripts/table_column_hover.js text/html
blog card click scripts/blog_card_click.js text/html
garden row click scripts/garden_row_click.js text/html
code note highlight scripts/code_note_highlight.js text/html
code copy & lines scripts/code_copy_lines.js text/html
title state badge scripts/title_state_badge.js text/html
bmc button scripts/bmc_button.js text/html
logo share alias scripts/logo_share_alias.js text/html
prev next scripts/prev_next.js text/html
reading time scripts/reading_time.js text/html
search header scripts/search_header.js text/html
note fallback scripts/note_fallback.js text/html
feed.xml generated/feed.xml code (regenerated)
sitemap.xml generated/sitemap.xml code (regenerated)
state_map generated/state_map.js text/html (regenerated)
blog_data generated/blog_data.js text/html (regenerated)

Also create, under the Blog book: blog_generator (from blog_generator.js, mime application/javascript;env=backend) and blog_publish_manager (from blog_publish_manager.js, mime application/javascript;env=backend).

3. Wire the attributes

On the blog root note (Richard's Blog), add:

Attribute Value Inheritable
shareRoot true
shareAlias blog
shareIndex (empty)
shareDescription e.g. Project documentation & technical blog
shareOpenGraphURL https://YOUR-INSTANCE.example.com/
shareOpenGraphColor #83a598
iconClass bx bx-edit-alt
~shareCss blog_share_theme.css yes
~shareFavicon favicon yes
~shareHtml table column hover, blog card click, garden row click, code note highlight, code copy & lines, state_map, title state badge, bmc button, logo share alias, blog_data, prev next, reading time, search header, ignis8 menu icon (optional), note fallback yes
~shareHtml hide home title no (index only)
~runOnNoteContentChange, ~runOnAttributeChange, ~runOnNoteCreation, ~runOnNoteTitleChange, ~runOnAttributeCreation, ~runOnBranchDeletion, ~runOnChildNoteCreation blog_generator yes
~runOnAttributeChange, ~runOnAttributeCreation blog_publish_manager yes

On the script notes (under .blog), add:

Note Attribute
hide home title shareHtmlLocation=head:end, shareHiddenFromTree
garden h1 green shareHtmlLocation=head:end, shareHiddenFromTree
state_map shareHtmlLocation=body:start, shareHiddenFromTree
title state badge shareHtmlLocation=content:start, shareHiddenFromTree
every other script shareHtmlLocation=body:end, shareHiddenFromTree
highlight.js shareHiddenFromTree
feed.xml shareAlias=feed, shareRaw, shareHiddenFromTree
sitemap.xml shareAlias=sitemap.xml, shareRaw, shareHiddenFromTree
.blog (book) shareHiddenFromTree, viewType=list

On the Digital Garden category note (and any other garden category), add:

Attribute Value Inheritable
blogGarden (empty)
shareAlias digital-garden
iconClass bx bx-leaf
label:state promoted,alias=Growth Condition,single,select,options=Seed;Seedling;Sprout;Sprouting;Bud;Evergreen;Draft;Review yes
~shareHtml garden h1 green

Categories: any top-level note under the blog root (that is not Tags, .blog, About Me, Impressum or Search) is treated as a category. blogGarden marks it as a growth-state garden.

4. Replace the placeholder note IDs

Trilium assigns random note IDs on creation, so the scripts that reference notes by ID contain placeholder tokens. Replace every __TOKEN__ with the real note ID of the corresponding note:

Token Replace with note
__BLOG_ROOT_ID__ Richard's Blog
__BLOG_SYSTEM_ID__ .blog
__UNPUBLISHED_ROOT_ID__ Unpublished
__BLOG_GENERATOR_ID__ blog_generator
__HIDE_HOME_TITLE_ID__ hide home title
__HLJS_ID__ highlight.js
__HLJS_LN_ID__ hljs line numbers plugin
__COOKIE_FONT_ID__ Cookie
__TITLE_ICON_ID__ (only needed for the ignis8 example)
__CATEGORY_NOTE_ID__ (only needed for the ignis8 example)

Then edit the constants at the top of blog_generator.js and blog_publish_manager.js:

  • BLOG_ROOT_NOTE_ID / BLOG_ROOT_ID → the blog root note ID
  • BLOG_SYSTEM_NOTE_ID → the .blog note ID
  • UNPUBLISHED_ROOT_ID → the Unpublished note ID
  • BLOG_GENERATOR_ID → the generator note ID
  • SHARE_BASE → your public base URL, e.g. https://YOUR-INSTANCE.example.com
  • SITE_TITLE, SITE_DESCRIPTION → your blog name/tagline

5. Enable Public Share and generate

  1. On Richard's Blog right-click → Share → enable sharing.
  2. Run the generator once: execute the blog_generator script (e.g. press play in the script editor, or trigger any attribute/content change). It is also wired to run automatically on every relevant change (runOn*), and you can add run=daily to it for a nightly run.
  3. Open the share (options → Public access → URL) the blog index is generated at the share root.

6. Publish an article

  1. Create a note from the templates/blog_article.html content (or clone the template note). It promotes the publish, date, category, summary, shareAlias and tags labels.
  2. Put it under a category inside Richard's Blog and set publish=true.
  3. To keep it private, put it under Unpublished instead blog_publish_manager clones it into the matching category (and back) when you flip publish.

7. Optional: clean hostname via nginx

If you want a clean domain instead of /share, proxy it and rewrite / to /share/:

server {
    server_name blog.example.com;
    location / {
        proxy_pass https://notes.example.com/share/;
        proxy_set_header Host notes.example.com;
    }
}

How the generator works

  • Walks the blog root and collects notes with publish=true.
  • Writes the index (article cards), category pages (sub-category chips + articles, respecting a <!-- blog:articles --> marker so your hand-written intro text is kept), tag pages and the tags overview.
  • Regenerates feed.xml (RSS), sitemap.xml, state_map (garden states) and blog_data (search index used by the header search + prev/next).
  • Sets shareDescription on every published note from its summary.

Customisation

  • Theme: edit theme/blog_share_theme.css (Gruvbox light/dark via html.theme-light/dark).
  • Buy me a coffee: edit scripts/bmc_button.js (link, text, copyright) the font is referenced via __COOKIE_FONT_ID__.
  • Category logos: copy the examples/ icon + ignis8_menu_icon.js pattern to give a category a custom menu icon and title logo.

Acknowledgements

This theme and blog system was created with the help of Opencode and Deepseek V4 Flash.

License

The vendored highlight.js is licensed under BSD-3-Clause (see its header). All other files in this repository are provided as-is see the original author's repository for details.