diff --git a/README.md b/README.md
index 6ffc8ad..ba17150 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,9 @@ no external dependencies (except `highlight.js`, vendored in `lib/`).
- 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 thumbnails**: each post card shows the first image of the article on the left
- (max 256×256, bounded by the teaser height), summary on the right, lazy-loaded.
+ (bounded by the teaser height), summary on the right, lazy-loaded. If an article has a child
+ note named `*_thumb.*` (e.g. `ngc281_thumb.jpg`), that image is used instead – ideal for
+ serving small pre-made thumbnails.
- **Pagination**: 10 posts per page on the index and category pages, with prev/next
navigation between the pages; article prev/next links stay within the article's category.
- Article metadata: date, category, summary, tags, prev/next navigation, reading time.
diff --git a/blog_generator.js b/blog_generator.js
index 8550297..4b29c66 100644
--- a/blog_generator.js
+++ b/blog_generator.js
@@ -101,7 +101,11 @@ function run() {
return SHARE_BASE + "/" + encodeURIComponent("tag-" + slugifyTag(t));
}
- function firstImageSrc(a) {
+ function thumbSrc(a) {
+ try {
+ const thumbs = (a.getChildNotes() || []).filter(n => /_thumb\.[A-Za-z0-9]+$/i.test(n.title));
+ if (thumbs.length) return "api/notes/" + thumbs[0].noteId + "/download";
+ } catch (e) {}
try {
const m = String(a.getContent() || "").match(/
]+src="([^"]+)"/);
return m ? m[1] : "";
@@ -118,7 +122,7 @@ function run() {
const summary = a.getLabelValue("summary") || "";
const link = `${SHARE_BASE}/${encodeURIComponent(a.getLabelValue("shareAlias") || a.noteId)}`;
const tags = tagList(a);
- const thumb = firstImageSrc(a);
+ const thumb = thumbSrc(a);
lines.push('');
lines.push('