Add pagination (10 posts/page), category-scoped prev/next, hide share footer nav; demo link in README
This commit is contained in:
+87
-16
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user