diff --git a/app.js b/app.js index b7cdbb5..95b6422 100644 --- a/app.js +++ b/app.js @@ -60,6 +60,71 @@ class ProjectFriction { if (!Array.isArray(this.data.sections) || this.data.sections.length === 0) { this.loadDefaultConfiguration(); } + + this.mergeBuilderSectionsFromStorage(); + } + + mergeBuilderSectionsFromStorage() { + if (typeof localStorage === 'undefined') return; + + var raw = localStorage.getItem('pf-builder-sections'); + if (!raw) return; + + try { + var parsed = JSON.parse(raw); + var order = Array.isArray(parsed.order) ? parsed.order : Object.keys(parsed.sections || {}); + var sectionMeta = parsed.sections || {}; + if (!Array.isArray(this.data.sections)) this.data.sections = []; + + var existingById = {}; + this.data.sections.forEach(function(section) { + existingById[section.id] = section; + }); + + order.forEach(function(id) { + var meta = sectionMeta[id]; + if (!meta) return; + + var stats = { + articles: parseInt(meta.stats && meta.stats.articles, 10) || 0, + storyMaps: parseInt(meta.stats && meta.stats.storyMaps, 10) || 0, + images: parseInt(meta.stats && meta.stats.images, 10) || 0 + }; + + if (existingById[id]) { + existingById[id].title = meta.title || existingById[id].title; + existingById[id].subtitle = meta.subtitle || existingById[id].subtitle; + existingById[id].description = meta.description || existingById[id].description; + existingById[id].icon = meta.icon || existingById[id].icon; + existingById[id].color = meta.color || existingById[id].color; + existingById[id].stats = stats; + } else { + var newSection = { + id: id, + title: meta.title || id, + subtitle: meta.subtitle || '', + icon: meta.icon || 'π', + color: meta.color || '#7f8c8d', + description: meta.description || '', + stats: stats + }; + this.data.sections.push(newSection); + existingById[id] = newSection; + } + }, this); + + // Keep display order aligned with builder tabs for kiosk consistency. + var reordered = []; + order.forEach(function(id) { + if (existingById[id]) reordered.push(existingById[id]); + }); + this.data.sections.forEach(function(section) { + if (order.indexOf(section.id) === -1) reordered.push(section); + }); + this.data.sections = reordered; + } catch (error) { + console.warn('Could not parse builder section metadata from localStorage.'); + } } async loadJSON(url) { @@ -434,6 +499,10 @@ class ProjectFriction { } initializeSectionInteractions(sectionId) { + if (typeof BlockRenderer !== 'undefined' && typeof BlockRenderer.initGalleries === 'function') { + BlockRenderer.initGalleries(document.getElementById('sectionContainer')); + } + // Wire map-button blocks to the Leaflet map const self = this; document.querySelectorAll('.block-map-btn').forEach(function(btn) { @@ -526,7 +595,7 @@ class ProjectFriction { if (sidebar && toggleIcon) { sidebar.classList.toggle('collapsed'); - toggleIcon.textContent = sidebar.classList.contains('collapsed') ? 'βΆ' : 'β'; + toggleIcon.textContent = sidebar.classList.contains('collapsed') ? 'β' : 'βΆ'; } } diff --git a/blocks.css b/blocks.css index e59e71c..079b268 100644 --- a/blocks.css +++ b/blocks.css @@ -77,11 +77,85 @@ /* ββ Quote Block βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ /* Uses existing .quote-block, .quote-text, .quote-attribution from components.css */ +/* ββ Fact Briefing Panel βββββββββββββββββββββββββββββββββββββββββββββββββββ */ +.block-fact-panel { + margin: 1.25rem 0; +} + +.block-fact-panel .fact-panel-list { + margin: 0; + padding: 0; +} + +/* ββ Timeline Card βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ +.block-timeline-card { + background: var(--color-white); + border: 1px solid var(--color-gray); + border-radius: var(--radius-md); + padding: 1rem 1.1rem; + margin: 1.25rem 0; +} + +.block-timeline-header { + display: flex; + align-items: flex-start; + gap: 0.55rem; + margin-bottom: 0.45rem; + flex-wrap: wrap; +} + +.block-timeline-date { + background: var(--color-accent); + color: var(--color-white); + padding: 0.18rem 0.45rem; + border-radius: var(--radius-sm); + font-size: 12px; + line-height: 1.2; + font-weight: 600; + font-family: var(--font-secondary); + white-space: nowrap; + margin-top: 0.05rem; +} + +.block-timeline-title { + margin: 0; + color: var(--color-primary); + font-size: 1.55rem; + line-height: 1.2; + font-family: var(--font-primary); + flex: 1; + min-width: 220px; +} + +.block-timeline-text { + margin: 0; + margin-left: calc(0.45rem + 0.55rem + 52px); + font-size: 1.1rem; + line-height: 1.45; + color: var(--color-primary); + font-family: var(--font-primary); +} + +@media (max-width: 640px) { + .block-timeline-text { + margin-left: 0; + } +} + /* ββ Gallery Block βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ .block-gallery { margin: 1.25rem 0; } +.gallery-empty { + padding: 0.75rem; + border: 1px dashed var(--color-gray); + border-radius: var(--radius-sm); + color: var(--color-dark-gray); + font-family: var(--font-secondary); + font-size: 13px; +} + .gallery-scroll { display: flex; gap: 0.75rem; @@ -127,6 +201,92 @@ right: 0; } +/* ββ Carousel Gallery Mode ββββββββββββββββββββββββββββββββββββββββββββββββββ */ +.gallery-mode-carousel .gallery-carousel { + position: relative; +} + +.gallery-mode-carousel .gallery-slides { + position: relative; + min-height: 220px; + border-radius: var(--radius-sm); + overflow: hidden; + box-shadow: var(--shadow-sm); + background: #0f1720; +} + +.gallery-mode-carousel .gallery-slide { + display: none; + margin: 0; + position: relative; +} + +.gallery-mode-carousel .gallery-slide.is-active { + display: block; +} + +.gallery-mode-carousel .gallery-slide img { + width: 100%; + height: 260px; + object-fit: cover; + display: block; +} + +.gallery-slide-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(to top, rgba(0,0,0,0.78), rgba(0,0,0,0)); + color: #fff; + font-size: 12px; + line-height: 1.45; + padding: 0.75rem; + font-family: var(--font-secondary); +} + +.gallery-nav { + position: absolute; + top: 50%; + transform: translateY(-50%); + width: 34px; + height: 34px; + border: none; + border-radius: var(--radius-full); + background: rgba(0, 0, 0, 0.42); + color: #fff; + font-size: 24px; + line-height: 1; + cursor: pointer; +} + +.gallery-nav:hover { + background: rgba(0, 0, 0, 0.62); +} + +.gallery-nav-prev { left: 0.5rem; } +.gallery-nav-next { right: 0.5rem; } + +.gallery-dots { + margin-top: 0.6rem; + display: flex; + justify-content: center; + gap: 0.4rem; +} + +.gallery-dot { + width: 9px; + height: 9px; + border-radius: var(--radius-full); + border: none; + background: #cbd5e1; + cursor: pointer; +} + +.gallery-dot.is-active { + background: var(--color-primary); +} + /* ββ 4-Image Grid Block ββββββββββββββββββββββββββββββββββββββββββββββββββββ */ .block-grid4 { margin: 1.25rem 0; diff --git a/builder.html b/builder.html index 14fbd76..bc1fe96 100644 --- a/builder.html +++ b/builder.html @@ -147,6 +147,24 @@ .tab-icon { font-size: 16px; } + .new-section-btn { + width: 100%; + margin-top: 0.5rem; + padding: 0.5rem 0.7rem; + border: 1px dashed #3498db; + border-radius: 6px; + background: #f5fbff; + color: #2b6ea4; + font-size: 13px; + cursor: pointer; + transition: all 0.15s; + } + + .new-section-btn:hover { + background: #eaf4fb; + border-color: #2f8dd8; + } + /* ββ Block Palette βββββββββββββββββββββββββββββββββββββββββββββββββ */ .palette-blocks { display: flex; @@ -321,18 +339,33 @@ .canvas-block-preview { padding: 1rem 1.25rem; - pointer-events: none; + pointer-events: auto; max-height: 280px; overflow: hidden; position: relative; } + .canvas-block-preview button, + .canvas-block-preview a, + .canvas-block-preview input, + .canvas-block-preview select, + .canvas-block-preview textarea { + pointer-events: none; + } + + .canvas-block-preview [data-gallery-prev], + .canvas-block-preview [data-gallery-next], + .canvas-block-preview [data-gallery-dot] { + pointer-events: auto; + } + .canvas-block-preview::after { content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 30px; background: linear-gradient(to bottom, transparent, rgba(255,255,255,0.8)); + pointer-events: none; } /* ββ Insert Strip ββββββββββββββββββββββββββββββββββββββββββββββββββ */ @@ -412,7 +445,8 @@ color: #2c3e50; } - #modalClose { + #modalClose, + #sectionWizardClose { background: none; border: none; font-size: 20px; @@ -422,7 +456,8 @@ padding: 0 0.2rem; } - #modalClose:hover { color: #2c3e50; } + #modalClose:hover, + #sectionWizardClose:hover { color: #2c3e50; } .modal-body { padding: 1.25rem; @@ -482,6 +517,12 @@ gap: 0.75rem; } + .form-row-2 { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0.75rem; + } + /* Gallery / Stats item rows */ .item-row { display: flex; @@ -595,6 +636,7 @@