diff --git a/js/blog.js b/js/blog.js index e77e9a3..930ae75 100644 --- a/js/blog.js +++ b/js/blog.js @@ -3,8 +3,6 @@ const ATTACHMENT_DIR = BLOG_DIR + 'files/'; const MANIFEST = BLOG_DIR + 'manifest.json'; const TXT_EXT = /\.(txt|text)$/i; const ATTACHMENT_RE = /\[\[(?:file|attachment):\s*([^\]]+)\]\]/gi; -const BLOG_COLLAPSE_THRESHOLD = 300; // characters before collapsing -const BLOG_PREVIEW_LINES = 3; // number of lines shown in preview function escapeHtml(value) { return value @@ -143,16 +141,11 @@ function renderBlogEntries(entries) { const meta = document.createElement('div'); meta.className = 'blog-meta'; - meta.textContent = entry.date - ? formatDate(entry.date) - : entry.dateLabel || 'Date not provided'; - + meta.textContent = entry.date ? formatDate(entry.date) : entry.dateLabel || 'Date not provided'; const body = document.createElement('div'); body.className = 'blog-body'; - const paragraphs = createParagraphs(entry.body); - if (!paragraphs.length) { const empty = document.createElement('p'); empty.textContent = 'No content yet.'; @@ -161,78 +154,65 @@ function renderBlogEntries(entries) { paragraphs.forEach((p) => body.appendChild(p)); } - - let content = body; - - // Collapse long posts - if (entry.body.length > BLOG_COLLAPSE_THRESHOLD) { - const wrapper = document.createElement('div'); - wrapper.className = 'blog-collapse'; - - const preview = document.createElement('p'); - preview.className = 'blog-preview'; - - preview.textContent = entry.body - .split('\n') - .filter(line => line.trim()) - .slice(0, BLOG_PREVIEW_LINES) - .join('\n'); - - - const button = document.createElement('button'); - button.className = 'blog-expand-button'; - button.textContent = 'Read more'; - - - body.style.display = 'none'; - - button.addEventListener('click', () => { - const expanded = body.style.display !== 'none'; - - body.style.display = expanded ? 'none' : 'block'; - preview.style.display = expanded ? 'block' : 'none'; - button.textContent = expanded ? 'Read more' : 'Show less'; - }); - - - wrapper.appendChild(preview); - wrapper.appendChild(button); - wrapper.appendChild(body); - - content = wrapper; - } - - if (entry.attachments && entry.attachments.length) { const attachTitle = document.createElement('div'); attachTitle.className = 'blog-meta'; attachTitle.textContent = 'Attachments:'; - const list = document.createElement('ul'); list.className = 'blog-attachment-list'; - entry.attachments.forEach((attachment) => { const item = document.createElement('li'); const link = document.createElement('a'); - link.href = ATTACHMENT_DIR + encodeURI(attachment); link.target = '_blank'; link.rel = 'noopener noreferrer'; link.textContent = attachment; - item.appendChild(link); list.appendChild(item); }); - article.appendChild(attachTitle); article.appendChild(list); } - article.appendChild(title); article.appendChild(meta); - article.appendChild(content); - + article.appendChild(body); container.appendChild(article); }); -} \ No newline at end of file +} + +function sortEntries(entries) { + return entries.slice().sort((a, b) => { + if (a.date && b.date) return b.date - a.date; + if (a.date) return -1; + if (b.date) return 1; + return a.filename.localeCompare(b.filename); + }); +} + +async function initBlog() { + const fileNames = await loadBlogFiles(); + if (!fileNames.length) { + renderBlogEntries([]); + return; + } + + const promises = fileNames + .filter((name) => TXT_EXT.test(name)) + .map(async (name) => { + try { + const response = await fetch(BLOG_DIR + name, { cache: 'no-cache' }); + if (!response.ok) throw new Error('Failed to load ' + name); + const text = await response.text(); + return parseBlogText(text, name); + } catch (error) { + console.warn(error); + return null; + } + }); + + const entries = (await Promise.all(promises)).filter(Boolean); + renderBlogEntries(sortEntries(entries)); +} + +document.addEventListener('DOMContentLoaded', initBlog);