Updated layout, added ability to make new sections, added new block types, increased layout size by 30%

This commit is contained in:
nathan
2026-05-01 14:37:36 -04:00
parent a472255a94
commit d0200f3975
7 changed files with 841 additions and 35 deletions

View File

@@ -5,6 +5,8 @@
*/
class BlockRenderer {
static galleryUid = 0;
static render(blocks) {
if (!Array.isArray(blocks)) return '';
return blocks.map(function(block) { return BlockRenderer.renderBlock(block); }).join('\n');
@@ -17,6 +19,8 @@ class BlockRenderer {
case 'paragraph': return BlockRenderer.renderParagraph(block);
case 'image': return BlockRenderer.renderImage(block);
case 'quote': return BlockRenderer.renderQuote(block);
case 'fact-panel': return BlockRenderer.renderFactPanel(block);
case 'timeline-card': return BlockRenderer.renderTimelineCard(block);
case 'gallery': return BlockRenderer.renderGallery(block);
case 'grid4': return BlockRenderer.renderGrid4(block);
case 'statistics': return BlockRenderer.renderStatistics(block);
@@ -48,15 +52,170 @@ class BlockRenderer {
+ '</blockquote>';
}
static renderGallery(block) {
var images = block.images || [];
var items = images.map(function(img) {
return '<div class="gallery-item">'
+ '<img src="' + (img.src || '') + '" alt="' + (img.alt || '') + '" loading="lazy">'
+ (img.caption ? '<div class="gallery-item-caption">' + img.caption + '</div>' : '')
+ '</div>';
static renderFactPanel(block) {
var title = block.title || 'Fact Briefing';
var factItems = block.facts || block.items || [];
var facts = factItems.map(function(item) {
if (typeof item === 'string') return item;
return item && item.text ? item.text : '';
}).filter(function(text) {
return String(text).trim() !== '';
});
if (facts.length === 0) {
facts = ['Add fact entries in the builder to populate this panel.'];
}
var listHtml = facts.map(function(text) {
return '<li>' + text + '</li>';
}).join('');
return '<div class="block block-gallery"><div class="gallery-scroll">' + items + '</div></div>';
return '<section class="block block-fact-panel fact-box">'
+ '<h3>' + title + '</h3>'
+ '<ul class="fact-panel-list">' + listHtml + '</ul>'
+ '</section>';
}
static renderTimelineCard(block) {
return '<article class="block block-timeline-card">'
+ '<header class="block-timeline-header">'
+ '<span class="block-timeline-date">' + (block.date || '') + '</span>'
+ '<h4 class="block-timeline-title">' + (block.title || '') + '</h4>'
+ '</header>'
+ '<p class="block-timeline-text">' + (block.text || '') + '</p>'
+ '</article>';
}
static renderGallery(block) {
var images = Array.isArray(block.images) ? block.images.filter(function(img) {
return img && img.src;
}) : [];
if (images.length === 0) {
return '<div class="block block-gallery"><div class="gallery-empty">No gallery images configured.</div></div>';
}
// Backward compatible: explicit strip mode keeps the original horizontal gallery.
var mode = (block.mode || 'carousel').toLowerCase();
if (mode === 'strip') {
var stripItems = images.map(function(img) {
return '<div class="gallery-item">'
+ '<img src="' + (img.src || '') + '" alt="' + (img.alt || '') + '" loading="lazy">'
+ (img.caption ? '<div class="gallery-item-caption">' + img.caption + '</div>' : '')
+ '</div>';
}).join('');
return '<div class="block block-gallery"><div class="gallery-scroll">' + stripItems + '</div></div>';
}
var id = 'gallery-' + (++BlockRenderer.galleryUid);
var autoplay = block.autoplay === false ? '0' : '1';
var intervalSec = parseInt(block.intervalSec, 10);
if (isNaN(intervalSec)) intervalSec = 5;
intervalSec = Math.max(2, Math.min(intervalSec, 15));
var showDots = block.showDots === false ? '0' : '1';
var showArrows = block.showArrows === false ? '0' : '1';
var slides = images.map(function(img, index) {
return '<figure class="gallery-slide' + (index === 0 ? ' is-active' : '') + '" data-slide-index="' + index + '">'
+ '<img src="' + (img.src || '') + '" alt="' + (img.alt || '') + '" loading="lazy">'
+ (img.caption ? '<figcaption class="gallery-slide-caption">' + img.caption + '</figcaption>' : '')
+ '</figure>';
}).join('');
var dots = images.map(function(_, index) {
return '<button type="button" class="gallery-dot' + (index === 0 ? ' is-active' : '') + '" data-gallery-dot="' + index + '" aria-label="Go to image ' + (index + 1) + '"></button>';
}).join('');
return '<div class="block block-gallery gallery-mode-carousel" id="' + id + '" data-gallery="1" data-autoplay="' + autoplay + '" data-interval-ms="' + (intervalSec * 1000) + '">'
+ '<div class="gallery-carousel">'
+ '<div class="gallery-slides">' + slides + '</div>'
+ (showArrows === '1' && images.length > 1
? '<button type="button" class="gallery-nav gallery-nav-prev" data-gallery-prev aria-label="Previous image">&#x2039;</button>'
+ '<button type="button" class="gallery-nav gallery-nav-next" data-gallery-next aria-label="Next image">&#x203A;</button>'
: '')
+ '</div>'
+ (showDots === '1' && images.length > 1 ? '<div class="gallery-dots">' + dots + '</div>' : '')
+ '</div>';
}
static initGalleries(root) {
var scope = root || document;
if (!scope || !scope.querySelectorAll) return;
scope.querySelectorAll('[data-gallery="1"]').forEach(function(gallery) {
if (gallery.dataset.galleryInit === '1') return;
gallery.dataset.galleryInit = '1';
var slides = Array.from(gallery.querySelectorAll('.gallery-slide'));
if (slides.length <= 1) return;
var dots = Array.from(gallery.querySelectorAll('[data-gallery-dot]'));
var nextBtn = gallery.querySelector('[data-gallery-next]');
var prevBtn = gallery.querySelector('[data-gallery-prev]');
var index = 0;
var timerId = null;
var autoplay = gallery.dataset.autoplay !== '0';
var intervalMs = parseInt(gallery.dataset.intervalMs, 10);
if (isNaN(intervalMs)) intervalMs = 5000;
intervalMs = Math.max(2000, Math.min(intervalMs, 15000));
function showAt(newIndex) {
index = (newIndex + slides.length) % slides.length;
slides.forEach(function(slide, i) {
slide.classList.toggle('is-active', i === index);
});
dots.forEach(function(dot, i) {
dot.classList.toggle('is-active', i === index);
});
}
function stopTimer() {
if (timerId) {
clearTimeout(timerId);
timerId = null;
}
}
function scheduleNext() {
stopTimer();
if (!autoplay) return;
timerId = setTimeout(function tick() {
if (!document.body.contains(gallery)) {
stopTimer();
return;
}
showAt(index + 1);
timerId = setTimeout(tick, intervalMs);
}, intervalMs);
}
if (nextBtn) {
nextBtn.addEventListener('click', function() {
showAt(index + 1);
scheduleNext();
});
}
if (prevBtn) {
prevBtn.addEventListener('click', function() {
showAt(index - 1);
scheduleNext();
});
}
dots.forEach(function(dot) {
dot.addEventListener('click', function() {
showAt(parseInt(dot.dataset.galleryDot, 10) || 0);
scheduleNext();
});
});
gallery.addEventListener('pointerenter', stopTimer);
gallery.addEventListener('pointerleave', scheduleNext);
showAt(0);
scheduleNext();
});
}
static renderGrid4(block) {