Add pagination (10 posts/page), category-scoped prev/next, hide share footer nav; demo link in README

This commit is contained in:
trilium-share-gruvbox
2026-08-28 13:55:54 +02:00
parent 74cf0a2b3b
commit 1664e55e4e
4 changed files with 129 additions and 24 deletions
+87 -16
View File
@@ -6,6 +6,8 @@ const BASE_URL = SHARE_BASE + "/" + BLOG_ALIAS;
const SITE_TITLE = "Your Blog";
const SITE_DESCRIPTION = "Project documentation & technical blog by the author";
const TAGS_SECTION_TITLE = "Tags";
const HIDE_HOME_TITLE_NOTE_ID = "__HIDE_HOME_TITLE_ID__";
const POSTS_PER_PAGE = 10;
function isInSubtree(note, targetId) {
try {
@@ -22,6 +24,8 @@ function isInSubtree(note, targetId) {
function isGeneratedNoteId(id) {
try {
if (id === BLOG_ROOT_NOTE_ID) return true;
const n = api.getNote(id);
if (n && n.hasLabel("blogPagedFor")) return true;
const systemNote = api.getNote(BLOG_SYSTEM_NOTE_ID);
if (systemNote) {
const feedNote = systemNote.getChildNotes().find(n => n.title === "feed.xml");
@@ -160,8 +164,77 @@ function run() {
return html;
}
function buildIndexHtml() {
return renderArticles(articles) || '<p>No articles published yet.</p>';
function pageUrl(aliasBase, p) {
return SHARE_BASE + "/" + (p <= 1 ? aliasBase : aliasBase + "-" + p);
}
function paginationHtml(page, totalPages, aliasBase) {
if (totalPages <= 1) return "";
let html = '<nav class="blog-pagination">';
if (page > 1) {
html += '<a class="blog-pn prev" href="' + pageUrl(aliasBase, page - 1) + '"><span class="blog-pn-label">Newer</span></a>';
} else {
html += '<span class="blog-pn empty"></span>';
}
html += '<span class="blog-page-num">Page ' + page + ' of ' + totalPages + '</span>';
if (page < totalPages) {
html += '<a class="blog-pn next" href="' + pageUrl(aliasBase, page + 1) + '"><span class="blog-pn-label">Older</span></a>';
} else {
html += '<span class="blog-pn empty"></span>';
}
html += '</nav>';
return html;
}
function syncPageNotes(pageLabel, aliasBase, totalPages, list, garden, hideTitle) {
const systemNote = api.getNote(BLOG_SYSTEM_NOTE_ID);
if (!systemNote) return;
const existing = systemNote.getChildNotes().filter(n => n.getLabelValue("blogPagedFor") === pageLabel);
for (let p = 2; p <= totalPages; p++) {
let note = existing.find(n => n.getLabelValue("blogPagedNumber") === String(p));
const created = !note;
if (!note) {
const res = api.createTextNote(systemNote.noteId, "Blog page " + p + " (" + pageLabel + ")", "");
note = res.note ? res.note : res;
}
const slice = list.slice((p - 1) * POSTS_PER_PAGE, p * POSTS_PER_PAGE);
let body = garden ? buildGardenTable(note, slice) : (renderArticles(slice) || '<p>No articles.</p>');
body += paginationHtml(p, totalPages, aliasBase);
if (note.getContent() !== body) {
note.setContent(body);
note.save();
}
note.setLabel("blogPagedFor", pageLabel);
note.setLabel("blogPagedNumber", String(p));
note.setLabel("shareAlias", aliasBase + "-" + p);
note.setLabel("shareHiddenFromTree", "");
if (hideTitle && !note.hasRelation("shareHtml", HIDE_HOME_TITLE_NOTE_ID)) {
note.setRelation("shareHtml", HIDE_HOME_TITLE_NOTE_ID);
}
note.save();
api.log("blog_generator: page " + pageLabel + " #" + p + (created ? " created" : " updated"));
}
for (const n of existing) {
const num = parseInt(n.getLabelValue("blogPagedNumber") || "999", 10);
if (num > totalPages) {
api.log("blog_generator: removing obsolete page note " + n.title);
n.deleteNote();
}
}
}
function buildIndex() {
const pageCount = Math.max(1, Math.ceil(articles.length / POSTS_PER_PAGE));
const body = (renderArticles(articles.slice(0, POSTS_PER_PAGE)) || '<p>No articles published yet.</p>')
+ paginationHtml(1, pageCount, BLOG_ALIAS);
if (blogRoot.getContent() !== body) {
blogRoot.setContent(body);
blogRoot.save();
api.log("blog_generator: index updated (" + articles.length + " articles, " + pageCount + " pages)");
} else {
api.log("blog_generator: index unchanged");
}
syncPageNotes("index", BLOG_ALIAS, pageCount, articles, false, true);
}
function buildFeedXml() {
@@ -286,7 +359,8 @@ function run() {
title: a.title,
url: SHARE_BASE + "/" + encodeURIComponent(a.getLabelValue("shareAlias") || a.noteId),
summary: a.getLabelValue("summary") || "",
tags: tagList(a)
tags: tagList(a),
category: a.getLabelValue("category") || ""
}));
const html = `<script>window.blogData = ${JSON.stringify({ articles: list })};</script>`;
if (dataNote.getContent() !== html) {
@@ -330,8 +404,8 @@ function run() {
note.setContent(html);
note.save();
}
if (!note.hasRelation("shareHtml", "__HIDE_HOME_TITLE_ID__")) {
note.setRelation("shareHtml", "__HIDE_HOME_TITLE_ID__");
if (!note.hasRelation("shareHtml", HIDE_HOME_TITLE_NOTE_ID)) {
note.setRelation("shareHtml", HIDE_HOME_TITLE_NOTE_ID);
note.save();
}
const alias = "tag-" + slugifyTag(tagName);
@@ -440,17 +514,21 @@ function run() {
}
html += "</div>\n";
}
const pageCount = Math.max(1, Math.ceil(articlesList.length / POSTS_PER_PAGE));
const aliasBase = catNote.getLabelValue("shareAlias") || catNote.noteId;
if (catNote.hasLabel("blogGarden")) {
html += buildGardenTable(catNote, articlesList);
html += buildGardenTable(catNote, articlesList.slice(0, POSTS_PER_PAGE));
} else {
html += renderArticles(articlesList) || '<p>No articles yet.</p>';
html += renderArticles(articlesList.slice(0, POSTS_PER_PAGE)) || '<p>No articles yet.</p>';
}
html += paginationHtml(1, pageCount, aliasBase);
if (catNote.getContent() !== html) {
catNote.setContent(html);
catNote.save();
api.log("blog_generator: category page updated: " + catNote.title);
api.log("blog_generator: category page updated: " + catNote.title + " (" + pageCount + " pages)");
}
syncPageNotes("cat:" + catNote.title, aliasBase, pageCount, articlesList, catNote.hasLabel("blogGarden"), false);
}
}
@@ -475,14 +553,7 @@ function run() {
}
}
const indexHtml = buildIndexHtml();
if (blogRoot.getContent() !== indexHtml) {
blogRoot.setContent(indexHtml);
blogRoot.save();
api.log("blog_generator: index updated (" + articles.length + " articles)");
} else {
api.log("blog_generator: index unchanged");
}
buildIndex();
const systemNote = api.getNote(BLOG_SYSTEM_NOTE_ID);
const feedNote = systemNote.getChildNotes().find(n => n.title === "feed.xml");