Compare commits
23 Commits
oribi-sync
...
oribi-sync
| Author | SHA1 | Date | |
|---|---|---|---|
| aef7e19fab | |||
|
|
c5d5ad33e5 | ||
|
|
c42c7d7dbc | ||
|
|
5d09382d0d | ||
|
|
accdfa9d70 | ||
|
|
a9697dd714 | ||
|
|
ab6f4212bd | ||
|
|
7e0c216e1c | ||
|
|
d68c2c1d31 | ||
|
|
4591578cb2 | ||
|
|
954c418556 | ||
|
|
b37bcfb72b | ||
|
|
0ec0e71d38 | ||
|
|
e1d9b1a402 | ||
|
|
a33a6d62d2 | ||
|
|
38d585e071 | ||
|
|
f8321568ce | ||
|
|
be30e4d59f | ||
|
|
3e211c376f | ||
|
|
618ba6ded4 | ||
| 3100a93d9a | |||
|
|
8ceb81008c | ||
|
|
0420be8bd6 |
@@ -10,7 +10,7 @@
|
||||
<!-- wp:oribi/page-hero-animated {"label":"Hardware","title":"Signage Players Engineered for the Real World","description":"Compact, silent, and built for 24/7 operation. Plug into any HDMI screen, connect to your network, and your content is live in minutes."} /-->
|
||||
|
||||
<!-- wp:oribi/platform-section {"label":"Our Devices","heading":"Commercial-Grade Hardware, Consumer-Level Simplicity","lead":"No IT degree required. Our players are designed to be set up in minutes and forgotten about for years."} -->
|
||||
<!-- wp:oribi/platform-row {"heading":"Plug Into Any Screen","description":"Our players work with any display that has an HDMI port — TVs, commercial panels, monitors, even projectors. Keep the screens you already own, or let us supply commercial-grade displays rated for continuous use. Either way, you\u0027re up and running fast.","btnText":"Get a Quote","btnUrl":"/contact"} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Works With Your Existing Screens","description":"Our player devices connect to any screen with an HDMI port — no proprietary hardware required. Already have displays? Plug in and go. Need a full setup? We offer bundled player-and-display packages too.","btnText":"Get a Quote","btnUrl":"/contact","tvStick":true} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Never Goes Dark","description":"Every player caches content locally. If your internet connection drops, your displays continue running seamlessly with the latest synced content. When connectivity returns, new content pulls down automatically — no manual steps, no reboots.","btnText":"See Features","btnUrl":"/features","reversed":true} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Locked Down by Default","description":"Secure boot, encrypted storage, and encrypted communications come standard on every device. Remote management lets you monitor, update, and troubleshoot from anywhere. Firmware updates roll out over the air with zero downtime.","btnText":"Learn More","btnUrl":"/about"} /-->
|
||||
<!-- /wp:oribi/platform-section -->
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
<!-- wp:oribi/page-hero-animated {"label":"FAQ","title":"Your Questions, Answered","description":"Everything you need to know about our platform, pricing, setup, and support — in plain language."} /-->
|
||||
|
||||
<!-- wp:oribi/faq-section {"label":"Platform \u0026 Pricing","heading":"Plans, Pricing \u0026 What\u0027s Included","lead":"Straightforward answers about what you get and what it costs."} -->
|
||||
<!-- wp:oribi/faq-item {"question":"What\u0027s included in the Essentials plan?","answer":"Essentials gives you up to 20 screens, a custom subdomain, content scheduling with day-parting, live data integration, unlimited users, and the ability to publish to your screens in seconds. Pricing is $7 per screen per month, or $70 per screen if you pay annually."} /-->
|
||||
<!-- wp:oribi/faq-item {"question":"What extra do I get with Pro?","answer":"Pro is built for larger deployments: 500+ screens, a dedicated CMS server, custom domain, bespoke data integrations, advanced analytics, SSO with role-based access, an SLA guarantee, and a named account manager. Contact us for a tailored quote."} /-->
|
||||
<!-- wp:oribi/faq-item {"question":"What\u0027s included in the Essentials plan?","answer":"Essentials gives you up to 50 screens on a shared CMS instance with a custom subdomain. You get full content scheduling with day-parting, DataSets, RSS feeds, social widgets, embedded HTML, menu boards, interactive layouts, Canva integration, offline playback, Proof of Play analytics with 30-day retention, unlimited users with standard roles, and two-factor authentication. Pricing is $7 per screen per month, or $70 per screen if you pay annually."} /-->
|
||||
<!-- wp:oribi/faq-item {"question":"What extra do I get with Pro?","answer":"Pro gives you unlimited screens on a dedicated CMS instance with a custom domain. On top of everything in Essentials, you get geo-location and weather-triggered scheduling, video wall support, ad campaigns with SSP monetisation, Dashboard Connector and custom API integrations, Audience Reporting with scheduled PDF reports, Proof of Play with 12+ month retention, SSO via SAML or CAS, custom user roles, extended audit trails, display map view, shell commands, in-house creative services, white-glove onboarding, priority support with a 4-hour SLA, a dedicated account manager, and a contractual SLA guarantee. Contact us for a tailored quote."} /-->
|
||||
<!-- wp:oribi/faq-item {"question":"Are there any hidden fees?","answer":"None. Your per-screen fee covers the CMS, cloud hosting, software updates, and standard support. Content creation services and hardware are quoted separately and always upfront."} /-->
|
||||
<!-- wp:oribi/faq-item {"question":"Can I upgrade later?","answer":"Yes — at any time. Moving from Essentials to Pro is seamless. We handle the migration behind the scenes with no disruption to your live displays."} /-->
|
||||
<!-- /wp:oribi/faq-section -->
|
||||
@@ -19,7 +19,7 @@
|
||||
<!-- wp:oribi/faq-section {"variant":"alt","label":"Setup \u0026 Integration","heading":"Getting Up and Running","lead":"What to expect when you set up your first screen and connect your systems."} -->
|
||||
<!-- wp:oribi/faq-item {"question":"How quickly can I be up and running?","answer":"Most installations go live within a day. Plug in the player device, connect it to your network, and your content appears on screen. We configure your CMS in advance and can have your first content loaded and ready before the hardware arrives."} /-->
|
||||
<!-- wp:oribi/faq-item {"question":"Do I need to buy new screens?","answer":"No. Our players work with any display that has an HDMI port — consumer TVs, commercial panels, or monitors you already own. If you do need screens, we offer bundled player-and-display packages built for commercial use."} /-->
|
||||
<!-- wp:oribi/faq-item {"question":"How do live data integrations work?","answer":"We connect your existing web dashboards, APIs, RSS feeds, and social accounts directly to your signage layouts. Data updates appear on screen in real time. Standard integrations are included on Essentials; Pro adds custom integration development for bespoke data sources."} /-->
|
||||
<!-- wp:oribi/faq-item {"question":"How do live data integrations work?","answer":"Every plan includes DataSets, RSS feeds, social widgets, and embedded HTML — data updates appear on screen in real time. Pro adds the Dashboard Connector for secure third-party service connections, custom API integrations for bespoke data sources, and the SSP Connector for ad monetisation."} /-->
|
||||
<!-- wp:oribi/faq-item {"question":"What kind of internet connection do I need?","answer":"A standard business broadband connection is more than enough. Our players sync content incrementally and cache everything locally, so bandwidth usage is minimal. For locations with unreliable connectivity, offline playback ensures your displays never go dark."} /-->
|
||||
<!-- /wp:oribi/faq-section -->
|
||||
|
||||
|
||||
@@ -12,17 +12,16 @@
|
||||
<!-- wp:oribi/platform-section {"label":"Core Features","heading":"Everything You Need, Nothing You Don\u0027t","lead":"Create, schedule, and manage digital signage content from a single dashboard — whether you have one screen or one thousand."} -->
|
||||
<!-- wp:oribi/platform-row {"heading":"One Dashboard for Every Display","description":"Manage your entire signage network from a single cloud-based console. Organise screens by location, group, or purpose. Push content updates across your whole estate in one click — no matter how many sites you operate.","btnText":"Get Started","btnUrl":"/contact"} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Scheduling That Runs Itself","description":"Set content to appear at the right time, in the right place, automatically. Day-parting, date ranges, and event-triggered playback let you plan weeks ahead while the platform handles the execution.","btnText":"See Pricing","btnUrl":"/pricing","reversed":true} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Works With Your Existing Screens","description":"Our player devices connect to any screen with an HDMI port — no proprietary hardware required. Already have displays? Plug in and go. Need a full setup? We offer bundled player-and-display packages too.","btnText":"View Devices","btnUrl":"/devices"} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Enterprise Security, Zero Hassle","description":"End-to-end encryption, role-based access, and secure cloud hosting keep your content and network locked down. Our player devices cache content locally and continue displaying even during internet outages.","btnText":"Learn More","btnUrl":"/about","reversed":true} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Live Data, Straight to Screen","description":"Pull in web dashboards, social feeds, KPIs, and real-time APIs directly to your displays. Content updates automatically — no manual refreshing, no extra steps. Turn any screen into a live information hub.","btnText":"Learn More","btnUrl":"/solutions","reversed":true} /-->
|
||||
<!-- /wp:oribi/platform-section -->
|
||||
|
||||
<!-- wp:oribi/feature-section {"variant":"alt","label":"Capabilities","heading":"The Tools Behind Great Signage","lead":"From content creation to performance tracking, every feature is designed to save you time and keep your screens looking sharp.","columns":3} -->
|
||||
<!-- wp:oribi/feature-card {"iconType":"fontawesome","faIcon":"fas fa-cloud","title":"Cloud-Native CMS","description":"Log in from any browser, anywhere. No software to install, no servers to maintain. Your content is always accessible and backed up."} /-->
|
||||
<!-- wp:oribi/feature-card {"iconType":"fontawesome","faIcon":"fas fa-clock","title":"Intelligent Scheduling","description":"Day-parting, date-based playlists, and event triggers let you automate content rotation down to the minute."} /-->
|
||||
<!-- wp:oribi/feature-card {"iconType":"fontawesome","faIcon":"fas fa-chart-line","title":"Live Data on Screen","description":"Pull in web dashboards, social feeds, KPIs, and APIs. Your displays update in real time without manual intervention."} /-->
|
||||
<!-- wp:oribi/feature-card {"iconType":"fontawesome","faIcon":"fas fa-wifi","title":"Offline Playback","description":"Content is cached on the player device. If your connection drops, your displays keep running seamlessly until it returns."} /-->
|
||||
<!-- wp:oribi/feature-card {"iconType":"fontawesome","faIcon":"fas fa-users","title":"Unlimited Users","description":"Invite your entire team at no extra cost. No per-seat charges, no access restrictions — on any plan."} /-->
|
||||
<!-- wp:oribi/feature-card {"iconType":"fontawesome","faIcon":"fas fa-shield-halved","title":"Enterprise Security","description":"End-to-end encryption, role-based access control, secure boot hardware, and SOC 2-aligned cloud infrastructure."} /-->
|
||||
<!-- wp:oribi/feature-card {"iconType":"fontawesome","faIcon":"fas fa-chart-pie","title":"Playback Analytics","description":"Track what\u0027s playing, where, and when. Proof of Play reporting, screen health monitoring, and content logs give you full visibility — with retention depth that scales with your plan."} /-->
|
||||
<!-- wp:oribi/feature-card {"iconType":"fontawesome","faIcon":"fas fa-shield-halved","title":"Enterprise Security","description":"End-to-end encryption, two-factor authentication, secure boot hardware, and predefined user roles on every plan. Pro adds SSO via SAML or CAS, custom role definitions, and extended audit trails."} /-->
|
||||
<!-- /wp:oribi/feature-section -->
|
||||
|
||||
<!-- wp:oribi/value-section {"variant":"normal","label":"Why Choose Us","heading":"Beyond the Software","lead":"Great signage takes more than a CMS. Here\u0027s what you get when you work with OTS Signs.","columns":3} -->
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
return <<<'ORIBI_SYNC_CONTENT'
|
||||
<!-- wp:oribi/hero-animated {"label":"● Digital Signage Solutions","title":"Turn any screen into a dynamic communication tool.","highlightWord":"dynamic","description":"Digital signage is the modern way to connect with your audience. From eye-catching retail displays to dynamic informational screens, we craft tailored solutions that capture attention and deliver your message.","secondaryBtnText":"Request Demo","secondaryBtnUrl":"/demo","stat1Value":"4K","stat1Label":"Resolution Supported","stat2Value":"500+","stat2Label":"Screens Supported","stat3Value":"99.9%","stat3Label":"Uptime"} /-->
|
||||
|
||||
<!-- wp:oribi/use-cases {"label":"● Use Cases","heading":"Built for Every Scenario","lead":"From menus to meeting-room dashboards, digital signage adapts to your environment.","case1Title":"Menu Boards","case1Desc":"Showcase food, drinks, and daily specials with dynamic, always-current displays.","case2Title":"Event Displays","case2Desc":"Promote schedules, speakers, and live countdowns across lobbies and venues.","case3Title":"Office Dashboards","case3Desc":"Surface KPIs, occupancy data, and team alerts on screens throughout your workspace.","case4Title":"Wayfinding","case4Desc":"Guide visitors through complex buildings with interactive maps and directional signs."} /-->
|
||||
|
||||
<!-- wp:oribi/platform-section {"label":"The Complete Package","heading":"Everything You Need for Engaging Digital Signage","lead":"High-quality visuals, real-time data, and reliable playback — all managed from one powerful platform."} -->
|
||||
<!-- wp:oribi/platform-row {"heading":"Professional Content Creation","description":"Our in-house photography and video production services showcase your products, services, and environment with polished, engaging visuals. From digital menu boards to branded promotions, we create content that captures attention.","btnText":"See Features","btnUrl":"/features"} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Professional Content Creation","description":"Our in-house photography and video production services showcase your products, services, and environment with polished, engaging visuals. From digital menu boards to branded promotions, we create content that captures attention.","btnText":"See Features","btnUrl":"/features","cameraAnim":true} /-->
|
||||
|
||||
<!-- wp:oribi/platform-row {"heading":"Live Data \u0026amp; Web Dashboards","description":"Integrate your existing web dashboards, social feeds, and real-time data sources directly to your displays. Bring your most important information to life on screen, automatically and effortlessly.","btnUrl":"/features","reversed":true} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Live Data u0026amp; Web Dashboards","description":"Integrate your existing web dashboards, social feeds, and real-time data sources directly to your displays. Bring your most important information to life on screen, automatically and effortlessly.","btnUrl":"/features","reversed":true,"isDashboard":true} /-->
|
||||
|
||||
<!-- wp:oribi/platform-row {"heading":"Reliable on Any Screen","description":"Our intelligent player devices work on any screen with HDMI, and keep your message running even when the internet goes down. Enterprise-grade hardware designed for uninterrupted, always-on signage.","btnText":"View Devices","btnUrl":"/devices"} /-->
|
||||
<!-- wp:oribi/platform-row {"heading":"Reliable on Any Screen","description":"Our intelligent player devices work on any screen with HDMI, and keep your message running even when the internet goes down. Enterprise-grade hardware designed for uninterrupted, always-on signage.","btnText":"View Devices","btnUrl":"/devices","deviceAnim":true} /-->
|
||||
<!-- /wp:oribi/platform-section -->
|
||||
|
||||
<!-- wp:oribi/feature-section {"variant":"alt","label":"Who It's For","heading":"Solutions for Every Industry","lead":"Modern businesses need real-time communication. Digital signage helps you connect, inform, and engage.","columns":4} -->
|
||||
|
||||
@@ -1,26 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
/*
|
||||
* Title: Pricing
|
||||
* Slug: ots-signs/page-pricing
|
||||
* Categories: oribi-pages
|
||||
* Keywords: pricing, plans, affordable, scalable, essentials, pro
|
||||
* Post Types: page
|
||||
* Slug: pricing
|
||||
* Post Type: page
|
||||
*/
|
||||
?>
|
||||
<!-- wp:oribi/page-hero-animated {"label":"Pricing","title":"Straightforward Pricing, No Surprises","description":"Every plan includes the full platform. Pick the tier that matches your scale, and start displaying. No hidden fees, no feature gates on the essentials."} /-->
|
||||
|
||||
<!-- wp:oribi/value-section {"variant":"normal","label":"Included on Every Plan","heading":"The Full Platform, From Day One","lead":"Whether you choose Essentials or Pro, you get the same powerful core. No artificial restrictions.","columns":4} -->
|
||||
<!-- wp:oribi/value-card {"iconType":"fontawesome","faIcon":"fas fa-clock","title":"Automated Scheduling","description":"Day-parting, date ranges, and event-based triggers — your content plays at exactly the right time, automatically."} /-->
|
||||
<!-- wp:oribi/value-card {"iconType":"fontawesome","faIcon":"fas fa-chart-line","title":"Live Data Feeds","description":"Display web dashboards, social feeds, and real-time metrics directly on your screens — updated automatically."} /-->
|
||||
return <<<'ORIBI_SYNC_CONTENT'
|
||||
<!-- wp:oribi/page-hero-animated {"label":"Pricing","title":"Straightforward Pricing, No Surprises","description":"Every plan includes the full content engine. Scale your infrastructure, integrations, and support as you grow. No hidden fees, no per-user charges."} /-->
|
||||
|
||||
<!-- wp:oribi/value-section {"label":"Included on Every Plan","heading":"The Full Content Engine, From Day One","lead":"Whether you choose Essentials or Pro, your team gets the same powerful tools to create, schedule, and publish.","columns":4} -->
|
||||
<!-- wp:oribi/value-card {"iconType":"fontawesome","faIcon":"fas fa-clock","title":"Automated Scheduling","description":"Day-parting, date ranges, and recurring schedules — your content plays at exactly the right time, automatically."} /-->
|
||||
|
||||
<!-- wp:oribi/value-card {"iconType":"fontawesome","faIcon":"fas fa-rss","title":"Live Data to Screen","description":"Pull DataSets, RSS feeds, social widgets, and embedded HTML directly to your displays — updated in real time."} /-->
|
||||
|
||||
<!-- wp:oribi/value-card {"iconType":"fontawesome","faIcon":"fas fa-users","title":"Unlimited Team Access","description":"Invite everyone who needs access. No per-user fees, no seat limits, no gatekeeping."} /-->
|
||||
|
||||
<!-- wp:oribi/value-card {"iconType":"fontawesome","faIcon":"fas fa-rocket","title":"Instant Publishing","description":"Upload content and push it live across your network in seconds — not hours."} /-->
|
||||
<!-- /wp:oribi/value-section -->
|
||||
|
||||
<!-- wp:oribi/pricing-section {"variant":"alt","label":"Choose Your Plan","heading":"Scale When You\u0027re Ready","lead":"Start with Essentials and upgrade seamlessly as your network grows. No disruption, no data loss."} -->
|
||||
<!-- wp:oribi/pricing-card {"name":"Essentials","tagline":"$7/Screen Monthly · $70/Screen Annually","features":["Up to 20 screens","Custom subdomain","Shared CMS server","Content scheduling & day-parting","Integration with live data sources","Unlimited user seats","Publish content in minutes","Offline playback support","Email support"],"btnText":"Get Started","btnUrl":"/contact"} /-->
|
||||
<!-- wp:oribi/pricing-card {"name":"Pro","tagline":"Contact us for more information","features":["500+ screens","Custom domain","Dedicated CMS server","Custom live data integrations","Priority support","Advanced analytics","SSO & role-based access","SLA guarantee","Dedicated account manager"],"btnText":"Contact Sales","btnUrl":"/contact","featured":true,"badge":"Enterprise"} /-->
|
||||
<!-- wp:oribi/pricing-section {"variant":"alt","label":"Choose Your Plan","heading":"Scale When Youu0027re Ready","lead":"Start with Essentials and upgrade seamlessly as your network grows. No disruption, no data loss."} -->
|
||||
<!-- wp:oribi/pricing-card {"name":"Essentials","tagline":"The full content engine for growing networks","price":"$7","pricePer":"per screen / month · or $70/screen annually","features":["Up to 50 screens","Custom subdomain","Shared CMS instance","Content scheduling \u0026 day-parting","DataSets, RSS, social \u0026 embedded widgets","Menu boards \u0026 interactive layouts","Unlimited users with standard roles","Canva integration","Offline playback","Proof of Play analytics (30-day retention)","Email support (next-business-day)"]} /-->
|
||||
|
||||
<!-- wp:oribi/pricing-card {"name":"Pro","tagline":"Dedicated infrastructure, enterprise integrations \u0026 white-glove service","price":"Custom","pricePer":"tailored to your network size","features":["Unlimited screens","Custom domain","Dedicated CMS instance","Geo-location \u0026 weather-triggered scheduling","Dashboard Connector \u0026 custom API integrations","Video wall support","Ad campaigns \u0026 SSP monetisation","SSO (SAML/CAS) \u0026 custom user roles","Proof of Play analytics (12+ month retention)","Audience Reporting \u0026 scheduled PDF reports","Priority support (4-hour SLA) \u0026 account manager","Contractual SLA guarantee"],"btnText":"Contact Sales","featured":true,"badge":"Enterprise"} /-->
|
||||
<!-- /wp:oribi/pricing-section -->
|
||||
|
||||
<!-- wp:oribi/intro-section {"variant":"normal","label":"Try Before You Commit","heading":"Want to Explore the Platform First?","description":"Request access to our live demo instance and take the full CMS for a spin — create content, set up schedules, and see exactly how it works. No credit card, no obligation.","visual":""} /-->
|
||||
<!-- wp:oribi/comparison-table {"label":"Plan Comparison","heading":"See Exactly Whatu0027s Included","lead":"A full breakdown of what you get on each plan — so there are no surprises.","columns":["Essentials","Pro"],"rows":[{"group":"Scale \u0026 Infrastructure"},{"feature":"Screen limit","values":["Up to 50","Unlimited"]},{"feature":"CMS instance","values":["Shared","Dedicated"]},{"feature":"Custom subdomain","values":[true,true]},{"feature":"Custom domain","values":[false,true]},{"group":"Content \u0026 Scheduling"},{"feature":"Day-parting \u0026 date scheduling","values":[true,true]},{"feature":"Playlists \u0026 campaigns","values":[true,true]},{"feature":"Menu boards","values":[true,true]},{"feature":"Interactive touchscreen actions","values":[true,true]},{"feature":"Overlay layouts","values":[true,true]},{"feature":"Geo-location scheduling","values":[false,true]},{"feature":"Weather-triggered scheduling","values":[false,true]},{"feature":"Video wall","values":[false,true]},{"feature":"Ad campaigns \u0026 plays-per-hour control","values":[false,true]},{"group":"Data \u0026 Integrations"},{"feature":"DataSets, RSS \u0026 tickers","values":[true,true]},{"feature":"Embedded HTML \u0026 web pages","values":[true,true]},{"feature":"Social feeds","values":[true,true]},{"feature":"Canva integration","values":[true,true]},{"feature":"Dashboard Connector","values":[false,true]},{"feature":"Custom API integrations","values":[false,true]},{"feature":"SSP Connector (ad monetisation)","values":[false,true]},{"group":"Analytics \u0026 Reporting"},{"feature":"Proof of Play reporting","values":["30-day retention","12+ month retention"]},{"feature":"Scheduled PDF reports","values":[false,true]},{"feature":"Audience Reporting","values":[false,true]},{"feature":"Display health monitoring","values":[true,true]},{"group":"Users \u0026 Security"},{"feature":"Unlimited user seats","values":[true,true]},{"feature":"Predefined roles (admin/editor/viewer)","values":[true,true]},{"feature":"Custom user roles \u0026 feature access","values":[false,true]},{"feature":"Two-factor authentication","values":[true,true]},{"feature":"SSO (SAML / CAS)","values":[false,true]},{"feature":"Audit trail","values":["7-day retention","Extended retention"]},{"group":"Display Management"},{"feature":"Screen power on/off control","values":[true,true]},{"feature":"Offline playback","values":[true,true]},{"feature":"Portrait / landscape","values":[true,true]},{"feature":"Email alerts (player offline)","values":[true,true]},{"feature":"Periodic screenshots","values":[false,true]},{"feature":"Display map view","values":[false,true]},{"feature":"Shell commands \u0026 RS232","values":[false,true]},{"group":"Support \u0026 Services"},{"feature":"Email support","values":["Next-business-day",true]},{"feature":"Priority support","values":[false,"4-hour SLA"]},{"feature":"Dedicated account manager","values":[false,true]},{"feature":"In-house creative services","values":[false,"Included hours"]},{"feature":"White-glove onboarding","values":[false,true]}]} /-->
|
||||
|
||||
<!-- wp:oribi/intro-section {"label":"Try Before You Commit","heading":"Want to Explore the Platform First?","description":"Request access to our live demo instance and take the full CMS for a spin — create content, set up schedules, and see exactly how it works. No credit card, no obligation."} /-->
|
||||
|
||||
<!-- wp:oribi/cta-banner {"heading":"Questions About Pricing?","text":"We're happy to walk you through the plans, build a custom quote, or set up a demo so you can see the value firsthand.","btnText":"Get in Touch","btnUrl":"/contact"} /-->
|
||||
ORIBI_SYNC_CONTENT;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
157
theme/assets/js/dashboard-animator.js
Normal file
157
theme/assets/js/dashboard-animator.js
Normal file
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* Dashboard Chart Animator
|
||||
* Gently animates SVG bar charts, line graph, and pie chart.
|
||||
* Pauses off-screen via IntersectionObserver for performance.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var SPEED = 0.002; // phase increment per frame
|
||||
var BAR_H = 120; // max bar height (SVG units)
|
||||
var BAR_MIN = 0.15; // min bar ratio
|
||||
var LINE_PTS = 8;
|
||||
var LINE_W = 340; // line graph width in SVG units
|
||||
var PIE_R = 55; // pie chart radius
|
||||
|
||||
var DARK = { text: '#E0E0E0', muted: '#9E9E9E', border: '#333', center: '#1A1A1A' };
|
||||
var LIGHT = { text: '#333333', muted: '#666666', border: '#E0E0E0', center: '#fff' };
|
||||
|
||||
function isDark() { return document.documentElement.getAttribute('data-theme') === 'dark'; }
|
||||
function pal() { return isDark() ? DARK : LIGHT; }
|
||||
|
||||
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 makeState(svg) {
|
||||
return {
|
||||
svg: svg,
|
||||
bars1: svg.querySelectorAll('#bars-group-1 .bar'),
|
||||
bars2: svg.querySelectorAll('#bars-group-2 .bar'),
|
||||
vals1: svg.querySelectorAll('#values-group-1 text'),
|
||||
vals2: svg.querySelectorAll('#values-group-2 text'),
|
||||
linePath: svg.querySelector('#line-path'),
|
||||
lineFill: svg.querySelector('#line-fill'),
|
||||
pieSegs: svg.querySelectorAll('.pie-segment'),
|
||||
phase: Math.random() * Math.PI * 2,
|
||||
paused: false,
|
||||
themeN: 0
|
||||
};
|
||||
}
|
||||
|
||||
function updateBars(bars, vals, st, pct) {
|
||||
for (var i = 0; i < bars.length; i++) {
|
||||
var v = Math.max(BAR_MIN, wave(st.phase, i * 1.1));
|
||||
var h = v * BAR_H;
|
||||
bars[i].setAttribute('height', h);
|
||||
bars[i].setAttribute('y', BAR_H - h);
|
||||
}
|
||||
for (var j = 0; j < Math.min(bars.length, vals.length); j++) {
|
||||
var val = Math.max(BAR_MIN, wave(st.phase, j * 1.1));
|
||||
vals[j].textContent = pct ? Math.round(val * 100) + '%' : Math.round(val * 5000);
|
||||
}
|
||||
}
|
||||
|
||||
function updateLine(st) {
|
||||
if (!st.linePath) return;
|
||||
var d = 'M';
|
||||
for (var i = 0; i < LINE_PTS; i++) {
|
||||
var x = (i / (LINE_PTS - 1)) * LINE_W;
|
||||
var y = 25 + (1 - wave(st.phase * 0.8, i * 0.9)) * 110;
|
||||
d += (i ? ' L' : '') + x.toFixed(1) + ',' + y.toFixed(1);
|
||||
}
|
||||
st.linePath.setAttribute('d', d);
|
||||
if (st.lineFill) st.lineFill.setAttribute('d', d + ' L' + LINE_W + ',145 L0,145 Z');
|
||||
}
|
||||
|
||||
/* Pie: each segment gently shifts its slice size, no spinning */
|
||||
function updatePie(st) {
|
||||
if (!st.pieSegs.length) return;
|
||||
var n = st.pieSegs.length;
|
||||
// Generate proportional weights that shift over time
|
||||
var weights = [], total = 0;
|
||||
for (var i = 0; i < n; i++) {
|
||||
var w = 0.5 + wave(st.phase * 0.4, i * 2.0) * 0.5;
|
||||
weights.push(w);
|
||||
total += w;
|
||||
}
|
||||
// Convert to cumulative angles
|
||||
var angle = 0;
|
||||
for (var j = 0; j < n; j++) {
|
||||
var sweep = (weights[j] / total) * 360;
|
||||
var startA = angle * Math.PI / 180;
|
||||
var endA = (angle + sweep) * Math.PI / 180;
|
||||
// Large-arc flag needed when sweep > 180
|
||||
var large = sweep > 180 ? 1 : 0;
|
||||
var r = PIE_R;
|
||||
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.pieSegs[j].querySelector('path');
|
||||
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'
|
||||
);
|
||||
}
|
||||
// Remove any rotation transform — segments are positioned by path geometry
|
||||
st.pieSegs[j].removeAttribute('transform');
|
||||
angle += sweep;
|
||||
}
|
||||
}
|
||||
|
||||
function applyTheme(st) {
|
||||
var c = pal(), q = st.svg.querySelectorAll.bind(st.svg), all, k;
|
||||
all = q('.ct'); for (k = 0; k < all.length; k++) all[k].setAttribute('fill', c.text);
|
||||
all = q('.cl'); for (k = 0; k < all.length; k++) all[k].setAttribute('fill', c.muted);
|
||||
all = q('.cv'); for (k = 0; k < all.length; k++) all[k].setAttribute('fill', c.text);
|
||||
all = q('.grid-line'); for (k = 0; k < all.length; k++) all[k].setAttribute('stroke', c.border);
|
||||
var cc = st.svg.querySelector('#pie-center');
|
||||
if (cc) { cc.setAttribute('fill', c.center); cc.setAttribute('stroke', c.border); }
|
||||
var pt = st.svg.querySelector('#pie-center-text');
|
||||
if (pt) pt.setAttribute('fill', c.text);
|
||||
}
|
||||
|
||||
function tick(st) {
|
||||
if (!st.paused) {
|
||||
st.phase += SPEED * 16;
|
||||
updateBars(st.bars1, st.vals1, st, true);
|
||||
updateBars(st.bars2, st.vals2, st, false);
|
||||
updateLine(st);
|
||||
updatePie(st);
|
||||
if (++st.themeN > 30) { st.themeN = 0; applyTheme(st); }
|
||||
}
|
||||
requestAnimationFrame(function () { tick(st); });
|
||||
}
|
||||
|
||||
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.svg);
|
||||
}
|
||||
|
||||
function boot() {
|
||||
var svgs = document.querySelectorAll('.dashboard-chart');
|
||||
if (!svgs.length) return;
|
||||
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
|
||||
for (var i = 0; i < svgs.length; i++) {
|
||||
if (svgs[i]._dbAnim) continue;
|
||||
var st = makeState(svgs[i]);
|
||||
svgs[i]._dbAnim = st;
|
||||
applyTheme(st);
|
||||
tick(st);
|
||||
observe(st);
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', boot);
|
||||
} else {
|
||||
boot();
|
||||
}
|
||||
})();
|
||||
@@ -610,3 +610,99 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
paintBg();
|
||||
start();
|
||||
})();
|
||||
|
||||
/* ── Device Animator ──────────────────────────────────────────────────────── */
|
||||
(function () {
|
||||
const DEVICES = [
|
||||
'da-tablet', 'da-monitor-sm', 'da-monitor-lg',
|
||||
'da-tv', 'da-projector', 'da-vwall'
|
||||
];
|
||||
const DWELL = 2500; // ms each device is shown
|
||||
|
||||
document.querySelectorAll('.da-stage').forEach(function (stage) {
|
||||
let current = 0;
|
||||
let timer = null;
|
||||
|
||||
// Collect the 6 device panels
|
||||
const panels = DEVICES.map(function (cls) {
|
||||
return stage.querySelector('.' + cls);
|
||||
});
|
||||
|
||||
function show(idx) {
|
||||
panels.forEach(function (el, i) {
|
||||
if (!el) return;
|
||||
el.classList.toggle('is-active', i === idx);
|
||||
el.classList.remove('is-leaving');
|
||||
});
|
||||
}
|
||||
|
||||
function advance() {
|
||||
const leaving = current;
|
||||
current = (current + 1) % DEVICES.length;
|
||||
if (panels[leaving]) panels[leaving].classList.add('is-leaving');
|
||||
show(current);
|
||||
setTimeout(function () {
|
||||
if (panels[leaving]) panels[leaving].classList.remove('is-leaving');
|
||||
}, 600);
|
||||
}
|
||||
|
||||
function startCycle() {
|
||||
if (timer) return;
|
||||
timer = setInterval(advance, DWELL);
|
||||
}
|
||||
|
||||
function stopCycle() {
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
|
||||
// Honour reduced-motion preference: show first device statically
|
||||
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
||||
show(0);
|
||||
return;
|
||||
}
|
||||
|
||||
show(0);
|
||||
startCycle();
|
||||
|
||||
// Pause when scrolled out of view to save resources
|
||||
if ('IntersectionObserver' in window) {
|
||||
new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (e) {
|
||||
e.isIntersecting ? startCycle() : stopCycle();
|
||||
});
|
||||
}, { threshold: 0.2 }).observe(stage);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
/* ── TV Stick Plug Animation ─────────────────────────────────────────────── */
|
||||
(function () {
|
||||
var stages = document.querySelectorAll('[data-tv-stick-anim]');
|
||||
if (!stages.length) return;
|
||||
|
||||
// Honour reduced-motion: show plugged-in state immediately
|
||||
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
||||
stages.forEach(function (stage) {
|
||||
stage.classList.add('is-plugged');
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if ('IntersectionObserver' in window) {
|
||||
var io = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (e) {
|
||||
if (e.isIntersecting) {
|
||||
var stage = e.target;
|
||||
stage.classList.add('is-animating');
|
||||
// Add plugged state after slide-in completes (1.4s)
|
||||
setTimeout(function () {
|
||||
stage.classList.add('is-plugged');
|
||||
}, 1400);
|
||||
io.unobserve(stage);
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.3 });
|
||||
stages.forEach(function (stage) { io.observe(stage); });
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -1067,6 +1067,8 @@ reg('oribi/pricing-card', {
|
||||
faIcon: { type: 'string', default: '' },
|
||||
name: { type: 'string', default: '' },
|
||||
tagline: { type: 'string', default: '' },
|
||||
price: { type: 'string', default: '' },
|
||||
pricePer: { type: 'string', default: '' },
|
||||
features: { type: 'array', default: [] },
|
||||
btnText: { type: 'string', default: 'Get Started' },
|
||||
btnUrl: { type: 'string', default: '/contact' },
|
||||
@@ -1122,6 +1124,17 @@ reg('oribi/pricing-card', {
|
||||
onChange: function(v){s({name:v});}, placeholder: 'Plan name...' }),
|
||||
el(RT, { tagName: 'p', className: 'pricing-tagline', value: a.tagline,
|
||||
onChange: function(v){s({tagline:v});}, placeholder: 'Tagline...' }),
|
||||
a.price || a.pricePer ? el('div', { className: 'pricing-price' },
|
||||
el(RT, { tagName: 'div', className: 'pricing-amount', value: a.price || '',
|
||||
onChange: function(v){s({price:v});}, placeholder: '$0' }),
|
||||
el(RT, { tagName: 'div', className: 'pricing-per', value: a.pricePer || '',
|
||||
onChange: function(v){s({pricePer:v});}, placeholder: 'per screen / month' })
|
||||
) : el('div', { className: 'pricing-price' },
|
||||
el(RT, { tagName: 'div', className: 'pricing-amount', value: '',
|
||||
onChange: function(v){s({price:v});}, placeholder: '$0' }),
|
||||
el(RT, { tagName: 'div', className: 'pricing-per', value: '',
|
||||
onChange: function(v){s({pricePer:v});}, placeholder: 'per screen / month' })
|
||||
),
|
||||
el('ul', { className: 'pricing-features' },
|
||||
features.map(function (f, fi) {
|
||||
return el('li', { key: fi, style: { display: 'flex', alignItems: 'center', gap: '4px' } },
|
||||
@@ -1167,6 +1180,7 @@ reg('oribi/platform-row', {
|
||||
imgUrl: { type: 'string', default: '' },
|
||||
imgAlt: { type: 'string', default: '' },
|
||||
imgWidth: { type: 'number', default: 300 },
|
||||
cameraAnim: { type: 'boolean', default: false },
|
||||
},
|
||||
edit: function (props) {
|
||||
var a = props.attributes, s = props.setAttributes;
|
||||
@@ -1176,7 +1190,8 @@ reg('oribi/platform-row', {
|
||||
el(PB, { title: 'Row Settings' },
|
||||
el(TC, { label: 'Visual (emoji)', value: a.visual, onChange: function(v){s({visual:v});} }),
|
||||
el(TC, { label: 'Button URL', value: a.btnUrl, onChange: function(v){s({btnUrl:v});} }),
|
||||
el(TG, { label: 'Reversed', checked: !!a.reversed, onChange: function(v){s({reversed:v});} })
|
||||
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: 'Visual Image', initialOpen: false },
|
||||
el(MUC, null,
|
||||
@@ -1207,7 +1222,67 @@ reg('oribi/platform-row', {
|
||||
a.btnUrl ? el(RT, { tagName: 'span', className: 'btn btn-outline mt-3',
|
||||
value: a.btnText, onChange: function(v){s({btnText:v});}, placeholder: 'Button...' }) : null
|
||||
),
|
||||
a.imgUrl
|
||||
a.cameraAnim
|
||||
? el('div', { className: 'platform-visual has-camera' },
|
||||
el('div', { className: 'cam-stage', 'aria-hidden': 'true' },
|
||||
// Photo camera (left)
|
||||
el('div', { className: 'pc-wrap' },
|
||||
el('div', { className: 'pc-body' },
|
||||
el('div', { className: 'pc-flash-unit' }),
|
||||
el('div', { className: 'pc-top' },
|
||||
el('div', { className: 'pc-shutter-btn' }),
|
||||
el('div', { className: 'pc-viewfinder' })
|
||||
),
|
||||
el('div', { className: 'pc-front' },
|
||||
el('div', { className: 'pc-lens-ring' },
|
||||
el('div', { className: 'pc-lens-glass' },
|
||||
el('div', { className: 'pc-lens-reflex' })
|
||||
)
|
||||
),
|
||||
el('div', { className: 'pc-grip' })
|
||||
)
|
||||
),
|
||||
el('div', { className: 'pc-prints' },
|
||||
el('div', { className: 'pc-print pc-print--1', style: { opacity: '1', transform: 'rotate(-12deg) translateY(0)' } },
|
||||
el('div', { className: 'pc-print__img' })
|
||||
)
|
||||
)
|
||||
),
|
||||
// Centre scene
|
||||
el('div', { className: 'cam-scene' },
|
||||
el('div', { className: 'cam-subject cam-subject--1' }),
|
||||
el('div', { className: 'cam-flash-overlay' }),
|
||||
el('div', { className: 'cam-vid-overlay' })
|
||||
),
|
||||
// Video camera on tripod (right)
|
||||
el('div', { className: 'vc-wrap' },
|
||||
el('div', { className: 'vc-camera' },
|
||||
el('div', { className: 'vc-handle' }),
|
||||
el('div', { className: 'vc-body' },
|
||||
el('div', { className: 'vc-lens-barrel' },
|
||||
el('div', { className: 'vc-lens-tip' },
|
||||
el('div', { className: 'vc-lens-glass' },
|
||||
el('div', { className: 'vc-lens-reflex' })
|
||||
)
|
||||
)
|
||||
),
|
||||
el('div', { className: 'vc-top-rail' }),
|
||||
el('div', { className: 'vc-rec-light' }),
|
||||
el('div', { className: 'vc-eyepiece' })
|
||||
)
|
||||
),
|
||||
el('div', { className: 'vc-tripod' },
|
||||
el('div', { className: 'vc-stem' }),
|
||||
el('div', { className: 'vc-legs' },
|
||||
el('div', { className: 'vc-leg vc-leg--l' }),
|
||||
el('div', { className: 'vc-leg vc-leg--c' }),
|
||||
el('div', { className: 'vc-leg vc-leg--r' })
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
: a.imgUrl
|
||||
? el('div', { className: 'platform-visual has-img' },
|
||||
el('img', { src: a.imgUrl, style: { width: imgW + 'px', maxWidth: '100%', height: 'auto', borderRadius: '4px', objectFit: 'contain', display: 'block', marginInline: 'auto' } })
|
||||
)
|
||||
@@ -1688,7 +1763,6 @@ reg('oribi/hero-animated', {
|
||||
save: function () { return null; }
|
||||
});
|
||||
|
||||
/* ANIMATED PAGE HERO ──────────────────────────────────────────────────── */
|
||||
reg('oribi/page-hero-animated', {
|
||||
title: 'Animated Page Hero',
|
||||
icon: 'flag',
|
||||
@@ -1771,4 +1845,81 @@ reg('oribi/site-footer', {
|
||||
save: function () { return null; }
|
||||
});
|
||||
|
||||
/* USE CASES SHOWCASE ──────────────────────────────────────────────────── */
|
||||
reg('oribi/use-cases', {
|
||||
title: 'Use Cases Showcase',
|
||||
icon: 'grid-view',
|
||||
category: 'oribi',
|
||||
supports: { html: false },
|
||||
attributes: {
|
||||
label: { type: 'string', default: '\u25cf Use Cases' },
|
||||
heading: { type: 'string', default: 'Built for Every Scenario' },
|
||||
lead: { type: 'string', default: 'From menus to meeting-room dashboards, digital signage adapts to your environment.' },
|
||||
case1Title: { type: 'string', default: 'Menu Boards' },
|
||||
case1Desc: { type: 'string', default: 'Showcase food, drinks, and daily specials with dynamic, always-current displays.' },
|
||||
case2Title: { type: 'string', default: 'Event Displays' },
|
||||
case2Desc: { type: 'string', default: 'Promote schedules, speakers, and live countdowns across lobbies and venues.' },
|
||||
case3Title: { type: 'string', default: 'Office Dashboards' },
|
||||
case3Desc: { type: 'string', default: 'Surface KPIs, occupancy data, and team alerts on screens throughout your workspace.' },
|
||||
case4Title: { type: 'string', default: 'Wayfinding' },
|
||||
case4Desc: { type: 'string', default: 'Guide visitors through complex buildings with interactive maps and directional signs.' },
|
||||
},
|
||||
edit: function (props) {
|
||||
var a = props.attributes, s = props.setAttributes;
|
||||
return el(Frag, null,
|
||||
el(IC, null,
|
||||
el(PB, { title: 'Section Header' },
|
||||
el(TC, { label: 'Label', value: a.label, onChange: function(v){s({label:v});} }),
|
||||
el(TC, { label: 'Heading', value: a.heading, onChange: function(v){s({heading:v});} }),
|
||||
el(TA, { label: 'Lead', value: a.lead, onChange: function(v){s({lead:v});} })
|
||||
),
|
||||
el(PB, { title: 'Use Case 1 – Menu Boards', initialOpen: false },
|
||||
el(TC, { label: 'Title', value: a.case1Title, onChange: function(v){s({case1Title:v});} }),
|
||||
el(TA, { label: 'Description', value: a.case1Desc, onChange: function(v){s({case1Desc:v});} })
|
||||
),
|
||||
el(PB, { title: 'Use Case 2 – Events', initialOpen: false },
|
||||
el(TC, { label: 'Title', value: a.case2Title, onChange: function(v){s({case2Title:v});} }),
|
||||
el(TA, { label: 'Description', value: a.case2Desc, onChange: function(v){s({case2Desc:v});} })
|
||||
),
|
||||
el(PB, { title: 'Use Case 3 – Dashboards', initialOpen: false },
|
||||
el(TC, { label: 'Title', value: a.case3Title, onChange: function(v){s({case3Title:v});} }),
|
||||
el(TA, { label: 'Description', value: a.case3Desc, onChange: function(v){s({case3Desc:v});} })
|
||||
),
|
||||
el(PB, { title: 'Use Case 4 – Wayfinding', initialOpen: false },
|
||||
el(TC, { label: 'Title', value: a.case4Title, onChange: function(v){s({case4Title:v});} }),
|
||||
el(TA, { label: 'Description', value: a.case4Desc, onChange: function(v){s({case4Desc:v});} })
|
||||
)
|
||||
),
|
||||
el('section', { className: 'section use-cases-section' },
|
||||
el('div', { className: 'container' },
|
||||
el('div', { className: 'section-header' },
|
||||
a.label ? el('span', { className: 'section-label' }, a.label) : null,
|
||||
a.heading ? el('h2', null, a.heading) : null,
|
||||
a.lead ? el('p', { className: 'lead' }, a.lead) : null
|
||||
),
|
||||
el('div', { className: 'uc-track' },
|
||||
['menu', 'event', 'dashboard', 'wayfinding'].map(function (mod, i) {
|
||||
var n = i + 1;
|
||||
var title = a['case' + n + 'Title'];
|
||||
var desc = a['case' + n + 'Desc'];
|
||||
return el('div', { key: mod, className: 'uc-item' },
|
||||
el('div', { className: 'uc-circle uc-anim--' + mod,
|
||||
style: { display:'flex', alignItems:'center', justifyContent:'center',
|
||||
fontSize:'.7rem', color:'var(--color-muted)', textAlign:'center', padding:'8px' } },
|
||||
mod
|
||||
),
|
||||
el('div', { className: 'uc-item-body' },
|
||||
el('div', { className: 'uc-item-title' }, title),
|
||||
desc ? el('p', { className: 'uc-item-desc' }, desc) : null
|
||||
)
|
||||
);
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
},
|
||||
save: function () { return null; }
|
||||
});
|
||||
|
||||
})(window.wp);
|
||||
|
||||
@@ -513,6 +513,8 @@ add_action( 'init', function () {
|
||||
'faIcon' => [ 'type' => 'string', 'default' => '' ],
|
||||
'name' => [ 'type' => 'string', 'default' => '' ],
|
||||
'tagline' => [ 'type' => 'string', 'default' => '' ],
|
||||
'price' => [ 'type' => 'string', 'default' => '' ],
|
||||
'pricePer' => [ 'type' => 'string', 'default' => '' ],
|
||||
'features' => [ 'type' => 'array', 'default' => [] ],
|
||||
'btnText' => [ 'type' => 'string', 'default' => 'Get Started' ],
|
||||
'btnUrl' => [ 'type' => 'string', 'default' => '/contact' ],
|
||||
@@ -551,6 +553,9 @@ add_action( 'init', function () {
|
||||
'imgUrl' => [ 'type' => 'string', 'default' => '' ],
|
||||
'imgAlt' => [ 'type' => 'string', 'default' => '' ],
|
||||
'imgWidth' => [ 'type' => 'number', 'default' => 300 ],
|
||||
'deviceAnim' => [ 'type' => 'boolean', 'default' => false ],
|
||||
'tvStick' => [ 'type' => 'boolean', 'default' => false ],
|
||||
'cameraAnim' => [ 'type' => 'boolean', 'default' => false ],
|
||||
],
|
||||
'supports' => $block_supports,
|
||||
'render_callback' => 'oribi_render_platform_row',
|
||||
@@ -651,6 +656,25 @@ add_action( 'init', function () {
|
||||
'render_callback' => 'oribi_render_page_hero_animated',
|
||||
] );
|
||||
|
||||
/* Use Cases Showcase - 4 animated circles beneath the homepage hero */
|
||||
register_block_type( 'oribi/use-cases', [
|
||||
'attributes' => [
|
||||
'label' => [ 'type' => 'string', 'default' => '● Use Cases' ],
|
||||
'heading' => [ 'type' => 'string', 'default' => 'Built for Every Scenario' ],
|
||||
'lead' => [ 'type' => 'string', 'default' => 'From menus to meeting-room dashboards, digital signage adapts to your environment.' ],
|
||||
'case1Title' => [ 'type' => 'string', 'default' => 'Menu Boards' ],
|
||||
'case1Desc' => [ 'type' => 'string', 'default' => 'Showcase food, drinks, and daily specials with dynamic, always-current displays.' ],
|
||||
'case2Title' => [ 'type' => 'string', 'default' => 'Event Displays' ],
|
||||
'case2Desc' => [ 'type' => 'string', 'default' => 'Promote schedules, speakers, and live countdowns across lobbies and venues.' ],
|
||||
'case3Title' => [ 'type' => 'string', 'default' => 'Office Dashboards' ],
|
||||
'case3Desc' => [ 'type' => 'string', 'default' => 'Surface KPIs, occupancy data, and team alerts on screens throughout your workspace.' ],
|
||||
'case4Title' => [ 'type' => 'string', 'default' => 'Wayfinding' ],
|
||||
'case4Desc' => [ 'type' => 'string', 'default' => 'Guide visitors through complex buildings with interactive maps and directional signs.' ],
|
||||
],
|
||||
'supports' => $block_supports,
|
||||
'render_callback' => 'oribi_render_use_cases',
|
||||
] );
|
||||
|
||||
} );
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════════════
|
||||
@@ -1296,6 +1320,12 @@ function oribi_render_pricing_card( $a ) {
|
||||
<?php if ( oribi_has_icon( $a ) ) : ?><div class="feature-icon" style="margin-inline:auto;"><?php echo oribi_render_icon( $a ); ?></div><?php endif; ?>
|
||||
<div class="pricing-name"><?php echo esc_html( $a['name'] ); ?></div>
|
||||
<p class="pricing-tagline"><?php echo wp_kses_post( $a['tagline'] ); ?></p>
|
||||
<?php if ( ! empty( $a['price'] ) ) : ?>
|
||||
<div class="pricing-price">
|
||||
<div class="pricing-amount"><?php echo wp_kses_post( $a['price'] ); ?></div>
|
||||
<?php if ( ! empty( $a['pricePer'] ) ) : ?><div class="pricing-per"><?php echo wp_kses_post( $a['pricePer'] ); ?></div><?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<ul class="pricing-features">
|
||||
<?php foreach ( ( $a['features'] ?? [] ) as $f ) : ?>
|
||||
<li><span class="pricing-check">✓</span> <?php echo wp_kses_post( $f ); ?></li>
|
||||
@@ -1330,7 +1360,128 @@ function oribi_render_platform_row( $a ) {
|
||||
$img_alt = ! empty( $a['imgAlt'] ) ? $a['imgAlt'] : '';
|
||||
$img_w = ! empty( $a['imgWidth'] ) ? intval( $a['imgWidth'] ) : 300;
|
||||
|
||||
if ( $img_url ) {
|
||||
// Only render animated dashboard when explicitly flagged
|
||||
$is_dashboard = ! empty( $a['isDashboard'] );
|
||||
|
||||
if ( $is_dashboard ) {
|
||||
// Render animated dashboard chart SVG
|
||||
// Text uses class hooks: .ct = title, .cl = label, .cv = value
|
||||
// JS will dynamically set fill colours based on data-theme
|
||||
$visual_html = '<div class="dashboard-tv" data-dashboard-container="true">
|
||||
<div class="dashboard-tv__body">
|
||||
<div class="dashboard-tv__screen">
|
||||
<svg viewBox="0 0 800 450" xmlns="http://www.w3.org/2000/svg" class="dashboard-chart" role="img" aria-label="Animated dashboard charts">
|
||||
<defs>
|
||||
<linearGradient id="barGradient" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" stop-color="#004225" stop-opacity="1"/>
|
||||
<stop offset="100%" stop-color="#4CAF50" stop-opacity=".8"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="lineGradient" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" stop-color="#4CAF50" stop-opacity=".3"/>
|
||||
<stop offset="100%" stop-color="#4CAF50" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- ── Top-left: Performance bars ── -->
|
||||
<g transform="translate(35,20)">
|
||||
<text class="ct" x="0" y="0" font-size="14" font-weight="600" fill="#333">Performance</text>
|
||||
<g id="bars-group-1" transform="translate(0,25)">
|
||||
<rect class="bar" x="0" y="120" width="28" height="0" fill="url(#barGradient)"/>
|
||||
<rect class="bar" x="40" y="120" width="28" height="0" fill="url(#barGradient)"/>
|
||||
<rect class="bar" x="80" y="120" width="28" height="0" fill="url(#barGradient)"/>
|
||||
<rect class="bar" x="120" y="120" width="28" height="0" fill="url(#barGradient)"/>
|
||||
<rect class="bar" x="160" y="120" width="28" height="0" fill="url(#barGradient)"/>
|
||||
</g>
|
||||
<g transform="translate(0,152)">
|
||||
<text class="cl" x="14" y="0" font-size="10" text-anchor="middle" fill="#666">API</text>
|
||||
<text class="cl" x="54" y="0" font-size="10" text-anchor="middle" fill="#666">Cache</text>
|
||||
<text class="cl" x="94" y="0" font-size="10" text-anchor="middle" fill="#666">DB</text>
|
||||
<text class="cl" x="134" y="0" font-size="10" text-anchor="middle" fill="#666">Queue</text>
|
||||
<text class="cl" x="174" y="0" font-size="10" text-anchor="middle" fill="#666">Worker</text>
|
||||
</g>
|
||||
<g id="values-group-1" transform="translate(0,168)">
|
||||
<text class="cv" x="14" y="0" font-size="11" font-weight="600" text-anchor="middle" fill="#333">0%</text>
|
||||
<text class="cv" x="54" y="0" font-size="11" font-weight="600" text-anchor="middle" fill="#333">0%</text>
|
||||
<text class="cv" x="94" y="0" font-size="11" font-weight="600" text-anchor="middle" fill="#333">0%</text>
|
||||
<text class="cv" x="134" y="0" font-size="11" font-weight="600" text-anchor="middle" fill="#333">0%</text>
|
||||
<text class="cv" x="174" y="0" font-size="11" font-weight="600" text-anchor="middle" fill="#333">0%</text>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- ── Top-right: Requests/sec bars ── -->
|
||||
<g transform="translate(430,20)">
|
||||
<text class="ct" x="0" y="0" font-size="14" font-weight="600" fill="#333">Requests/sec</text>
|
||||
<g id="bars-group-2" transform="translate(0,25)">
|
||||
<rect class="bar" x="0" y="120" width="28" height="0" fill="url(#barGradient)"/>
|
||||
<rect class="bar" x="40" y="120" width="28" height="0" fill="url(#barGradient)"/>
|
||||
<rect class="bar" x="80" y="120" width="28" height="0" fill="url(#barGradient)"/>
|
||||
<rect class="bar" x="120" y="120" width="28" height="0" fill="url(#barGradient)"/>
|
||||
</g>
|
||||
<g transform="translate(0,152)">
|
||||
<text class="cl" x="14" y="0" font-size="10" text-anchor="middle" fill="#666">Read</text>
|
||||
<text class="cl" x="54" y="0" font-size="10" text-anchor="middle" fill="#666">Write</text>
|
||||
<text class="cl" x="94" y="0" font-size="10" text-anchor="middle" fill="#666">Update</text>
|
||||
<text class="cl" x="134" y="0" font-size="10" text-anchor="middle" fill="#666">Delete</text>
|
||||
</g>
|
||||
<g id="values-group-2" transform="translate(0,168)">
|
||||
<text class="cv" x="14" y="0" font-size="11" font-weight="600" text-anchor="middle" fill="#333">0</text>
|
||||
<text class="cv" x="54" y="0" font-size="11" font-weight="600" text-anchor="middle" fill="#333">0</text>
|
||||
<text class="cv" x="94" y="0" font-size="11" font-weight="600" text-anchor="middle" fill="#333">0</text>
|
||||
<text class="cv" x="134" y="0" font-size="11" font-weight="600" text-anchor="middle" fill="#333">0</text>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- ── Bottom-left: Traffic Trend line ── -->
|
||||
<g id="line-graph" transform="translate(35,245)">
|
||||
<text class="ct" x="0" y="0" font-size="14" font-weight="600" fill="#333">Traffic Trend</text>
|
||||
<g transform="translate(0,25)">
|
||||
<line class="grid-line" x1="0" y1="0" x2="340" y2="0" stroke="#E0E0E0" stroke-width=".5"/>
|
||||
<line class="grid-line" x1="0" y1="40" x2="340" y2="40" stroke="#E0E0E0" stroke-width=".5"/>
|
||||
<line class="grid-line" x1="0" y1="80" x2="340" y2="80" stroke="#E0E0E0" stroke-width=".5"/>
|
||||
<line class="grid-line" x1="0" y1="120" x2="340" y2="120" stroke="#E0E0E0" stroke-width=".5"/>
|
||||
</g>
|
||||
<g transform="translate(0,25)">
|
||||
<path id="line-fill" d="M0,80 L340,80 L340,145 L0,145 Z" fill="url(#lineGradient)"/>
|
||||
<path id="line-path" d="M0,80 L340,80" stroke="#4CAF50" stroke-width="2.5" fill="none" stroke-linecap="round"/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- ── Bottom-right: Distribution pie ── -->
|
||||
<g transform="translate(490,245)">
|
||||
<text class="ct" x="100" y="0" font-size="14" font-weight="600" text-anchor="middle" fill="#333">Distribution</text>
|
||||
<g transform="translate(100,90)">
|
||||
<g class="pie-segment" transform="rotate(0)">
|
||||
<path d="M0,0 L0,-55 A55,55 0 0,1 38.89,-38.89 Z" fill="#004225" opacity=".9"/>
|
||||
</g>
|
||||
<g class="pie-segment" transform="rotate(90)">
|
||||
<path d="M0,0 L0,-55 A55,55 0 0,1 38.89,-38.89 Z" fill="#4CAF50" opacity=".8"/>
|
||||
</g>
|
||||
<g class="pie-segment" transform="rotate(180)">
|
||||
<path d="M0,0 L0,-55 A55,55 0 0,1 38.89,-38.89 Z" fill="#f59e0b" opacity=".7"/>
|
||||
</g>
|
||||
<g class="pie-segment" transform="rotate(270)">
|
||||
<path d="M0,0 L0,-55 A55,55 0 0,1 38.89,-38.89 Z" fill="#ef4444" opacity=".7"/>
|
||||
</g>
|
||||
<circle id="pie-center" cx="0" cy="0" r="22" fill="#fff" stroke="#E0E0E0" stroke-width="1"/>
|
||||
<text id="pie-center-text" x="0" y="5" text-anchor="middle" font-size="13" font-weight="600" fill="#333">100%</text>
|
||||
</g>
|
||||
<g transform="translate(30,170)">
|
||||
<rect x="0" y="0" width="8" height="8" fill="#004225"/>
|
||||
<text class="cl" x="12" y="8" font-size="11" fill="#666">Service A</text>
|
||||
<rect x="0" y="15" width="8" height="8" fill="#4CAF50"/>
|
||||
<text class="cl" x="12" y="23" font-size="11" fill="#666">Service B</text>
|
||||
<rect x="100" y="0" width="8" height="8" fill="#f59e0b"/>
|
||||
<text class="cl" x="112" y="8" font-size="11" fill="#666">Service C</text>
|
||||
<rect x="100" y="15" width="8" height="8" fill="#ef4444"/>
|
||||
<text class="cl" x="112" y="23" font-size="11" fill="#666">Service D</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div></div>
|
||||
<div class="dashboard-tv__feet"><div class="dashboard-tv__foot"></div><div class="dashboard-tv__foot"></div></div>
|
||||
</div>';
|
||||
$visual_cls = 'platform-visual has-dashboard';
|
||||
} elseif ( $img_url ) {
|
||||
$img_style = 'width:' . $img_w . 'px;max-width:100%;height:auto;border-radius:var(--radius-sm);object-fit:contain;display:block;margin-inline:auto;';
|
||||
if ( $img_id ) {
|
||||
$visual_html = wp_get_attachment_image( $img_id, 'full', false, [ 'style' => $img_style, 'alt' => $img_alt ] );
|
||||
@@ -1338,6 +1489,88 @@ function oribi_render_platform_row( $a ) {
|
||||
$visual_html = '<img src="' . esc_url( $img_url ) . '" alt="' . esc_attr( $img_alt ) . '" style="' . esc_attr( $img_style ) . '">';
|
||||
}
|
||||
$visual_cls = 'platform-visual has-img';
|
||||
} elseif ( ! empty( $a['deviceAnim'] ) ) {
|
||||
$da = '<div class="da-stage" aria-hidden="true">';
|
||||
$da .= '<div class="da-device da-tablet"><div class="da-body"><div class="da-screen"></div></div><span class="da-label">Tablet</span></div>';
|
||||
$da .= '<div class="da-device da-monitor-sm"><div class="da-body"><div class="da-screen"></div></div><div class="da-stand"><div class="da-stem"></div><div class="da-base"></div></div><span class="da-label">Small Monitor</span></div>';
|
||||
$da .= '<div class="da-device da-monitor-lg"><div class="da-body"><div class="da-screen"></div></div><div class="da-stand"><div class="da-stem"></div><div class="da-base"></div></div><span class="da-label">Large Monitor</span></div>';
|
||||
$da .= '<div class="da-device da-tv"><div class="da-body"><div class="da-screen"></div></div><div class="da-feet"><div class="da-foot"></div><div class="da-foot"></div></div><span class="da-label">TV</span></div>';
|
||||
$da .= '<div class="da-device da-projector"><div class="da-proj-layout"><div class="da-proj-body"><div class="da-lens"></div></div><div class="da-beam"></div><div class="da-proj-screen"><div class="da-screen"></div></div></div><span class="da-label">Projector</span></div>';
|
||||
$da .= '<div class="da-device da-vwall"><div class="da-vwall-grid"><div class="da-panel"><div class="da-screen"></div></div><div class="da-panel"><div class="da-screen"></div></div><div class="da-panel"><div class="da-screen"></div></div><div class="da-panel"><div class="da-screen"></div></div></div><span class="da-label">Video Wall</span></div>';
|
||||
$da .= '</div>';
|
||||
$visual_html = $da;
|
||||
$visual_cls = 'platform-visual has-anim';
|
||||
} elseif ( ! empty( $a['tvStick'] ) ) {
|
||||
$ts = '<div class="ts-stage" data-tv-stick-anim aria-hidden="true">';
|
||||
$ts .= '<div class="ts-tv">';
|
||||
$ts .= '<div class="ts-tv__body">';
|
||||
$ts .= '<div class="ts-tv__screen"></div>';
|
||||
$ts .= '<div class="ts-tv__port"></div>';
|
||||
$ts .= '</div>';
|
||||
$ts .= '<div class="ts-tv__feet"><div class="ts-tv__foot"></div><div class="ts-tv__foot"></div></div>';
|
||||
$ts .= '</div>';
|
||||
$ts .= '<div class="ts-stick">';
|
||||
$ts .= '<div class="ts-stick__body">';
|
||||
$ts .= '<div class="ts-stick__led"></div>';
|
||||
$ts .= '</div>';
|
||||
$ts .= '<div class="ts-stick__connector"></div>';
|
||||
$ts .= '</div>';
|
||||
$ts .= '</div>';
|
||||
$visual_html = $ts;
|
||||
$visual_cls = 'platform-visual has-tv-stick';
|
||||
} elseif ( ! empty( $a['cameraAnim'] ) ) {
|
||||
$ca = '<div class="cam-stage" aria-hidden="true">';
|
||||
|
||||
// ── Left: compact photo camera ──
|
||||
$ca .= '<div class="pc-wrap">';
|
||||
$ca .= '<div class="pc-body">';
|
||||
$ca .= '<div class="pc-flash-unit"></div>';
|
||||
$ca .= '<div class="pc-top"><div class="pc-shutter-btn"></div><div class="pc-viewfinder"></div></div>';
|
||||
$ca .= '<div class="pc-front">';
|
||||
$ca .= '<div class="pc-lens-ring"><div class="pc-lens-glass"><div class="pc-lens-reflex"></div></div></div>';
|
||||
$ca .= '<div class="pc-grip"></div>';
|
||||
$ca .= '</div>';
|
||||
$ca .= '</div>'; // pc-body
|
||||
$ca .= '<div class="pc-prints">';
|
||||
$ca .= '<div class="pc-print pc-print--1"><div class="pc-print__img"></div></div>';
|
||||
$ca .= '<div class="pc-print pc-print--2"><div class="pc-print__img"></div></div>';
|
||||
$ca .= '<div class="pc-print pc-print--3"><div class="pc-print__img"></div></div>';
|
||||
$ca .= '</div>'; // pc-prints
|
||||
$ca .= '</div>'; // pc-wrap
|
||||
|
||||
// ── Centre: product scene both cameras shoot ──
|
||||
$ca .= '<div class="cam-scene">';
|
||||
$ca .= '<div class="cam-subject cam-subject--1"></div>';
|
||||
$ca .= '<div class="cam-subject cam-subject--2"></div>';
|
||||
$ca .= '<div class="cam-subject cam-subject--3"></div>';
|
||||
$ca .= '<div class="cam-flash-overlay"></div>';
|
||||
$ca .= '<div class="cam-vid-overlay"></div>';
|
||||
$ca .= '</div>'; // cam-scene
|
||||
|
||||
// ── Right: retro VHS video camera on tripod ──
|
||||
$ca .= '<div class="vc-wrap">';
|
||||
$ca .= '<div class="vc-camera">';
|
||||
$ca .= '<div class="vc-handle"></div>';
|
||||
$ca .= '<div class="vc-body">';
|
||||
$ca .= '<div class="vc-lens-barrel"><div class="vc-lens-tip"><div class="vc-lens-glass"><div class="vc-lens-reflex"></div></div></div></div>';
|
||||
$ca .= '<div class="vc-top-rail"></div>';
|
||||
$ca .= '<div class="vc-rec-light"></div>';
|
||||
$ca .= '<div class="vc-eyepiece"></div>';
|
||||
$ca .= '</div>'; // vc-body
|
||||
$ca .= '</div>'; // vc-camera
|
||||
$ca .= '<div class="vc-tripod">';
|
||||
$ca .= '<div class="vc-stem"></div>';
|
||||
$ca .= '<div class="vc-legs">';
|
||||
$ca .= '<div class="vc-leg vc-leg--l"></div>';
|
||||
$ca .= '<div class="vc-leg vc-leg--c"></div>';
|
||||
$ca .= '<div class="vc-leg vc-leg--r"></div>';
|
||||
$ca .= '</div>'; // vc-legs
|
||||
$ca .= '</div>'; // vc-tripod
|
||||
$ca .= '</div>'; // vc-wrap
|
||||
|
||||
$ca .= '</div>'; // cam-stage
|
||||
$visual_html = $ca;
|
||||
$visual_cls = 'platform-visual has-camera';
|
||||
} else {
|
||||
$visual_html = oribi_render_icon( $a['visual'] ?? '' );
|
||||
$visual_cls = 'platform-visual';
|
||||
@@ -1548,3 +1781,95 @@ function oribi_render_page_hero_animated( $a ) {
|
||||
</section>
|
||||
<?php return ob_get_clean();
|
||||
}
|
||||
|
||||
/* ── Use Cases Showcase ────────────────────────────────────────────────── */
|
||||
function oribi_uc_anim_inner( $mod ) {
|
||||
switch ( $mod ) {
|
||||
case 'menu':
|
||||
return '
|
||||
<div class="uc-inner uc-inner--menu" aria-hidden="true">
|
||||
<div class="uc-menu-header"></div>
|
||||
<div class="uc-menu-row"><span class="uc-menu-name"></span><span class="uc-menu-price"></span></div>
|
||||
<div class="uc-menu-row uc-menu-row--highlight"><span class="uc-menu-name"></span><span class="uc-menu-price"></span></div>
|
||||
<div class="uc-menu-row"><span class="uc-menu-name uc-menu-name--sm"></span><span class="uc-menu-price"></span></div>
|
||||
<div class="uc-menu-row"><span class="uc-menu-name"></span><span class="uc-menu-price"></span></div>
|
||||
<div class="uc-menu-divider"></div>
|
||||
<div class="uc-menu-row"><span class="uc-menu-name uc-menu-name--sm"></span><span class="uc-menu-price"></span></div>
|
||||
</div>';
|
||||
case 'event':
|
||||
return '
|
||||
<div class="uc-inner uc-inner--event" aria-hidden="true">
|
||||
<div class="uc-event-cursor"></div>
|
||||
<div class="uc-event-header"></div>
|
||||
<div class="uc-event-row"><div class="uc-event-time"></div><div class="uc-event-bar uc-event-bar--active"></div></div>
|
||||
<div class="uc-event-row"><div class="uc-event-time"></div><div class="uc-event-bar"></div></div>
|
||||
<div class="uc-event-row"><div class="uc-event-time"></div><div class="uc-event-bar uc-event-bar--accent"></div></div>
|
||||
<div class="uc-event-row"><div class="uc-event-time"></div><div class="uc-event-bar"></div></div>
|
||||
</div>';
|
||||
case 'dashboard':
|
||||
return '
|
||||
<div class="uc-inner uc-inner--dashboard" aria-hidden="true">
|
||||
<div class="uc-db-bars">
|
||||
<div class="uc-db-bar uc-db-bar--1"></div>
|
||||
<div class="uc-db-bar uc-db-bar--2"></div>
|
||||
<div class="uc-db-bar uc-db-bar--3"></div>
|
||||
<div class="uc-db-bar uc-db-bar--4"></div>
|
||||
</div>
|
||||
<div class="uc-db-baseline"></div>
|
||||
<div class="uc-db-labels">
|
||||
<div class="uc-db-lbl"></div>
|
||||
<div class="uc-db-lbl"></div>
|
||||
<div class="uc-db-lbl"></div>
|
||||
<div class="uc-db-lbl"></div>
|
||||
</div>
|
||||
</div>';
|
||||
case 'wayfinding':
|
||||
return '
|
||||
<div class="uc-inner uc-inner--wayfinding" aria-hidden="true">
|
||||
<div class="uc-wf-corridor uc-wf-corridor--h"></div>
|
||||
<div class="uc-wf-corridor uc-wf-corridor--v"></div>
|
||||
<div class="uc-wf-room uc-wf-room--1"></div>
|
||||
<div class="uc-wf-room uc-wf-room--2"></div>
|
||||
<div class="uc-wf-room uc-wf-room--3"></div>
|
||||
<div class="uc-wf-dot"></div>
|
||||
<div class="uc-wf-arrow"></div>
|
||||
</div>';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function oribi_render_use_cases( $a ) {
|
||||
$cases = [
|
||||
[ 'title' => $a['case1Title'], 'desc' => $a['case1Desc'], 'mod' => 'menu' ],
|
||||
[ 'title' => $a['case2Title'], 'desc' => $a['case2Desc'], 'mod' => 'event' ],
|
||||
[ 'title' => $a['case3Title'], 'desc' => $a['case3Desc'], 'mod' => 'dashboard' ],
|
||||
[ 'title' => $a['case4Title'], 'desc' => $a['case4Desc'], 'mod' => 'wayfinding' ],
|
||||
];
|
||||
ob_start(); ?>
|
||||
<section class="section use-cases-section">
|
||||
<div class="container">
|
||||
<?php if ( $a['label'] || $a['heading'] || $a['lead'] ) : ?>
|
||||
<div class="section-header">
|
||||
<?php if ( $a['label'] ) : ?><span class="section-label"><?php echo esc_html( $a['label'] ); ?></span><?php endif; ?>
|
||||
<?php if ( $a['heading'] ) : ?><h2><?php echo wp_kses_post( $a['heading'] ); ?></h2><?php endif; ?>
|
||||
<?php if ( $a['lead'] ) : ?><p class="lead"><?php echo wp_kses_post( $a['lead'] ); ?></p><?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="uc-track">
|
||||
<?php foreach ( $cases as $c ) : ?>
|
||||
<div class="uc-item">
|
||||
<div class="uc-circle uc-anim--<?php echo esc_attr( $c['mod'] ); ?>">
|
||||
<?php echo oribi_uc_anim_inner( $c['mod'] ); ?>
|
||||
</div>
|
||||
<div class="uc-item-body">
|
||||
<div class="uc-item-title"><?php echo esc_html( $c['title'] ); ?></div>
|
||||
<?php if ( $c['desc'] ) : ?><p class="uc-item-desc"><?php echo esc_html( $c['desc'] ); ?></p><?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php return ob_get_clean();
|
||||
}
|
||||
|
||||
@@ -29,6 +29,15 @@ add_action( 'wp_enqueue_scripts', function () {
|
||||
true
|
||||
);
|
||||
|
||||
// Dashboard chart animator - smooth continuous animations for dashboard cards
|
||||
wp_enqueue_script(
|
||||
'oribi-dashboard-animator',
|
||||
ORIBI_URI . '/assets/js/dashboard-animator.js',
|
||||
[],
|
||||
ORIBI_VERSION . '.' . filemtime( ORIBI_DIR . '/assets/js/dashboard-animator.js' ),
|
||||
true
|
||||
);
|
||||
|
||||
// Localize AJAX endpoint for the contact form
|
||||
wp_localize_script( 'oribi-main', 'oribiAjax', [
|
||||
'url' => admin_url( 'admin-ajax.php' ),
|
||||
|
||||
Reference in New Issue
Block a user