Update script handle and description for gallery TV slideshow in enqueue.php
This commit is contained in:
@@ -10,12 +10,12 @@
|
||||
<!-- wp:oribi/page-hero-animated {"label":"Industry Solutions","title":"Built for the Way You Work","description":"Every industry communicates differently. Our platform adapts to your environment — whether that's a hotel lobby, a shop floor, a boardroom, or a lecture hall."} /-->
|
||||
|
||||
<!-- wp:oribi/platform-section {"label":"Industries We Serve","heading":"One Platform, Tailored to Your Sector","lead":"We've worked with businesses across six key industries. Here's how our platform fits into each one."} -->
|
||||
<!-- wp:oribi/platform-row {"heading":"Hospitality","description":"Digital menu boards that update with your POS, lobby displays that guide guests, and promotional screens that drive upsells in bars and restaurants. Create a polished guest experience from the moment they walk in — and keep it fresh without touching a single printed sign.","btnText":"Get Started","btnUrl":"/contact","industryHospitality":true} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Retail","description":"Launch promotions across every store instantly, spotlight seasonal products, and guide shoppers with in-store wayfinding. Retailers using digital signage see up to 30% more sales. Our platform makes it simple to keep content current, targeted, and data-driven across every location.","btnText":"See Pricing","btnUrl":"/pricing","reversed":true,"industryRetail":true} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Corporate Office","description":"Meeting room displays with native Microsoft Teams integration, company-wide announcement boards, and live KPI dashboards in common areas. Turn your office into a connected, well-informed workplace where important information is always visible.","btnText":"Learn More","btnUrl":"/features","industryCorporate":true} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Education","description":"Timetable displays, campus wayfinding, emergency alerts, and event boards — all managed centrally. Keep students, faculty, and visitors informed across multiple buildings without the overhead of maintaining individual screens.","btnText":"Contact Us","btnUrl":"/contact","reversed":true,"industryEducation":true} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Outdoor Marketplace","description":"From farmers' markets to seasonal fairs, digital signage adds a professional edge without losing the character of your venue. Weather-resistant display options and built-in offline playback ensure your screens perform reliably, rain or shine.","btnText":"Get a Quote","btnUrl":"/contact","industryOutdoor":true} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Live Data Displays","description":"Bring your web dashboards, real-time KPIs, and operational data to large-format screens. Ideal for operations centres, trading floors, and management war rooms where critical information needs to be visible to the entire team at a glance.","btnText":"See Features","btnUrl":"/features","reversed":true,"industryLiveData":true} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Hospitality","description":"Digital menu boards that update with your POS, lobby displays that guide guests, and promotional screens that drive upsells in bars and restaurants. Create a polished guest experience from the moment they walk in — and keep it fresh without touching a single printed sign.","btnText":"Get Started","btnUrl":"/contact","galleryIds":[]} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Retail","description":"Launch promotions across every store instantly, spotlight seasonal products, and guide shoppers with in-store wayfinding. Retailers using digital signage see up to 30% more sales. Our platform makes it simple to keep content current, targeted, and data-driven across every location.","btnText":"See Pricing","btnUrl":"/pricing","reversed":true,"galleryIds":[]} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Corporate Office","description":"Meeting room displays with native Microsoft Teams integration, company-wide announcement boards, and live KPI dashboards in common areas. Turn your office into a connected, well-informed workplace where important information is always visible.","btnText":"Learn More","btnUrl":"/features","galleryIds":[]} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Education","description":"Timetable displays, campus wayfinding, emergency alerts, and event boards — all managed centrally. Keep students, faculty, and visitors informed across multiple buildings without the overhead of maintaining individual screens.","btnText":"Contact Us","btnUrl":"/contact","reversed":true,"galleryIds":[]} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Outdoor Marketplace","description":"From farmers' markets to seasonal fairs, digital signage adds a professional edge without losing the character of your venue. Weather-resistant display options and built-in offline playback ensure your screens perform reliably, rain or shine.","btnText":"Get a Quote","btnUrl":"/contact","galleryIds":[]} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Live Data Displays","description":"Bring your web dashboards, real-time KPIs, and operational data to large-format screens. Ideal for operations centres, trading floors, and management war rooms where critical information needs to be visible to the entire team at a glance.","btnText":"See Features","btnUrl":"/features","reversed":true,"galleryIds":[]} /-->
|
||||
<!-- /wp:oribi/platform-section -->
|
||||
|
||||
<!-- wp:oribi/stat-section {"variant":"alt","label":"By the Numbers","heading":"The Results Speak for Themselves","lead":"Businesses that invest in digital signage see measurable returns across every metric that matters.","columns":4} -->
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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') {
|
||||
|
||||
@@ -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, {
|
||||
|
||||
@@ -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 = '<div class="ind-stage" data-industry-anim="hospitality" aria-hidden="true">'
|
||||
. '<svg viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Hospitality signage environment">'
|
||||
/* ── Background: restaurant counter area ── */
|
||||
. '<rect x="0" y="0" width="400" height="300" rx="8" fill="#1a1a2e" />'
|
||||
. '<rect x="0" y="240" width="400" height="60" rx="0" fill="#12121f" />'
|
||||
/* ── Wall-mounted menu board (large display) ── */
|
||||
. '<g transform="translate(20,20)">'
|
||||
. '<rect x="0" y="0" width="220" height="150" rx="4" fill="#111" stroke="#333" stroke-width="1.5" />'
|
||||
. '<rect x="6" y="6" width="208" height="138" rx="2" fill="#1c2333" />'
|
||||
/* Menu header */
|
||||
. '<rect x="14" y="14" width="80" height="8" rx="2" fill="#D83302" opacity=".8" />'
|
||||
. '<text x="14" y="35" font-size="7" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">TODAY\'S SPECIALS</text>'
|
||||
/* Menu items with prices */
|
||||
. '<text x="14" y="52" font-size="8" fill="rgba(255,255,255,.7)" font-family="Inter,sans-serif">Grilled Salmon</text>'
|
||||
. '<text class="ind-menu-price" x="192" y="52" font-size="8" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="end">$18.50</text>'
|
||||
. '<rect class="ind-menu-bar" x="14" y="55" width="40" height="3" rx="1" fill="#D83302" opacity=".4" />'
|
||||
. '<text x="14" y="72" font-size="8" fill="rgba(255,255,255,.7)" font-family="Inter,sans-serif">Wagyu Burger</text>'
|
||||
. '<text class="ind-menu-price" x="192" y="72" font-size="8" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="end">$22.00</text>'
|
||||
. '<rect class="ind-menu-bar" x="14" y="75" width="55" height="3" rx="1" fill="#D83302" opacity=".4" />'
|
||||
. '<text x="14" y="92" font-size="8" fill="rgba(255,255,255,.7)" font-family="Inter,sans-serif">Caesar Salad</text>'
|
||||
. '<text class="ind-menu-price" x="192" y="92" font-size="8" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="end">$12.00</text>'
|
||||
. '<rect class="ind-menu-bar" x="14" y="95" width="30" height="3" rx="1" fill="#D83302" opacity=".4" />'
|
||||
. '<text x="14" y="112" font-size="8" fill="rgba(255,255,255,.7)" font-family="Inter,sans-serif">Pasta Carbonara</text>'
|
||||
. '<text class="ind-menu-price" x="192" y="112" font-size="8" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="end">$15.00</text>'
|
||||
. '<rect class="ind-menu-bar" x="14" y="115" width="45" height="3" rx="1" fill="#D83302" opacity=".4" />'
|
||||
/* Promo banner */
|
||||
. '<rect x="6" y="126" width="208" height="18" fill="#D83302" opacity=".15" />'
|
||||
. '<text class="ind-promo-text" x="110" y="138" font-size="7" fill="#D83302" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600">HAPPY HOUR 5-7PM</text>'
|
||||
. '</g>'
|
||||
/* ── Tablet on counter (POS integration) ── */
|
||||
. '<g transform="translate(270,60)">'
|
||||
. '<rect x="0" y="0" width="100" height="140" rx="6" fill="#222" stroke="#444" stroke-width="1" />'
|
||||
. '<rect x="6" y="8" width="88" height="110" rx="2" fill="#1c2333" />'
|
||||
. '<circle cx="50" cy="132" r="4" fill="#333" />'
|
||||
/* POS mini-UI */
|
||||
. '<rect x="12" y="16" width="76" height="6" rx="1" fill="#00757c" opacity=".6" />'
|
||||
. '<text x="50" y="38" font-size="6" fill="rgba(255,255,255,.5)" font-family="Inter,sans-serif" text-anchor="middle">Order #47</text>'
|
||||
. '<rect x="12" y="44" width="76" height="1" fill="rgba(255,255,255,.1)" />'
|
||||
. '<text x="12" y="56" font-size="5.5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">1x Salmon</text>'
|
||||
. '<text x="88" y="56" font-size="5.5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif" text-anchor="end">$18.50</text>'
|
||||
. '<text x="12" y="66" font-size="5.5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">2x Lager</text>'
|
||||
. '<text x="88" y="66" font-size="5.5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif" text-anchor="end">$14.00</text>'
|
||||
. '<rect x="12" y="74" width="76" height="1" fill="rgba(255,255,255,.1)" />'
|
||||
. '<text x="12" y="86" font-size="6" fill="rgba(255,255,255,.7)" font-family="Inter,sans-serif" font-weight="600">Total</text>'
|
||||
. '<text x="88" y="86" font-size="6" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="end" font-weight="600">$32.50</text>'
|
||||
. '<rect x="12" y="96" width="76" height="16" rx="3" fill="#4CAF50" opacity=".8" />'
|
||||
. '<text x="50" y="107" font-size="6" fill="#fff" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600">PAY</text>'
|
||||
. '</g>'
|
||||
/* ── Ambient: counter top ── */
|
||||
. '<rect x="0" y="235" width="400" height="3" fill="#333" />'
|
||||
/* ── Label: wall screen type ── */
|
||||
. '<text x="130" y="185" font-size="7" fill="rgba(255,255,255,.25)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600" letter-spacing=".1em">MENU BOARD</text>'
|
||||
. '<text x="320" y="215" font-size="7" fill="rgba(255,255,255,.25)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600" letter-spacing=".1em">POS TABLET</text>'
|
||||
. '</svg></div>';
|
||||
$visual_cls = 'platform-visual has-industry';
|
||||
|
||||
/* ── Industry: Retail ──────────────────────────────────── */
|
||||
} elseif ( ! empty( $a['industryRetail'] ) ) {
|
||||
$visual_html = '<div class="ind-stage" data-industry-anim="retail" aria-hidden="true">'
|
||||
. '<svg viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Retail signage environment">'
|
||||
. '<rect x="0" y="0" width="400" height="300" rx="8" fill="#1a1a2e" />'
|
||||
/* ── Large overhead promo display ── */
|
||||
. '<g transform="translate(20,15)">'
|
||||
. '<rect x="0" y="0" width="240" height="130" rx="4" fill="#111" stroke="#333" stroke-width="1.5" />'
|
||||
. '<rect x="5" y="5" width="230" height="120" rx="2" fill="#1c2333" />'
|
||||
/* Promo content */
|
||||
. '<rect x="12" y="12" width="60" height="8" rx="2" fill="#D83302" opacity=".8" />'
|
||||
. '<text x="12" y="36" font-size="11" fill="rgba(255,255,255,.9)" font-family="Inter,sans-serif" font-weight="700">SPRING SALE</text>'
|
||||
. '<text x="12" y="50" font-size="7" fill="rgba(255,255,255,.5)" font-family="Inter,sans-serif">Up to 40% off selected items</text>'
|
||||
/* Product grid */
|
||||
. '<g transform="translate(12,60)">'
|
||||
. '<rect class="ind-product-slot" x="0" y="0" width="48" height="48" rx="3" fill="#252540" stroke="#D83302" stroke-width="0" />'
|
||||
. '<rect x="6" y="6" width="36" height="24" rx="2" fill="#333" />'
|
||||
. '<text class="ind-sale-tag" x="24" y="42" font-size="6" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="middle">$29.99</text>'
|
||||
. '<rect class="ind-product-slot" x="56" y="0" width="48" height="48" rx="3" fill="#252540" stroke="#D83302" stroke-width="0" />'
|
||||
. '<rect x="62" y="6" width="36" height="24" rx="2" fill="#333" />'
|
||||
. '<text class="ind-sale-tag" x="80" y="42" font-size="6" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="middle">$49.99</text>'
|
||||
. '<rect class="ind-product-slot" x="112" y="0" width="48" height="48" rx="3" fill="#252540" stroke="#D83302" stroke-width="0" />'
|
||||
. '<rect x="118" y="6" width="36" height="24" rx="2" fill="#333" />'
|
||||
. '<text class="ind-sale-tag" x="136" y="42" font-size="6" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="middle">$19.99</text>'
|
||||
. '<rect class="ind-product-slot" x="168" y="0" width="48" height="48" rx="3" fill="#252540" stroke="#D83302" stroke-width="0" />'
|
||||
. '<rect x="174" y="6" width="36" height="24" rx="2" fill="#333" />'
|
||||
. '<text class="ind-sale-tag" x="192" y="42" font-size="6" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="middle">$39.99</text>'
|
||||
. '</g>'
|
||||
. '</g>'
|
||||
/* ── Analytics monitor (small) ── */
|
||||
. '<g transform="translate(280,15)">'
|
||||
. '<rect x="0" y="0" width="100" height="80" rx="3" fill="#111" stroke="#333" stroke-width="1" />'
|
||||
. '<rect x="4" y="4" width="92" height="72" rx="2" fill="#1c2333" />'
|
||||
. '<text x="10" y="16" font-size="6" fill="rgba(255,255,255,.5)" font-family="Inter,sans-serif" font-weight="600">FOOTFALL</text>'
|
||||
. '<text class="ind-footfall-val" x="10" y="32" font-size="14" fill="#D83302" font-family="Inter,sans-serif" font-weight="700">243</text>'
|
||||
. '<text x="10" y="42" font-size="5" fill="rgba(255,255,255,.3)" font-family="Inter,sans-serif">visitors today</text>'
|
||||
/* Revenue mini bars */
|
||||
. '<g transform="translate(10,48)">'
|
||||
. '<rect class="ind-rev-bar" x="0" y="35" width="10" height="5" fill="#4CAF50" />'
|
||||
. '<rect class="ind-rev-bar" x="14" y="30" width="10" height="10" fill="#4CAF50" />'
|
||||
. '<rect class="ind-rev-bar" x="28" y="25" width="10" height="15" fill="#4CAF50" />'
|
||||
. '<rect class="ind-rev-bar" x="42" y="20" width="10" height="20" fill="#D83302" />'
|
||||
. '<rect class="ind-rev-bar" x="56" y="28" width="10" height="12" fill="#4CAF50" />'
|
||||
. '<rect class="ind-rev-bar" x="70" y="22" width="10" height="18" fill="#4CAF50" />'
|
||||
. '</g>'
|
||||
. '</g>'
|
||||
/* ── Wayfinding pillar (floor standing) ── */
|
||||
. '<g transform="translate(290,110)">'
|
||||
. '<rect x="10" y="0" width="80" height="120" rx="3" fill="#111" stroke="#333" stroke-width="1" />'
|
||||
. '<rect x="14" y="4" width="72" height="112" rx="2" fill="#1c2333" />'
|
||||
. '<text x="50" y="18" font-size="6" fill="rgba(255,255,255,.5)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600">FLOOR GUIDE</text>'
|
||||
. '<text x="22" y="34" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">\u2190 Menswear</text>'
|
||||
. '<text x="22" y="48" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">\u2192 Electronics</text>'
|
||||
. '<text x="22" y="62" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">\u2191 Food Court</text>'
|
||||
. '<text x="22" y="76" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">\u2190 Home & Garden</text>'
|
||||
. '<rect x="30" y="86" width="40" height="22" rx="3" fill="#D83302" opacity=".2" />'
|
||||
. '<text x="50" y="100" font-size="6" fill="#D83302" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600">MAP</text>'
|
||||
. '</g>'
|
||||
/* ── Shelf edge (store floor) ── */
|
||||
. '<rect x="0" y="248" width="270" height="52" fill="#12121f" />'
|
||||
. '<rect x="20" y="250" width="230" height="4" fill="#333" />'
|
||||
. '<text x="135" y="270" font-size="7" fill="rgba(255,255,255,.25)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600" letter-spacing=".1em">PROMO DISPLAY</text>'
|
||||
. '<text x="340" y="245" font-size="7" fill="rgba(255,255,255,.25)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600" letter-spacing=".1em">WAYFINDING</text>'
|
||||
. '</svg></div>';
|
||||
$visual_cls = 'platform-visual has-industry';
|
||||
|
||||
/* ── Industry: Corporate Office ─────────────────────────── */
|
||||
} elseif ( ! empty( $a['industryCorporate'] ) ) {
|
||||
$visual_html = '<div class="ind-stage" data-industry-anim="corporate" aria-hidden="true">'
|
||||
. '<svg viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Corporate office signage environment">'
|
||||
. '<rect x="0" y="0" width="400" height="300" rx="8" fill="#1a1a2e" />'
|
||||
/* ── Meeting room display (wall-mounted) ── */
|
||||
. '<g transform="translate(20,20)">'
|
||||
. '<rect x="0" y="0" width="170" height="120" rx="4" fill="#111" stroke="#333" stroke-width="1.5" />'
|
||||
. '<rect x="5" y="5" width="160" height="110" rx="2" fill="#1c2333" />'
|
||||
/* Teams-style header */
|
||||
. '<rect x="10" y="10" width="150" height="14" rx="2" fill="#5b5fc7" opacity=".3" />'
|
||||
. '<text x="18" y="20" font-size="6" fill="rgba(255,255,255,.8)" font-family="Inter,sans-serif" font-weight="600">\uD83D\uDCF9 Room: Boardroom A</text>'
|
||||
/* Status */
|
||||
. '<circle class="ind-meet-dot" cx="18" cy="38" r="4" fill="#4CAF50" />'
|
||||
. '<text class="ind-meet-status" x="28" y="41" font-size="7" fill="rgba(255,255,255,.7)" font-family="Inter,sans-serif">Available</text>'
|
||||
/* Schedule */
|
||||
. '<text x="10" y="58" font-size="5.5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">UPCOMING</text>'
|
||||
. '<text x="10" y="70" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">10:00 - Sprint Planning</text>'
|
||||
. '<text x="10" y="82" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">13:00 - Design Review</text>'
|
||||
. '<text x="10" y="94" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">15:30 - All Hands</text>'
|
||||
. '<rect x="10" y="100" width="150" height="10" rx="2" fill="#4CAF50" opacity=".15" />'
|
||||
. '<text x="85" y="108" font-size="5.5" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="middle">Book Now</text>'
|
||||
. '</g>'
|
||||
/* ── KPI Dashboard (large monitor on stand) ── */
|
||||
. '<g transform="translate(210,10)">'
|
||||
. '<rect x="0" y="0" width="170" height="130" rx="4" fill="#111" stroke="#333" stroke-width="1.5" />'
|
||||
. '<rect x="5" y="5" width="160" height="120" rx="2" fill="#1c2333" />'
|
||||
. '<text x="12" y="18" font-size="6" fill="rgba(255,255,255,.5)" font-family="Inter,sans-serif" font-weight="600">LIVE DASHBOARD</text>'
|
||||
/* KPI cards */
|
||||
. '<g transform="translate(12,26)">'
|
||||
. '<rect x="0" y="0" width="44" height="32" rx="2" fill="#252540" />'
|
||||
. '<text x="22" y="11" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif" text-anchor="middle">Uptime</text>'
|
||||
. '<text class="ind-kpi-val" x="22" y="24" font-size="10" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="middle" font-weight="700">99%</text>'
|
||||
. '</g>'
|
||||
. '<g transform="translate(62,26)">'
|
||||
. '<rect x="0" y="0" width="44" height="32" rx="2" fill="#252540" />'
|
||||
. '<text x="22" y="11" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif" text-anchor="middle">Users</text>'
|
||||
. '<text class="ind-kpi-val" x="22" y="24" font-size="10" fill="#D83302" font-family="Inter,sans-serif" text-anchor="middle" font-weight="700">240</text>'
|
||||
. '</g>'
|
||||
. '<g transform="translate(112,26)">'
|
||||
. '<rect x="0" y="0" width="44" height="32" rx="2" fill="#252540" />'
|
||||
. '<text x="22" y="11" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif" text-anchor="middle">Latency</text>'
|
||||
. '<text class="ind-kpi-val" x="22" y="24" font-size="10" fill="#f59e0b" font-family="Inter,sans-serif" text-anchor="middle" font-weight="700">22ms</text>'
|
||||
. '</g>'
|
||||
/* Trend line */
|
||||
. '<g transform="translate(12,66)">'
|
||||
. '<text x="0" y="0" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">REQUESTS / MIN</text>'
|
||||
. '<line x1="0" y1="10" x2="140" y2="10" stroke="rgba(255,255,255,.06)" stroke-width=".5" />'
|
||||
. '<line x1="0" y1="25" x2="140" y2="25" stroke="rgba(255,255,255,.06)" stroke-width=".5" />'
|
||||
. '<line x1="0" y1="40" x2="140" y2="40" stroke="rgba(255,255,255,.06)" stroke-width=".5" />'
|
||||
. '<path class="ind-corp-line" d="M0,25 L140,25" stroke="#4CAF50" stroke-width="1.5" fill="none" stroke-linecap="round" />'
|
||||
. '</g>'
|
||||
/* Monitor stand */
|
||||
. '<rect x="75" y="130" width="20" height="12" fill="#222" />'
|
||||
. '<rect x="55" y="140" width="60" height="4" rx="2" fill="#333" />'
|
||||
. '</g>'
|
||||
/* ── Announcement ticker (lobby display) ── */
|
||||
. '<g transform="translate(20,160)">'
|
||||
. '<rect x="0" y="0" width="360" height="40" rx="4" fill="#111" stroke="#333" stroke-width="1" />'
|
||||
. '<rect x="4" y="4" width="352" height="32" rx="2" fill="#0d1117" />'
|
||||
. '<rect x="8" y="8" width="60" height="12" rx="2" fill="#D83302" opacity=".2" />'
|
||||
. '<text x="38" y="17" font-size="6" fill="#D83302" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600">COMPANY NEWS</text>'
|
||||
. '<text x="80" y="30" font-size="6.5" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">Q4 Results exceed forecast \u2022 New office opening in March \u2022 Hackathon registrations open</text>'
|
||||
. '</g>'
|
||||
/* Labels */
|
||||
. '<text x="105" y="220" font-size="7" fill="rgba(255,255,255,.25)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600" letter-spacing=".1em">MEETING ROOM</text>'
|
||||
. '<text x="295" y="220" font-size="7" fill="rgba(255,255,255,.25)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600" letter-spacing=".1em">KPI DASHBOARD</text>'
|
||||
. '</svg></div>';
|
||||
$visual_cls = 'platform-visual has-industry';
|
||||
|
||||
/* ── Industry: Education ───────────────────────────────── */
|
||||
} elseif ( ! empty( $a['industryEducation'] ) ) {
|
||||
$visual_html = '<div class="ind-stage" data-industry-anim="education" aria-hidden="true">'
|
||||
. '<svg viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Education signage environment">'
|
||||
. '<rect x="0" y="0" width="400" height="300" rx="8" fill="#1a1a2e" />'
|
||||
/* ── Timetable display (large wall-mount) ── */
|
||||
. '<g transform="translate(15,15)">'
|
||||
. '<rect x="0" y="0" width="230" height="160" rx="4" fill="#111" stroke="#333" stroke-width="1.5" />'
|
||||
. '<rect x="5" y="5" width="220" height="150" rx="2" fill="#1c2333" />'
|
||||
. '<text x="12" y="18" font-size="7" fill="rgba(255,255,255,.5)" font-family="Inter,sans-serif" font-weight="600">DAILY TIMETABLE</text>'
|
||||
. '<text x="200" y="18" font-size="6" fill="rgba(255,255,255,.3)" font-family="Inter,sans-serif" text-anchor="end">Tuesday</text>'
|
||||
/* Column headers */
|
||||
. '<g transform="translate(12,28)">'
|
||||
. '<rect x="0" y="0" width="200" height="10" rx="1" fill="rgba(255,255,255,.05)" />'
|
||||
. '<text x="6" y="7" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">TIME</text>'
|
||||
. '<text x="50" y="7" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">ROOM</text>'
|
||||
. '<text x="100" y="7" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">SUBJECT</text>'
|
||||
. '<text x="170" y="7" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">STATUS</text>'
|
||||
. '</g>'
|
||||
/* Schedule rows */
|
||||
. '<g transform="translate(12,44)">'
|
||||
. '<rect class="ind-sched-slot" x="0" y="0" width="200" height="18" rx="2" fill="#252540" />'
|
||||
. '<text x="6" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">09:00</text>'
|
||||
. '<text x="50" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">B201</text>'
|
||||
. '<text x="100" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">Mathematics</text>'
|
||||
. '<circle cx="185" cy="9" r="3" fill="#4CAF50" />'
|
||||
. '</g>'
|
||||
. '<g transform="translate(12,66)">'
|
||||
. '<rect class="ind-sched-slot" x="0" y="0" width="200" height="18" rx="2" fill="#252540" />'
|
||||
. '<text x="6" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">10:30</text>'
|
||||
. '<text x="50" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">Lab 3</text>'
|
||||
. '<text x="100" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">Chemistry</text>'
|
||||
. '<circle cx="185" cy="9" r="3" fill="#f59e0b" />'
|
||||
. '</g>'
|
||||
. '<g transform="translate(12,88)">'
|
||||
. '<rect class="ind-sched-slot" x="0" y="0" width="200" height="18" rx="2" fill="#252540" />'
|
||||
. '<text x="6" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">13:00</text>'
|
||||
. '<text x="50" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">Hall A</text>'
|
||||
. '<text x="100" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">Literature</text>'
|
||||
. '<circle cx="185" cy="9" r="3" fill="#4CAF50" />'
|
||||
. '</g>'
|
||||
. '<g transform="translate(12,110)">'
|
||||
. '<rect class="ind-sched-slot" x="0" y="0" width="200" height="18" rx="2" fill="#252540" />'
|
||||
. '<text x="6" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">14:30</text>'
|
||||
. '<text x="50" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">Gym</text>'
|
||||
. '<text x="100" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">PE</text>'
|
||||
. '<circle cx="185" cy="9" r="3" fill="#4CAF50" />'
|
||||
. '</g>'
|
||||
. '<g transform="translate(12,132)">'
|
||||
. '<rect class="ind-sched-slot" x="0" y="0" width="200" height="18" rx="2" fill="#252540" />'
|
||||
. '<text x="6" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">16:00</text>'
|
||||
. '<text x="50" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">C105</text>'
|
||||
. '<text x="100" y="12" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">Art</text>'
|
||||
. '<circle cx="185" cy="9" r="3" fill="#4CAF50" />'
|
||||
. '</g>'
|
||||
. '</g>'
|
||||
/* ── Campus wayfinding (floor directory) ── */
|
||||
. '<g transform="translate(260,15)">'
|
||||
. '<rect x="0" y="0" width="120" height="100" rx="3" fill="#111" stroke="#333" stroke-width="1" />'
|
||||
. '<rect x="4" y="4" width="112" height="92" rx="2" fill="#1c2333" />'
|
||||
. '<text x="60" y="16" font-size="6" fill="rgba(255,255,255,.5)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600">CAMPUS MAP</text>'
|
||||
/* Simplified building outlines with wayfinding dots */
|
||||
. '<rect x="15" y="24" width="30" height="20" rx="2" fill="#252540" stroke="rgba(255,255,255,.1)" stroke-width=".5" />'
|
||||
. '<rect x="55" y="28" width="25" height="16" rx="2" fill="#252540" stroke="rgba(255,255,255,.1)" stroke-width=".5" />'
|
||||
. '<rect x="90" y="22" width="18" height="24" rx="2" fill="#252540" stroke="rgba(255,255,255,.1)" stroke-width=".5" />'
|
||||
. '<rect x="30" y="54" width="45" height="18" rx="2" fill="#252540" stroke="rgba(255,255,255,.1)" stroke-width=".5" />'
|
||||
. '<circle class="ind-wf-dot" cx="30" cy="34" r="3" fill="#D83302" />'
|
||||
. '<circle class="ind-wf-dot" cx="67" cy="36" r="3" fill="#D83302" opacity=".2" />'
|
||||
. '<circle class="ind-wf-dot" cx="99" cy="34" r="3" fill="#D83302" opacity=".2" />'
|
||||
. '<circle class="ind-wf-dot" cx="52" cy="63" r="3" fill="#D83302" opacity=".2" />'
|
||||
. '<text x="60" y="86" font-size="5" fill="rgba(255,255,255,.3)" font-family="Inter,sans-serif" text-anchor="middle">You are here \u2022</text>'
|
||||
. '</g>'
|
||||
/* ── Emergency alert banner ── */
|
||||
. '<g transform="translate(260,130)">'
|
||||
. '<rect class="ind-alert-bar" x="0" y="0" width="120" height="30" rx="3" fill="#ef4444" opacity=".7" />'
|
||||
. '<text x="10" y="12" font-size="5" fill="#fff" font-family="Inter,sans-serif" font-weight="700">\u26A0 ALERT</text>'
|
||||
. '<text class="ind-alert-text" x="10" y="23" font-size="5.5" fill="rgba(255,255,255,.9)" font-family="Inter,sans-serif">Fire Drill 2:00 PM</text>'
|
||||
. '</g>'
|
||||
/* Labels */
|
||||
. '<text x="130" y="195" font-size="7" fill="rgba(255,255,255,.25)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600" letter-spacing=".1em">TIMETABLE</text>'
|
||||
. '<text x="320" y="180" font-size="7" fill="rgba(255,255,255,.25)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600" letter-spacing=".1em">WAYFINDING</text>'
|
||||
. '</svg></div>';
|
||||
$visual_cls = 'platform-visual has-industry';
|
||||
|
||||
/* ── Industry: Outdoor Marketplace ─────────────────────── */
|
||||
} elseif ( ! empty( $a['industryOutdoor'] ) ) {
|
||||
$visual_html = '<div class="ind-stage" data-industry-anim="outdoor" aria-hidden="true">'
|
||||
. '<svg viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Outdoor marketplace signage environment">'
|
||||
. '<rect x="0" y="0" width="400" height="300" rx="8" fill="#1a1a2e" />'
|
||||
/* ── Market stall canopy ── */
|
||||
. '<path d="M30,100 L200,80 L370,100 L370,110 L30,110 Z" fill="#252540" />'
|
||||
. '<path d="M30,100 L200,80 L370,100" fill="none" stroke="#D83302" stroke-width="1.5" opacity=".4" />'
|
||||
/* ── Overhead digital sign (weather resistant) ── */
|
||||
. '<g transform="translate(60,20)">'
|
||||
. '<rect x="0" y="0" width="280" height="55" rx="4" fill="#111" stroke="#00757c" stroke-width="1.5" />'
|
||||
. '<rect x="4" y="4" width="272" height="47" rx="2" fill="#1c2333" />'
|
||||
/* Weather widget */
|
||||
. '<text class="ind-weather-icon" x="22" y="32" font-size="20" text-anchor="middle">\u2600</text>'
|
||||
. '<text class="ind-weather-temp" x="22" y="46" font-size="7" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif" text-anchor="middle">24\u00B0C</text>'
|
||||
/* Market info */
|
||||
. '<text x="55" y="18" font-size="6" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif" font-weight="600">GREENFIELD MARKET</text>'
|
||||
. '<text x="55" y="30" font-size="8" fill="rgba(255,255,255,.8)" font-family="Inter,sans-serif" font-weight="700">Fresh Produce \u2022 Artisan Goods</text>'
|
||||
. '<text x="55" y="42" font-size="6" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">Open Today 8AM \u2013 4PM</text>'
|
||||
/* Busy indicator */
|
||||
. '<circle class="ind-busy-dot" cx="252" cy="25" r="5" fill="#4CAF50" />'
|
||||
. '<text class="ind-busy-label" x="252" y="40" font-size="5" fill="rgba(255,255,255,.5)" font-family="Inter,sans-serif" text-anchor="middle">Quiet</text>'
|
||||
. '</g>'
|
||||
/* ── Vendor tablet (on counter) ── */
|
||||
. '<g transform="translate(40,120)">'
|
||||
. '<rect x="0" y="0" width="140" height="100" rx="4" fill="#111" stroke="#333" stroke-width="1" />'
|
||||
. '<rect x="4" y="4" width="132" height="92" rx="2" fill="#1c2333" />'
|
||||
. '<text x="10" y="16" font-size="6" fill="rgba(255,255,255,.5)" font-family="Inter,sans-serif" font-weight="600">VENDOR: FARM FRESH</text>'
|
||||
. '<rect x="10" y="22" width="120" height="1" fill="rgba(255,255,255,.1)" />'
|
||||
/* Product categories */
|
||||
. '<text x="10" y="36" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">Tomatoes</text>'
|
||||
. '<text x="110" y="36" font-size="6" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="end">$3/kg</text>'
|
||||
. '<text x="10" y="48" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">Strawberries</text>'
|
||||
. '<text x="110" y="48" font-size="6" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="end">$5/punnet</text>'
|
||||
. '<text x="10" y="60" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">Sourdough</text>'
|
||||
. '<text x="110" y="60" font-size="6" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="end">$8/loaf</text>'
|
||||
/* Activity mini chart */
|
||||
. '<text x="10" y="76" font-size="5" fill="rgba(255,255,255,.3)" font-family="Inter,sans-serif" font-weight="600">SALES TODAY</text>'
|
||||
. '<g transform="translate(10,80)">'
|
||||
. '<rect class="ind-vendor-bar" x="0" y="25" width="12" height="3" fill="#D83302" />'
|
||||
. '<rect class="ind-vendor-bar" x="16" y="20" width="12" height="8" fill="#D83302" />'
|
||||
. '<rect class="ind-vendor-bar" x="32" y="15" width="12" height="13" fill="#D83302" />'
|
||||
. '<rect class="ind-vendor-bar" x="48" y="10" width="12" height="18" fill="#4CAF50" />'
|
||||
. '<rect class="ind-vendor-bar" x="64" y="18" width="12" height="10" fill="#D83302" />'
|
||||
. '<rect class="ind-vendor-bar" x="80" y="12" width="12" height="16" fill="#D83302" />'
|
||||
. '<rect class="ind-vendor-bar" x="96" y="8" width="12" height="20" fill="#4CAF50" />'
|
||||
. '</g>'
|
||||
. '</g>'
|
||||
/* ── Second display – event board (standing) ── */
|
||||
. '<g transform="translate(220,120)">'
|
||||
. '<rect x="0" y="0" width="140" height="100" rx="3" fill="#111" stroke="#333" stroke-width="1" />'
|
||||
. '<rect x="4" y="4" width="132" height="92" rx="2" fill="#1c2333" />'
|
||||
. '<text x="70" y="16" font-size="6" fill="rgba(255,255,255,.5)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600">UPCOMING EVENTS</text>'
|
||||
. '<rect x="10" y="22" width="120" height="1" fill="rgba(255,255,255,.1)" />'
|
||||
. '<text x="10" y="36" font-size="6" fill="#D83302" font-family="Inter,sans-serif">\u2022 Live Music 12:00</text>'
|
||||
. '<text x="10" y="48" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">\u2022 Cooking Demo 1:30</text>'
|
||||
. '<text x="10" y="60" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">\u2022 Kids Workshop 2:00</text>'
|
||||
. '<text x="10" y="72" font-size="6" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">\u2022 Prize Draw 3:30</text>'
|
||||
. '<rect x="10" y="78" width="120" height="12" rx="2" fill="#00757c" opacity=".2" />'
|
||||
. '<text x="70" y="87" font-size="5.5" fill="#00757c" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600">VIEW FULL SCHEDULE</text>'
|
||||
. '</g>'
|
||||
/* Ground/grass hint */
|
||||
. '<rect x="0" y="250" width="400" height="50" fill="#12121f" />'
|
||||
. '<text x="110" y="245" font-size="7" fill="rgba(255,255,255,.25)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600" letter-spacing=".1em">VENDOR DISPLAY</text>'
|
||||
. '<text x="290" y="245" font-size="7" fill="rgba(255,255,255,.25)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600" letter-spacing=".1em">EVENT BOARD</text>'
|
||||
. '</svg></div>';
|
||||
$visual_cls = 'platform-visual has-industry';
|
||||
|
||||
/* ── Industry: Live Data Displays ──────────────────────── */
|
||||
} elseif ( ! empty( $a['industryLiveData'] ) ) {
|
||||
$visual_html = '<div class="ind-stage" data-industry-anim="livedata" aria-hidden="true">'
|
||||
. '<svg viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Live data display environment">'
|
||||
. '<defs>'
|
||||
. '<linearGradient id="indLdGrad" x1="0%" y1="0%" x2="0%" y2="100%">'
|
||||
. '<stop offset="0%" stop-color="#D83302" stop-opacity="1"/>'
|
||||
. '<stop offset="100%" stop-color="#4CAF50" stop-opacity=".8"/>'
|
||||
. '</linearGradient>'
|
||||
. '</defs>'
|
||||
. '<rect x="0" y="0" width="400" height="300" rx="8" fill="#1a1a2e" />'
|
||||
/* ── Monitor 1: Bar chart (left) ── */
|
||||
. '<g transform="translate(10,15)">'
|
||||
. '<rect x="0" y="0" width="125" height="130" rx="4" fill="#111" stroke="#333" stroke-width="1.5" />'
|
||||
. '<rect x="4" y="4" width="117" height="122" rx="2" fill="#1c2333" />'
|
||||
. '<text x="10" y="16" font-size="5.5" fill="rgba(255,255,255,.5)" font-family="Inter,sans-serif" font-weight="600">THROUGHPUT</text>'
|
||||
. '<g transform="translate(10,22)">'
|
||||
. '<rect class="ind-ld-bar" x="0" y="30" width="12" height="5" fill="url(#indLdGrad)" />'
|
||||
. '<rect class="ind-ld-bar" x="16" y="25" width="12" height="10" fill="url(#indLdGrad)" />'
|
||||
. '<rect class="ind-ld-bar" x="32" y="20" width="12" height="15" fill="url(#indLdGrad)" />'
|
||||
. '<rect class="ind-ld-bar" x="48" y="15" width="12" height="20" fill="url(#indLdGrad)" />'
|
||||
. '<rect class="ind-ld-bar" x="64" y="22" width="12" height="13" fill="url(#indLdGrad)" />'
|
||||
. '<rect class="ind-ld-bar" x="80" y="18" width="12" height="17" fill="url(#indLdGrad)" />'
|
||||
. '<rect class="ind-ld-bar" x="96" y="12" width="12" height="23" fill="url(#indLdGrad)" />'
|
||||
. '</g>'
|
||||
. '<g transform="translate(10,62)">'
|
||||
. '<text class="ind-ld-val" x="6" y="0" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif" text-anchor="middle">0</text>'
|
||||
. '<text class="ind-ld-val" x="22" y="0" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif" text-anchor="middle">0</text>'
|
||||
. '<text class="ind-ld-val" x="38" y="0" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif" text-anchor="middle">0</text>'
|
||||
. '<text class="ind-ld-val" x="54" y="0" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif" text-anchor="middle">0</text>'
|
||||
. '<text class="ind-ld-val" x="70" y="0" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif" text-anchor="middle">0</text>'
|
||||
. '<text class="ind-ld-val" x="86" y="0" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif" text-anchor="middle">0</text>'
|
||||
. '<text class="ind-ld-val" x="102" y="0" font-size="5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif" text-anchor="middle">0</text>'
|
||||
. '</g>'
|
||||
/* Status line */
|
||||
. '<g transform="translate(10,76)">'
|
||||
. '<circle class="ind-ld-alert" cx="4" cy="4" r="3" fill="#4CAF50" />'
|
||||
. '<text class="ind-ld-alert-text" x="12" y="7" font-size="5.5" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">All Systems OK</text>'
|
||||
. '</g>'
|
||||
/* Line chart below */
|
||||
. '<g transform="translate(10,90)">'
|
||||
. '<text x="0" y="0" font-size="5" fill="rgba(255,255,255,.3)" font-family="Inter,sans-serif">LATENCY</text>'
|
||||
. '<line x1="0" y1="8" x2="100" y2="8" stroke="rgba(255,255,255,.05)" stroke-width=".5" />'
|
||||
. '<line x1="0" y1="20" x2="100" y2="20" stroke="rgba(255,255,255,.05)" stroke-width=".5" />'
|
||||
. '<line x1="0" y1="32" x2="100" y2="32" stroke="rgba(255,255,255,.05)" stroke-width=".5" />'
|
||||
. '<path class="ind-ld-line" d="M0,20 L110,20" stroke="#4CAF50" stroke-width="1.5" fill="none" stroke-linecap="round" />'
|
||||
. '</g>'
|
||||
/* Monitor stand */
|
||||
. '<rect x="50" y="130" width="25" height="10" fill="#222" />'
|
||||
. '<rect x="35" y="138" width="55" height="3" rx="1" fill="#333" />'
|
||||
. '</g>'
|
||||
/* ── Monitor 2: Pie chart + KPIs (center) ── */
|
||||
. '<g transform="translate(145,15)">'
|
||||
. '<rect x="0" y="0" width="110" height="130" rx="4" fill="#111" stroke="#333" stroke-width="1.5" />'
|
||||
. '<rect x="4" y="4" width="102" height="122" rx="2" fill="#1c2333" />'
|
||||
. '<text x="10" y="16" font-size="5.5" fill="rgba(255,255,255,.5)" font-family="Inter,sans-serif" font-weight="600">DISTRIBUTION</text>'
|
||||
/* Pie chart */
|
||||
. '<g transform="translate(55,56)">'
|
||||
. '<path class="ind-ld-pie" d="M0,0 L0,-22 A22,22 0 0,1 15.56,-15.56 Z" fill="#D83302" opacity=".9"/>'
|
||||
. '<path class="ind-ld-pie" d="M0,0 L15.56,-15.56 A22,22 0 0,1 22,0 Z" fill="#4CAF50" opacity=".8"/>'
|
||||
. '<path class="ind-ld-pie" d="M0,0 L22,0 A22,22 0 0,1 0,22 Z" fill="#f59e0b" opacity=".7"/>'
|
||||
. '<path class="ind-ld-pie" d="M0,0 L0,22 A22,22 0 0,1 -22,0 Z" fill="#5b5fc7" opacity=".7"/>'
|
||||
. '<path class="ind-ld-pie" d="M0,0 L-22,0 A22,22 0 0,1 0,-22 Z" fill="#ef4444" opacity=".6"/>'
|
||||
. '<circle cx="0" cy="0" r="10" fill="#1c2333" stroke="rgba(255,255,255,.1)" stroke-width=".5"/>'
|
||||
. '</g>'
|
||||
/* Legend */
|
||||
. '<g transform="translate(10,88)">'
|
||||
. '<rect x="0" y="0" width="5" height="5" fill="#D83302"/><text x="8" y="5" font-size="4.5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">API</text>'
|
||||
. '<rect x="30" y="0" width="5" height="5" fill="#4CAF50"/><text x="38" y="5" font-size="4.5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">DB</text>'
|
||||
. '<rect x="58" y="0" width="5" height="5" fill="#f59e0b"/><text x="66" y="5" font-size="4.5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">Cache</text>'
|
||||
. '<rect x="0" y="12" width="5" height="5" fill="#5b5fc7"/><text x="8" y="17" font-size="4.5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">Queue</text>'
|
||||
. '<rect x="40" y="12" width="5" height="5" fill="#ef4444"/><text x="48" y="17" font-size="4.5" fill="rgba(255,255,255,.4)" font-family="Inter,sans-serif">Worker</text>'
|
||||
. '</g>'
|
||||
/* Monitor stand */
|
||||
. '<rect x="40" y="130" width="30" height="10" fill="#222" />'
|
||||
. '<rect x="25" y="138" width="60" height="3" rx="1" fill="#333" />'
|
||||
. '</g>'
|
||||
/* ── Monitor 3: Alert feed (right) ── */
|
||||
. '<g transform="translate(265,15)">'
|
||||
. '<rect x="0" y="0" width="125" height="130" rx="4" fill="#111" stroke="#333" stroke-width="1.5" />'
|
||||
. '<rect x="4" y="4" width="117" height="122" rx="2" fill="#1c2333" />'
|
||||
. '<text x="10" y="16" font-size="5.5" fill="rgba(255,255,255,.5)" font-family="Inter,sans-serif" font-weight="600">SYSTEM STATUS</text>'
|
||||
/* Status rows */
|
||||
. '<g transform="translate(10,24)">'
|
||||
. '<circle cx="5" cy="4" r="3" fill="#4CAF50"/>'
|
||||
. '<text x="12" y="7" font-size="5.5" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">API Gateway</text>'
|
||||
. '<text x="100" y="7" font-size="5" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="end">OK</text>'
|
||||
. '</g>'
|
||||
. '<g transform="translate(10,38)">'
|
||||
. '<circle cx="5" cy="4" r="3" fill="#4CAF50"/>'
|
||||
. '<text x="12" y="7" font-size="5.5" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">Database</text>'
|
||||
. '<text x="100" y="7" font-size="5" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="end">OK</text>'
|
||||
. '</g>'
|
||||
. '<g transform="translate(10,52)">'
|
||||
. '<circle cx="5" cy="4" r="3" fill="#f59e0b"/>'
|
||||
. '<text x="12" y="7" font-size="5.5" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">Cache Layer</text>'
|
||||
. '<text x="100" y="7" font-size="5" fill="#f59e0b" font-family="Inter,sans-serif" text-anchor="end">WARN</text>'
|
||||
. '</g>'
|
||||
. '<g transform="translate(10,66)">'
|
||||
. '<circle cx="5" cy="4" r="3" fill="#4CAF50"/>'
|
||||
. '<text x="12" y="7" font-size="5.5" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">CDN</text>'
|
||||
. '<text x="100" y="7" font-size="5" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="end">OK</text>'
|
||||
. '</g>'
|
||||
. '<g transform="translate(10,80)">'
|
||||
. '<circle cx="5" cy="4" r="3" fill="#4CAF50"/>'
|
||||
. '<text x="12" y="7" font-size="5.5" fill="rgba(255,255,255,.6)" font-family="Inter,sans-serif">Workers</text>'
|
||||
. '<text x="100" y="7" font-size="5" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="end">OK</text>'
|
||||
. '</g>'
|
||||
/* Uptime badge */
|
||||
. '<rect x="10" y="95" width="97" height="18" rx="3" fill="#252540" />'
|
||||
. '<text x="58" y="107" font-size="7" fill="#4CAF50" font-family="Inter,sans-serif" text-anchor="middle" font-weight="700">99.98% Uptime</text>'
|
||||
/* Monitor stand */
|
||||
. '<rect x="48" y="130" width="29" height="10" fill="#222" />'
|
||||
. '<rect x="33" y="138" width="59" height="3" rx="1" fill="#333" />'
|
||||
. '</g>'
|
||||
/* ── Desk surface ── */
|
||||
. '<rect x="0" y="160" width="400" height="4" fill="#333" />'
|
||||
/* Labels */
|
||||
. '<text x="72" y="180" font-size="7" fill="rgba(255,255,255,.25)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600" letter-spacing=".1em">THROUGHPUT</text>'
|
||||
. '<text x="200" y="180" font-size="7" fill="rgba(255,255,255,.25)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600" letter-spacing=".1em">DISTRIBUTION</text>'
|
||||
. '<text x="327" y="180" font-size="7" fill="rgba(255,255,255,.25)" font-family="Inter,sans-serif" text-anchor="middle" font-weight="600" letter-spacing=".1em">SYSTEM STATUS</text>'
|
||||
. '</svg></div>';
|
||||
$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 .= '<div class="gtv-slide' . $active . '">';
|
||||
$slides .= '<img src="' . esc_url( $url ) . '" alt="' . esc_attr( $alt ) . '" loading="lazy" />';
|
||||
$slides .= '</div>';
|
||||
$count++;
|
||||
}
|
||||
if ( $count > 0 ) {
|
||||
$visual_html = '<div class="gtv-stage" data-gtv-slideshow aria-hidden="true">';
|
||||
$visual_html .= '<div class="gtv-tv">';
|
||||
$visual_html .= '<div class="gtv-tv__body">';
|
||||
$visual_html .= '<div class="gtv-tv__screen">';
|
||||
$visual_html .= '<div class="gtv-slides">' . $slides . '</div>';
|
||||
$visual_html .= '</div>'; // screen
|
||||
$visual_html .= '</div>'; // body
|
||||
$visual_html .= '<div class="gtv-tv__feet"><div class="gtv-tv__foot"></div><div class="gtv-tv__foot"></div></div>';
|
||||
$visual_html .= '</div>'; // tv
|
||||
$visual_html .= '</div>'; // 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 ) {
|
||||
</div>
|
||||
<?php return ob_get_clean();
|
||||
}
|
||||
|
||||
/* ── Trust Section (parent - wraps child trust-item blocks) ────────────────── */
|
||||
function oribi_render_trust_section( $a, $content ) {
|
||||
ob_start(); ?>
|
||||
|
||||
@@ -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' ),
|
||||
|
||||
Reference in New Issue
Block a user