diff --git a/pages/solutions.php b/pages/solutions.php index b2b5c97..aebfbd6 100644 --- a/pages/solutions.php +++ b/pages/solutions.php @@ -10,12 +10,12 @@ - - - - - - + + + + + + diff --git a/theme/assets/css/main.css b/theme/assets/css/main.css index 6347abb..b43676e 100644 --- a/theme/assets/css/main.css +++ b/theme/assets/css/main.css @@ -5424,10 +5424,10 @@ p:last-child { margin-bottom: 0; } } /* ═══════════════════════════════════════════════════════════════ - INDUSTRY MOCKUP ANIMATIONS (.platform-visual.has-industry) + GALLERY TV SLIDESHOW (.platform-visual.has-gallery-tv) ═══════════════════════════════════════════════════════════════ */ -.platform-visual.has-industry { +.platform-visual.has-gallery-tv { background: none !important; border: none !important; border-radius: 0; @@ -5438,93 +5438,76 @@ p:last-child { margin-bottom: 0; } font-size: inherit; } -.ind-stage { +.gtv-stage { width: 100%; - max-width: 480px; + max-width: 520px; margin: 0 auto; } -.ind-stage svg { + +/* TV frame (mirrors dashboard-tv pattern) */ +.gtv-tv { + display: flex; + flex-direction: column; + align-items: center; width: 100%; - height: auto; +} +.gtv-tv__body { + width: 100%; + background: #111; + border: 4px solid #111; + border-radius: 6px 6px 4px 4px; + outline: 1px solid #000; + padding: 3px; + position: relative; + box-shadow: 0 14px 48px rgba(0,0,0,0.55); +} +.gtv-tv__screen { + width: 100%; + aspect-ratio: 16/9; + background: var(--color-bg); + border-radius: 2px; + overflow: hidden; + position: relative; +} +.gtv-tv__feet { + display: flex; + justify-content: space-between; + width: 60%; + max-width: 300px; +} +.gtv-tv__foot { + width: 12px; + height: 8px; + background: #111; + border: 1px solid #000; + border-radius: 0 0 4px 4px; +} + +/* Slides */ +.gtv-slides { + position: relative; + width: 100%; + height: 100%; +} +.gtv-slide { + position: absolute; + inset: 0; + opacity: 0; + transition: opacity 0.8s ease; +} +.gtv-slide.is-active { + opacity: 1; +} +.gtv-slide img { + width: 100%; + height: 100%; + object-fit: cover; display: block; - border-radius: var(--radius-md); - box-shadow: 0 8px 32px rgba(0,0,0,.3); } -/* Subtle glow around active screens */ -.ind-stage svg rect[fill="#1c2333"] { - transition: filter .6s ease; -} - -/* Animated content transitions */ -.ind-menu-price, -.ind-sale-tag, -.ind-footfall-val, -.ind-kpi-val, -.ind-meet-status, -.ind-alert-text, -.ind-weather-icon, -.ind-weather-temp, -.ind-busy-label, -.ind-ld-val, -.ind-ld-alert-text { - transition: opacity .3s ease; -} - -.ind-menu-bar, -.ind-rev-bar, -.ind-vendor-bar, -.ind-ld-bar { - transition: height .4s ease, y .4s ease; -} - -.ind-product-slot { - transition: stroke-width .3s ease; -} - -.ind-sched-slot { - transition: opacity .4s ease, stroke .3s ease; -} - -.ind-wf-dot { - transition: opacity .5s ease; -} - -.ind-alert-bar { - transition: opacity .4s ease; -} - -.ind-meet-dot, -.ind-busy-dot, -.ind-ld-alert { - transition: fill .4s ease; -} - -.ind-corp-line, -.ind-ld-line { - transition: d .3s ease; -} - -.ind-ld-pie { - transition: d .4s ease; -} - -/* ── Reduced-motion overrides for industry animations ── */ +/* ── Reduced-motion overrides for gallery TV ── */ @media (prefers-reduced-motion: reduce) { - .ind-menu-bar, - .ind-rev-bar, - .ind-vendor-bar, - .ind-ld-bar, - .ind-product-slot, - .ind-sched-slot, - .ind-wf-dot, - .ind-alert-bar, - .ind-corp-line, - .ind-ld-line, - .ind-ld-pie, - .ind-meet-dot, - .ind-busy-dot, - .ind-ld-alert { + .gtv-slide { transition: none !important; } } diff --git a/theme/assets/js/industry-animator.js b/theme/assets/js/industry-animator.js index 214dc18..45e6ae5 100644 --- a/theme/assets/js/industry-animator.js +++ b/theme/assets/js/industry-animator.js @@ -1,380 +1,56 @@ /** - * Industry Mockup Animator - * Animates SVG environment mockups for each industry on the solutions page. - * Each mockup shows devices in real-world use with animated screen content. + * Gallery TV Slideshow + * Cycles through images inside gallery-TV blocks. * Pauses off-screen via IntersectionObserver for performance. + * Respects prefers-reduced-motion. */ (function () { 'use strict'; - if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; - - var SPEED = 0.0018; - - /* ── Utility ────────────────────────────────────────────── */ - function wave(t, off) { - return Math.max(0, Math.min(1, - 0.55 + Math.sin(t + off) * 0.25 + Math.sin(t * 1.8 + off * 1.3) * 0.15 - )); - } - - function lerp(a, b, t) { return a + (b - a) * t; } - - function isDark() { - return document.documentElement.getAttribute('data-theme') === 'dark'; - } - - /* ── Hospitality ────────────────────────────────────────── */ - function initHospitality(svg, st) { - st.menuPrices = svg.querySelectorAll('.ind-menu-price'); - st.menuBars = svg.querySelectorAll('.ind-menu-bar'); - st.promoBanner = svg.querySelector('.ind-promo-text'); - st.promoPhase = 0; - st.promos = ['HAPPY HOUR 5-7PM', 'NEW: SUMMER MENU', '20% OFF DESSERTS', 'LIVE MUSIC FRI']; - } - - function tickHospitality(st) { - // Animate menu prices (shimmer) - for (var i = 0; i < st.menuPrices.length; i++) { - var v = wave(st.phase, i * 1.4); - var price = (5 + Math.round(v * 20)).toFixed(2); - st.menuPrices[i].textContent = '$' + price; - } - // Animate popularity bars - for (var j = 0; j < st.menuBars.length; j++) { - var bv = wave(st.phase * 0.6, j * 1.8); - st.menuBars[j].setAttribute('width', Math.round(bv * 50 + 10)); - } - // Cycle promo banner - st.promoPhase += SPEED * 0.3; - if (st.promoPhase > 1) { - st.promoPhase = 0; - if (st.promoBanner) { - var idx = Math.floor(Math.random() * st.promos.length); - st.promoBanner.textContent = st.promos[idx]; - } - } - } - - /* ── Retail ─────────────────────────────────────────────── */ - function initRetail(svg, st) { - st.saleTags = svg.querySelectorAll('.ind-sale-tag'); - st.footfall = svg.querySelector('.ind-footfall-val'); - st.revBars = svg.querySelectorAll('.ind-rev-bar'); - st.productSlots = svg.querySelectorAll('.ind-product-slot'); - st.productPhase = 0; - } - - function tickRetail(st) { - // Sale tags pulse opacity - for (var i = 0; i < st.saleTags.length; i++) { - var op = 0.5 + wave(st.phase * 1.2, i * 2.0) * 0.5; - st.saleTags[i].setAttribute('opacity', op.toFixed(2)); - } - // Footfall counter - if (st.footfall) { - var count = Math.round(wave(st.phase * 0.3, 0) * 450 + 50); - st.footfall.textContent = count; - } - // Revenue bars - for (var j = 0; j < st.revBars.length; j++) { - var rv = wave(st.phase * 0.5, j * 1.5); - var h = Math.round(rv * 35 + 5); - st.revBars[j].setAttribute('height', h); - st.revBars[j].setAttribute('y', 40 - h); - } - // Product slots cycle highlight - st.productPhase += SPEED * 0.15; - if (st.productPhase > 1) { - st.productPhase = 0; - var active = Math.floor(Math.random() * st.productSlots.length); - for (var k = 0; k < st.productSlots.length; k++) { - st.productSlots[k].setAttribute('stroke-width', k === active ? '2' : '0'); - } - } - } - - /* ── Corporate ──────────────────────────────────────────── */ - function initCorporate(svg, st) { - st.kpiVals = svg.querySelectorAll('.ind-kpi-val'); - st.kpiArrows = svg.querySelectorAll('.ind-kpi-arrow'); - st.meetStatus = svg.querySelector('.ind-meet-status'); - st.meetDot = svg.querySelector('.ind-meet-dot'); - st.meetPhase = 0; - st.statuses = ['Available', 'In Meeting', 'Reserved 2:30', 'Available']; - st.statusIdx = 0; - st.linePath = svg.querySelector('.ind-corp-line'); - st.lineW = 140; - st.linePts = 6; - } - - function tickCorporate(st) { - // KPI counters - for (var i = 0; i < st.kpiVals.length; i++) { - var kv = wave(st.phase * 0.6, i * 2.2); - var vals = [ - Math.round(kv * 98) + '%', - Math.round(kv * 340 + 60), - Math.round(kv * 50 + 10) + 'ms' - ]; - if (vals[i]) st.kpiVals[i].textContent = vals[i]; - } - // KPI arrows - for (var j = 0; j < st.kpiArrows.length; j++) { - var up = wave(st.phase * 0.6, j * 2.2) > 0.5; - st.kpiArrows[j].setAttribute('transform', - up ? 'rotate(0)' : 'rotate(180)'); - st.kpiArrows[j].setAttribute('fill', up ? '#4CAF50' : '#ef4444'); - } - // Meeting room status cycle - st.meetPhase += SPEED * 0.15; - if (st.meetPhase > 1) { - st.meetPhase = 0; - st.statusIdx = (st.statusIdx + 1) % st.statuses.length; - if (st.meetStatus) st.meetStatus.textContent = st.statuses[st.statusIdx]; - if (st.meetDot) { - st.meetDot.setAttribute('fill', - st.statusIdx === 1 ? '#ef4444' : st.statusIdx === 2 ? '#f59e0b' : '#4CAF50'); - } - } - // Line chart - if (st.linePath) { - var d = 'M'; - for (var p = 0; p < st.linePts; p++) { - var x = (p / (st.linePts - 1)) * st.lineW; - var y = 10 + (1 - wave(st.phase * 0.8, p * 0.9)) * 30; - d += (p ? ' L' : '') + x.toFixed(1) + ',' + y.toFixed(1); - } - st.linePath.setAttribute('d', d); - } - } - - /* ── Education ──────────────────────────────────────────── */ - function initEducation(svg, st) { - st.schedSlots = svg.querySelectorAll('.ind-sched-slot'); - st.alertBar = svg.querySelector('.ind-alert-bar'); - st.alertText = svg.querySelector('.ind-alert-text'); - st.alertPhase = 0; - st.alerts = ['Fire Drill 2:00 PM', 'Early Dismissal Fri', 'Gym Closed Today', 'Bus 12 Delayed']; - st.alertIdx = 0; - st.wayfindDots = svg.querySelectorAll('.ind-wf-dot'); - st.wfActive = 0; - st.wfPhase = 0; - } - - function tickEducation(st) { - // Schedule slots pulse (current class highlight) - for (var i = 0; i < st.schedSlots.length; i++) { - var isCurrent = (Math.floor(st.phase * 0.3) % st.schedSlots.length) === i; - st.schedSlots[i].setAttribute('opacity', isCurrent ? '1' : '0.5'); - st.schedSlots[i].setAttribute('stroke', isCurrent ? '#D83302' : 'none'); - st.schedSlots[i].setAttribute('stroke-width', isCurrent ? '1.5' : '0'); - } - // Alert banner cycle - st.alertPhase += SPEED * 0.12; - if (st.alertPhase > 1) { - st.alertPhase = 0; - st.alertIdx = (st.alertIdx + 1) % st.alerts.length; - if (st.alertText) st.alertText.textContent = st.alerts[st.alertIdx]; - } - // Alert bar pulse - if (st.alertBar) { - var ap = 0.6 + Math.sin(st.phase * 2) * 0.4; - st.alertBar.setAttribute('opacity', ap.toFixed(2)); - } - // Wayfinding dot sequence - st.wfPhase += SPEED * 0.2; - if (st.wfPhase > 1) { - st.wfPhase = 0; - st.wfActive = (st.wfActive + 1) % Math.max(st.wayfindDots.length, 1); - } - for (var w = 0; w < st.wayfindDots.length; w++) { - st.wayfindDots[w].setAttribute('opacity', w === st.wfActive ? '1' : '0.2'); - } - } - - /* ── Outdoor Marketplace ────────────────────────────────── */ - function initOutdoor(svg, st) { - st.weatherIcon = svg.querySelector('.ind-weather-icon'); - st.weatherTemp = svg.querySelector('.ind-weather-temp'); - st.weatherPhase = 0; - st.weathers = [ - { icon: '\u2600', temp: '24°C' }, - { icon: '\u26C5', temp: '19°C' }, - { icon: '\u2601', temp: '16°C' }, - { icon: '\u2600', temp: '22°C' } - ]; - st.weatherIdx = 0; - st.vendorBars = svg.querySelectorAll('.ind-vendor-bar'); - st.busyDot = svg.querySelector('.ind-busy-dot'); - st.busyLabel = svg.querySelector('.ind-busy-label'); - } - - function tickOutdoor(st) { - // Weather cycle - st.weatherPhase += SPEED * 0.1; - if (st.weatherPhase > 1) { - st.weatherPhase = 0; - st.weatherIdx = (st.weatherIdx + 1) % st.weathers.length; - var w = st.weathers[st.weatherIdx]; - if (st.weatherIcon) st.weatherIcon.textContent = w.icon; - if (st.weatherTemp) st.weatherTemp.textContent = w.temp; - } - // Vendor activity bars - for (var i = 0; i < st.vendorBars.length; i++) { - var bv = wave(st.phase * 0.5, i * 1.6); - var h = Math.round(bv * 25 + 3); - st.vendorBars[i].setAttribute('height', h); - st.vendorBars[i].setAttribute('y', 28 - h); - } - // Busy indicator pulse - if (st.busyDot) { - var busy = wave(st.phase * 0.3, 0) > 0.6; - st.busyDot.setAttribute('fill', busy ? '#ef4444' : '#4CAF50'); - if (st.busyLabel) st.busyLabel.textContent = busy ? 'Busy' : 'Quiet'; - } - } - - /* ── Live Data Displays ─────────────────────────────────── */ - function initLiveData(svg, st) { - st.ldBars = svg.querySelectorAll('.ind-ld-bar'); - st.ldVals = svg.querySelectorAll('.ind-ld-val'); - st.ldLine = svg.querySelector('.ind-ld-line'); - st.ldLineW = 110; - st.ldLinePts = 8; - st.ldPieSegs = svg.querySelectorAll('.ind-ld-pie'); - st.ldPieR = 22; - st.ldAlertDot = svg.querySelector('.ind-ld-alert'); - st.ldAlertText = svg.querySelector('.ind-ld-alert-text'); - st.ldAlertPhase = 0; - st.ldAlerts = ['All Systems OK', 'CPU: 72%', 'Latency: 12ms', 'Queue: 340']; - st.ldAlertIdx = 0; - } - - function tickLiveData(st) { - // Bars animate - for (var i = 0; i < st.ldBars.length; i++) { - var bv = wave(st.phase, i * 1.1); - var h = Math.round(bv * 30 + 5); - st.ldBars[i].setAttribute('height', h); - st.ldBars[i].setAttribute('y', 35 - h); - } - // Values update - for (var v = 0; v < st.ldVals.length; v++) { - var val = wave(st.phase, v * 1.1); - st.ldVals[v].textContent = Math.round(val * 5000); - } - // Line chart - if (st.ldLine) { - var d = 'M'; - for (var p = 0; p < st.ldLinePts; p++) { - var x = (p / (st.ldLinePts - 1)) * st.ldLineW; - var y = 5 + (1 - wave(st.phase * 0.8, p * 0.9)) * 30; - d += (p ? ' L' : '') + x.toFixed(1) + ',' + y.toFixed(1); - } - st.ldLine.setAttribute('d', d); - } - // Pie chart - if (st.ldPieSegs.length) { - var n = st.ldPieSegs.length; - var weights = [], total = 0; - for (var pi = 0; pi < n; pi++) { - var pw = 0.5 + wave(st.phase * 0.4, pi * 2.0) * 0.5; - weights.push(pw); - total += pw; - } - var angle = 0; - for (var pj = 0; pj < n; pj++) { - var sweep = (weights[pj] / total) * 360; - var startA = angle * Math.PI / 180; - var endA = (angle + sweep) * Math.PI / 180; - var large = sweep > 180 ? 1 : 0; - var r = st.ldPieR; - var x1 = Math.sin(startA) * r, y1 = -Math.cos(startA) * r; - var x2 = Math.sin(endA) * r, y2 = -Math.cos(endA) * r; - var path = st.ldPieSegs[pj]; - if (path) { - path.setAttribute('d', - 'M0,0 L' + x1.toFixed(2) + ',' + y1.toFixed(2) + - ' A' + r + ',' + r + ' 0 ' + large + ',1 ' + - x2.toFixed(2) + ',' + y2.toFixed(2) + ' Z'); - } - angle += sweep; - } - } - // Alert text cycle - st.ldAlertPhase += SPEED * 0.12; - if (st.ldAlertPhase > 1) { - st.ldAlertPhase = 0; - st.ldAlertIdx = (st.ldAlertIdx + 1) % st.ldAlerts.length; - if (st.ldAlertText) st.ldAlertText.textContent = st.ldAlerts[st.ldAlertIdx]; - if (st.ldAlertDot) { - st.ldAlertDot.setAttribute('fill', st.ldAlertIdx === 0 ? '#4CAF50' : '#f59e0b'); - } - } - } - - /* ── Registry ───────────────────────────────────────────── */ - var INDUSTRIES = { - hospitality: { init: initHospitality, tick: tickHospitality }, - retail: { init: initRetail, tick: tickRetail }, - corporate: { init: initCorporate, tick: tickCorporate }, - education: { init: initEducation, tick: tickEducation }, - outdoor: { init: initOutdoor, tick: tickOutdoor }, - livedata: { init: initLiveData, tick: tickLiveData } - }; - - /* ── Main loop ──────────────────────────────────────────── */ - var instances = []; - - function tickAll() { - for (var i = 0; i < instances.length; i++) { - var st = instances[i]; - if (st.paused) continue; - st.phase += SPEED * 16; - st.handler.tick(st); - } - requestAnimationFrame(tickAll); - } - - function observe(st) { - if (!('IntersectionObserver' in window)) return; - new IntersectionObserver(function (entries) { - for (var i = 0; i < entries.length; i++) { - st.paused = !entries[i].isIntersecting; - } - }, { rootMargin: '200px', threshold: 0.05 }).observe(st.el); - } + var INTERVAL = 4000; // ms between slides function boot() { - var els = document.querySelectorAll('[data-industry-anim]'); - if (!els.length) return; + var stages = document.querySelectorAll('[data-gtv-slideshow]'); + if (!stages.length) return; - for (var i = 0; i < els.length; i++) { - var el = els[i]; - var type = el.getAttribute('data-industry-anim'); - var handler = INDUSTRIES[type]; - if (!handler) continue; - if (el._indAnim) continue; + /* Honour reduced-motion – show first slide only */ + if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; - var svg = el.querySelector('svg'); - if (!svg) continue; + for (var i = 0; i < stages.length; i++) { + initSlideshow(stages[i]); + } + } - var st = { - el: el, - svg: svg, - handler: handler, - phase: Math.random() * Math.PI * 2, - paused: false - }; + function initSlideshow(stage) { + var slides = stage.querySelectorAll('.gtv-slide'); + if (slides.length < 2) return; - handler.init(svg, st); - observe(st); - el._indAnim = st; - instances.push(st); + var state = { current: 0, paused: false, timer: null }; + + /* IntersectionObserver – pause when off-screen */ + if ('IntersectionObserver' in window) { + new IntersectionObserver(function (entries) { + for (var j = 0; j < entries.length; j++) { + state.paused = !entries[j].isIntersecting; + } + if (!state.paused && !state.timer) { + state.timer = setInterval(function () { advance(slides, state); }, INTERVAL); + } else if (state.paused && state.timer) { + clearInterval(state.timer); + state.timer = null; + } + }, { rootMargin: '200px', threshold: 0.05 }).observe(stage); } - if (instances.length) requestAnimationFrame(tickAll); + /* Start cycling */ + state.timer = setInterval(function () { advance(slides, state); }, INTERVAL); + } + + function advance(slides, state) { + if (state.paused) return; + slides[state.current].classList.remove('is-active'); + state.current = (state.current + 1) % slides.length; + slides[state.current].classList.add('is-active'); } if (document.readyState === 'loading') { diff --git a/theme/blocks/editor.js b/theme/blocks/editor.js index df31875..0adffde 100644 --- a/theme/blocks/editor.js +++ b/theme/blocks/editor.js @@ -1181,6 +1181,7 @@ reg('oribi/platform-row', { imgAlt: { type: 'string', default: '' }, imgWidth: { type: 'number', default: 300 }, cameraAnim: { type: 'boolean', default: false }, + galleryIds: { type: 'array', default: [] }, }, edit: function (props) { var a = props.attributes, s = props.setAttributes; @@ -1193,6 +1194,31 @@ reg('oribi/platform-row', { el(TG, { label: 'Reversed', checked: !!a.reversed, onChange: function(v){s({reversed:v});} }), el(TG, { label: 'Camera Animation', checked: !!a.cameraAnim, onChange: function(v){s({cameraAnim:v});} }) ), + el(PB, { title: 'Gallery TV Slideshow', initialOpen: false }, + el(MUC, null, + el(MU, { + onSelect: function(media) { + s({ galleryIds: media.map(function(m){ return m.id; }) }); + }, + allowedTypes: ['image'], + gallery: true, + multiple: true, + value: a.galleryIds || [], + render: function(ref) { + return el(Frag, null, + a.galleryIds && a.galleryIds.length + ? el('div', { style: { marginBottom: '8px' } }, + el('p', { style: { margin: '0 0 4px' } }, a.galleryIds.length + ' image(s) selected'), + el(Btn, { variant: 'link', isDestructive: true, onClick: function(){ s({ galleryIds: [] }); } }, 'Clear gallery') + ) + : null, + el(Btn, { onClick: ref.open, variant: 'secondary', __next40pxDefaultSize: true }, + a.galleryIds && a.galleryIds.length ? 'Edit gallery' : 'Select images for TV slideshow') + ); + } + }) + ) + ), el(PB, { title: 'Visual Image', initialOpen: false }, el(MUC, null, el(MU, { diff --git a/theme/blocks/index.php b/theme/blocks/index.php index 2c12f1b..2283bb6 100644 --- a/theme/blocks/index.php +++ b/theme/blocks/index.php @@ -558,12 +558,7 @@ add_action( 'init', function () { 'cameraAnim' => [ 'type' => 'boolean', 'default' => false ], 'neverGoesDark'=> [ 'type' => 'boolean', 'default' => false ], 'brandedAnim' => [ 'type' => 'boolean', 'default' => false ], - 'industryHospitality' => [ 'type' => 'boolean', 'default' => false ], - 'industryRetail' => [ 'type' => 'boolean', 'default' => false ], - 'industryCorporate' => [ 'type' => 'boolean', 'default' => false ], - 'industryEducation' => [ 'type' => 'boolean', 'default' => false ], - 'industryOutdoor' => [ 'type' => 'boolean', 'default' => false ], - 'industryLiveData' => [ 'type' => 'boolean', 'default' => false ], + 'galleryIds' => [ 'type' => 'array', 'default' => [], 'items' => [ 'type' => 'number' ] ], ], 'supports' => $block_supports, 'render_callback' => 'oribi_render_platform_row', @@ -1795,475 +1790,38 @@ function oribi_render_platform_row( $a ) { $visual_html = $ca; $visual_cls = 'platform-visual has-camera'; - /* ── Industry: Hospitality ─────────────────────────────── */ - } elseif ( ! empty( $a['industryHospitality'] ) ) { - $visual_html = ''; - $visual_cls = 'platform-visual has-industry'; - - /* ── Industry: Retail ──────────────────────────────────── */ - } elseif ( ! empty( $a['industryRetail'] ) ) { - $visual_html = ''; - $visual_cls = 'platform-visual has-industry'; - - /* ── Industry: Corporate Office ─────────────────────────── */ - } elseif ( ! empty( $a['industryCorporate'] ) ) { - $visual_html = ''; - $visual_cls = 'platform-visual has-industry'; - - /* ── Industry: Education ───────────────────────────────── */ - } elseif ( ! empty( $a['industryEducation'] ) ) { - $visual_html = ''; - $visual_cls = 'platform-visual has-industry'; - - /* ── Industry: Outdoor Marketplace ─────────────────────── */ - } elseif ( ! empty( $a['industryOutdoor'] ) ) { - $visual_html = ''; - $visual_cls = 'platform-visual has-industry'; - - /* ── Industry: Live Data Displays ──────────────────────── */ - } elseif ( ! empty( $a['industryLiveData'] ) ) { - $visual_html = ''; - $visual_cls = 'platform-visual has-industry'; + /* ── Gallery TV Slideshow ───────────────────────────────── */ + } elseif ( ! empty( $a['galleryIds'] ) && is_array( $a['galleryIds'] ) && count( $a['galleryIds'] ) > 0 ) { + $slides = ''; + $count = 0; + foreach ( $a['galleryIds'] as $gid ) { + $gid = intval( $gid ); + if ( ! $gid ) continue; + $url = wp_get_attachment_url( $gid ); + $alt = get_post_meta( $gid, '_wp_attachment_image_alt', true ); + if ( ! $url ) continue; + $active = $count === 0 ? ' is-active' : ''; + $slides .= '
'; + $slides .= '' . esc_attr( $alt ) . ''; + $slides .= '
'; + $count++; + } + if ( $count > 0 ) { + $visual_html = ''; // stage + $visual_cls = 'platform-visual has-gallery-tv'; + } else { + $visual_html = oribi_render_icon( $a['visual'] ?? '' ); + $visual_cls = 'platform-visual'; + } } else { $visual_html = oribi_render_icon( $a['visual'] ?? '' ); @@ -2283,7 +1841,6 @@ function oribi_render_platform_row( $a ) { diff --git a/theme/inc/enqueue.php b/theme/inc/enqueue.php index 0bcb17d..eafd3fd 100644 --- a/theme/inc/enqueue.php +++ b/theme/inc/enqueue.php @@ -38,9 +38,9 @@ add_action( 'wp_enqueue_scripts', function () { true ); - // Industry mockup animator - animated device mockups for solutions page + // Gallery TV slideshow - cycles images in TV-frame cards wp_enqueue_script( - 'oribi-industry-animator', + 'oribi-gallery-tv', ORIBI_URI . '/assets/js/industry-animator.js', [], ORIBI_VERSION . '.' . filemtime( ORIBI_DIR . '/assets/js/industry-animator.js' ),