Updated layout, added ability to make new sections, added new block types, increased layout size by 30%
This commit is contained in:
@@ -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">‹</button>'
|
||||
+ '<button type="button" class="gallery-nav gallery-nav-next" data-gallery-next aria-label="Next image">›</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) {
|
||||
|
||||
Reference in New Issue
Block a user