diff --git a/pages/about.php b/pages/about.php
index c5e2a30..8409071 100644
--- a/pages/about.php
+++ b/pages/about.php
@@ -8,7 +8,7 @@
return <<<'ORIBI_SYNC_CONTENT'
-
+
@@ -38,5 +38,4 @@ return <<<'ORIBI_SYNC_CONTENT'
-
-ORIBI_SYNC_CONTENT;
+ORIBI_SYNC_CONTENT;
\ No newline at end of file
diff --git a/theme/assets/css/main.css b/theme/assets/css/main.css
index e78faa7..3e6a8d9 100644
--- a/theme/assets/css/main.css
+++ b/theme/assets/css/main.css
@@ -3272,7 +3272,8 @@ p:last-child { margin-bottom: 0; }
color: #fff;
}
/* When an image is set, remove the gradient box styling */
-.about-intro-visual.has-img {
+.about-intro-visual.has-img,
+.about-intro-visual.has-cloud-anim {
background: none;
box-shadow: none;
aspect-ratio: unset;
@@ -3284,6 +3285,119 @@ p:last-child { margin-bottom: 0; }
.about-intro-visual { max-width: 280px; margin-inline: auto; }
}
+/* ── Digital Signage Animation ────────────────────────────── */
+.ds-anim-container {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ max-width: 400px;
+ margin: 0 auto;
+ padding: 2rem 0;
+ position: relative;
+ color: var(--color-primary);
+}
+
+[data-theme="dark"] .ds-anim-container {
+ color: #fff;
+}
+
+.ds-tv, .ds-cloud {
+ position: relative;
+ z-index: 2;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.ds-tv {
+ font-size: 5rem;
+ position: relative;
+}
+
+.ds-tv-screen {
+ position: absolute;
+ top: 15%;
+ left: 10%;
+ width: 80%;
+ height: 60%;
+ background: rgba(var(--color-primary-rgb), 0.2);
+ border-radius: 4px;
+ animation: ds-screen-pulse 3s infinite alternate;
+}
+
+[data-theme="dark"] .ds-tv-screen {
+ background: rgba(255, 255, 255, 0.15);
+}
+
+@keyframes ds-screen-pulse {
+ 0% { opacity: 0.4; }
+ 100% { opacity: 1; }
+}
+
+.ds-cloud {
+ font-size: 4.5rem;
+ animation: ds-float 4s ease-in-out infinite;
+}
+
+@keyframes ds-float {
+ 0% { transform: translateY(0); }
+ 50% { transform: translateY(-8px); }
+ 100% { transform: translateY(0); }
+}
+
+.ds-line {
+ flex-grow: 1;
+ height: 2px;
+ background: rgba(var(--color-primary-rgb), 0.2);
+ margin: 0 1.5rem;
+ position: relative;
+ display: flex;
+ align-items: center;
+ overflow: hidden;
+ border-radius: 2px;
+}
+
+[data-theme="dark"] .ds-line {
+ background: rgba(255, 255, 255, 0.1);
+}
+
+.ds-packet {
+ width: 12px;
+ height: 4px;
+ background: var(--color-primary);
+ border-radius: 4px;
+ position: absolute;
+ left: -20px;
+ box-shadow: 0 0 8px var(--color-primary);
+}
+
+[data-theme="dark"] .ds-packet {
+ background: #fff;
+ box-shadow: 0 0 8px rgba(255, 255, 255, 0.8);
+}
+
+.ds-packet-1 { animation: ds-travel 2s linear infinite; }
+.ds-packet-2 { animation: ds-travel 2s linear infinite 0.6s; }
+.ds-packet-3 { animation: ds-travel 2s linear infinite 1.2s; }
+
+@keyframes ds-travel {
+ 0% { left: -20px; opacity: 0; }
+ 10% { opacity: 1; }
+ 90% { opacity: 1; }
+ 100% { left: 100%; opacity: 0; }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .ds-tv-screen, .ds-cloud, .ds-packet {
+ animation: none;
+ }
+ .ds-packet-1 { left: 20%; opacity: 1; }
+ .ds-packet-2 { left: 50%; opacity: 1; }
+ .ds-packet-3 { left: 80%; opacity: 1; }
+}
+
+
/* ── 13. Contact ────────────────────────────────────────────── */
.contact-layout {
display: grid;
diff --git a/theme/blocks/editor.js b/theme/blocks/editor.js
index a8c8bdc..add7336 100644
--- a/theme/blocks/editor.js
+++ b/theme/blocks/editor.js
@@ -6,2050 +6,2167 @@
* Child blocks are dynamic (save -> null) with inline RichText editing.
*/
(function (wp) {
-'use strict';
+ 'use strict';
-var el = wp.element.createElement;
-var Frag = wp.element.Fragment;
-var reg = wp.blocks.registerBlockType;
-var RT = wp.blockEditor.RichText;
-var IC = wp.blockEditor.InspectorControls;
-var IB = wp.blockEditor.InnerBlocks;
-var PB = wp.components.PanelBody;
-var TC = wp.components.TextControl;
-var TA = wp.components.TextareaControl;
-var SC = wp.components.SelectControl;
-var TG = wp.components.ToggleControl;
-var RC = wp.components.RangeControl;
-var Btn = wp.components.Button;
-var MUC = wp.blockEditor.MediaUploadCheck;
-var MU = wp.blockEditor.MediaUpload;
-var useS = wp.element.useState;
+ var el = wp.element.createElement;
+ var Frag = wp.element.Fragment;
+ var reg = wp.blocks.registerBlockType;
+ var RT = wp.blockEditor.RichText;
+ var IC = wp.blockEditor.InspectorControls;
+ var IB = wp.blockEditor.InnerBlocks;
+ var PB = wp.components.PanelBody;
+ var TC = wp.components.TextControl;
+ var TA = wp.components.TextareaControl;
+ var SC = wp.components.SelectControl;
+ var TG = wp.components.ToggleControl;
+ var RC = wp.components.RangeControl;
+ var Btn = wp.components.Button;
+ var MUC = wp.blockEditor.MediaUploadCheck;
+ var MU = wp.blockEditor.MediaUpload;
+ var useS = wp.element.useState;
-/* ── Simple array helpers (for pricing-card features) ────────────────── */
-function arrSet(arr, i, val) { var c = arr.slice(); c[i] = val; return c; }
-function arrAdd(arr, val) { return arr.concat([val]); }
-function arrRm(arr, i) { var c = arr.slice(); c.splice(i, 1); return c; }
+ /* ── Simple array helpers (for pricing-card features) ────────────────── */
+ function arrSet(arr, i, val) { var c = arr.slice(); c[i] = val; return c; }
+ function arrAdd(arr, val) { return arr.concat([val]); }
+ function arrRm(arr, i) { var c = arr.slice(); c.splice(i, 1); return c; }
-/* ── Shared card image attributes ────────────────────────────────────── */
-var CARD_IMAGE_ATTRS = {
- imgId: { type: 'number', default: 0 },
- imgUrl: { type: 'string', default: '' },
- imgAlt: { type: 'string', default: '' },
- imgWidth: { type: 'number', default: 80 },
- imgHeight: { type: 'number', default: 0 },
- imgFit: { type: 'string', default: 'contain' },
- imgPosition: { type: 'string', default: 'top' }
-};
-
-/* ── Shared icon attributes ──────────────────────────────────────────── */
-var CARD_ICON_ATTRS = {
- icon: { type: 'string', default: '' },
- iconType: { type: 'string', default: 'emoji' },
- faIcon: { type: 'string', default: '' }
-};
-
-/**
- * Build icon InspectorControls: a toggle that switches between emoji and
- * Font Awesome mode, with the appropriate text input shown beneath it.
- */
-
-/* ── Font Awesome icon catalogue ─────────────────────────────────────── */
-// Format: ['s' = fas solid | 'b' = fab brand, 'icon-name']
-var FA_ICONS = [
- // Navigation
- ['s','angle-down'],['s','angle-left'],['s','angle-right'],['s','angle-up'],
- ['s','angles-down'],['s','angles-left'],['s','angles-right'],['s','angles-up'],
- ['s','arrow-down'],['s','arrow-left'],['s','arrow-right'],['s','arrow-up'],
- ['s','arrow-rotate-left'],['s','arrow-rotate-right'],['s','arrows-rotate'],
- ['s','arrows-up-down-left-right'],['s','caret-down'],['s','caret-left'],
- ['s','caret-right'],['s','caret-up'],['s','chevron-down'],['s','chevron-left'],
- ['s','chevron-right'],['s','chevron-up'],['s','circle-arrow-down'],
- ['s','circle-arrow-left'],['s','circle-arrow-right'],['s','circle-arrow-up'],
- // Interface
- ['s','asterisk'],['s','at'],['s','ban'],['s','bars'],['s','bell'],['s','bell-slash'],
- ['s','bolt'],['s','check'],['s','check-double'],['s','circle-check'],
- ['s','circle-exclamation'],['s','circle-info'],['s','circle-minus'],
- ['s','circle-plus'],['s','circle-question'],['s','circle-xmark'],
- ['s','ellipsis'],['s','ellipsis-vertical'],['s','eye'],['s','eye-slash'],
- ['s','filter'],['s','grip'],['s','grip-vertical'],['s','hashtag'],['s','key'],
- ['s','lock'],['s','lock-open'],['s','magnifying-glass'],['s','minus'],['s','plus'],
- ['s','power-off'],['s','rotate'],['s','shield'],['s','shield-check'],
- ['s','shield-halved'],['s','sliders'],['s','sort'],['s','sort-down'],['s','sort-up'],
- ['s','spinner'],['s','star'],['s','star-half-stroke'],['s','toggle-off'],
- ['s','toggle-on'],['s','xmark'],
- // Text editing
- ['s','align-center'],['s','align-justify'],['s','align-left'],['s','align-right'],
- ['s','bold'],['s','code'],['s','crop'],['s','eraser'],['s','highlight'],
- ['s','indent'],['s','italic'],['s','link'],['s','link-slash'],['s','list'],
- ['s','list-check'],['s','list-ol'],['s','list-ul'],['s','outdent'],['s','pen'],
- ['s','pen-to-square'],['s','pencil'],['s','quote-left'],['s','quote-right'],
- ['s','scissors'],['s','strikethrough'],['s','subscript'],['s','superscript'],
- ['s','table'],['s','table-list'],['s','underline'],
- // Files and documents
- ['s','book'],['s','book-open'],['s','bookmark'],['s','box'],['s','box-archive'],
- ['s','boxes-stacked'],['s','clipboard'],['s','clipboard-check'],
- ['s','clipboard-list'],['s','copy'],['s','database'],['s','download'],
- ['s','envelope'],['s','envelope-open'],['s','file'],['s','file-arrow-down'],
- ['s','file-arrow-up'],['s','file-code'],['s','file-excel'],['s','file-image'],
- ['s','file-lines'],['s','file-pdf'],['s','file-powerpoint'],['s','file-word'],
- ['s','file-zipper'],['s','floppy-disk'],['s','folder'],['s','folder-minus'],
- ['s','folder-open'],['s','folder-plus'],['s','inbox'],['s','newspaper'],
- ['s','paper-plane'],['s','paperclip'],['s','print'],['s','share'],
- ['s','share-nodes'],['s','upload'],
- // Technology
- ['s','barcode'],['s','bug'],['s','cloud'],['s','cloud-arrow-down'],
- ['s','cloud-arrow-up'],['s','code-branch'],['s','cpu'],['s','desktop'],
- ['s','display'],['s','ethernet'],['s','gear'],['s','gears'],['s','hard-drive'],
- ['s','keyboard'],['s','laptop'],['s','memory'],['s','microchip'],['s','mobile'],
- ['s','mobile-screen'],['s','network-wired'],['s','plug'],['s','qrcode'],
- ['s','robot'],['s','satellite'],['s','satellite-dish'],['s','server'],
- ['s','tablet'],['s','terminal'],['s','toolbox'],['s','wifi'],['s','wrench'],
- // Media and communication
- ['s','backward'],['s','backward-fast'],['s','camera'],['s','camera-retro'],
- ['s','clapperboard'],['s','comment'],['s','comment-dots'],['s','comments'],
- ['s','film'],['s','forward'],['s','forward-fast'],['s','headphones'],
- ['s','message'],['s','microphone'],['s','microphone-slash'],['s','music'],
- ['s','pause'],['s','phone'],['s','phone-slash'],['s','phone-volume'],
- ['s','photo-film'],['s','play'],['s','radio'],['s','repeat'],['s','rss'],
- ['s','shuffle'],['s','stop'],['s','tv'],['s','video'],['s','video-slash'],
- ['s','voicemail'],['s','volume-high'],['s','volume-low'],['s','volume-xmark'],
- // People
- ['s','address-book'],['s','address-card'],['s','baby'],['s','child'],
- ['s','circle-user'],['s','people-group'],['s','person'],['s','person-running'],
- ['s','person-walking'],['s','thumbs-down'],['s','thumbs-up'],['s','user'],
- ['s','user-check'],['s','user-group'],['s','user-minus'],['s','user-plus'],
- ['s','user-slash'],['s','user-tie'],['s','users'],
- // Location and maps
- ['s','building'],['s','buildings'],['s','city'],['s','compass'],
- ['s','earth-americas'],['s','earth-asia'],['s','earth-europe'],['s','flag'],
- ['s','globe'],['s','house'],['s','location-dot'],['s','location-pin'],
- ['s','map'],['s','map-pin'],['s','mountain'],['s','road'],['s','route'],
- ['s','signs-post'],
- // Business and finance
- ['s','award'],['s','briefcase'],['s','bullhorn'],['s','bullseye'],
- ['s','calendar'],['s','calendar-check'],['s','calendar-days'],
- ['s','calendar-minus'],['s','calendar-plus'],['s','certificate'],
- ['s','chart-bar'],['s','chart-column'],['s','chart-line'],['s','chart-pie'],
- ['s','chart-simple'],['s','clock'],['s','coins'],['s','credit-card'],
- ['s','crown'],['s','gem'],['s','gift'],['s','handshake'],['s','medal'],
- ['s','money-bill'],['s','money-bill-wave'],['s','piggy-bank'],['s','receipt'],
- ['s','stopwatch'],['s','suitcase'],['s','tag'],['s','tags'],['s','timer'],
- ['s','trophy'],['s','truck'],['s','wallet'],
- // Nature and weather
- ['s','fire'],['s','fire-flame-curved'],['s','leaf'],['s','moon'],
- ['s','seedling'],['s','snowflake'],['s','sun'],['s','thermometer'],
- ['s','tree'],['s','water'],['s','wind'],
- // Health and medical
- ['s','bandage'],['s','bone'],['s','brain'],['s','dna'],['s','heart'],
- ['s','heart-pulse'],['s','hospital'],['s','pills'],['s','stethoscope'],
- ['s','syringe'],['s','tooth'],['s','virus'],['s','wheelchair'],
- // Brands
- ['b','android'],['b','angular'],['b','apple'],['b','aws'],['b','bitbucket'],
- ['b','bootstrap'],['b','chrome'],['b','css3'],['b','discord'],['b','docker'],
- ['b','dribbble'],['b','dropbox'],['b','facebook'],['b','facebook-f'],
- ['b','figma'],['b','firefox'],['b','git'],['b','github'],['b','gitlab'],
- ['b','google'],['b','html5'],['b','instagram'],['b','java'],['b','linkedin'],
- ['b','linux'],['b','microsoft'],['b','node-js'],['b','npm'],['b','php'],
- ['b','python'],['b','react'],['b','slack'],['b','square-js'],['b','tiktok'],
- ['b','vuejs'],['b','whatsapp'],['b','windows'],['b','wordpress'],
- ['b','x-twitter'],['b','youtube']
-];
-
-/* ── Icon picker component ───────────────────────────────────────────── */
-function IconPicker(props) {
- var value = props.value || '';
- var onChange = props.onChange;
- var qs = useS('');
- var query = qs[0], setQuery = qs[1];
-
- var lower = query.toLowerCase().replace(/\s+/g, '-');
- var filtered = query
- ? FA_ICONS.filter(function(ic){ return ic[1].indexOf(lower) !== -1; })
- : FA_ICONS;
-
- return el('div', { className: 'oribi-icon-picker' },
- // Current selection row
- value
- ? el('div', { className: 'oribi-icon-current' },
- el('i', { className: value, 'aria-hidden': 'true' }),
- el('span', { className: 'oribi-icon-current-label' }, value),
- el('button', {
- className: 'oribi-icon-clear',
- type: 'button',
- onClick: function(){ onChange(''); }
- }, '\u2715 Clear')
- )
- : null,
- // Search input
- el('input', {
- type: 'search',
- className: 'oribi-icon-search',
- placeholder: 'Search ' + FA_ICONS.length + ' icons…',
- value: query,
- onChange: function(e){ setQuery(e.target.value); }
- }),
- // Result count badge (only when filtering)
- query
- ? el('div', { className: 'oribi-icon-count' }, filtered.length + ' result' + (filtered.length === 1 ? '' : 's'))
- : null,
- // Icon grid
- el('div', { className: 'oribi-icon-grid' },
- filtered.length === 0
- ? el('div', { className: 'oribi-icon-empty' }, 'No icons found.')
- : filtered.map(function(ic) {
- var prefix = ic[0] === 'b' ? 'fab' : 'fas';
- var cls = prefix + ' fa-' + ic[1];
- var active = cls === value;
- return el('button', {
- key: cls,
- type: 'button',
- title: ic[1],
- className: 'oribi-icon-cell' + (active ? ' is-active' : ''),
- onClick: function(){ onChange(cls); }
- },
- el('i', { className: cls, 'aria-hidden': 'true' }),
- el('span', null, ic[1])
- );
- })
- )
- );
-}
-
-function iconControls(a, s) {
- var useFa = a.iconType === 'fontawesome';
- return el(Frag, null,
- el(TG, {
- label: 'Use Font Awesome icon',
- checked: useFa,
- onChange: function(v){ s({ iconType: v ? 'fontawesome' : 'emoji' }); }
- }),
- useFa
- ? el(IconPicker, { value: a.faIcon || '', onChange: function(v){ s({ faIcon: v }); } })
- : el(TC, { label: 'Icon (emoji)', value: a.icon || '', onChange: function(v){ s({ icon: v }); } })
- );
-}
-
-/**
- * Return the element to render in the card preview for the current icon state.
- * cssClass - the wrapper class, e.g. 'feature-icon' or 'value-icon'
- * extraStyle - optional inline style object for the wrapper
- */
-function iconPreview(a, cssClass, extraStyle) {
- var useFa = a.iconType === 'fontawesome';
- var hasIcon = useFa ? !!a.faIcon : !!a.icon;
- if (!hasIcon) return null;
- var child = useFa
- ? el('i', { className: a.faIcon || '', 'aria-hidden': 'true' })
- : a.icon;
- return el('div', { className: cssClass, style: extraStyle || {} }, child);
-}
-
-/** Build shared Card Image InspectorControls panel. */
-function cardImageControls(a, s) {
- var imgW = a.imgWidth || 80;
- var imgH = a.imgHeight || 0;
- var imgPos = a.imgPosition || 'top';
- var imgFit = a.imgFit || 'contain';
-
- return el(PB, { title: 'Card Image', initialOpen: false },
- el(MUC, null,
- el(MU, {
- onSelect: function(media){ s({ imgId: media.id, imgUrl: media.url, imgAlt: media.alt || '' }); },
- allowedTypes: ['image'],
- value: a.imgId || 0,
- render: function(ref) {
- return el(Frag, null,
- a.imgUrl ? el('div', { style: { marginBottom: '8px' } },
- el('img', { src: a.imgUrl, style: { maxWidth: '100%', height: 'auto', borderRadius: '4px', display: 'block', marginBottom: '6px' } }),
- el(Btn, { variant: 'link', isDestructive: true, onClick: function(){ s({ imgId: 0, imgUrl: '', imgAlt: '' }); } }, 'Remove image')
- ) : null,
- el(Btn, { onClick: ref.open, variant: 'secondary', __next40pxDefaultSize: true },
- a.imgUrl ? 'Replace image' : 'Select from Media Library')
- );
- }
- })
- ),
- a.imgUrl ? el(Frag, null,
- el(RC, { label: 'Width (px)', value: imgW, min: 20, max: 600, step: 4,
- onChange: function(v){ s({ imgWidth: v }); } }),
- el(RC, { label: 'Height (px) - 0 = auto', value: imgH, min: 0, max: 600, step: 4,
- onChange: function(v){ s({ imgHeight: v }); } }),
- el(TG, { label: 'Scale to fill (cover)', checked: imgFit === 'cover',
- onChange: function(v){ s({ imgFit: v ? 'cover' : 'contain' }); } }),
- el(SC, { label: 'Position', value: imgPos, options: [
- { label: 'Above content', value: 'top' },
- { label: 'Left of content', value: 'left' },
- { label: 'Replace icon', value: 'replace-icon' },
- { label: 'Background', value: 'background' }
- ], onChange: function(v){ s({ imgPosition: v }); } })
- ) : null
- );
-}
-
-/** Build an image preview element for the editor. */
-function cardImagePreview(a) {
- if (!a.imgUrl) return null;
- var imgW = a.imgWidth || 80;
- var imgH = a.imgHeight || 0;
- var imgFit = a.imgFit || 'contain';
- var style = {
- width: imgW + 'px', maxWidth: '100%',
- height: imgH > 0 ? imgH + 'px' : 'auto',
- borderRadius: '4px', objectFit: imgFit, display: 'block'
+ /* ── Shared card image attributes ────────────────────────────────────── */
+ var CARD_IMAGE_ATTRS = {
+ imgId: { type: 'number', default: 0 },
+ imgUrl: { type: 'string', default: '' },
+ imgAlt: { type: 'string', default: '' },
+ imgWidth: { type: 'number', default: 80 },
+ imgHeight: { type: 'number', default: 0 },
+ imgFit: { type: 'string', default: 'contain' },
+ imgPosition: { type: 'string', default: 'top' }
};
- return el('div', { className: 'oribi-card-img-wrap', style: { marginBottom: '1.25rem' } },
- el('img', { src: a.imgUrl, className: 'oribi-card-img oribi-card-img--' + imgFit, style: style })
- );
-}
-/** Build a shared card section edit component. */
-function createCardSectionEdit(allowedBlocks, defaultTemplate, label) {
- return function(props) {
- var a = props.attributes, s = props.setAttributes;
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Section Settings' },
- el(SC, { label: 'Background', value: a.variant, options: [
- { label: 'Normal', value: 'normal' }, { label: 'Alternate', value: 'alt' }
- ], onChange: function(v){s({variant:v});} }),
- el(RC, { label: 'Columns', value: a.columns, min: 1, max: 4, onChange: function(v){s({columns:v});} }),
- el(TC, { label: 'Label', value: a.label, onChange: function(v){s({label:v});} })
- )
- ),
- el('section', { className: a.variant === 'alt' ? 'section section-alt' : 'section' },
- el('div', { className: 'container' },
- el('div', { className: 'section-header' },
- a.label ? el('span', { className: 'section-label' }, a.label) : null,
- el(RT, { tagName: 'h2', value: a.heading, onChange: function(v){s({heading:v});}, placeholder: 'Section heading...' }),
- el(RT, { tagName: 'p', className: 'lead', value: a.lead, onChange: function(v){s({lead:v});}, placeholder: 'Lead text...' })
- ),
- el('div', { className: 'grid-' + a.columns },
- el(IB, {
- allowedBlocks: allowedBlocks,
- template: defaultTemplate,
- templateLock: false
- })
- )
- )
- )
- );
+ /* ── Shared icon attributes ──────────────────────────────────────────── */
+ var CARD_ICON_ATTRS = {
+ icon: { type: 'string', default: '' },
+ iconType: { type: 'string', default: 'emoji' },
+ faIcon: { type: 'string', default: '' }
};
-}
-/** Standard section attributes for JS. */
-var SECTION_ATTRS = {
- align: { type: 'string', default: 'full' },
- variant: { type: 'string', default: 'normal' },
- label: { type: 'string', default: '' },
- heading: { type: 'string', default: '' },
- lead: { type: 'string', default: '' },
- columns: { type: 'number', default: 3 }
-};
+ /**
+ * Build icon InspectorControls: a toggle that switches between emoji and
+ * Font Awesome mode, with the appropriate text input shown beneath it.
+ */
-/* ═══════════════════════════════════════════════════════════════════════
- STANDALONE BLOCKS (unchanged architecture)
- ═══════════════════════════════════════════════════════════════════════ */
+ /* ── Font Awesome icon catalogue ─────────────────────────────────────── */
+ // Format: ['s' = fas solid | 'b' = fab brand, 'icon-name']
+ var FA_ICONS = [
+ // Navigation
+ ['s', 'angle-down'], ['s', 'angle-left'], ['s', 'angle-right'], ['s', 'angle-up'],
+ ['s', 'angles-down'], ['s', 'angles-left'], ['s', 'angles-right'], ['s', 'angles-up'],
+ ['s', 'arrow-down'], ['s', 'arrow-left'], ['s', 'arrow-right'], ['s', 'arrow-up'],
+ ['s', 'arrow-rotate-left'], ['s', 'arrow-rotate-right'], ['s', 'arrows-rotate'],
+ ['s', 'arrows-up-down-left-right'], ['s', 'caret-down'], ['s', 'caret-left'],
+ ['s', 'caret-right'], ['s', 'caret-up'], ['s', 'chevron-down'], ['s', 'chevron-left'],
+ ['s', 'chevron-right'], ['s', 'chevron-up'], ['s', 'circle-arrow-down'],
+ ['s', 'circle-arrow-left'], ['s', 'circle-arrow-right'], ['s', 'circle-arrow-up'],
+ // Interface
+ ['s', 'asterisk'], ['s', 'at'], ['s', 'ban'], ['s', 'bars'], ['s', 'bell'], ['s', 'bell-slash'],
+ ['s', 'bolt'], ['s', 'check'], ['s', 'check-double'], ['s', 'circle-check'],
+ ['s', 'circle-exclamation'], ['s', 'circle-info'], ['s', 'circle-minus'],
+ ['s', 'circle-plus'], ['s', 'circle-question'], ['s', 'circle-xmark'],
+ ['s', 'ellipsis'], ['s', 'ellipsis-vertical'], ['s', 'eye'], ['s', 'eye-slash'],
+ ['s', 'filter'], ['s', 'grip'], ['s', 'grip-vertical'], ['s', 'hashtag'], ['s', 'key'],
+ ['s', 'lock'], ['s', 'lock-open'], ['s', 'magnifying-glass'], ['s', 'minus'], ['s', 'plus'],
+ ['s', 'power-off'], ['s', 'rotate'], ['s', 'shield'], ['s', 'shield-check'],
+ ['s', 'shield-halved'], ['s', 'sliders'], ['s', 'sort'], ['s', 'sort-down'], ['s', 'sort-up'],
+ ['s', 'spinner'], ['s', 'star'], ['s', 'star-half-stroke'], ['s', 'toggle-off'],
+ ['s', 'toggle-on'], ['s', 'xmark'],
+ // Text editing
+ ['s', 'align-center'], ['s', 'align-justify'], ['s', 'align-left'], ['s', 'align-right'],
+ ['s', 'bold'], ['s', 'code'], ['s', 'crop'], ['s', 'eraser'], ['s', 'highlight'],
+ ['s', 'indent'], ['s', 'italic'], ['s', 'link'], ['s', 'link-slash'], ['s', 'list'],
+ ['s', 'list-check'], ['s', 'list-ol'], ['s', 'list-ul'], ['s', 'outdent'], ['s', 'pen'],
+ ['s', 'pen-to-square'], ['s', 'pencil'], ['s', 'quote-left'], ['s', 'quote-right'],
+ ['s', 'scissors'], ['s', 'strikethrough'], ['s', 'subscript'], ['s', 'superscript'],
+ ['s', 'table'], ['s', 'table-list'], ['s', 'underline'],
+ // Files and documents
+ ['s', 'book'], ['s', 'book-open'], ['s', 'bookmark'], ['s', 'box'], ['s', 'box-archive'],
+ ['s', 'boxes-stacked'], ['s', 'clipboard'], ['s', 'clipboard-check'],
+ ['s', 'clipboard-list'], ['s', 'copy'], ['s', 'database'], ['s', 'download'],
+ ['s', 'envelope'], ['s', 'envelope-open'], ['s', 'file'], ['s', 'file-arrow-down'],
+ ['s', 'file-arrow-up'], ['s', 'file-code'], ['s', 'file-excel'], ['s', 'file-image'],
+ ['s', 'file-lines'], ['s', 'file-pdf'], ['s', 'file-powerpoint'], ['s', 'file-word'],
+ ['s', 'file-zipper'], ['s', 'floppy-disk'], ['s', 'folder'], ['s', 'folder-minus'],
+ ['s', 'folder-open'], ['s', 'folder-plus'], ['s', 'inbox'], ['s', 'newspaper'],
+ ['s', 'paper-plane'], ['s', 'paperclip'], ['s', 'print'], ['s', 'share'],
+ ['s', 'share-nodes'], ['s', 'upload'],
+ // Technology
+ ['s', 'barcode'], ['s', 'bug'], ['s', 'cloud'], ['s', 'cloud-arrow-down'],
+ ['s', 'cloud-arrow-up'], ['s', 'code-branch'], ['s', 'cpu'], ['s', 'desktop'],
+ ['s', 'display'], ['s', 'ethernet'], ['s', 'gear'], ['s', 'gears'], ['s', 'hard-drive'],
+ ['s', 'keyboard'], ['s', 'laptop'], ['s', 'memory'], ['s', 'microchip'], ['s', 'mobile'],
+ ['s', 'mobile-screen'], ['s', 'network-wired'], ['s', 'plug'], ['s', 'qrcode'],
+ ['s', 'robot'], ['s', 'satellite'], ['s', 'satellite-dish'], ['s', 'server'],
+ ['s', 'tablet'], ['s', 'terminal'], ['s', 'toolbox'], ['s', 'wifi'], ['s', 'wrench'],
+ // Media and communication
+ ['s', 'backward'], ['s', 'backward-fast'], ['s', 'camera'], ['s', 'camera-retro'],
+ ['s', 'clapperboard'], ['s', 'comment'], ['s', 'comment-dots'], ['s', 'comments'],
+ ['s', 'film'], ['s', 'forward'], ['s', 'forward-fast'], ['s', 'headphones'],
+ ['s', 'message'], ['s', 'microphone'], ['s', 'microphone-slash'], ['s', 'music'],
+ ['s', 'pause'], ['s', 'phone'], ['s', 'phone-slash'], ['s', 'phone-volume'],
+ ['s', 'photo-film'], ['s', 'play'], ['s', 'radio'], ['s', 'repeat'], ['s', 'rss'],
+ ['s', 'shuffle'], ['s', 'stop'], ['s', 'tv'], ['s', 'video'], ['s', 'video-slash'],
+ ['s', 'voicemail'], ['s', 'volume-high'], ['s', 'volume-low'], ['s', 'volume-xmark'],
+ // People
+ ['s', 'address-book'], ['s', 'address-card'], ['s', 'baby'], ['s', 'child'],
+ ['s', 'circle-user'], ['s', 'people-group'], ['s', 'person'], ['s', 'person-running'],
+ ['s', 'person-walking'], ['s', 'thumbs-down'], ['s', 'thumbs-up'], ['s', 'user'],
+ ['s', 'user-check'], ['s', 'user-group'], ['s', 'user-minus'], ['s', 'user-plus'],
+ ['s', 'user-slash'], ['s', 'user-tie'], ['s', 'users'],
+ // Location and maps
+ ['s', 'building'], ['s', 'buildings'], ['s', 'city'], ['s', 'compass'],
+ ['s', 'earth-americas'], ['s', 'earth-asia'], ['s', 'earth-europe'], ['s', 'flag'],
+ ['s', 'globe'], ['s', 'house'], ['s', 'location-dot'], ['s', 'location-pin'],
+ ['s', 'map'], ['s', 'map-pin'], ['s', 'mountain'], ['s', 'road'], ['s', 'route'],
+ ['s', 'signs-post'],
+ // Business and finance
+ ['s', 'award'], ['s', 'briefcase'], ['s', 'bullhorn'], ['s', 'bullseye'],
+ ['s', 'calendar'], ['s', 'calendar-check'], ['s', 'calendar-days'],
+ ['s', 'calendar-minus'], ['s', 'calendar-plus'], ['s', 'certificate'],
+ ['s', 'chart-bar'], ['s', 'chart-column'], ['s', 'chart-line'], ['s', 'chart-pie'],
+ ['s', 'chart-simple'], ['s', 'clock'], ['s', 'coins'], ['s', 'credit-card'],
+ ['s', 'crown'], ['s', 'gem'], ['s', 'gift'], ['s', 'handshake'], ['s', 'medal'],
+ ['s', 'money-bill'], ['s', 'money-bill-wave'], ['s', 'piggy-bank'], ['s', 'receipt'],
+ ['s', 'stopwatch'], ['s', 'suitcase'], ['s', 'tag'], ['s', 'tags'], ['s', 'timer'],
+ ['s', 'trophy'], ['s', 'truck'], ['s', 'wallet'],
+ // Nature and weather
+ ['s', 'fire'], ['s', 'fire-flame-curved'], ['s', 'leaf'], ['s', 'moon'],
+ ['s', 'seedling'], ['s', 'snowflake'], ['s', 'sun'], ['s', 'thermometer'],
+ ['s', 'tree'], ['s', 'water'], ['s', 'wind'],
+ // Health and medical
+ ['s', 'bandage'], ['s', 'bone'], ['s', 'brain'], ['s', 'dna'], ['s', 'heart'],
+ ['s', 'heart-pulse'], ['s', 'hospital'], ['s', 'pills'], ['s', 'stethoscope'],
+ ['s', 'syringe'], ['s', 'tooth'], ['s', 'virus'], ['s', 'wheelchair'],
+ // Brands
+ ['b', 'android'], ['b', 'angular'], ['b', 'apple'], ['b', 'aws'], ['b', 'bitbucket'],
+ ['b', 'bootstrap'], ['b', 'chrome'], ['b', 'css3'], ['b', 'discord'], ['b', 'docker'],
+ ['b', 'dribbble'], ['b', 'dropbox'], ['b', 'facebook'], ['b', 'facebook-f'],
+ ['b', 'figma'], ['b', 'firefox'], ['b', 'git'], ['b', 'github'], ['b', 'gitlab'],
+ ['b', 'google'], ['b', 'html5'], ['b', 'instagram'], ['b', 'java'], ['b', 'linkedin'],
+ ['b', 'linux'], ['b', 'microsoft'], ['b', 'node-js'], ['b', 'npm'], ['b', 'php'],
+ ['b', 'python'], ['b', 'react'], ['b', 'slack'], ['b', 'square-js'], ['b', 'tiktok'],
+ ['b', 'vuejs'], ['b', 'whatsapp'], ['b', 'windows'], ['b', 'wordpress'],
+ ['b', 'x-twitter'], ['b', 'youtube']
+ ];
-/* 1. HERO ─────────────────────────────────────────────────────────────── */
-reg('oribi/hero', {
- title: 'Oribi Hero',
- icon: 'cover-image',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: {
- align: { type: 'string', default: 'full' },
- label: { type: 'string', default: '' },
- title: { type: 'string', default: '' },
- highlightWord: { type: 'string', default: '' },
- description: { type: 'string', default: '' },
- primaryBtnText: { type: 'string', default: 'Get in Touch' },
- primaryBtnUrl: { type: 'string', default: '/contact' },
- secondaryBtnText: { type: 'string', default: '' },
- secondaryBtnUrl: { type: 'string', default: '' },
- stat1Value: { type: 'string', default: '' },
- stat1Label: { type: 'string', default: '' },
- stat2Value: { type: 'string', default: '' },
- stat2Label: { type: 'string', default: '' },
- svcLaptop1: { type: 'string', default: 'Data Backup' },
- svcLaptop2: { type: 'string', default: 'Endpoint Security' },
- svcLaptop3: { type: 'string', default: 'Patch Management' },
- svcCloud1: { type: 'string', default: 'Email Protection' },
- svcCloud2: { type: 'string', default: 'License Management' },
- svcCloud3: { type: 'string', default: 'Cloud Backup' },
- svcDesktop1: { type: 'string', default: 'Network Monitoring' },
- svcDesktop2: { type: 'string', default: 'Threat Detection' },
- svcDesktop3: { type: 'string', default: 'Cloud Management' },
- svcPhone1: { type: 'string', default: 'Mobile Security' },
- svcPhone2: { type: 'string', default: 'Data Encryption' },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Highlight' },
- el(TC, { label: 'Word to highlight in title', value: a.highlightWord, onChange: function(v){s({highlightWord:v});} })
- ),
- el(PB, { title: 'Primary Button' },
- el(TC, { label: 'URL', value: a.primaryBtnUrl, onChange: function(v){s({primaryBtnUrl:v});} })
- ),
- el(PB, { title: 'Secondary Button', initialOpen: false },
- el(TC, { label: 'URL', value: a.secondaryBtnUrl, onChange: function(v){s({secondaryBtnUrl:v});} })
+ /* ── Icon picker component ───────────────────────────────────────────── */
+ function IconPicker(props) {
+ var value = props.value || '';
+ var onChange = props.onChange;
+ var qs = useS('');
+ var query = qs[0], setQuery = qs[1];
+
+ var lower = query.toLowerCase().replace(/\s+/g, '-');
+ var filtered = query
+ ? FA_ICONS.filter(function (ic) { return ic[1].indexOf(lower) !== -1; })
+ : FA_ICONS;
+
+ return el('div', { className: 'oribi-icon-picker' },
+ // Current selection row
+ value
+ ? el('div', { className: 'oribi-icon-current' },
+ el('i', { className: value, 'aria-hidden': 'true' }),
+ el('span', { className: 'oribi-icon-current-label' }, value),
+ el('button', {
+ className: 'oribi-icon-clear',
+ type: 'button',
+ onClick: function () { onChange(''); }
+ }, '\u2715 Clear')
)
- ),
- el('section', { className: 'hero' },
- el('div', { className: 'container hero-inner' },
- el('div', { className: 'hero-content' },
- el(RT, { tagName: 'span', className: 'hero-label', value: a.label,
- onChange: function(v){s({label:v});}, placeholder: '\u25CF Label text', allowedFormats: [] }),
- el(RT, { tagName: 'h1', className: 'hero-title', value: a.title,
- onChange: function(v){s({title:v});}, placeholder: 'Hero title...' }),
- el(RT, { tagName: 'p', className: 'hero-description', value: a.description,
- onChange: function(v){s({description:v});}, placeholder: 'Description...' }),
- el('div', { className: 'btn-group' },
- el(RT, { tagName: 'span', className: 'btn btn-primary btn-lg', value: a.primaryBtnText,
- onChange: function(v){s({primaryBtnText:v});}, placeholder: 'Button', allowedFormats: [] }),
- el(RT, { tagName: 'span', className: 'btn btn-ghost btn-lg', value: a.secondaryBtnText,
- onChange: function(v){s({secondaryBtnText:v});}, placeholder: 'Secondary button', allowedFormats: [] })
- ),
- el('div', { className: 'hero-stats' },
- el('div', null,
- el(RT, { tagName: 'div', className: 'hero-stat-value', value: a.stat1Value,
- onChange: function(v){s({stat1Value:v});}, placeholder: '\u2014', allowedFormats: [] }),
- el(RT, { tagName: 'div', className: 'hero-stat-label', value: a.stat1Label,
- onChange: function(v){s({stat1Label:v});}, placeholder: 'Stat label', allowedFormats: [] })
- ),
- el('div', null,
- el(RT, { tagName: 'div', className: 'hero-stat-value', value: a.stat2Value,
- onChange: function(v){s({stat2Value:v});}, placeholder: '\u2014', allowedFormats: [] }),
- el(RT, { tagName: 'div', className: 'hero-stat-label', value: a.stat2Label,
- onChange: function(v){s({stat2Label:v});}, placeholder: 'Stat label', allowedFormats: [] })
- )
- )
- ),
- el('div', { className: 'hero-visual' },
- el('div', { className: 'hero-devices' },
- el('div', { className: 'hero-device hero-device--laptop', style: { opacity: 1 } },
- el('div', { className: 'hero-device__frame' },
- el('div', { className: 'hero-device__screen' },
- el('div', { className: 'hero-device__screen-content' },
- el('div', { className: 'hero-device__app-bars' }, el('div'),el('div'),el('div'),el('div'))
- )
- ),
- el('div', { className: 'hero-device__base' })
- ),
- el('ul', { className: 'hero-device__services' },
- el('li', { className: 'svc', style: { opacity: 1 } }, el('span',{className:'svc__dot'}), ' Data Backup'),
- el('li', { className: 'svc', style: { opacity: 1 } }, el('span',{className:'svc__dot'}), ' Endpoint Security'),
- el('li', { className: 'svc', style: { opacity: 1 } }, el('span',{className:'svc__dot'}), ' Patch Management')
- )
- ),
- el('div', { className: 'hero-device hero-device--cloud', style: { opacity: 1 } },
- el('div', { className: 'hero-device__frame' },
- el('div', { className: 'hero-device__cloud-icon' },
- el('span', { className: 'hero-device__cloud-label' }, '365')
- )
- ),
- el('ul', { className: 'hero-device__services' },
- el('li', { className: 'svc', style: { opacity: 1 } }, el('span',{className:'svc__dot'}), ' Email Protection'),
- el('li', { className: 'svc', style: { opacity: 1 } }, el('span',{className:'svc__dot'}), ' License Management'),
- el('li', { className: 'svc', style: { opacity: 1 } }, el('span',{className:'svc__dot'}), ' Cloud Backup')
- )
- ),
- el('div', { className: 'hero-device hero-device--desktop', style: { opacity: 1 } },
- el('div', { className: 'hero-device__frame' },
- el('div', { className: 'hero-device__screen' },
- el('div', { className: 'hero-device__screen-content' },
- el('div', { className: 'hero-device__dash-row' }, el('div',{className:'hero-device__dash-card'}), el('div',{className:'hero-device__dash-card'})),
- el('div', { className: 'hero-device__dash-bar' }),
- el('div', { className: 'hero-device__dash-bar hero-device__dash-bar--short' })
- )
- ),
- el('div', { className: 'hero-device__stand' }),
- el('div', { className: 'hero-device__stand-base' })
- ),
- el('ul', { className: 'hero-device__services' },
- el('li', { className: 'svc', style: { opacity: 1 } }, el('span',{className:'svc__dot'}), ' Network Monitoring'),
- el('li', { className: 'svc', style: { opacity: 1 } }, el('span',{className:'svc__dot'}), ' Threat Detection'),
- el('li', { className: 'svc', style: { opacity: 1 } }, el('span',{className:'svc__dot'}), ' Cloud Management')
- )
- ),
- el('div', { className: 'hero-device hero-device--phone', style: { opacity: 1 } },
- el('div', { className: 'hero-device__frame' },
- el('div', { className: 'hero-device__screen' },
- el('div', { className: 'hero-device__screen-content' },
- el('div', { className: 'hero-device__notif' },
- el('span', { className: 'hero-device__notif-icon' }, '\u2713'),
- el('span', { className: 'hero-device__notif-text' }, 'Secure')
- )
- )
- )
- ),
- el('ul', { className: 'hero-device__services' },
- el('li', { className: 'svc', style: { opacity: 1 } }, el('span',{className:'svc__dot'}), ' Mobile Security'),
- el('li', { className: 'svc', style: { opacity: 1 } }, el('span',{className:'svc__dot'}), ' Data Encryption')
- )
- )
- )
- )
- )
- )
- );
- },
- save: function () { return null; }
-});
-
-/* 2. PAGE HERO ────────────────────────────────────────────────────────── */
-reg('oribi/page-hero', {
- title: 'Oribi Page Hero',
- icon: 'flag',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: {
- align: { type: 'string', default: 'full' },
- label: { type: 'string', default: '' },
- title: { type: 'string', default: '' },
- description: { type: 'string', default: '' },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Settings' },
- el(TC, { label: 'Label (optional)', value: a.label, onChange: function(v){s({label:v});} })
- )
- ),
- el('section', { className: 'page-hero' },
- el('div', { className: 'container' },
- a.label ? el('span', { className: 'hero-label' }, a.label) : null,
- el(RT, { tagName: 'h1', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Page title...' }),
- el(RT, { tagName: 'p', className: 'lead', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description...' })
- )
- )
- );
- },
- save: function () { return null; }
-});
-
-/* 5. CTA BANNER ───────────────────────────────────────────────────────── */
-reg('oribi/cta-banner', {
- title: 'Oribi CTA Banner',
- icon: 'megaphone',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: {
- align: { type: 'string', default: 'full' },
- heading: { type: 'string', default: '' },
- text: { type: 'string', default: '' },
- btnText: { type: 'string', default: '' },
- btnUrl: { type: 'string', default: '' },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Button' },
- el(TC, { label: 'URL', value: a.btnUrl, onChange: function(v){s({btnUrl:v});} })
- )
- ),
- el('section', { className: 'cta-banner' },
- el('div', { className: 'container text-center' },
- el(RT, { tagName: 'h2', value: a.heading, onChange: function(v){s({heading:v});}, placeholder: 'CTA heading...' }),
- el(RT, { tagName: 'p', value: a.text, onChange: function(v){s({text:v});}, placeholder: 'CTA text...' }),
- el(RT, { tagName: 'span', className: 'btn btn-primary btn-lg', style: { background: '#fff', color: 'var(--color-primary)' }, value: a.btnText, onChange: function(v){s({btnText:v});}, placeholder: 'Button text...' })
- )
- )
- );
- },
- save: function () { return null; }
-});
-
-/* 6. INTRO SECTION ────────────────────────────────────────────────────── */
-reg('oribi/intro-section', {
- title: 'Oribi Intro Section',
- icon: 'id',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: {
- align: { type: 'string', default: 'full' },
- variant: { type: 'string', default: 'normal' },
- label: { type: 'string', default: '' },
- heading: { type: 'string', default: '' },
- description: { type: 'string', default: '' },
- visual: { type: 'string', default: '' },
- reversed: { type: 'boolean', default: false },
- imgId: { type: 'number', default: 0 },
- imgUrl: { type: 'string', default: '' },
- imgAlt: { type: 'string', default: '' },
- imgWidth: { type: 'number', default: 280 },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- var imgW = a.imgWidth || 280;
- var visualContent = a.imgUrl
- ? el('img', { src: a.imgUrl, style: { width: imgW + 'px', maxWidth: '100%', height: 'auto', borderRadius: '8px', objectFit: 'contain', display: 'block' } })
- : (a.visual || '\uD83D\uDCBB');
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Settings' },
- el(SC, { label: 'Background', value: a.variant, options: [
- { label: 'Normal', value: 'normal' }, { label: 'Alternate', value: 'alt' }
- ], onChange: function(v){s({variant:v});} }),
- el(TC, { label: 'Label', value: a.label, onChange: function(v){s({label:v});} }),
- el(TC, { label: 'Visual (emoji or text)', value: a.visual, onChange: function(v){s({visual:v});} }),
- el(TG, { label: 'Reversed layout', checked: a.reversed, onChange: function(v){s({reversed:v});} })
- ),
- el(PB, { title: 'Visual Image', initialOpen: false },
- el(MUC, null,
- el(MU, {
- onSelect: function(media){ s({ imgId: media.id, imgUrl: media.url, imgAlt: media.alt || '' }); },
- allowedTypes: ['image'],
- value: a.imgId || 0,
- render: function(ref) {
- return el(Frag, null,
- a.imgUrl ? el('div', { style: { marginBottom: '8px' } },
- el('img', { src: a.imgUrl, style: { maxWidth: '100%', height: 'auto', borderRadius: '4px', display: 'block', marginBottom: '6px' } }),
- el(Btn, { variant: 'link', isDestructive: true, onClick: function(){ s({ imgId: 0, imgUrl: '', imgAlt: '' }); } }, 'Remove image')
- ) : null,
- el(Btn, { onClick: ref.open, variant: 'secondary', __next40pxDefaultSize: true },
- a.imgUrl ? 'Replace image' : 'Select from Media Library')
- );
- }
- })
- ),
- a.imgUrl ? el(RC, { label: 'Width (px)', value: imgW, min: 50, max: 420, step: 4,
- onChange: function(v){ s({ imgWidth: v }); } }) : null
- )
- ),
- el('section', { className: a.variant === 'alt' ? 'section section-alt' : 'section' },
- el('div', { className: 'container' },
- el('div', { className: 'about-intro', style: a.reversed ? { direction: 'rtl' } : {} },
- el('div', { style: a.reversed ? { direction: 'ltr' } : {} },
- a.label ? el('span', { className: 'section-label' }, a.label) : null,
- el(RT, { tagName: 'h2', style: { marginBottom: '1.5rem' }, value: a.heading, onChange: function(v){s({heading:v});}, placeholder: 'Heading...' }),
- el(RT, { tagName: 'p', className: 'lead', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description...' })
- ),
- el('div', { className: 'about-intro-visual' + (a.imgUrl ? ' has-img' : ''), style: a.reversed ? { direction: 'ltr' } : {} }, visualContent)
- )
- )
- )
- );
- },
- save: function () { return null; }
-});
-
-/* 8. CONTACT SECTION ──────────────────────────────────────────────────── */
-reg('oribi/contact-section', {
- title: 'Oribi Contact',
- icon: 'email',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: {
- align: { type: 'string', default: 'full' },
- heading: { type: 'string', default: "Let's Talk" },
- lead: { type: 'string', default: '' },
- email: { type: 'string', default: 'solutions@oribi-tech.com' },
- supportUrl: { type: 'string', default: '' },
- portalUrl: { type: 'string', default: '' },
- location: { type: 'string', default: 'Saratoga Springs, Upstate New York' },
- formHeading: { type: 'string', default: 'Want to Learn More?' },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Contact Settings' },
- el(TC, { label: 'Email', value: a.email, onChange: function(v){s({email:v});} }),
- el(TC, { label: 'Support URL', value: a.supportUrl, onChange: function(v){s({supportUrl:v});} }),
- el(TC, { label: 'Portal URL', value: a.portalUrl, onChange: function(v){s({portalUrl:v});} }),
- el(TC, { label: 'Location', value: a.location, onChange: function(v){s({location:v});} }),
- el(TC, { label: 'Form Heading', value: a.formHeading, onChange: function(v){s({formHeading:v});} })
- )
- ),
- el('section', { className: 'section' },
- el('div', { className: 'container' },
- el('div', { className: 'contact-layout' },
- el('div', { className: 'contact-info' },
- el(RT, { tagName: 'h2', value: a.heading, onChange: function(v){s({heading:v});}, placeholder: 'Heading...' }),
- el(RT, { tagName: 'p', className: 'lead', value: a.lead, onChange: function(v){s({lead:v});}, placeholder: 'Lead text...' }),
- el('div', { className: 'contact-method' },
- el('div',{className:'contact-method-icon'},'\uD83D\uDCE7'),
- el('div',null, el('div',{className:'contact-method-label'},'Email Us'), el('div',{className:'contact-method-value'}, a.email))
- ),
- el('div', { className: 'contact-method' },
- el('div',{className:'contact-method-icon'},'\uD83C\uDFAB'),
- el('div',null, el('div',{className:'contact-method-label'},'Support'), el('div',{className:'contact-method-value'}, 'Open a Support Ticket'))
- ),
- el('div', { className: 'contact-method' },
- el('div',{className:'contact-method-icon'},'\uD83C\uDF0E'),
- el('div',null, el('div',{className:'contact-method-label'},'Client Portal'), el('div',{className:'contact-method-value'}, 'portal.oribi-tech.com'))
- ),
- el('div', { className: 'contact-method' },
- el('div',{className:'contact-method-icon'},'\uD83D\uDCCD'),
- el('div',null, el('div',{className:'contact-method-label'},'Location'), el('div',{className:'contact-method-value'}, a.location))
- )
- ),
- el('div', { className: 'contact-form-wrap' },
- el('h3', { style: { marginBottom: '1.5rem' } }, a.formHeading),
- el('div', { style: { padding: '2rem', background: 'var(--color-bg-alt)', borderRadius: 'var(--radius-md)', textAlign: 'center', color: 'var(--color-text-muted)' } },
- 'Contact form renders on the live site'
- )
- )
- )
- )
- )
- );
- },
- save: function () { return null; }
-});
-
-/* ═══════════════════════════════════════════════════════════════════════
- CHILD BLOCKS (each renders one item inside a parent)
- ═══════════════════════════════════════════════════════════════════════ */
-
-/* ── Feature Card ─────────────────────────────────────────────────────── */
-reg('oribi/feature-card', {
- title: 'Feature Card',
- icon: 'screenoptions',
- category: 'oribi',
- parent: ['oribi/feature-section'],
- supports: { html: false, reusable: false },
- attributes: Object.assign({}, {
- icon: { type: 'string', default: '' },
- iconType: { type: 'string', default: 'emoji' },
- faIcon: { type: 'string', default: '' },
- title: { type: 'string', default: '' },
- description: { type: 'string', default: '' },
- url: { type: 'string', default: '' },
- centered: { type: 'boolean', default: false }
- }, CARD_IMAGE_ATTRS),
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- var imgPos = a.imgPosition || 'top';
- var imgPrev = cardImagePreview(a);
- var centeredStyle = a.centered ? { marginInline: 'auto' } : {};
-
- var cardPreview;
- if ( a.imgUrl && imgPos === 'left' ) {
- cardPreview = el('div', { className: 'oribi-card img-left' },
- imgPrev,
- el('div', { className: 'oribi-card-body' },
- el(RT, { tagName: 'h3', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Card title...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Card description...' })
- )
- );
- } else if ( a.imgUrl && imgPos === 'background' ) {
- cardPreview = el('div', { className: 'oribi-card img-bg', style: { backgroundImage: 'url(' + a.imgUrl + ')', backgroundSize: 'cover', backgroundPosition: 'center', color: '#fff' } },
- el('div', { className: 'oribi-card-body' },
- iconPreview(a, 'feature-icon', centeredStyle),
- el(RT, { tagName: 'h3', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Card title...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Card description...' })
- )
- );
- } else {
- var showIconPrev = !a.imgUrl || imgPos !== 'replace-icon';
- cardPreview = el('div', { className: 'oribi-card' + (a.centered ? ' text-center' : '') + (a.imgUrl ? ' img-' + imgPos : '') },
- a.imgUrl && (imgPos === 'top' || imgPos === 'replace-icon') ? imgPrev : null,
- showIconPrev ? iconPreview(a, 'feature-icon', centeredStyle) : null,
- el(RT, { tagName: 'h3', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Card title...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Card description...' })
- );
- }
-
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Card Settings' },
- iconControls(a, s),
- el(TC, { label: 'URL (optional)', value: a.url || '', onChange: function(v){s({url:v});} }),
- el(TG, { label: 'Centered', checked: !!a.centered, onChange: function(v){s({centered:v});} })
- ),
- cardImageControls(a, s)
- ),
- cardPreview
- );
- },
- save: function () { return null; }
-});
-
-/* ── Value Card ───────────────────────────────────────────────────────── */
-reg('oribi/value-card', {
- title: 'Value Card',
- icon: 'heart',
- category: 'oribi',
- parent: ['oribi/value-section'],
- supports: { html: false, reusable: false },
- attributes: Object.assign({}, {
- icon: { type: 'string', default: '' },
- iconType: { type: 'string', default: 'emoji' },
- faIcon: { type: 'string', default: '' },
- title: { type: 'string', default: '' },
- description: { type: 'string', default: '' }
- }, CARD_IMAGE_ATTRS),
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- var imgPos = a.imgPosition || 'top';
- var imgPrev = cardImagePreview(a);
- var showIconPrev = !a.imgUrl || imgPos !== 'replace-icon';
-
- var body;
- if ( a.imgUrl && imgPos === 'left' ) {
- body = el('div', { className: 'oribi-card value-card img-left' },
- imgPrev,
- el('div', { className: 'oribi-card-body' },
- el(RT, { tagName: 'h3', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Title...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description...' })
- )
- );
- } else if ( a.imgUrl && imgPos === 'background' ) {
- body = el('div', { className: 'oribi-card value-card img-bg', style: { backgroundImage: 'url(' + a.imgUrl + ')', backgroundSize: 'cover', backgroundPosition: 'center', color: '#fff' } },
- el('div', { className: 'oribi-card-body' },
- showIconPrev ? iconPreview(a, 'value-icon') : null,
- el(RT, { tagName: 'h3', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Title...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description...' })
- )
- );
- } else {
- body = el('div', { className: 'oribi-card value-card' + (a.imgUrl ? ' img-' + imgPos : '') },
- a.imgUrl && (imgPos === 'top' || imgPos === 'replace-icon') ? imgPrev : null,
- showIconPrev ? iconPreview(a, 'value-icon') : null,
- el(RT, { tagName: 'h3', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Title...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description...' })
- );
- }
-
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Card Settings' },
- iconControls(a, s)
- ),
- cardImageControls(a, s)
- ),
- body
- );
- },
- save: function () { return null; }
-});
-
-/* ── Addon Card ───────────────────────────────────────────────────────── */
-reg('oribi/addon-card', {
- title: 'Addon Card',
- icon: 'plus-alt2',
- category: 'oribi',
- parent: ['oribi/addon-section'],
- supports: { html: false, reusable: false },
- attributes: Object.assign({}, {
- icon: { type: 'string', default: '' },
- iconType: { type: 'string', default: 'emoji' },
- faIcon: { type: 'string', default: '' },
- title: { type: 'string', default: '' },
- description: { type: 'string', default: '' },
- tag: { type: 'string', default: '' }
- }, CARD_IMAGE_ATTRS),
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- var imgPos = a.imgPosition || 'top';
- var imgPrev = cardImagePreview(a);
- var showIconPrev = !a.imgUrl || imgPos !== 'replace-icon';
-
- var body;
- if ( a.imgUrl && imgPos === 'left' ) {
- body = el('div', { className: 'oribi-card img-left' },
- imgPrev,
- el('div', { className: 'oribi-card-body' },
- a.tag ? el('span', { className: 'addon-tag' }, a.tag) : null,
- el(RT, { tagName: 'h3', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Title...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description...' })
- )
- );
- } else if ( a.imgUrl && imgPos === 'background' ) {
- body = el('div', { className: 'oribi-card img-bg', style: { backgroundImage: 'url(' + a.imgUrl + ')', backgroundSize: 'cover', backgroundPosition: 'center', color: '#fff' } },
- el('div', { className: 'oribi-card-body' },
- showIconPrev ? iconPreview(a, 'feature-icon') : null,
- a.tag ? el('span', { className: 'addon-tag' }, a.tag) : null,
- el(RT, { tagName: 'h3', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Title...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description...' })
- )
- );
- } else {
- body = el('div', { className: 'oribi-card' + (a.imgUrl ? ' img-' + imgPos : '') },
- a.imgUrl && (imgPos === 'top' || imgPos === 'replace-icon') ? imgPrev : null,
- showIconPrev ? iconPreview(a, 'feature-icon') : null,
- a.tag ? el('span', { className: 'addon-tag' }, a.tag) : null,
- el(RT, { tagName: 'h3', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Title...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description...' })
- );
- }
-
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Card Settings' },
- iconControls(a, s),
- el(TC, { label: 'Tag / Badge (optional)', value: a.tag || '', onChange: function(v){s({tag:v});} })
- ),
- cardImageControls(a, s)
- ),
- body
- );
- },
- save: function () { return null; }
-});
-
-/* ── Image Card ───────────────────────────────────────────────────────── */
-reg('oribi/image-card', {
- title: 'Image Card',
- icon: 'format-image',
- category: 'oribi',
- parent: ['oribi/image-section'],
- supports: { html: false, reusable: false },
- attributes: Object.assign({}, {
- icon: { type: 'string', default: '' },
- iconType: { type: 'string', default: 'emoji' },
- faIcon: { type: 'string', default: '' },
- title: { type: 'string', default: '' },
- description: { type: 'string', default: '' },
- url: { type: 'string', default: '' }
- }, CARD_IMAGE_ATTRS),
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- var imgPos = a.imgPosition || 'top';
- var imgPrev = cardImagePreview(a);
- var showIconPrev = !a.imgUrl || imgPos !== 'replace-icon';
-
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Card Settings' },
- iconControls(a, s),
- el(TC, { label: 'URL (optional)', value: a.url || '', onChange: function(v){s({url:v});} })
- ),
- cardImageControls(a, s)
- ),
- el('div', { className: 'oribi-card image-card' + (a.imgUrl ? ' img-' + imgPos : '') },
- a.imgUrl && (imgPos === 'top' || imgPos === 'replace-icon') ? imgPrev : null,
- showIconPrev ? iconPreview(a, 'feature-icon') : null,
- el('div', { className: 'oribi-card-body' },
- el(RT, { tagName: 'h3', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Title...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description...' })
- )
- )
- );
- },
- save: function () { return null; }
-});
-
-/* ── Stat Card ────────────────────────────────────────────────────────── */
-reg('oribi/stat-card', {
- title: 'Stat Card',
- icon: 'chart-bar',
- category: 'oribi',
- parent: ['oribi/stat-section'],
- supports: { html: false, reusable: false },
- attributes: Object.assign({}, {
- icon: { type: 'string', default: '' },
- iconType: { type: 'string', default: 'emoji' },
- faIcon: { type: 'string', default: '' },
- value: { type: 'string', default: '' },
- label: { type: 'string', default: '' },
- description: { type: 'string', default: '' }
- }, CARD_IMAGE_ATTRS),
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- var imgPrev = cardImagePreview(a);
- var imgPos = a.imgPosition || 'top';
-
- var body;
- if ( a.imgUrl && imgPos === 'background' ) {
- body = el('div', { className: 'oribi-card stat-card img-bg', style: { backgroundImage: 'url(' + a.imgUrl + ')', backgroundSize: 'cover', backgroundPosition: 'center', color: '#fff' } },
- el('div', { className: 'oribi-card-body' },
- iconPreview(a, 'feature-icon'),
- el(RT, { tagName: 'div', className: 'stat-value', value: a.value, onChange: function(v){s({value:v});}, placeholder: '99.9%' }),
- el(RT, { tagName: 'div', className: 'stat-label', value: a.label, onChange: function(v){s({label:v});}, placeholder: 'Label...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description (optional)...' })
- )
- );
- } else {
- body = el('div', { className: 'oribi-card stat-card' + (a.imgUrl ? ' img-' + imgPos : '') },
- (a.imgUrl && imgPos !== 'replace-icon') ? imgPrev : null,
- iconPreview(a, 'feature-icon'),
- el(RT, { tagName: 'div', className: 'stat-value', value: a.value, onChange: function(v){s({value:v});}, placeholder: '99.9%' }),
- el(RT, { tagName: 'div', className: 'stat-label', value: a.label, onChange: function(v){s({label:v});}, placeholder: 'Label...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description (optional)...' })
- );
- }
-
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Card Settings' },
- iconControls(a, s)
- ),
- cardImageControls(a, s)
- ),
- body
- );
- },
- save: function () { return null; }
-});
-
-/* ── Link Card ────────────────────────────────────────────────────────── */
-reg('oribi/link-card', {
- title: 'Link Card',
- icon: 'admin-links',
- category: 'oribi',
- parent: ['oribi/link-section'],
- supports: { html: false, reusable: false },
- attributes: Object.assign({}, {
- icon: { type: 'string', default: '' },
- iconType: { type: 'string', default: 'emoji' },
- faIcon: { type: 'string', default: '' },
- title: { type: 'string', default: '' },
- description: { type: 'string', default: '' },
- linkText: { type: 'string', default: '' },
- linkUrl: { type: 'string', default: '' }
- }, CARD_IMAGE_ATTRS),
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- var imgPos = a.imgPosition || 'top';
- var imgPrev = cardImagePreview(a);
- var showIconPrev = !a.imgUrl || imgPos !== 'replace-icon';
-
- var body;
- if ( a.imgUrl && imgPos === 'left' ) {
- body = el('div', { className: 'oribi-card link-card img-left' },
- imgPrev,
- el('div', { className: 'oribi-card-body' },
- showIconPrev ? iconPreview(a, 'feature-icon') : null,
- el(RT, { tagName: 'h3', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Title...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description...' }),
- el(RT, { tagName: 'span', className: 'link-card-cta', value: a.linkText, onChange: function(v){s({linkText:v});}, placeholder: 'Link text → ...' })
- )
- );
- } else if ( a.imgUrl && imgPos === 'background' ) {
- body = el('div', { className: 'oribi-card link-card img-bg', style: { backgroundImage: 'url(' + a.imgUrl + ')', backgroundSize: 'cover', backgroundPosition: 'center', color: '#fff' } },
- el('div', { className: 'oribi-card-body' },
- showIconPrev ? iconPreview(a, 'feature-icon') : null,
- el(RT, { tagName: 'h3', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Title...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description...' }),
- el(RT, { tagName: 'span', className: 'link-card-cta', value: a.linkText, onChange: function(v){s({linkText:v});}, placeholder: 'Link text → ...' })
- )
- );
- } else {
- body = el('div', { className: 'oribi-card link-card' + (a.imgUrl ? ' img-' + imgPos : '') },
- (a.imgUrl && (imgPos === 'top' || imgPos === 'replace-icon')) ? imgPrev : null,
- showIconPrev ? iconPreview(a, 'feature-icon') : null,
- el(RT, { tagName: 'h3', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Title...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description...' }),
- el(RT, { tagName: 'span', className: 'link-card-cta', value: a.linkText, onChange: function(v){s({linkText:v});}, placeholder: 'Link text → ...' })
- );
- }
-
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Card Settings' },
- iconControls(a, s),
- el(TC, { label: 'Link URL', value: a.linkUrl || '', onChange: function(v){s({linkUrl:v});} })
- ),
- cardImageControls(a, s)
- ),
- body
- );
- },
- save: function () { return null; }
-});
-
-/* ── Pricing Card ─────────────────────────────────────────────────────── */
-reg('oribi/pricing-card', {
- title: 'Pricing Card',
- icon: 'money-alt',
- category: 'oribi',
- parent: ['oribi/pricing-section'],
- supports: { html: false, reusable: false },
- attributes: {
- icon: { type: 'string', default: '' },
- iconType: { type: 'string', default: 'emoji' },
- 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' },
- featured: { type: 'boolean', default: false },
- badge: { type: 'string', default: '' },
- imgId: { type: 'number', default: 0 },
- imgUrl: { type: 'string', default: '' },
- imgAlt: { type: 'string', default: '' },
- imgWidth: { type: 'number', default: 80 },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- var features = a.features || [];
- var imgW = a.imgWidth || 80;
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Card Settings' },
- iconControls(a, s),
- el(TC, { label: 'Button URL', value: a.btnUrl, onChange: function(v){s({btnUrl:v});} }),
- el(TG, { label: 'Featured', checked: !!a.featured, onChange: function(v){s({featured:v});} }),
- a.featured ? el(TC, { label: 'Badge Text', value: a.badge, onChange: function(v){s({badge:v});} }) : null
- ),
- el(PB, { title: 'Card Image', initialOpen: false },
- el(MUC, null,
- el(MU, {
- onSelect: function(media){ s({ imgId: media.id, imgUrl: media.url, imgAlt: media.alt || '' }); },
- allowedTypes: ['image'],
- value: a.imgId || 0,
- render: function(ref) {
- return el(Frag, null,
- a.imgUrl ? el('div', { style: { marginBottom: '8px' } },
- el('img', { src: a.imgUrl, style: { maxWidth: '100%', height: 'auto', borderRadius: '4px', display: 'block', marginBottom: '6px' } }),
- el(Btn, { variant: 'link', isDestructive: true, onClick: function(){ s({ imgId: 0, imgUrl: '', imgAlt: '' }); } }, 'Remove image')
- ) : null,
- el(Btn, { onClick: ref.open, variant: 'secondary', __next40pxDefaultSize: true },
- a.imgUrl ? 'Replace image' : 'Select from Media Library')
- );
- }
- })
- ),
- a.imgUrl ? el(RC, { label: 'Width (px)', value: imgW, min: 20, max: 400, step: 4,
- onChange: function(v){ s({ imgWidth: v }); } }) : null
- )
- ),
- el('div', { className: 'pricing-card' + (a.featured ? ' featured' : '') },
- a.featured && a.badge ? el(RT, { tagName: 'span', className: 'pricing-badge', value: a.badge,
- onChange: function(v){s({badge:v});}, placeholder: 'Badge...' }) : null,
- a.imgUrl ? el('div', { style: { textAlign: 'center', marginBottom: '1.25rem' } },
- el('img', { src: a.imgUrl, style: { width: imgW + 'px', maxWidth: '100%', height: 'auto', borderRadius: '4px', objectFit: 'contain' } })
- ) : null,
- iconPreview(a, 'feature-icon', { marginInline: 'auto' }),
- el(RT, { tagName: 'div', className: 'pricing-name', value: a.name,
- 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' } },
- el('span', { className: 'pricing-check' }, '\u2713'),
- el(RT, { tagName: 'span', style: { flex: 1, minWidth: 0 }, value: f,
- onChange: function(v){ s({features: arrSet(features, fi, v)}); }, placeholder: 'Feature...' }),
- el(Btn, { isSmall: true, isDestructive: true,
- style: { minWidth: '20px', padding: 0, height: '20px', flexShrink: 0 },
- onClick: function(){ s({features: arrRm(features, fi)}); } }, '\u2715')
+ : null,
+ // Search input
+ el('input', {
+ type: 'search',
+ className: 'oribi-icon-search',
+ placeholder: 'Search ' + FA_ICONS.length + ' icons…',
+ value: query,
+ onChange: function (e) { setQuery(e.target.value); }
+ }),
+ // Result count badge (only when filtering)
+ query
+ ? el('div', { className: 'oribi-icon-count' }, filtered.length + ' result' + (filtered.length === 1 ? '' : 's'))
+ : null,
+ // Icon grid
+ el('div', { className: 'oribi-icon-grid' },
+ filtered.length === 0
+ ? el('div', { className: 'oribi-icon-empty' }, 'No icons found.')
+ : filtered.map(function (ic) {
+ var prefix = ic[0] === 'b' ? 'fab' : 'fas';
+ var cls = prefix + ' fa-' + ic[1];
+ var active = cls === value;
+ return el('button', {
+ key: cls,
+ type: 'button',
+ title: ic[1],
+ className: 'oribi-icon-cell' + (active ? ' is-active' : ''),
+ onClick: function () { onChange(cls); }
+ },
+ el('i', { className: cls, 'aria-hidden': 'true' }),
+ el('span', null, ic[1])
);
- }),
- el('li', { style: { listStyle: 'none', marginTop: '4px' } },
- el(Btn, { isSmall: true, variant: 'secondary',
- onClick: function(){ s({features: arrAdd(features, '')}); } }, '+ Feature')
- )
- ),
- el(RT, { tagName: 'span',
- className: 'btn ' + (a.featured ? 'btn-primary' : 'btn-outline'),
- style: { width: '100%', justifyContent: 'center', cursor: 'text' },
- value: a.btnText || '',
- onChange: function(v){s({btnText:v});}, placeholder: 'Button text...' })
- )
- );
- },
- save: function () { return null; }
-});
-
-/* ── Platform Row ─────────────────────────────────────────────────────── */
-reg('oribi/platform-row', {
- title: 'Platform Row',
- icon: 'slides',
- category: 'oribi',
- parent: ['oribi/platform-section'],
- supports: { html: false, reusable: false },
- attributes: {
- heading: { type: 'string', default: '' },
- description: { type: 'string', default: '' },
- btnText: { type: 'string', default: 'Learn More' },
- btnUrl: { type: 'string', default: '' },
- visual: { type: 'string', default: '' },
- reversed: { type: 'boolean', default: false },
- imgId: { type: 'number', default: 0 },
- imgUrl: { type: 'string', default: '' },
- imgAlt: { type: 'string', default: '' },
- imgWidth: { type: 'number', default: 300 },
- isDashboard: { type: 'boolean', default: false },
- deviceAnim: { type: 'boolean', default: false },
- tvStick: { type: 'boolean', default: false },
- cameraAnim: { type: 'boolean', default: false },
- neverGoesDark: { type: 'boolean', default: false },
- brandedAnim: { type: 'boolean', default: false },
- galleryIds: { type: 'array', default: [] },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- var imgW = a.imgWidth || 300;
-
- /* ── Animation HTML strings (mirror PHP render, used via dangerouslySetInnerHTML) ── */
- var DA_SCREEN = '
';
- var DA_HTML = '' +
- '
' +
- '
' + DA_SCREEN + '
Small Monitor' +
- '
' + DA_SCREEN + '
Large Monitor' +
- '
' +
- '
' +
- '
' + DA_SCREEN + '
' + DA_SCREEN + '
' + DA_SCREEN + '
' + DA_SCREEN + '
Video Wall' +
- '
';
-
- var TS_MI = '';
- var TS_COL = '';
- var TS_HTML = '' +
- '
' +
- '' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
';
-
- var NGD_ROW = '';
- var NGD_ROWH = '';
- var NGD_HTML = '' +
- '
' +
- '
' +
- '
' +
- '
';
-
- var BD_SPLASH = '';
- var BD_HDR = '';
- var BD_HTML = '' +
- '
' +
- '
' +
- '
' +
- '
';
-
- var DB_HTML = ' ';
-
- return el(Frag, null,
- el(IC, null,
- 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: 'Dashboard Animation', checked: !!a.isDashboard, onChange: function(v){s({isDashboard:v});} }),
- el(TG, { label: 'Device Animation', checked: !!a.deviceAnim, onChange: function(v){s({deviceAnim:v});} }),
- el(TG, { label: 'TV Stick Animation', checked: !!a.tvStick, onChange: function(v){s({tvStick:v});} }),
- el(TG, { label: 'Camera Animation', checked: !!a.cameraAnim, onChange: function(v){s({cameraAnim:v});} }),
- el(TG, { label: 'Never Goes Dark', checked: !!a.neverGoesDark, onChange: function(v){s({neverGoesDark:v});} }),
- el(TG, { label: 'Branded Display', checked: !!a.brandedAnim, onChange: function(v){s({brandedAnim: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, {
- onSelect: function(media){ s({ imgId: media.id, imgUrl: media.url, imgAlt: media.alt || '' }); },
- allowedTypes: ['image'],
- value: a.imgId || 0,
- render: function(ref) {
- return el(Frag, null,
- a.imgUrl ? el('div', { style: { marginBottom: '8px' } },
- el('img', { src: a.imgUrl, style: { maxWidth: '100%', height: 'auto', borderRadius: '4px', display: 'block', marginBottom: '6px' } }),
- el(Btn, { variant: 'link', isDestructive: true, onClick: function(){ s({ imgId: 0, imgUrl: '', imgAlt: '' }); } }, 'Remove image')
- ) : null,
- el(Btn, { onClick: ref.open, variant: 'secondary', __next40pxDefaultSize: true },
- a.imgUrl ? 'Replace image' : 'Select from Media Library')
- );
- }
- })
- ),
- a.imgUrl ? el(RC, { label: 'Width (px)', value: imgW, min: 50, max: 600, step: 4,
- onChange: function(v){ s({ imgWidth: v }); } }) : null
- )
- ),
- el('div', { className: 'platform-row' + (a.reversed ? ' reverse' : '') },
- el('div', { className: 'platform-text' },
- el(RT, { tagName: 'h3', value: a.heading, onChange: function(v){s({heading:v});}, placeholder: 'Service name...' }),
- el(RT, { tagName: 'p', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Service description...' }),
- 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.isDashboard
- ? el('div', { className: 'platform-visual has-dashboard', dangerouslySetInnerHTML: { __html: DB_HTML } })
- : 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.deviceAnim
- ? el('div', { className: 'platform-visual has-anim', dangerouslySetInnerHTML: { __html: DA_HTML } })
- : a.tvStick
- ? el('div', { className: 'platform-visual has-tv-stick', dangerouslySetInnerHTML: { __html: TS_HTML } })
- : a.neverGoesDark
- ? el('div', { className: 'platform-visual has-ngd', dangerouslySetInnerHTML: { __html: NGD_HTML } })
- : a.brandedAnim
- ? el('div', { className: 'platform-visual has-branded', dangerouslySetInnerHTML: { __html: BD_HTML } })
- : 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' } })
- )
- : el('div', { className: 'platform-visual' }, a.visual || '\uD83D\uDCBB')
- )
- );
- },
- save: function () { return null; }
-});
-
-/* ── Trust Item ───────────────────────────────────────────────────────── */
-reg('oribi/trust-item', {
- title: 'Trust Item',
- icon: 'shield',
- category: 'oribi',
- parent: ['oribi/trust-section'],
- supports: { html: false, reusable: false },
- attributes: {
- heading: { type: 'string', default: '' },
- description: { type: 'string', default: '' },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- return el('div', { className: 'trust-item' },
- el(RT, { tagName: 'h3', style: { marginBottom: '1rem' },
- value: a.heading, onChange: function(v){s({heading:v});}, placeholder: 'Sub-heading...' }),
- el(RT, { tagName: 'p', value: a.description,
- onChange: function(v){s({description:v});}, placeholder: 'Description...' })
- );
- },
- save: function () { return null; }
-});
-
-/* ═══════════════════════════════════════════════════════════════════════
- PARENT BLOCKS (use InnerBlocks for child items)
- ═══════════════════════════════════════════════════════════════════════ */
-
-/* 3. FEATURE SECTION ──────────────────────────────────────────────────── */
-reg('oribi/feature-section', {
- title: 'Oribi Feature Section',
- icon: 'grid-view',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: SECTION_ATTRS,
- edit: createCardSectionEdit(['oribi/feature-card'], [['oribi/feature-card', {}]], 'Feature Card'),
- save: function () { return el(IB.Content); }
-});
-
-/* VALUE SECTION ────────────────────────────────────────────────────────── */
-reg('oribi/value-section', {
- title: 'Oribi Value Section',
- icon: 'heart',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: SECTION_ATTRS,
- edit: createCardSectionEdit(['oribi/value-card'], [['oribi/value-card', {}]], 'Value Card'),
- save: function () { return el(IB.Content); }
-});
-
-/* ADDON SECTION ────────────────────────────────────────────────────────── */
-reg('oribi/addon-section', {
- title: 'Oribi Addon Section',
- icon: 'plus-alt2',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: SECTION_ATTRS,
- edit: createCardSectionEdit(['oribi/addon-card'], [['oribi/addon-card', {}]], 'Addon Card'),
- save: function () { return el(IB.Content); }
-});
-
-/* IMAGE SECTION ────────────────────────────────────────────────────────── */
-reg('oribi/image-section', {
- title: 'Oribi Image Section',
- icon: 'format-image',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: SECTION_ATTRS,
- edit: createCardSectionEdit(['oribi/image-card'], [['oribi/image-card', {}]], 'Image Card'),
- save: function () { return el(IB.Content); }
-});
-
-/* STAT SECTION ─────────────────────────────────────────────────────────── */
-reg('oribi/stat-section', {
- title: 'Oribi Stat Section',
- icon: 'chart-bar',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: SECTION_ATTRS,
- edit: createCardSectionEdit(['oribi/stat-card'], [['oribi/stat-card', {}]], 'Stat Card'),
- save: function () { return el(IB.Content); }
-});
-
-/* LINK SECTION ─────────────────────────────────────────────────────────── */
-reg('oribi/link-section', {
- title: 'Oribi Link Section',
- icon: 'admin-links',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: SECTION_ATTRS,
- edit: createCardSectionEdit(['oribi/link-card'], [['oribi/link-card', {}]], 'Link Card'),
- save: function () { return el(IB.Content); }
-});
-
-/* 4. PRICING SECTION ──────────────────────────────────────────────────── */
-reg('oribi/pricing-section', {
- title: 'Oribi Pricing',
- icon: 'money-alt',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: {
- align: { type: 'string', default: 'full' },
- variant: { type: 'string', default: 'normal' },
- label: { type: 'string', default: '' },
- heading: { type: 'string', default: '' },
- lead: { type: 'string', default: '' },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Section Settings' },
- el(SC, { label: 'Background', value: a.variant, options: [
- { label: 'Normal', value: 'normal' }, { label: 'Alternate', value: 'alt' }
- ], onChange: function(v){s({variant:v});} }),
- el(TC, { label: 'Label', value: a.label, onChange: function(v){s({label:v});} })
- )
- ),
- el('section', { className: a.variant === 'alt' ? 'section section-alt' : 'section' },
- el('div', { className: 'container' },
- el('div', { className: 'section-header' },
- a.label ? el('span', { className: 'section-label' }, a.label) : null,
- el(RT, { tagName: 'h2', value: a.heading, onChange: function(v){s({heading:v});}, placeholder: 'Pricing heading...' }),
- el(RT, { tagName: 'p', className: 'lead', value: a.lead, onChange: function(v){s({lead:v});}, placeholder: 'Lead text...' })
- ),
- el('div', { className: 'pricing-grid' },
- el(IB, {
- allowedBlocks: ['oribi/pricing-card'],
- template: [
- ['oribi/pricing-card', { name: 'Essentials' }],
- ['oribi/pricing-card', { name: 'Pro', featured: true, badge: 'Most Popular' }],
- ['oribi/pricing-card', { name: 'Enterprise' }]
- ],
- templateLock: false
- })
- )
- )
- )
- );
- },
- save: function () { return el(IB.Content); }
-});
-
-/* 7. PLATFORM SECTION ─────────────────────────────────────────────────── */
-reg('oribi/platform-section', {
- title: 'Oribi Platform Section',
- icon: 'slides',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: {
- align: { type: 'string', default: 'full' },
- label: { type: 'string', default: '' },
- heading: { type: 'string', default: '' },
- lead: { type: 'string', default: '' },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Section' },
- el(TC, { label: 'Label', value: a.label, onChange: function(v){s({label:v});} })
- )
- ),
- el('section', { className: 'section' },
- el('div', { className: 'container' },
- el('div', { className: 'section-header' },
- a.label ? el('span', { className: 'section-label' }, a.label) : null,
- el(RT, { tagName: 'h2', value: a.heading, onChange: function(v){s({heading:v});}, placeholder: 'Section heading...' }),
- el(RT, { tagName: 'p', className: 'lead', value: a.lead, onChange: function(v){s({lead:v});}, placeholder: 'Lead text...' })
- ),
- el(IB, {
- allowedBlocks: ['oribi/platform-row'],
- template: [['oribi/platform-row', {}]],
- templateLock: false
})
- )
)
);
- },
- save: function () { return el(IB.Content); }
-});
+ }
-/* 9. TRUST SECTION ────────────────────────────────────────────────────── */
-reg('oribi/trust-section', {
- title: 'Oribi Trust Section',
- icon: 'shield',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: {
- align: { type: 'string', default: 'full' },
- label: { type: 'string', default: '' },
- heading: { type: 'string', default: '' },
- lead: { type: 'string', default: '' },
- btnText: { type: 'string', default: '' },
- btnUrl: { type: 'string', default: '' },
- btnSub: { type: 'string', default: '' },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
+ function iconControls(a, s) {
+ var useFa = a.iconType === 'fontawesome';
return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Settings' },
- el(TC, { label: 'Label', value: a.label, onChange: function(v){s({label:v});} }),
- el(TC, { label: 'Button Text', value: a.btnText, onChange: function(v){s({btnText:v});} }),
- el(TC, { label: 'Button URL', value: a.btnUrl, onChange: function(v){s({btnUrl:v});} }),
- el(TC, { label: 'Button Subtext', value: a.btnSub, onChange: function(v){s({btnSub:v});} })
- )
+ el(TG, {
+ label: 'Use Font Awesome icon',
+ checked: useFa,
+ onChange: function (v) { s({ iconType: v ? 'fontawesome' : 'emoji' }); }
+ }),
+ useFa
+ ? el(IconPicker, { value: a.faIcon || '', onChange: function (v) { s({ faIcon: v }); } })
+ : el(TC, { label: 'Icon (emoji)', value: a.icon || '', onChange: function (v) { s({ icon: v }); } })
+ );
+ }
+
+ /**
+ * Return the element to render in the card preview for the current icon state.
+ * cssClass - the wrapper class, e.g. 'feature-icon' or 'value-icon'
+ * extraStyle - optional inline style object for the wrapper
+ */
+ function iconPreview(a, cssClass, extraStyle) {
+ var useFa = a.iconType === 'fontawesome';
+ var hasIcon = useFa ? !!a.faIcon : !!a.icon;
+ if (!hasIcon) return null;
+ var child = useFa
+ ? el('i', { className: a.faIcon || '', 'aria-hidden': 'true' })
+ : a.icon;
+ return el('div', { className: cssClass, style: extraStyle || {} }, child);
+ }
+
+ /** Build shared Card Image InspectorControls panel. */
+ function cardImageControls(a, s) {
+ var imgW = a.imgWidth || 80;
+ var imgH = a.imgHeight || 0;
+ var imgPos = a.imgPosition || 'top';
+ var imgFit = a.imgFit || 'contain';
+
+ return el(PB, { title: 'Card Image', initialOpen: false },
+ el(MUC, null,
+ el(MU, {
+ onSelect: function (media) { s({ imgId: media.id, imgUrl: media.url, imgAlt: media.alt || '' }); },
+ allowedTypes: ['image'],
+ value: a.imgId || 0,
+ render: function (ref) {
+ return el(Frag, null,
+ a.imgUrl ? el('div', { style: { marginBottom: '8px' } },
+ el('img', { src: a.imgUrl, style: { maxWidth: '100%', height: 'auto', borderRadius: '4px', display: 'block', marginBottom: '6px' } }),
+ el(Btn, { variant: 'link', isDestructive: true, onClick: function () { s({ imgId: 0, imgUrl: '', imgAlt: '' }); } }, 'Remove image')
+ ) : null,
+ el(Btn, { onClick: ref.open, variant: 'secondary', __next40pxDefaultSize: true },
+ a.imgUrl ? 'Replace image' : 'Select from Media Library')
+ );
+ }
+ })
),
- el('section', { className: 'section' },
- el('div', { className: 'container' },
- el('div', { className: 'section-header' },
- a.label ? el('span', { className: 'section-label' }, a.label) : null,
- el(RT, { tagName: 'h2', value: a.heading, onChange: function(v){s({heading:v});}, placeholder: 'Heading...' }),
- el(RT, { tagName: 'p', className: 'lead', value: a.lead, onChange: function(v){s({lead:v});}, placeholder: 'Lead text...' })
- ),
- el('div', { className: 'grid-2', style: { alignItems: 'center' } },
- el('div', { style: { display: 'flex', flexDirection: 'column', gap: '1.5rem' } },
+ a.imgUrl ? el(Frag, null,
+ el(RC, {
+ label: 'Width (px)', value: imgW, min: 20, max: 600, step: 4,
+ onChange: function (v) { s({ imgWidth: v }); }
+ }),
+ el(RC, {
+ label: 'Height (px) - 0 = auto', value: imgH, min: 0, max: 600, step: 4,
+ onChange: function (v) { s({ imgHeight: v }); }
+ }),
+ el(TG, {
+ label: 'Scale to fill (cover)', checked: imgFit === 'cover',
+ onChange: function (v) { s({ imgFit: v ? 'cover' : 'contain' }); }
+ }),
+ el(SC, {
+ label: 'Position', value: imgPos, options: [
+ { label: 'Above content', value: 'top' },
+ { label: 'Left of content', value: 'left' },
+ { label: 'Replace icon', value: 'replace-icon' },
+ { label: 'Background', value: 'background' }
+ ], onChange: function (v) { s({ imgPosition: v }); }
+ })
+ ) : null
+ );
+ }
+
+ /** Build an image preview element for the editor. */
+ function cardImagePreview(a) {
+ if (!a.imgUrl) return null;
+ var imgW = a.imgWidth || 80;
+ var imgH = a.imgHeight || 0;
+ var imgFit = a.imgFit || 'contain';
+ var style = {
+ width: imgW + 'px', maxWidth: '100%',
+ height: imgH > 0 ? imgH + 'px' : 'auto',
+ borderRadius: '4px', objectFit: imgFit, display: 'block'
+ };
+ return el('div', { className: 'oribi-card-img-wrap', style: { marginBottom: '1.25rem' } },
+ el('img', { src: a.imgUrl, className: 'oribi-card-img oribi-card-img--' + imgFit, style: style })
+ );
+ }
+
+ /** Build a shared card section edit component. */
+ function createCardSectionEdit(allowedBlocks, defaultTemplate, label) {
+ return function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Section Settings' },
+ el(SC, {
+ label: 'Background', value: a.variant, options: [
+ { label: 'Normal', value: 'normal' }, { label: 'Alternate', value: 'alt' }
+ ], onChange: function (v) { s({ variant: v }); }
+ }),
+ el(RC, { label: 'Columns', value: a.columns, min: 1, max: 4, onChange: function (v) { s({ columns: v }); } }),
+ el(TC, { label: 'Label', value: a.label, onChange: function (v) { s({ label: v }); } })
+ )
+ ),
+ el('section', { className: a.variant === 'alt' ? 'section section-alt' : 'section' },
+ el('div', { className: 'container' },
+ el('div', { className: 'section-header' },
+ a.label ? el('span', { className: 'section-label' }, a.label) : null,
+ el(RT, { tagName: 'h2', value: a.heading, onChange: function (v) { s({ heading: v }); }, placeholder: 'Section heading...' }),
+ el(RT, { tagName: 'p', className: 'lead', value: a.lead, onChange: function (v) { s({ lead: v }); }, placeholder: 'Lead text...' })
+ ),
+ el('div', { className: 'grid-' + a.columns },
el(IB, {
- allowedBlocks: ['oribi/trust-item'],
- template: [['oribi/trust-item', {}]],
+ allowedBlocks: allowedBlocks,
+ template: defaultTemplate,
templateLock: false
})
- ),
- el('div', { style: { textAlign: 'center' } },
- el('span', { className: 'btn btn-primary btn-lg' }, a.btnText || 'Button'),
- a.btnSub ? el('p', { className: 'lead mt-2', style: { fontSize: '.9rem' } }, a.btnSub) : null
)
)
)
- )
- );
- },
- save: function () { return el(IB.Content); }
-});
+ );
+ };
+ }
-/* 10. FAQ SECTION ─────────────────────────────────────────────────────── */
-reg('oribi/faq-section', {
- title: 'Oribi FAQ Section',
- icon: 'editor-help',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: {
- align: { type: 'string', default: 'full' },
+ /** Standard section attributes for JS. */
+ var SECTION_ATTRS = {
+ align: { type: 'string', default: 'full' },
variant: { type: 'string', default: 'normal' },
- label: { type: 'string', default: '' },
+ label: { type: 'string', default: '' },
heading: { type: 'string', default: '' },
- lead: { type: 'string', default: '' },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Section Settings' },
- el(SC, { label: 'Background', value: a.variant, options: [
- { label: 'Normal', value: 'normal' }, { label: 'Alternate', value: 'alt' }
- ], onChange: function(v){s({variant:v});} }),
- el(TC, { label: 'Label', value: a.label, onChange: function(v){s({label:v});} })
- )
- ),
- el('section', { className: a.variant === 'alt' ? 'section section-alt' : 'section' },
- el('div', { className: 'container' },
- el('div', { className: 'section-header' },
- a.label ? el('span', { className: 'section-label' }, a.label) : null,
- el(RT, { tagName: 'h2', value: a.heading, onChange: function(v){s({heading:v});}, placeholder: 'FAQ heading...' }),
- el(RT, { tagName: 'p', className: 'lead', value: a.lead, onChange: function(v){s({lead:v});}, placeholder: 'Lead text...' })
+ lead: { type: 'string', default: '' },
+ columns: { type: 'number', default: 3 }
+ };
+
+ /* ═══════════════════════════════════════════════════════════════════════
+ STANDALONE BLOCKS (unchanged architecture)
+ ═══════════════════════════════════════════════════════════════════════ */
+
+ /* 1. HERO ─────────────────────────────────────────────────────────────── */
+ reg('oribi/hero', {
+ title: 'Oribi Hero',
+ icon: 'cover-image',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: {
+ align: { type: 'string', default: 'full' },
+ label: { type: 'string', default: '' },
+ title: { type: 'string', default: '' },
+ highlightWord: { type: 'string', default: '' },
+ description: { type: 'string', default: '' },
+ primaryBtnText: { type: 'string', default: 'Get in Touch' },
+ primaryBtnUrl: { type: 'string', default: '/contact' },
+ secondaryBtnText: { type: 'string', default: '' },
+ secondaryBtnUrl: { type: 'string', default: '' },
+ stat1Value: { type: 'string', default: '' },
+ stat1Label: { type: 'string', default: '' },
+ stat2Value: { type: 'string', default: '' },
+ stat2Label: { type: 'string', default: '' },
+ svcLaptop1: { type: 'string', default: 'Data Backup' },
+ svcLaptop2: { type: 'string', default: 'Endpoint Security' },
+ svcLaptop3: { type: 'string', default: 'Patch Management' },
+ svcCloud1: { type: 'string', default: 'Email Protection' },
+ svcCloud2: { type: 'string', default: 'License Management' },
+ svcCloud3: { type: 'string', default: 'Cloud Backup' },
+ svcDesktop1: { type: 'string', default: 'Network Monitoring' },
+ svcDesktop2: { type: 'string', default: 'Threat Detection' },
+ svcDesktop3: { type: 'string', default: 'Cloud Management' },
+ svcPhone1: { type: 'string', default: 'Mobile Security' },
+ svcPhone2: { type: 'string', default: 'Data Encryption' },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Highlight' },
+ el(TC, { label: 'Word to highlight in title', value: a.highlightWord, onChange: function (v) { s({ highlightWord: v }); } })
),
- el('div', { className: 'faq-list' },
+ el(PB, { title: 'Primary Button' },
+ el(TC, { label: 'URL', value: a.primaryBtnUrl, onChange: function (v) { s({ primaryBtnUrl: v }); } })
+ ),
+ el(PB, { title: 'Secondary Button', initialOpen: false },
+ el(TC, { label: 'URL', value: a.secondaryBtnUrl, onChange: function (v) { s({ secondaryBtnUrl: v }); } })
+ )
+ ),
+ el('section', { className: 'hero' },
+ el('div', { className: 'container hero-inner' },
+ el('div', { className: 'hero-content' },
+ el(RT, {
+ tagName: 'span', className: 'hero-label', value: a.label,
+ onChange: function (v) { s({ label: v }); }, placeholder: '\u25CF Label text', allowedFormats: []
+ }),
+ el(RT, {
+ tagName: 'h1', className: 'hero-title', value: a.title,
+ onChange: function (v) { s({ title: v }); }, placeholder: 'Hero title...'
+ }),
+ el(RT, {
+ tagName: 'p', className: 'hero-description', value: a.description,
+ onChange: function (v) { s({ description: v }); }, placeholder: 'Description...'
+ }),
+ el('div', { className: 'btn-group' },
+ el(RT, {
+ tagName: 'span', className: 'btn btn-primary btn-lg', value: a.primaryBtnText,
+ onChange: function (v) { s({ primaryBtnText: v }); }, placeholder: 'Button', allowedFormats: []
+ }),
+ el(RT, {
+ tagName: 'span', className: 'btn btn-ghost btn-lg', value: a.secondaryBtnText,
+ onChange: function (v) { s({ secondaryBtnText: v }); }, placeholder: 'Secondary button', allowedFormats: []
+ })
+ ),
+ el('div', { className: 'hero-stats' },
+ el('div', null,
+ el(RT, {
+ tagName: 'div', className: 'hero-stat-value', value: a.stat1Value,
+ onChange: function (v) { s({ stat1Value: v }); }, placeholder: '\u2014', allowedFormats: []
+ }),
+ el(RT, {
+ tagName: 'div', className: 'hero-stat-label', value: a.stat1Label,
+ onChange: function (v) { s({ stat1Label: v }); }, placeholder: 'Stat label', allowedFormats: []
+ })
+ ),
+ el('div', null,
+ el(RT, {
+ tagName: 'div', className: 'hero-stat-value', value: a.stat2Value,
+ onChange: function (v) { s({ stat2Value: v }); }, placeholder: '\u2014', allowedFormats: []
+ }),
+ el(RT, {
+ tagName: 'div', className: 'hero-stat-label', value: a.stat2Label,
+ onChange: function (v) { s({ stat2Label: v }); }, placeholder: 'Stat label', allowedFormats: []
+ })
+ )
+ )
+ ),
+ el('div', { className: 'hero-visual' },
+ el('div', { className: 'hero-devices' },
+ el('div', { className: 'hero-device hero-device--laptop', style: { opacity: 1 } },
+ el('div', { className: 'hero-device__frame' },
+ el('div', { className: 'hero-device__screen' },
+ el('div', { className: 'hero-device__screen-content' },
+ el('div', { className: 'hero-device__app-bars' }, el('div'), el('div'), el('div'), el('div'))
+ )
+ ),
+ el('div', { className: 'hero-device__base' })
+ ),
+ el('ul', { className: 'hero-device__services' },
+ el('li', { className: 'svc', style: { opacity: 1 } }, el('span', { className: 'svc__dot' }), ' Data Backup'),
+ el('li', { className: 'svc', style: { opacity: 1 } }, el('span', { className: 'svc__dot' }), ' Endpoint Security'),
+ el('li', { className: 'svc', style: { opacity: 1 } }, el('span', { className: 'svc__dot' }), ' Patch Management')
+ )
+ ),
+ el('div', { className: 'hero-device hero-device--cloud', style: { opacity: 1 } },
+ el('div', { className: 'hero-device__frame' },
+ el('div', { className: 'hero-device__cloud-icon' },
+ el('span', { className: 'hero-device__cloud-label' }, '365')
+ )
+ ),
+ el('ul', { className: 'hero-device__services' },
+ el('li', { className: 'svc', style: { opacity: 1 } }, el('span', { className: 'svc__dot' }), ' Email Protection'),
+ el('li', { className: 'svc', style: { opacity: 1 } }, el('span', { className: 'svc__dot' }), ' License Management'),
+ el('li', { className: 'svc', style: { opacity: 1 } }, el('span', { className: 'svc__dot' }), ' Cloud Backup')
+ )
+ ),
+ el('div', { className: 'hero-device hero-device--desktop', style: { opacity: 1 } },
+ el('div', { className: 'hero-device__frame' },
+ el('div', { className: 'hero-device__screen' },
+ el('div', { className: 'hero-device__screen-content' },
+ el('div', { className: 'hero-device__dash-row' }, el('div', { className: 'hero-device__dash-card' }), el('div', { className: 'hero-device__dash-card' })),
+ el('div', { className: 'hero-device__dash-bar' }),
+ el('div', { className: 'hero-device__dash-bar hero-device__dash-bar--short' })
+ )
+ ),
+ el('div', { className: 'hero-device__stand' }),
+ el('div', { className: 'hero-device__stand-base' })
+ ),
+ el('ul', { className: 'hero-device__services' },
+ el('li', { className: 'svc', style: { opacity: 1 } }, el('span', { className: 'svc__dot' }), ' Network Monitoring'),
+ el('li', { className: 'svc', style: { opacity: 1 } }, el('span', { className: 'svc__dot' }), ' Threat Detection'),
+ el('li', { className: 'svc', style: { opacity: 1 } }, el('span', { className: 'svc__dot' }), ' Cloud Management')
+ )
+ ),
+ el('div', { className: 'hero-device hero-device--phone', style: { opacity: 1 } },
+ el('div', { className: 'hero-device__frame' },
+ el('div', { className: 'hero-device__screen' },
+ el('div', { className: 'hero-device__screen-content' },
+ el('div', { className: 'hero-device__notif' },
+ el('span', { className: 'hero-device__notif-icon' }, '\u2713'),
+ el('span', { className: 'hero-device__notif-text' }, 'Secure')
+ )
+ )
+ )
+ ),
+ el('ul', { className: 'hero-device__services' },
+ el('li', { className: 'svc', style: { opacity: 1 } }, el('span', { className: 'svc__dot' }), ' Mobile Security'),
+ el('li', { className: 'svc', style: { opacity: 1 } }, el('span', { className: 'svc__dot' }), ' Data Encryption')
+ )
+ )
+ )
+ )
+ )
+ )
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* 2. PAGE HERO ────────────────────────────────────────────────────────── */
+ reg('oribi/page-hero', {
+ title: 'Oribi Page Hero',
+ icon: 'flag',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: {
+ align: { type: 'string', default: 'full' },
+ label: { type: 'string', default: '' },
+ title: { type: 'string', default: '' },
+ description: { type: 'string', default: '' },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Settings' },
+ el(TC, { label: 'Label (optional)', value: a.label, onChange: function (v) { s({ label: v }); } })
+ )
+ ),
+ el('section', { className: 'page-hero' },
+ el('div', { className: 'container' },
+ a.label ? el('span', { className: 'hero-label' }, a.label) : null,
+ el(RT, { tagName: 'h1', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Page title...' }),
+ el(RT, { tagName: 'p', className: 'lead', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description...' })
+ )
+ )
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* 5. CTA BANNER ───────────────────────────────────────────────────────── */
+ reg('oribi/cta-banner', {
+ title: 'Oribi CTA Banner',
+ icon: 'megaphone',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: {
+ align: { type: 'string', default: 'full' },
+ heading: { type: 'string', default: '' },
+ text: { type: 'string', default: '' },
+ btnText: { type: 'string', default: '' },
+ btnUrl: { type: 'string', default: '' },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Button' },
+ el(TC, { label: 'URL', value: a.btnUrl, onChange: function (v) { s({ btnUrl: v }); } })
+ )
+ ),
+ el('section', { className: 'cta-banner' },
+ el('div', { className: 'container text-center' },
+ el(RT, { tagName: 'h2', value: a.heading, onChange: function (v) { s({ heading: v }); }, placeholder: 'CTA heading...' }),
+ el(RT, { tagName: 'p', value: a.text, onChange: function (v) { s({ text: v }); }, placeholder: 'CTA text...' }),
+ el(RT, { tagName: 'span', className: 'btn btn-primary btn-lg', style: { background: '#fff', color: 'var(--color-primary)' }, value: a.btnText, onChange: function (v) { s({ btnText: v }); }, placeholder: 'Button text...' })
+ )
+ )
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* 6. INTRO SECTION ────────────────────────────────────────────────────── */
+ reg('oribi/intro-section', {
+ title: 'Oribi Intro Section',
+ icon: 'id',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: {
+ align: { type: 'string', default: 'full' },
+ variant: { type: 'string', default: 'normal' },
+ label: { type: 'string', default: '' },
+ heading: { type: 'string', default: '' },
+ description: { type: 'string', default: '' },
+ visual: { type: 'string', default: '' },
+ reversed: { type: 'boolean', default: false },
+ cloudAnim: { type: 'boolean', default: false },
+ imgId: { type: 'number', default: 0 },
+ imgUrl: { type: 'string', default: '' },
+ imgAlt: { type: 'string', default: '' },
+ imgWidth: { type: 'number', default: 280 },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ var imgW = a.imgWidth || 280;
+
+ var animHtml = null;
+ if (a.cloudAnim) {
+ animHtml = el('div', { className: 'ds-anim-container' },
+ el('div', { className: 'ds-tv' },
+ el('i', { className: 'fas fa-tv', 'aria-hidden': 'true' }),
+ el('div', { className: 'ds-tv-screen' })
+ ),
+ el('div', { className: 'ds-line' },
+ el('div', { className: 'ds-packet ds-packet-1' }),
+ el('div', { className: 'ds-packet ds-packet-2' }),
+ el('div', { className: 'ds-packet ds-packet-3' })
+ ),
+ el('div', { className: 'ds-cloud' },
+ el('i', { className: 'fas fa-cloud', 'aria-hidden': 'true' })
+ )
+ );
+ }
+
+ var visualContent = a.cloudAnim ? animHtml : (a.imgUrl
+ ? el('img', { src: a.imgUrl, style: { width: imgW + 'px', maxWidth: '100%', height: 'auto', borderRadius: '8px', objectFit: 'contain', display: 'block' } })
+ : (a.visual || '\uD83D\uDCBB'));
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Settings' },
+ el(SC, {
+ label: 'Background', value: a.variant, options: [
+ { label: 'Normal', value: 'normal' }, { label: 'Alternate', value: 'alt' }
+ ], onChange: function (v) { s({ variant: v }); }
+ }),
+ el(TC, { label: 'Label', value: a.label, onChange: function (v) { s({ label: v }); } }),
+ el(TC, { label: 'Visual (emoji or text)', value: a.visual, onChange: function (v) { s({ visual: v }); } }),
+ el(TG, { label: 'Reversed layout', checked: a.reversed, onChange: function (v) { s({ reversed: v }); } }),
+ el(TG, { label: 'Cloud Server Animation', checked: a.cloudAnim, onChange: function (v) { s({ cloudAnim: v }); } })
+ ),
+ el(PB, { title: 'Visual Image', initialOpen: false },
+ el(MUC, null,
+ el(MU, {
+ onSelect: function (media) { s({ imgId: media.id, imgUrl: media.url, imgAlt: media.alt || '' }); },
+ allowedTypes: ['image'],
+ value: a.imgId || 0,
+ render: function (ref) {
+ return el(Frag, null,
+ a.imgUrl ? el('div', { style: { marginBottom: '8px' } },
+ el('img', { src: a.imgUrl, style: { maxWidth: '100%', height: 'auto', borderRadius: '4px', display: 'block', marginBottom: '6px' } }),
+ el(Btn, { variant: 'link', isDestructive: true, onClick: function () { s({ imgId: 0, imgUrl: '', imgAlt: '' }); } }, 'Remove image')
+ ) : null,
+ el(Btn, { onClick: ref.open, variant: 'secondary', __next40pxDefaultSize: true },
+ a.imgUrl ? 'Replace image' : 'Select from Media Library')
+ );
+ }
+ })
+ ),
+ a.imgUrl ? el(RC, {
+ label: 'Width (px)', value: imgW, min: 50, max: 420, step: 4,
+ onChange: function (v) { s({ imgWidth: v }); }
+ }) : null
+ )
+ ),
+ el('section', { className: a.variant === 'alt' ? 'section section-alt' : 'section' },
+ el('div', { className: 'container' },
+ el('div', { className: 'about-intro', style: a.reversed ? { direction: 'rtl' } : {} },
+ el('div', { style: a.reversed ? { direction: 'ltr' } : {} },
+ a.label ? el('span', { className: 'section-label' }, a.label) : null,
+ el(RT, { tagName: 'h2', style: { marginBottom: '1.5rem' }, value: a.heading, onChange: function (v) { s({ heading: v }); }, placeholder: 'Heading...' }),
+ el(RT, { tagName: 'p', className: 'lead', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description...' })
+ ),
+ el('div', { className: 'about-intro-visual' + (a.cloudAnim ? ' has-cloud-anim' : (a.imgUrl ? ' has-img' : '')), style: a.reversed ? { direction: 'ltr' } : {} }, visualContent)
+ )
+ )
+ )
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* 8. CONTACT SECTION ──────────────────────────────────────────────────── */
+ reg('oribi/contact-section', {
+ title: 'Oribi Contact',
+ icon: 'email',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: {
+ align: { type: 'string', default: 'full' },
+ heading: { type: 'string', default: "Let's Talk" },
+ lead: { type: 'string', default: '' },
+ email: { type: 'string', default: 'solutions@oribi-tech.com' },
+ supportUrl: { type: 'string', default: '' },
+ portalUrl: { type: 'string', default: '' },
+ location: { type: 'string', default: 'Saratoga Springs, Upstate New York' },
+ formHeading: { type: 'string', default: 'Want to Learn More?' },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Contact Settings' },
+ el(TC, { label: 'Email', value: a.email, onChange: function (v) { s({ email: v }); } }),
+ el(TC, { label: 'Support URL', value: a.supportUrl, onChange: function (v) { s({ supportUrl: v }); } }),
+ el(TC, { label: 'Portal URL', value: a.portalUrl, onChange: function (v) { s({ portalUrl: v }); } }),
+ el(TC, { label: 'Location', value: a.location, onChange: function (v) { s({ location: v }); } }),
+ el(TC, { label: 'Form Heading', value: a.formHeading, onChange: function (v) { s({ formHeading: v }); } })
+ )
+ ),
+ el('section', { className: 'section' },
+ el('div', { className: 'container' },
+ el('div', { className: 'contact-layout' },
+ el('div', { className: 'contact-info' },
+ el(RT, { tagName: 'h2', value: a.heading, onChange: function (v) { s({ heading: v }); }, placeholder: 'Heading...' }),
+ el(RT, { tagName: 'p', className: 'lead', value: a.lead, onChange: function (v) { s({ lead: v }); }, placeholder: 'Lead text...' }),
+ el('div', { className: 'contact-method' },
+ el('div', { className: 'contact-method-icon' }, '\uD83D\uDCE7'),
+ el('div', null, el('div', { className: 'contact-method-label' }, 'Email Us'), el('div', { className: 'contact-method-value' }, a.email))
+ ),
+ el('div', { className: 'contact-method' },
+ el('div', { className: 'contact-method-icon' }, '\uD83C\uDFAB'),
+ el('div', null, el('div', { className: 'contact-method-label' }, 'Support'), el('div', { className: 'contact-method-value' }, 'Open a Support Ticket'))
+ ),
+ el('div', { className: 'contact-method' },
+ el('div', { className: 'contact-method-icon' }, '\uD83C\uDF0E'),
+ el('div', null, el('div', { className: 'contact-method-label' }, 'Client Portal'), el('div', { className: 'contact-method-value' }, 'portal.oribi-tech.com'))
+ ),
+ el('div', { className: 'contact-method' },
+ el('div', { className: 'contact-method-icon' }, '\uD83D\uDCCD'),
+ el('div', null, el('div', { className: 'contact-method-label' }, 'Location'), el('div', { className: 'contact-method-value' }, a.location))
+ )
+ ),
+ el('div', { className: 'contact-form-wrap' },
+ el('h3', { style: { marginBottom: '1.5rem' } }, a.formHeading),
+ el('div', { style: { padding: '2rem', background: 'var(--color-bg-alt)', borderRadius: 'var(--radius-md)', textAlign: 'center', color: 'var(--color-text-muted)' } },
+ 'Contact form renders on the live site'
+ )
+ )
+ )
+ )
+ )
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* ═══════════════════════════════════════════════════════════════════════
+ CHILD BLOCKS (each renders one item inside a parent)
+ ═══════════════════════════════════════════════════════════════════════ */
+
+ /* ── Feature Card ─────────────────────────────────────────────────────── */
+ reg('oribi/feature-card', {
+ title: 'Feature Card',
+ icon: 'screenoptions',
+ category: 'oribi',
+ parent: ['oribi/feature-section'],
+ supports: { html: false, reusable: false },
+ attributes: Object.assign({}, {
+ icon: { type: 'string', default: '' },
+ iconType: { type: 'string', default: 'emoji' },
+ faIcon: { type: 'string', default: '' },
+ title: { type: 'string', default: '' },
+ description: { type: 'string', default: '' },
+ url: { type: 'string', default: '' },
+ centered: { type: 'boolean', default: false }
+ }, CARD_IMAGE_ATTRS),
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ var imgPos = a.imgPosition || 'top';
+ var imgPrev = cardImagePreview(a);
+ var centeredStyle = a.centered ? { marginInline: 'auto' } : {};
+
+ var cardPreview;
+ if (a.imgUrl && imgPos === 'left') {
+ cardPreview = el('div', { className: 'oribi-card img-left' },
+ imgPrev,
+ el('div', { className: 'oribi-card-body' },
+ el(RT, { tagName: 'h3', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Card title...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Card description...' })
+ )
+ );
+ } else if (a.imgUrl && imgPos === 'background') {
+ cardPreview = el('div', { className: 'oribi-card img-bg', style: { backgroundImage: 'url(' + a.imgUrl + ')', backgroundSize: 'cover', backgroundPosition: 'center', color: '#fff' } },
+ el('div', { className: 'oribi-card-body' },
+ iconPreview(a, 'feature-icon', centeredStyle),
+ el(RT, { tagName: 'h3', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Card title...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Card description...' })
+ )
+ );
+ } else {
+ var showIconPrev = !a.imgUrl || imgPos !== 'replace-icon';
+ cardPreview = el('div', { className: 'oribi-card' + (a.centered ? ' text-center' : '') + (a.imgUrl ? ' img-' + imgPos : '') },
+ a.imgUrl && (imgPos === 'top' || imgPos === 'replace-icon') ? imgPrev : null,
+ showIconPrev ? iconPreview(a, 'feature-icon', centeredStyle) : null,
+ el(RT, { tagName: 'h3', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Card title...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Card description...' })
+ );
+ }
+
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Card Settings' },
+ iconControls(a, s),
+ el(TC, { label: 'URL (optional)', value: a.url || '', onChange: function (v) { s({ url: v }); } }),
+ el(TG, { label: 'Centered', checked: !!a.centered, onChange: function (v) { s({ centered: v }); } })
+ ),
+ cardImageControls(a, s)
+ ),
+ cardPreview
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* ── Value Card ───────────────────────────────────────────────────────── */
+ reg('oribi/value-card', {
+ title: 'Value Card',
+ icon: 'heart',
+ category: 'oribi',
+ parent: ['oribi/value-section'],
+ supports: { html: false, reusable: false },
+ attributes: Object.assign({}, {
+ icon: { type: 'string', default: '' },
+ iconType: { type: 'string', default: 'emoji' },
+ faIcon: { type: 'string', default: '' },
+ title: { type: 'string', default: '' },
+ description: { type: 'string', default: '' }
+ }, CARD_IMAGE_ATTRS),
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ var imgPos = a.imgPosition || 'top';
+ var imgPrev = cardImagePreview(a);
+ var showIconPrev = !a.imgUrl || imgPos !== 'replace-icon';
+
+ var body;
+ if (a.imgUrl && imgPos === 'left') {
+ body = el('div', { className: 'oribi-card value-card img-left' },
+ imgPrev,
+ el('div', { className: 'oribi-card-body' },
+ el(RT, { tagName: 'h3', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Title...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description...' })
+ )
+ );
+ } else if (a.imgUrl && imgPos === 'background') {
+ body = el('div', { className: 'oribi-card value-card img-bg', style: { backgroundImage: 'url(' + a.imgUrl + ')', backgroundSize: 'cover', backgroundPosition: 'center', color: '#fff' } },
+ el('div', { className: 'oribi-card-body' },
+ showIconPrev ? iconPreview(a, 'value-icon') : null,
+ el(RT, { tagName: 'h3', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Title...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description...' })
+ )
+ );
+ } else {
+ body = el('div', { className: 'oribi-card value-card' + (a.imgUrl ? ' img-' + imgPos : '') },
+ a.imgUrl && (imgPos === 'top' || imgPos === 'replace-icon') ? imgPrev : null,
+ showIconPrev ? iconPreview(a, 'value-icon') : null,
+ el(RT, { tagName: 'h3', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Title...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description...' })
+ );
+ }
+
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Card Settings' },
+ iconControls(a, s)
+ ),
+ cardImageControls(a, s)
+ ),
+ body
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* ── Addon Card ───────────────────────────────────────────────────────── */
+ reg('oribi/addon-card', {
+ title: 'Addon Card',
+ icon: 'plus-alt2',
+ category: 'oribi',
+ parent: ['oribi/addon-section'],
+ supports: { html: false, reusable: false },
+ attributes: Object.assign({}, {
+ icon: { type: 'string', default: '' },
+ iconType: { type: 'string', default: 'emoji' },
+ faIcon: { type: 'string', default: '' },
+ title: { type: 'string', default: '' },
+ description: { type: 'string', default: '' },
+ tag: { type: 'string', default: '' }
+ }, CARD_IMAGE_ATTRS),
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ var imgPos = a.imgPosition || 'top';
+ var imgPrev = cardImagePreview(a);
+ var showIconPrev = !a.imgUrl || imgPos !== 'replace-icon';
+
+ var body;
+ if (a.imgUrl && imgPos === 'left') {
+ body = el('div', { className: 'oribi-card img-left' },
+ imgPrev,
+ el('div', { className: 'oribi-card-body' },
+ a.tag ? el('span', { className: 'addon-tag' }, a.tag) : null,
+ el(RT, { tagName: 'h3', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Title...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description...' })
+ )
+ );
+ } else if (a.imgUrl && imgPos === 'background') {
+ body = el('div', { className: 'oribi-card img-bg', style: { backgroundImage: 'url(' + a.imgUrl + ')', backgroundSize: 'cover', backgroundPosition: 'center', color: '#fff' } },
+ el('div', { className: 'oribi-card-body' },
+ showIconPrev ? iconPreview(a, 'feature-icon') : null,
+ a.tag ? el('span', { className: 'addon-tag' }, a.tag) : null,
+ el(RT, { tagName: 'h3', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Title...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description...' })
+ )
+ );
+ } else {
+ body = el('div', { className: 'oribi-card' + (a.imgUrl ? ' img-' + imgPos : '') },
+ a.imgUrl && (imgPos === 'top' || imgPos === 'replace-icon') ? imgPrev : null,
+ showIconPrev ? iconPreview(a, 'feature-icon') : null,
+ a.tag ? el('span', { className: 'addon-tag' }, a.tag) : null,
+ el(RT, { tagName: 'h3', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Title...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description...' })
+ );
+ }
+
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Card Settings' },
+ iconControls(a, s),
+ el(TC, { label: 'Tag / Badge (optional)', value: a.tag || '', onChange: function (v) { s({ tag: v }); } })
+ ),
+ cardImageControls(a, s)
+ ),
+ body
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* ── Image Card ───────────────────────────────────────────────────────── */
+ reg('oribi/image-card', {
+ title: 'Image Card',
+ icon: 'format-image',
+ category: 'oribi',
+ parent: ['oribi/image-section'],
+ supports: { html: false, reusable: false },
+ attributes: Object.assign({}, {
+ icon: { type: 'string', default: '' },
+ iconType: { type: 'string', default: 'emoji' },
+ faIcon: { type: 'string', default: '' },
+ title: { type: 'string', default: '' },
+ description: { type: 'string', default: '' },
+ url: { type: 'string', default: '' }
+ }, CARD_IMAGE_ATTRS),
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ var imgPos = a.imgPosition || 'top';
+ var imgPrev = cardImagePreview(a);
+ var showIconPrev = !a.imgUrl || imgPos !== 'replace-icon';
+
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Card Settings' },
+ iconControls(a, s),
+ el(TC, { label: 'URL (optional)', value: a.url || '', onChange: function (v) { s({ url: v }); } })
+ ),
+ cardImageControls(a, s)
+ ),
+ el('div', { className: 'oribi-card image-card' + (a.imgUrl ? ' img-' + imgPos : '') },
+ a.imgUrl && (imgPos === 'top' || imgPos === 'replace-icon') ? imgPrev : null,
+ showIconPrev ? iconPreview(a, 'feature-icon') : null,
+ el('div', { className: 'oribi-card-body' },
+ el(RT, { tagName: 'h3', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Title...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description...' })
+ )
+ )
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* ── Stat Card ────────────────────────────────────────────────────────── */
+ reg('oribi/stat-card', {
+ title: 'Stat Card',
+ icon: 'chart-bar',
+ category: 'oribi',
+ parent: ['oribi/stat-section'],
+ supports: { html: false, reusable: false },
+ attributes: Object.assign({}, {
+ icon: { type: 'string', default: '' },
+ iconType: { type: 'string', default: 'emoji' },
+ faIcon: { type: 'string', default: '' },
+ value: { type: 'string', default: '' },
+ label: { type: 'string', default: '' },
+ description: { type: 'string', default: '' }
+ }, CARD_IMAGE_ATTRS),
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ var imgPrev = cardImagePreview(a);
+ var imgPos = a.imgPosition || 'top';
+
+ var body;
+ if (a.imgUrl && imgPos === 'background') {
+ body = el('div', { className: 'oribi-card stat-card img-bg', style: { backgroundImage: 'url(' + a.imgUrl + ')', backgroundSize: 'cover', backgroundPosition: 'center', color: '#fff' } },
+ el('div', { className: 'oribi-card-body' },
+ iconPreview(a, 'feature-icon'),
+ el(RT, { tagName: 'div', className: 'stat-value', value: a.value, onChange: function (v) { s({ value: v }); }, placeholder: '99.9%' }),
+ el(RT, { tagName: 'div', className: 'stat-label', value: a.label, onChange: function (v) { s({ label: v }); }, placeholder: 'Label...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description (optional)...' })
+ )
+ );
+ } else {
+ body = el('div', { className: 'oribi-card stat-card' + (a.imgUrl ? ' img-' + imgPos : '') },
+ (a.imgUrl && imgPos !== 'replace-icon') ? imgPrev : null,
+ iconPreview(a, 'feature-icon'),
+ el(RT, { tagName: 'div', className: 'stat-value', value: a.value, onChange: function (v) { s({ value: v }); }, placeholder: '99.9%' }),
+ el(RT, { tagName: 'div', className: 'stat-label', value: a.label, onChange: function (v) { s({ label: v }); }, placeholder: 'Label...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description (optional)...' })
+ );
+ }
+
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Card Settings' },
+ iconControls(a, s)
+ ),
+ cardImageControls(a, s)
+ ),
+ body
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* ── Link Card ────────────────────────────────────────────────────────── */
+ reg('oribi/link-card', {
+ title: 'Link Card',
+ icon: 'admin-links',
+ category: 'oribi',
+ parent: ['oribi/link-section'],
+ supports: { html: false, reusable: false },
+ attributes: Object.assign({}, {
+ icon: { type: 'string', default: '' },
+ iconType: { type: 'string', default: 'emoji' },
+ faIcon: { type: 'string', default: '' },
+ title: { type: 'string', default: '' },
+ description: { type: 'string', default: '' },
+ linkText: { type: 'string', default: '' },
+ linkUrl: { type: 'string', default: '' }
+ }, CARD_IMAGE_ATTRS),
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ var imgPos = a.imgPosition || 'top';
+ var imgPrev = cardImagePreview(a);
+ var showIconPrev = !a.imgUrl || imgPos !== 'replace-icon';
+
+ var body;
+ if (a.imgUrl && imgPos === 'left') {
+ body = el('div', { className: 'oribi-card link-card img-left' },
+ imgPrev,
+ el('div', { className: 'oribi-card-body' },
+ showIconPrev ? iconPreview(a, 'feature-icon') : null,
+ el(RT, { tagName: 'h3', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Title...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description...' }),
+ el(RT, { tagName: 'span', className: 'link-card-cta', value: a.linkText, onChange: function (v) { s({ linkText: v }); }, placeholder: 'Link text → ...' })
+ )
+ );
+ } else if (a.imgUrl && imgPos === 'background') {
+ body = el('div', { className: 'oribi-card link-card img-bg', style: { backgroundImage: 'url(' + a.imgUrl + ')', backgroundSize: 'cover', backgroundPosition: 'center', color: '#fff' } },
+ el('div', { className: 'oribi-card-body' },
+ showIconPrev ? iconPreview(a, 'feature-icon') : null,
+ el(RT, { tagName: 'h3', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Title...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description...' }),
+ el(RT, { tagName: 'span', className: 'link-card-cta', value: a.linkText, onChange: function (v) { s({ linkText: v }); }, placeholder: 'Link text → ...' })
+ )
+ );
+ } else {
+ body = el('div', { className: 'oribi-card link-card' + (a.imgUrl ? ' img-' + imgPos : '') },
+ (a.imgUrl && (imgPos === 'top' || imgPos === 'replace-icon')) ? imgPrev : null,
+ showIconPrev ? iconPreview(a, 'feature-icon') : null,
+ el(RT, { tagName: 'h3', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Title...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description...' }),
+ el(RT, { tagName: 'span', className: 'link-card-cta', value: a.linkText, onChange: function (v) { s({ linkText: v }); }, placeholder: 'Link text → ...' })
+ );
+ }
+
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Card Settings' },
+ iconControls(a, s),
+ el(TC, { label: 'Link URL', value: a.linkUrl || '', onChange: function (v) { s({ linkUrl: v }); } })
+ ),
+ cardImageControls(a, s)
+ ),
+ body
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* ── Pricing Card ─────────────────────────────────────────────────────── */
+ reg('oribi/pricing-card', {
+ title: 'Pricing Card',
+ icon: 'money-alt',
+ category: 'oribi',
+ parent: ['oribi/pricing-section'],
+ supports: { html: false, reusable: false },
+ attributes: {
+ icon: { type: 'string', default: '' },
+ iconType: { type: 'string', default: 'emoji' },
+ 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' },
+ featured: { type: 'boolean', default: false },
+ badge: { type: 'string', default: '' },
+ imgId: { type: 'number', default: 0 },
+ imgUrl: { type: 'string', default: '' },
+ imgAlt: { type: 'string', default: '' },
+ imgWidth: { type: 'number', default: 80 },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ var features = a.features || [];
+ var imgW = a.imgWidth || 80;
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Card Settings' },
+ iconControls(a, s),
+ el(TC, { label: 'Button URL', value: a.btnUrl, onChange: function (v) { s({ btnUrl: v }); } }),
+ el(TG, { label: 'Featured', checked: !!a.featured, onChange: function (v) { s({ featured: v }); } }),
+ a.featured ? el(TC, { label: 'Badge Text', value: a.badge, onChange: function (v) { s({ badge: v }); } }) : null
+ ),
+ el(PB, { title: 'Card Image', initialOpen: false },
+ el(MUC, null,
+ el(MU, {
+ onSelect: function (media) { s({ imgId: media.id, imgUrl: media.url, imgAlt: media.alt || '' }); },
+ allowedTypes: ['image'],
+ value: a.imgId || 0,
+ render: function (ref) {
+ return el(Frag, null,
+ a.imgUrl ? el('div', { style: { marginBottom: '8px' } },
+ el('img', { src: a.imgUrl, style: { maxWidth: '100%', height: 'auto', borderRadius: '4px', display: 'block', marginBottom: '6px' } }),
+ el(Btn, { variant: 'link', isDestructive: true, onClick: function () { s({ imgId: 0, imgUrl: '', imgAlt: '' }); } }, 'Remove image')
+ ) : null,
+ el(Btn, { onClick: ref.open, variant: 'secondary', __next40pxDefaultSize: true },
+ a.imgUrl ? 'Replace image' : 'Select from Media Library')
+ );
+ }
+ })
+ ),
+ a.imgUrl ? el(RC, {
+ label: 'Width (px)', value: imgW, min: 20, max: 400, step: 4,
+ onChange: function (v) { s({ imgWidth: v }); }
+ }) : null
+ )
+ ),
+ el('div', { className: 'pricing-card' + (a.featured ? ' featured' : '') },
+ a.featured && a.badge ? el(RT, {
+ tagName: 'span', className: 'pricing-badge', value: a.badge,
+ onChange: function (v) { s({ badge: v }); }, placeholder: 'Badge...'
+ }) : null,
+ a.imgUrl ? el('div', { style: { textAlign: 'center', marginBottom: '1.25rem' } },
+ el('img', { src: a.imgUrl, style: { width: imgW + 'px', maxWidth: '100%', height: 'auto', borderRadius: '4px', objectFit: 'contain' } })
+ ) : null,
+ iconPreview(a, 'feature-icon', { marginInline: 'auto' }),
+ el(RT, {
+ tagName: 'div', className: 'pricing-name', value: a.name,
+ 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' } },
+ el('span', { className: 'pricing-check' }, '\u2713'),
+ el(RT, {
+ tagName: 'span', style: { flex: 1, minWidth: 0 }, value: f,
+ onChange: function (v) { s({ features: arrSet(features, fi, v) }); }, placeholder: 'Feature...'
+ }),
+ el(Btn, {
+ isSmall: true, isDestructive: true,
+ style: { minWidth: '20px', padding: 0, height: '20px', flexShrink: 0 },
+ onClick: function () { s({ features: arrRm(features, fi) }); }
+ }, '\u2715')
+ );
+ }),
+ el('li', { style: { listStyle: 'none', marginTop: '4px' } },
+ el(Btn, {
+ isSmall: true, variant: 'secondary',
+ onClick: function () { s({ features: arrAdd(features, '') }); }
+ }, '+ Feature')
+ )
+ ),
+ el(RT, {
+ tagName: 'span',
+ className: 'btn ' + (a.featured ? 'btn-primary' : 'btn-outline'),
+ style: { width: '100%', justifyContent: 'center', cursor: 'text' },
+ value: a.btnText || '',
+ onChange: function (v) { s({ btnText: v }); }, placeholder: 'Button text...'
+ })
+ )
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* ── Platform Row ─────────────────────────────────────────────────────── */
+ reg('oribi/platform-row', {
+ title: 'Platform Row',
+ icon: 'slides',
+ category: 'oribi',
+ parent: ['oribi/platform-section'],
+ supports: { html: false, reusable: false },
+ attributes: {
+ heading: { type: 'string', default: '' },
+ description: { type: 'string', default: '' },
+ btnText: { type: 'string', default: 'Learn More' },
+ btnUrl: { type: 'string', default: '' },
+ visual: { type: 'string', default: '' },
+ reversed: { type: 'boolean', default: false },
+ imgId: { type: 'number', default: 0 },
+ imgUrl: { type: 'string', default: '' },
+ imgAlt: { type: 'string', default: '' },
+ imgWidth: { type: 'number', default: 300 },
+ isDashboard: { type: 'boolean', default: false },
+ deviceAnim: { type: 'boolean', default: false },
+ tvStick: { type: 'boolean', default: false },
+ cameraAnim: { type: 'boolean', default: false },
+ neverGoesDark: { type: 'boolean', default: false },
+ brandedAnim: { type: 'boolean', default: false },
+ galleryIds: { type: 'array', default: [] },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ var imgW = a.imgWidth || 300;
+
+ /* ── Animation HTML strings (mirror PHP render, used via dangerouslySetInnerHTML) ── */
+ var DA_SCREEN = '';
+ var DA_HTML = '' +
+ '
' +
+ '
' + DA_SCREEN + '
Small Monitor' +
+ '
' + DA_SCREEN + '
Large Monitor' +
+ '
' +
+ '
' +
+ '
' + DA_SCREEN + '
' + DA_SCREEN + '
' + DA_SCREEN + '
' + DA_SCREEN + '
Video Wall' +
+ '
';
+
+ var TS_MI = '';
+ var TS_COL = '';
+ var TS_HTML = '' +
+ '
' +
+ '' +
+ '
' +
+ '
' +
+ '
' +
+ '
' +
+ '
';
+
+ var NGD_ROW = '';
+ var NGD_ROWH = '';
+ var NGD_HTML = '' +
+ '
' +
+ '
' +
+ '
' +
+ '
';
+
+ var BD_SPLASH = '';
+ var BD_HDR = '';
+ var BD_HTML = '' +
+ '
' +
+ '
' +
+ '
' +
+ '
';
+
+ var DB_HTML = ' ';
+
+ return el(Frag, null,
+ el(IC, null,
+ 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: 'Dashboard Animation', checked: !!a.isDashboard, onChange: function (v) { s({ isDashboard: v }); } }),
+ el(TG, { label: 'Device Animation', checked: !!a.deviceAnim, onChange: function (v) { s({ deviceAnim: v }); } }),
+ el(TG, { label: 'TV Stick Animation', checked: !!a.tvStick, onChange: function (v) { s({ tvStick: v }); } }),
+ el(TG, { label: 'Camera Animation', checked: !!a.cameraAnim, onChange: function (v) { s({ cameraAnim: v }); } }),
+ el(TG, { label: 'Never Goes Dark', checked: !!a.neverGoesDark, onChange: function (v) { s({ neverGoesDark: v }); } }),
+ el(TG, { label: 'Branded Display', checked: !!a.brandedAnim, onChange: function (v) { s({ brandedAnim: 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, {
+ onSelect: function (media) { s({ imgId: media.id, imgUrl: media.url, imgAlt: media.alt || '' }); },
+ allowedTypes: ['image'],
+ value: a.imgId || 0,
+ render: function (ref) {
+ return el(Frag, null,
+ a.imgUrl ? el('div', { style: { marginBottom: '8px' } },
+ el('img', { src: a.imgUrl, style: { maxWidth: '100%', height: 'auto', borderRadius: '4px', display: 'block', marginBottom: '6px' } }),
+ el(Btn, { variant: 'link', isDestructive: true, onClick: function () { s({ imgId: 0, imgUrl: '', imgAlt: '' }); } }, 'Remove image')
+ ) : null,
+ el(Btn, { onClick: ref.open, variant: 'secondary', __next40pxDefaultSize: true },
+ a.imgUrl ? 'Replace image' : 'Select from Media Library')
+ );
+ }
+ })
+ ),
+ a.imgUrl ? el(RC, {
+ label: 'Width (px)', value: imgW, min: 50, max: 600, step: 4,
+ onChange: function (v) { s({ imgWidth: v }); }
+ }) : null
+ )
+ ),
+ el('div', { className: 'platform-row' + (a.reversed ? ' reverse' : '') },
+ el('div', { className: 'platform-text' },
+ el(RT, { tagName: 'h3', value: a.heading, onChange: function (v) { s({ heading: v }); }, placeholder: 'Service name...' }),
+ el(RT, { tagName: 'p', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Service description...' }),
+ 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.isDashboard
+ ? el('div', { className: 'platform-visual has-dashboard', dangerouslySetInnerHTML: { __html: DB_HTML } })
+ : 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.deviceAnim
+ ? el('div', { className: 'platform-visual has-anim', dangerouslySetInnerHTML: { __html: DA_HTML } })
+ : a.tvStick
+ ? el('div', { className: 'platform-visual has-tv-stick', dangerouslySetInnerHTML: { __html: TS_HTML } })
+ : a.neverGoesDark
+ ? el('div', { className: 'platform-visual has-ngd', dangerouslySetInnerHTML: { __html: NGD_HTML } })
+ : a.brandedAnim
+ ? el('div', { className: 'platform-visual has-branded', dangerouslySetInnerHTML: { __html: BD_HTML } })
+ : 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' } })
+ )
+ : el('div', { className: 'platform-visual' }, a.visual || '\uD83D\uDCBB')
+ )
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* ── Trust Item ───────────────────────────────────────────────────────── */
+ reg('oribi/trust-item', {
+ title: 'Trust Item',
+ icon: 'shield',
+ category: 'oribi',
+ parent: ['oribi/trust-section'],
+ supports: { html: false, reusable: false },
+ attributes: {
+ heading: { type: 'string', default: '' },
+ description: { type: 'string', default: '' },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ return el('div', { className: 'trust-item' },
+ el(RT, {
+ tagName: 'h3', style: { marginBottom: '1rem' },
+ value: a.heading, onChange: function (v) { s({ heading: v }); }, placeholder: 'Sub-heading...'
+ }),
+ el(RT, {
+ tagName: 'p', value: a.description,
+ onChange: function (v) { s({ description: v }); }, placeholder: 'Description...'
+ })
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* ═══════════════════════════════════════════════════════════════════════
+ PARENT BLOCKS (use InnerBlocks for child items)
+ ═══════════════════════════════════════════════════════════════════════ */
+
+ /* 3. FEATURE SECTION ──────────────────────────────────────────────────── */
+ reg('oribi/feature-section', {
+ title: 'Oribi Feature Section',
+ icon: 'grid-view',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: SECTION_ATTRS,
+ edit: createCardSectionEdit(['oribi/feature-card'], [['oribi/feature-card', {}]], 'Feature Card'),
+ save: function () { return el(IB.Content); }
+ });
+
+ /* VALUE SECTION ────────────────────────────────────────────────────────── */
+ reg('oribi/value-section', {
+ title: 'Oribi Value Section',
+ icon: 'heart',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: SECTION_ATTRS,
+ edit: createCardSectionEdit(['oribi/value-card'], [['oribi/value-card', {}]], 'Value Card'),
+ save: function () { return el(IB.Content); }
+ });
+
+ /* ADDON SECTION ────────────────────────────────────────────────────────── */
+ reg('oribi/addon-section', {
+ title: 'Oribi Addon Section',
+ icon: 'plus-alt2',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: SECTION_ATTRS,
+ edit: createCardSectionEdit(['oribi/addon-card'], [['oribi/addon-card', {}]], 'Addon Card'),
+ save: function () { return el(IB.Content); }
+ });
+
+ /* IMAGE SECTION ────────────────────────────────────────────────────────── */
+ reg('oribi/image-section', {
+ title: 'Oribi Image Section',
+ icon: 'format-image',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: SECTION_ATTRS,
+ edit: createCardSectionEdit(['oribi/image-card'], [['oribi/image-card', {}]], 'Image Card'),
+ save: function () { return el(IB.Content); }
+ });
+
+ /* STAT SECTION ─────────────────────────────────────────────────────────── */
+ reg('oribi/stat-section', {
+ title: 'Oribi Stat Section',
+ icon: 'chart-bar',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: SECTION_ATTRS,
+ edit: createCardSectionEdit(['oribi/stat-card'], [['oribi/stat-card', {}]], 'Stat Card'),
+ save: function () { return el(IB.Content); }
+ });
+
+ /* LINK SECTION ─────────────────────────────────────────────────────────── */
+ reg('oribi/link-section', {
+ title: 'Oribi Link Section',
+ icon: 'admin-links',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: SECTION_ATTRS,
+ edit: createCardSectionEdit(['oribi/link-card'], [['oribi/link-card', {}]], 'Link Card'),
+ save: function () { return el(IB.Content); }
+ });
+
+ /* 4. PRICING SECTION ──────────────────────────────────────────────────── */
+ reg('oribi/pricing-section', {
+ title: 'Oribi Pricing',
+ icon: 'money-alt',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: {
+ align: { type: 'string', default: 'full' },
+ variant: { type: 'string', default: 'normal' },
+ label: { type: 'string', default: '' },
+ heading: { type: 'string', default: '' },
+ lead: { type: 'string', default: '' },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Section Settings' },
+ el(SC, {
+ label: 'Background', value: a.variant, options: [
+ { label: 'Normal', value: 'normal' }, { label: 'Alternate', value: 'alt' }
+ ], onChange: function (v) { s({ variant: v }); }
+ }),
+ el(TC, { label: 'Label', value: a.label, onChange: function (v) { s({ label: v }); } })
+ )
+ ),
+ el('section', { className: a.variant === 'alt' ? 'section section-alt' : 'section' },
+ el('div', { className: 'container' },
+ el('div', { className: 'section-header' },
+ a.label ? el('span', { className: 'section-label' }, a.label) : null,
+ el(RT, { tagName: 'h2', value: a.heading, onChange: function (v) { s({ heading: v }); }, placeholder: 'Pricing heading...' }),
+ el(RT, { tagName: 'p', className: 'lead', value: a.lead, onChange: function (v) { s({ lead: v }); }, placeholder: 'Lead text...' })
+ ),
+ el('div', { className: 'pricing-grid' },
+ el(IB, {
+ allowedBlocks: ['oribi/pricing-card'],
+ template: [
+ ['oribi/pricing-card', { name: 'Essentials' }],
+ ['oribi/pricing-card', { name: 'Pro', featured: true, badge: 'Most Popular' }],
+ ['oribi/pricing-card', { name: 'Enterprise' }]
+ ],
+ templateLock: false
+ })
+ )
+ )
+ )
+ );
+ },
+ save: function () { return el(IB.Content); }
+ });
+
+ /* 7. PLATFORM SECTION ─────────────────────────────────────────────────── */
+ reg('oribi/platform-section', {
+ title: 'Oribi Platform Section',
+ icon: 'slides',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: {
+ align: { type: 'string', default: 'full' },
+ label: { type: 'string', default: '' },
+ heading: { type: 'string', default: '' },
+ lead: { type: 'string', default: '' },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Section' },
+ el(TC, { label: 'Label', value: a.label, onChange: function (v) { s({ label: v }); } })
+ )
+ ),
+ el('section', { className: 'section' },
+ el('div', { className: 'container' },
+ el('div', { className: 'section-header' },
+ a.label ? el('span', { className: 'section-label' }, a.label) : null,
+ el(RT, { tagName: 'h2', value: a.heading, onChange: function (v) { s({ heading: v }); }, placeholder: 'Section heading...' }),
+ el(RT, { tagName: 'p', className: 'lead', value: a.lead, onChange: function (v) { s({ lead: v }); }, placeholder: 'Lead text...' })
+ ),
el(IB, {
- allowedBlocks: ['oribi/faq-item'],
- template: [['oribi/faq-item', {}]],
+ allowedBlocks: ['oribi/platform-row'],
+ template: [['oribi/platform-row', {}]],
templateLock: false
})
)
)
- )
- );
- },
- save: function () { return el(IB.Content); }
-});
+ );
+ },
+ save: function () { return el(IB.Content); }
+ });
-/* FAQ ITEM (child) ─────────────────────────────────────────────────────── */
-reg('oribi/faq-item', {
- title: 'Oribi FAQ Item',
- icon: 'editor-help',
- category: 'oribi',
- parent: ['oribi/faq-section'],
- supports: { html: false, reusable: false },
- attributes: {
- question: { type: 'string', default: '' },
- answer: { type: 'string', default: '' },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- return el('details', { className: 'faq-item', open: true },
- el('summary', { className: 'faq-question' },
- el(RT, { tagName: 'span', value: a.question,
- onChange: function(v){s({question:v});}, placeholder: 'Question...' })
- ),
- el('div', { className: 'faq-answer' },
- el(RT, { tagName: 'p', value: a.answer,
- onChange: function(v){s({answer:v});}, placeholder: 'Answer...' })
- )
- );
- },
- save: function () { return null; }
-});
-
-/* 11. COMPARISON TABLE (standalone) ───────────────────────────────────── */
-reg('oribi/comparison-table', {
- title: 'Oribi Comparison Table',
- icon: 'editor-table',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: {
- align: { type: 'string', default: 'full' },
- variant: { type: 'string', default: 'normal' },
- label: { type: 'string', default: '' },
- heading: { type: 'string', default: '' },
- lead: { type: 'string', default: '' },
- columns: { type: 'array', default: [] },
- rows: { type: 'array', default: [] },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- var cols = a.columns || [];
- var rows = a.rows || [];
-
- /* ── Column helpers ─────────────────────────────────────── */
- function updateCol(idx, val) {
- var c = cols.slice(); c[idx] = val; s({ columns: c });
- }
- function addCol() {
- var newRows = rows.map(function(r) {
- if (r.group) return r;
- return Object.assign({}, r, { values: (r.values || []).concat([false]) });
- });
- s({ columns: cols.concat(['Plan']), rows: newRows });
- }
- function removeCol(idx) {
- var c = cols.slice(); c.splice(idx, 1);
- var newRows = rows.map(function(r) {
- if (r.group) return r;
- var v = (r.values || []).slice(); v.splice(idx, 1);
- return Object.assign({}, r, { values: v });
- });
- s({ columns: c, rows: newRows });
- }
-
- /* ── Row helpers ────────────────────────────────────────── */
- function updateRow(idx, key, val) {
- var r = rows.slice();
- r[idx] = Object.assign({}, r[idx]);
- r[idx][key] = val;
- s({ rows: r });
- }
- function updateCell(ri, ci, val) {
- var r = rows.slice();
- r[ri] = Object.assign({}, r[ri]);
- var v = (r[ri].values || []).slice();
- v[ci] = val;
- r[ri].values = v;
- s({ rows: r });
- }
- function toggleCell(ri, ci) {
- var val = (rows[ri].values || [])[ci];
- updateCell(ri, ci, val === true ? false : val === false ? true : true);
- }
- function switchCellToText(ri, ci) { updateCell(ri, ci, ''); }
- function addFeatureRow() {
- var vals = cols.map(function() { return false; });
- s({ rows: rows.concat([{ feature: 'New feature', values: vals }]) });
- }
- function addGroupRow() {
- s({ rows: rows.concat([{ group: 'New Group' }]) });
- }
- function removeRow(idx) {
- var r = rows.slice(); r.splice(idx, 1); s({ rows: r });
- }
- function moveRow(idx, dir) {
- var t = idx + dir;
- if (t < 0 || t >= rows.length) return;
- var r = rows.slice();
- var tmp = r[idx]; r[idx] = r[t]; r[t] = tmp;
- s({ rows: r });
- }
-
- /* ── Inline styles for editor controls ──────────────────── */
- var inputStyle = { width: '100%', padding: '4px 6px', border: '1px solid #ddd', borderRadius: '3px', fontSize: '13px', background: 'transparent', boxSizing: 'border-box' };
- var thInputStyle = Object.assign({}, inputStyle, { fontWeight: 600, textAlign: 'center' });
- var smallBtnStyle = { background: 'none', border: 'none', cursor: 'pointer', padding: '2px 4px', fontSize: '11px', lineHeight: 1, opacity: 0.6, verticalAlign: 'middle' };
- var rowCtrlStyle = { whiteSpace: 'nowrap', width: '1%', padding: '4px', verticalAlign: 'middle', border: 'none', background: 'transparent' };
- var cellBtnStyle = { background: 'none', border: '1px solid #ddd', borderRadius: '3px', cursor: 'pointer', padding: '2px 6px', fontSize: '13px', lineHeight: '1.4', margin: '0 1px' };
-
- /* ── Render ─────────────────────────────────────────────── */
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Table Settings' },
- el(SC, { label: 'Background', value: a.variant, options: [
- { label: 'Normal', value: 'normal' }, { label: 'Alternate', value: 'alt' }
- ], onChange: function(v){s({variant:v});} }),
- el(TC, { label: 'Label', value: a.label, onChange: function(v){s({label:v});} })
+ /* 9. TRUST SECTION ────────────────────────────────────────────────────── */
+ reg('oribi/trust-section', {
+ title: 'Oribi Trust Section',
+ icon: 'shield',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: {
+ align: { type: 'string', default: 'full' },
+ label: { type: 'string', default: '' },
+ heading: { type: 'string', default: '' },
+ lead: { type: 'string', default: '' },
+ btnText: { type: 'string', default: '' },
+ btnUrl: { type: 'string', default: '' },
+ btnSub: { type: 'string', default: '' },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Settings' },
+ el(TC, { label: 'Label', value: a.label, onChange: function (v) { s({ label: v }); } }),
+ el(TC, { label: 'Button Text', value: a.btnText, onChange: function (v) { s({ btnText: v }); } }),
+ el(TC, { label: 'Button URL', value: a.btnUrl, onChange: function (v) { s({ btnUrl: v }); } }),
+ el(TC, { label: 'Button Subtext', value: a.btnSub, onChange: function (v) { s({ btnSub: v }); } })
+ )
),
- el(PB, { title: 'Columns', initialOpen: false },
- cols.map(function(col, i) {
- return el('div', { key: i, style: { display: 'flex', gap: '4px', marginBottom: '8px', alignItems: 'center' } },
- el(TC, { label: '', value: col, onChange: function(v){ updateCol(i, v); }, style: { flex: 1 } }),
- el(Btn, { isDestructive: true, isSmall: true, onClick: function(){ removeCol(i); } }, '\u2715')
- );
- }),
- el(Btn, { isSecondary: true, isSmall: true, onClick: addCol }, '+ Add Column')
- ),
- el(PB, { title: 'Add Rows', initialOpen: false },
- el('div', { style: { display: 'flex', gap: '8px' } },
- el(Btn, { isSecondary: true, isSmall: true, onClick: addFeatureRow }, '+ Feature Row'),
- el(Btn, { isSecondary: true, isSmall: true, onClick: addGroupRow }, '+ Group Row')
+ el('section', { className: 'section' },
+ el('div', { className: 'container' },
+ el('div', { className: 'section-header' },
+ a.label ? el('span', { className: 'section-label' }, a.label) : null,
+ el(RT, { tagName: 'h2', value: a.heading, onChange: function (v) { s({ heading: v }); }, placeholder: 'Heading...' }),
+ el(RT, { tagName: 'p', className: 'lead', value: a.lead, onChange: function (v) { s({ lead: v }); }, placeholder: 'Lead text...' })
+ ),
+ el('div', { className: 'grid-2', style: { alignItems: 'center' } },
+ el('div', { style: { display: 'flex', flexDirection: 'column', gap: '1.5rem' } },
+ el(IB, {
+ allowedBlocks: ['oribi/trust-item'],
+ template: [['oribi/trust-item', {}]],
+ templateLock: false
+ })
+ ),
+ el('div', { style: { textAlign: 'center' } },
+ el('span', { className: 'btn btn-primary btn-lg' }, a.btnText || 'Button'),
+ a.btnSub ? el('p', { className: 'lead mt-2', style: { fontSize: '.9rem' } }, a.btnSub) : null
+ )
+ )
)
)
- ),
- el('section', { className: a.variant === 'alt' ? 'section section-alt' : 'section' },
- el('div', { className: 'container' },
- el('div', { className: 'section-header' },
- a.label ? el('span', { className: 'section-label' }, a.label) : null,
- el(RT, { tagName: 'h2', value: a.heading, onChange: function(v){s({heading:v});}, placeholder: 'Table heading...' }),
- el(RT, { tagName: 'p', className: 'lead', value: a.lead, onChange: function(v){s({lead:v});}, placeholder: 'Lead text...' })
+ );
+ },
+ save: function () { return el(IB.Content); }
+ });
+
+ /* 10. FAQ SECTION ─────────────────────────────────────────────────────── */
+ reg('oribi/faq-section', {
+ title: 'Oribi FAQ Section',
+ icon: 'editor-help',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: {
+ align: { type: 'string', default: 'full' },
+ variant: { type: 'string', default: 'normal' },
+ label: { type: 'string', default: '' },
+ heading: { type: 'string', default: '' },
+ lead: { type: 'string', default: '' },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Section Settings' },
+ el(SC, {
+ label: 'Background', value: a.variant, options: [
+ { label: 'Normal', value: 'normal' }, { label: 'Alternate', value: 'alt' }
+ ], onChange: function (v) { s({ variant: v }); }
+ }),
+ el(TC, { label: 'Label', value: a.label, onChange: function (v) { s({ label: v }); } })
+ )
+ ),
+ el('section', { className: a.variant === 'alt' ? 'section section-alt' : 'section' },
+ el('div', { className: 'container' },
+ el('div', { className: 'section-header' },
+ a.label ? el('span', { className: 'section-label' }, a.label) : null,
+ el(RT, { tagName: 'h2', value: a.heading, onChange: function (v) { s({ heading: v }); }, placeholder: 'FAQ heading...' }),
+ el(RT, { tagName: 'p', className: 'lead', value: a.lead, onChange: function (v) { s({ lead: v }); }, placeholder: 'Lead text...' })
+ ),
+ el('div', { className: 'faq-list' },
+ el(IB, {
+ allowedBlocks: ['oribi/faq-item'],
+ template: [['oribi/faq-item', {}]],
+ templateLock: false
+ })
+ )
+ )
+ )
+ );
+ },
+ save: function () { return el(IB.Content); }
+ });
+
+ /* FAQ ITEM (child) ─────────────────────────────────────────────────────── */
+ reg('oribi/faq-item', {
+ title: 'Oribi FAQ Item',
+ icon: 'editor-help',
+ category: 'oribi',
+ parent: ['oribi/faq-section'],
+ supports: { html: false, reusable: false },
+ attributes: {
+ question: { type: 'string', default: '' },
+ answer: { type: 'string', default: '' },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ return el('details', { className: 'faq-item', open: true },
+ el('summary', { className: 'faq-question' },
+ el(RT, {
+ tagName: 'span', value: a.question,
+ onChange: function (v) { s({ question: v }); }, placeholder: 'Question...'
+ })
+ ),
+ el('div', { className: 'faq-answer' },
+ el(RT, {
+ tagName: 'p', value: a.answer,
+ onChange: function (v) { s({ answer: v }); }, placeholder: 'Answer...'
+ })
+ )
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* 11. COMPARISON TABLE (standalone) ───────────────────────────────────── */
+ reg('oribi/comparison-table', {
+ title: 'Oribi Comparison Table',
+ icon: 'editor-table',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: {
+ align: { type: 'string', default: 'full' },
+ variant: { type: 'string', default: 'normal' },
+ label: { type: 'string', default: '' },
+ heading: { type: 'string', default: '' },
+ lead: { type: 'string', default: '' },
+ columns: { type: 'array', default: [] },
+ rows: { type: 'array', default: [] },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ var cols = a.columns || [];
+ var rows = a.rows || [];
+
+ /* ── Column helpers ─────────────────────────────────────── */
+ function updateCol(idx, val) {
+ var c = cols.slice(); c[idx] = val; s({ columns: c });
+ }
+ function addCol() {
+ var newRows = rows.map(function (r) {
+ if (r.group) return r;
+ return Object.assign({}, r, { values: (r.values || []).concat([false]) });
+ });
+ s({ columns: cols.concat(['Plan']), rows: newRows });
+ }
+ function removeCol(idx) {
+ var c = cols.slice(); c.splice(idx, 1);
+ var newRows = rows.map(function (r) {
+ if (r.group) return r;
+ var v = (r.values || []).slice(); v.splice(idx, 1);
+ return Object.assign({}, r, { values: v });
+ });
+ s({ columns: c, rows: newRows });
+ }
+
+ /* ── Row helpers ────────────────────────────────────────── */
+ function updateRow(idx, key, val) {
+ var r = rows.slice();
+ r[idx] = Object.assign({}, r[idx]);
+ r[idx][key] = val;
+ s({ rows: r });
+ }
+ function updateCell(ri, ci, val) {
+ var r = rows.slice();
+ r[ri] = Object.assign({}, r[ri]);
+ var v = (r[ri].values || []).slice();
+ v[ci] = val;
+ r[ri].values = v;
+ s({ rows: r });
+ }
+ function toggleCell(ri, ci) {
+ var val = (rows[ri].values || [])[ci];
+ updateCell(ri, ci, val === true ? false : val === false ? true : true);
+ }
+ function switchCellToText(ri, ci) { updateCell(ri, ci, ''); }
+ function addFeatureRow() {
+ var vals = cols.map(function () { return false; });
+ s({ rows: rows.concat([{ feature: 'New feature', values: vals }]) });
+ }
+ function addGroupRow() {
+ s({ rows: rows.concat([{ group: 'New Group' }]) });
+ }
+ function removeRow(idx) {
+ var r = rows.slice(); r.splice(idx, 1); s({ rows: r });
+ }
+ function moveRow(idx, dir) {
+ var t = idx + dir;
+ if (t < 0 || t >= rows.length) return;
+ var r = rows.slice();
+ var tmp = r[idx]; r[idx] = r[t]; r[t] = tmp;
+ s({ rows: r });
+ }
+
+ /* ── Inline styles for editor controls ──────────────────── */
+ var inputStyle = { width: '100%', padding: '4px 6px', border: '1px solid #ddd', borderRadius: '3px', fontSize: '13px', background: 'transparent', boxSizing: 'border-box' };
+ var thInputStyle = Object.assign({}, inputStyle, { fontWeight: 600, textAlign: 'center' });
+ var smallBtnStyle = { background: 'none', border: 'none', cursor: 'pointer', padding: '2px 4px', fontSize: '11px', lineHeight: 1, opacity: 0.6, verticalAlign: 'middle' };
+ var rowCtrlStyle = { whiteSpace: 'nowrap', width: '1%', padding: '4px', verticalAlign: 'middle', border: 'none', background: 'transparent' };
+ var cellBtnStyle = { background: 'none', border: '1px solid #ddd', borderRadius: '3px', cursor: 'pointer', padding: '2px 6px', fontSize: '13px', lineHeight: '1.4', margin: '0 1px' };
+
+ /* ── Render ─────────────────────────────────────────────── */
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Table Settings' },
+ el(SC, {
+ label: 'Background', value: a.variant, options: [
+ { label: 'Normal', value: 'normal' }, { label: 'Alternate', value: 'alt' }
+ ], onChange: function (v) { s({ variant: v }); }
+ }),
+ el(TC, { label: 'Label', value: a.label, onChange: function (v) { s({ label: v }); } })
),
- el('div', { className: 'comparison-table-wrap' },
- el('table', { className: 'comparison-table' },
- el('thead', null,
- el('tr', null,
- el('th', { className: 'comparison-feature-col' }, 'Feature'),
- cols.map(function(col, i) {
- return el('th', { key: i },
- el('input', { type: 'text', value: col, style: thInputStyle, onChange: function(e){ updateCol(i, e.target.value); } })
- );
- }),
- el('th', { style: rowCtrlStyle })
- )
- ),
- el('tbody', null,
- rows.map(function(row, ri) {
- if (row.group) {
- return el('tr', { key: ri, className: 'comparison-group-row' },
- el('td', { colSpan: cols.length + 1 },
- el('input', { type: 'text', value: row.group, style: Object.assign({}, inputStyle, { fontWeight: 700 }), onChange: function(e){ updateRow(ri, 'group', e.target.value); } })
- ),
- el('td', { style: rowCtrlStyle },
- el('button', { style: smallBtnStyle, onClick: function(){ moveRow(ri, -1); }, title: 'Move up' }, '\u25B2'),
- el('button', { style: smallBtnStyle, onClick: function(){ moveRow(ri, 1); }, title: 'Move down' }, '\u25BC'),
- el('button', { style: Object.assign({}, smallBtnStyle, { color: '#b00' }), onClick: function(){ removeRow(ri); }, title: 'Remove row' }, '\u2715')
- )
- );
- }
- return el('tr', { key: ri },
- el('td', { className: 'comparison-feature-name' },
- el('input', { type: 'text', value: row.feature || '', style: inputStyle, placeholder: 'Feature name\u2026', onChange: function(e){ updateRow(ri, 'feature', e.target.value); } })
- ),
- (row.values || []).map(function(val, ci) {
- if (typeof val === 'boolean') {
- return el('td', { key: ci, className: 'comparison-cell', style: { textAlign: 'center' } },
- el('button', { style: Object.assign({}, cellBtnStyle, { color: val ? '#2e7d32' : '#c62828' }), onClick: function(){ toggleCell(ri, ci); }, title: 'Toggle \u2713/\u2717' },
- val ? '\u2713' : '\u2717'
- ),
- el('button', { style: Object.assign({}, smallBtnStyle, { fontSize: '10px' }), onClick: function(){ switchCellToText(ri, ci); }, title: 'Switch to text' }, 'Aa')
- );
- }
- return el('td', { key: ci, className: 'comparison-cell' },
- el('div', { style: { display: 'flex', alignItems: 'center', gap: '2px' } },
- el('input', { type: 'text', value: String(val), style: Object.assign({}, inputStyle, { flex: 1, minWidth: '60px' }), placeholder: 'Value\u2026', onChange: function(e){ updateCell(ri, ci, e.target.value); } }),
- el('button', { style: Object.assign({}, smallBtnStyle, { color: '#2e7d32' }), onClick: function(){ updateCell(ri, ci, true); }, title: 'Set as \u2713' }, '\u2713'),
- el('button', { style: Object.assign({}, smallBtnStyle, { color: '#c62828' }), onClick: function(){ updateCell(ri, ci, false); }, title: 'Set as \u2717' }, '\u2717')
- )
+ el(PB, { title: 'Columns', initialOpen: false },
+ cols.map(function (col, i) {
+ return el('div', { key: i, style: { display: 'flex', gap: '4px', marginBottom: '8px', alignItems: 'center' } },
+ el(TC, { label: '', value: col, onChange: function (v) { updateCol(i, v); }, style: { flex: 1 } }),
+ el(Btn, { isDestructive: true, isSmall: true, onClick: function () { removeCol(i); } }, '\u2715')
+ );
+ }),
+ el(Btn, { isSecondary: true, isSmall: true, onClick: addCol }, '+ Add Column')
+ ),
+ el(PB, { title: 'Add Rows', initialOpen: false },
+ el('div', { style: { display: 'flex', gap: '8px' } },
+ el(Btn, { isSecondary: true, isSmall: true, onClick: addFeatureRow }, '+ Feature Row'),
+ el(Btn, { isSecondary: true, isSmall: true, onClick: addGroupRow }, '+ Group Row')
+ )
+ )
+ ),
+ el('section', { className: a.variant === 'alt' ? 'section section-alt' : 'section' },
+ el('div', { className: 'container' },
+ el('div', { className: 'section-header' },
+ a.label ? el('span', { className: 'section-label' }, a.label) : null,
+ el(RT, { tagName: 'h2', value: a.heading, onChange: function (v) { s({ heading: v }); }, placeholder: 'Table heading...' }),
+ el(RT, { tagName: 'p', className: 'lead', value: a.lead, onChange: function (v) { s({ lead: v }); }, placeholder: 'Lead text...' })
+ ),
+ el('div', { className: 'comparison-table-wrap' },
+ el('table', { className: 'comparison-table' },
+ el('thead', null,
+ el('tr', null,
+ el('th', { className: 'comparison-feature-col' }, 'Feature'),
+ cols.map(function (col, i) {
+ return el('th', { key: i },
+ el('input', { type: 'text', value: col, style: thInputStyle, onChange: function (e) { updateCol(i, e.target.value); } })
);
}),
- el('td', { style: rowCtrlStyle },
- el('button', { style: smallBtnStyle, onClick: function(){ moveRow(ri, -1); }, title: 'Move up' }, '\u25B2'),
- el('button', { style: smallBtnStyle, onClick: function(){ moveRow(ri, 1); }, title: 'Move down' }, '\u25BC'),
- el('button', { style: Object.assign({}, smallBtnStyle, { color: '#b00' }), onClick: function(){ removeRow(ri); }, title: 'Remove row' }, '\u2715')
- )
- );
+ el('th', { style: rowCtrlStyle })
+ )
+ ),
+ el('tbody', null,
+ rows.map(function (row, ri) {
+ if (row.group) {
+ return el('tr', { key: ri, className: 'comparison-group-row' },
+ el('td', { colSpan: cols.length + 1 },
+ el('input', { type: 'text', value: row.group, style: Object.assign({}, inputStyle, { fontWeight: 700 }), onChange: function (e) { updateRow(ri, 'group', e.target.value); } })
+ ),
+ el('td', { style: rowCtrlStyle },
+ el('button', { style: smallBtnStyle, onClick: function () { moveRow(ri, -1); }, title: 'Move up' }, '\u25B2'),
+ el('button', { style: smallBtnStyle, onClick: function () { moveRow(ri, 1); }, title: 'Move down' }, '\u25BC'),
+ el('button', { style: Object.assign({}, smallBtnStyle, { color: '#b00' }), onClick: function () { removeRow(ri); }, title: 'Remove row' }, '\u2715')
+ )
+ );
+ }
+ return el('tr', { key: ri },
+ el('td', { className: 'comparison-feature-name' },
+ el('input', { type: 'text', value: row.feature || '', style: inputStyle, placeholder: 'Feature name\u2026', onChange: function (e) { updateRow(ri, 'feature', e.target.value); } })
+ ),
+ (row.values || []).map(function (val, ci) {
+ if (typeof val === 'boolean') {
+ return el('td', { key: ci, className: 'comparison-cell', style: { textAlign: 'center' } },
+ el('button', { style: Object.assign({}, cellBtnStyle, { color: val ? '#2e7d32' : '#c62828' }), onClick: function () { toggleCell(ri, ci); }, title: 'Toggle \u2713/\u2717' },
+ val ? '\u2713' : '\u2717'
+ ),
+ el('button', { style: Object.assign({}, smallBtnStyle, { fontSize: '10px' }), onClick: function () { switchCellToText(ri, ci); }, title: 'Switch to text' }, 'Aa')
+ );
+ }
+ return el('td', { key: ci, className: 'comparison-cell' },
+ el('div', { style: { display: 'flex', alignItems: 'center', gap: '2px' } },
+ el('input', { type: 'text', value: String(val), style: Object.assign({}, inputStyle, { flex: 1, minWidth: '60px' }), placeholder: 'Value\u2026', onChange: function (e) { updateCell(ri, ci, e.target.value); } }),
+ el('button', { style: Object.assign({}, smallBtnStyle, { color: '#2e7d32' }), onClick: function () { updateCell(ri, ci, true); }, title: 'Set as \u2713' }, '\u2713'),
+ el('button', { style: Object.assign({}, smallBtnStyle, { color: '#c62828' }), onClick: function () { updateCell(ri, ci, false); }, title: 'Set as \u2717' }, '\u2717')
+ )
+ );
+ }),
+ el('td', { style: rowCtrlStyle },
+ el('button', { style: smallBtnStyle, onClick: function () { moveRow(ri, -1); }, title: 'Move up' }, '\u25B2'),
+ el('button', { style: smallBtnStyle, onClick: function () { moveRow(ri, 1); }, title: 'Move down' }, '\u25BC'),
+ el('button', { style: Object.assign({}, smallBtnStyle, { color: '#b00' }), onClick: function () { removeRow(ri); }, title: 'Remove row' }, '\u2715')
+ )
+ );
+ })
+ )
+ ),
+ el('div', { style: { display: 'flex', gap: '8px', marginTop: '12px', justifyContent: 'center' } },
+ el(Btn, { isSecondary: true, isSmall: true, onClick: addFeatureRow }, '+ Feature Row'),
+ el(Btn, { isSecondary: true, isSmall: true, onClick: addGroupRow }, '+ Group Row'),
+ el(Btn, { isSecondary: true, isSmall: true, onClick: addCol }, '+ Column')
+ )
+ )
+ )
+ )
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* ═══════════════════════════════════════════════════════════════════════
+ TEMPLATE-PART HELPER BLOCKS
+ ═══════════════════════════════════════════════════════════════════════ */
+
+ /* ═══════════════════════════════════════════════════════════════════════
+ ANIMATED HERO BLOCKS (OTS Signs)
+ ═══════════════════════════════════════════════════════════════════════ */
+
+ /* ANIMATED HERO ───────────────────────────────────────────────────────── */
+ reg('oribi/hero-animated', {
+ title: 'Animated Hero',
+ icon: 'admin-site-alt3',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: {
+ align: { type: 'string', default: 'full' },
+ label: { type: 'string', default: '' },
+ title: { type: 'string', default: '' },
+ highlightWord: { type: 'string', default: '' },
+ description: { type: 'string', default: '' },
+ primaryBtnText: { type: 'string', default: 'Get Started' },
+ primaryBtnUrl: { type: 'string', default: '/contact' },
+ secondaryBtnText: { type: 'string', default: '' },
+ secondaryBtnUrl: { type: 'string', default: '' },
+ stat1Value: { type: 'string', default: '' },
+ stat1Label: { type: 'string', default: '' },
+ stat2Value: { type: 'string', default: '' },
+ stat2Label: { type: 'string', default: '' },
+ stat3Value: { type: 'string', default: '' },
+ stat3Label: { type: 'string', default: '' },
+ },
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ // Build particle elements for editor preview
+ var particles = [];
+ for (var i = 1; i <= 12; i++) {
+ particles.push(el('div', { key: 'p' + i, className: 'hero-particle hero-particle--' + i }));
+ }
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Highlight' },
+ el(TC, { label: 'Word to highlight in title', value: a.highlightWord, onChange: function (v) { s({ highlightWord: v }); } })
+ ),
+ el(PB, { title: 'Primary Button' },
+ el(TC, { label: 'URL', value: a.primaryBtnUrl, onChange: function (v) { s({ primaryBtnUrl: v }); } })
+ ),
+ el(PB, { title: 'Secondary Button', initialOpen: false },
+ el(TC, { label: 'URL', value: a.secondaryBtnUrl, onChange: function (v) { s({ secondaryBtnUrl: v }); } })
+ )
+ ),
+ el('section', { className: 'hero hero-animated' },
+ el('div', { className: 'hero-particles', 'aria-hidden': 'true' }, particles),
+ el('div', { className: 'hero-animated__glow' }),
+ el('div', { className: 'container hero-animated__inner' },
+ el('div', { className: 'hero-animated__content' },
+ el(RT, {
+ tagName: 'span', className: 'hero-label', value: a.label,
+ onChange: function (v) { s({ label: v }); }, placeholder: '\u25CF Label text', allowedFormats: []
+ }),
+ el(RT, {
+ tagName: 'h1', className: 'hero-title', value: a.title,
+ onChange: function (v) { s({ title: v }); }, placeholder: 'Hero title...'
+ }),
+ el(RT, {
+ tagName: 'p', className: 'hero-description', value: a.description,
+ onChange: function (v) { s({ description: v }); }, placeholder: 'Description...'
+ }),
+ el('div', { className: 'btn-group' },
+ el(RT, {
+ tagName: 'span', className: 'btn btn-primary btn-lg', value: a.primaryBtnText,
+ onChange: function (v) { s({ primaryBtnText: v }); }, placeholder: 'Button', allowedFormats: []
+ }),
+ el(RT, {
+ tagName: 'span', className: 'btn btn-ghost btn-lg', value: a.secondaryBtnText,
+ onChange: function (v) { s({ secondaryBtnText: v }); }, placeholder: 'Secondary button', allowedFormats: []
})
- )
- ),
- el('div', { style: { display: 'flex', gap: '8px', marginTop: '12px', justifyContent: 'center' } },
- el(Btn, { isSecondary: true, isSmall: true, onClick: addFeatureRow }, '+ Feature Row'),
- el(Btn, { isSecondary: true, isSmall: true, onClick: addGroupRow }, '+ Group Row'),
- el(Btn, { isSecondary: true, isSmall: true, onClick: addCol }, '+ Column')
- )
- )
- )
- )
- );
- },
- save: function () { return null; }
-});
-
-/* ═══════════════════════════════════════════════════════════════════════
- TEMPLATE-PART HELPER BLOCKS
- ═══════════════════════════════════════════════════════════════════════ */
-
-/* ═══════════════════════════════════════════════════════════════════════
- ANIMATED HERO BLOCKS (OTS Signs)
- ═══════════════════════════════════════════════════════════════════════ */
-
-/* ANIMATED HERO ───────────────────────────────────────────────────────── */
-reg('oribi/hero-animated', {
- title: 'Animated Hero',
- icon: 'admin-site-alt3',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: {
- align: { type: 'string', default: 'full' },
- label: { type: 'string', default: '' },
- title: { type: 'string', default: '' },
- highlightWord: { type: 'string', default: '' },
- description: { type: 'string', default: '' },
- primaryBtnText: { type: 'string', default: 'Get Started' },
- primaryBtnUrl: { type: 'string', default: '/contact' },
- secondaryBtnText: { type: 'string', default: '' },
- secondaryBtnUrl: { type: 'string', default: '' },
- stat1Value: { type: 'string', default: '' },
- stat1Label: { type: 'string', default: '' },
- stat2Value: { type: 'string', default: '' },
- stat2Label: { type: 'string', default: '' },
- stat3Value: { type: 'string', default: '' },
- stat3Label: { type: 'string', default: '' },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- // Build particle elements for editor preview
- var particles = [];
- for (var i = 1; i <= 12; i++) {
- particles.push(el('div', { key: 'p' + i, className: 'hero-particle hero-particle--' + i }));
- }
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Highlight' },
- el(TC, { label: 'Word to highlight in title', value: a.highlightWord, onChange: function(v){s({highlightWord:v});} })
- ),
- el(PB, { title: 'Primary Button' },
- el(TC, { label: 'URL', value: a.primaryBtnUrl, onChange: function(v){s({primaryBtnUrl:v});} })
- ),
- el(PB, { title: 'Secondary Button', initialOpen: false },
- el(TC, { label: 'URL', value: a.secondaryBtnUrl, onChange: function(v){s({secondaryBtnUrl:v});} })
- )
- ),
- el('section', { className: 'hero hero-animated' },
- el('div', { className: 'hero-particles', 'aria-hidden': 'true' }, particles),
- el('div', { className: 'hero-animated__glow' }),
- el('div', { className: 'container hero-animated__inner' },
- el('div', { className: 'hero-animated__content' },
- el(RT, { tagName: 'span', className: 'hero-label', value: a.label,
- onChange: function(v){s({label:v});}, placeholder: '\u25CF Label text', allowedFormats: [] }),
- el(RT, { tagName: 'h1', className: 'hero-title', value: a.title,
- onChange: function(v){s({title:v});}, placeholder: 'Hero title...' }),
- el(RT, { tagName: 'p', className: 'hero-description', value: a.description,
- onChange: function(v){s({description:v});}, placeholder: 'Description...' }),
- el('div', { className: 'btn-group' },
- el(RT, { tagName: 'span', className: 'btn btn-primary btn-lg', value: a.primaryBtnText,
- onChange: function(v){s({primaryBtnText:v});}, placeholder: 'Button', allowedFormats: [] }),
- el(RT, { tagName: 'span', className: 'btn btn-ghost btn-lg', value: a.secondaryBtnText,
- onChange: function(v){s({secondaryBtnText:v});}, placeholder: 'Secondary button', allowedFormats: [] })
- ),
- el('div', { className: 'hero-stats hero-stats--three' },
- el('div', null,
- el(RT, { tagName: 'div', className: 'hero-stat-value', value: a.stat1Value,
- onChange: function(v){s({stat1Value:v});}, placeholder: '\u2014', allowedFormats: [] }),
- el(RT, { tagName: 'div', className: 'hero-stat-label', value: a.stat1Label,
- onChange: function(v){s({stat1Label:v});}, placeholder: 'Stat label', allowedFormats: [] })
),
- el('div', null,
- el(RT, { tagName: 'div', className: 'hero-stat-value', value: a.stat2Value,
- onChange: function(v){s({stat2Value:v});}, placeholder: '\u2014', allowedFormats: [] }),
- el(RT, { tagName: 'div', className: 'hero-stat-label', value: a.stat2Label,
- onChange: function(v){s({stat2Label:v});}, placeholder: 'Stat label', allowedFormats: [] })
- ),
- el('div', null,
- el(RT, { tagName: 'div', className: 'hero-stat-value', value: a.stat3Value,
- onChange: function(v){s({stat3Value:v});}, placeholder: '\u2014', allowedFormats: [] }),
- el(RT, { tagName: 'div', className: 'hero-stat-label', value: a.stat3Label,
- onChange: function(v){s({stat3Label:v});}, placeholder: 'Stat label', allowedFormats: [] })
+ el('div', { className: 'hero-stats hero-stats--three' },
+ el('div', null,
+ el(RT, {
+ tagName: 'div', className: 'hero-stat-value', value: a.stat1Value,
+ onChange: function (v) { s({ stat1Value: v }); }, placeholder: '\u2014', allowedFormats: []
+ }),
+ el(RT, {
+ tagName: 'div', className: 'hero-stat-label', value: a.stat1Label,
+ onChange: function (v) { s({ stat1Label: v }); }, placeholder: 'Stat label', allowedFormats: []
+ })
+ ),
+ el('div', null,
+ el(RT, {
+ tagName: 'div', className: 'hero-stat-value', value: a.stat2Value,
+ onChange: function (v) { s({ stat2Value: v }); }, placeholder: '\u2014', allowedFormats: []
+ }),
+ el(RT, {
+ tagName: 'div', className: 'hero-stat-label', value: a.stat2Label,
+ onChange: function (v) { s({ stat2Label: v }); }, placeholder: 'Stat label', allowedFormats: []
+ })
+ ),
+ el('div', null,
+ el(RT, {
+ tagName: 'div', className: 'hero-stat-value', value: a.stat3Value,
+ onChange: function (v) { s({ stat3Value: v }); }, placeholder: '\u2014', allowedFormats: []
+ }),
+ el(RT, {
+ tagName: 'div', className: 'hero-stat-label', value: a.stat3Label,
+ onChange: function (v) { s({ stat3Label: v }); }, placeholder: 'Stat label', allowedFormats: []
+ })
+ )
)
)
)
)
- )
- );
- },
- save: function () { return null; }
-});
-
-/* ANIMATED PAGE HERO ──────────────────────────────────────────────────── */
-reg('oribi/page-hero-animated', {
- title: 'Animated Page Hero',
- icon: 'flag',
- category: 'oribi',
- supports: { align: ['full'], html: false },
- attributes: {
- align: { type: 'string', default: 'full' },
- label: { type: 'string', default: '' },
- title: { type: 'string', default: '' },
- description: { type: 'string', default: '' },
- },
- edit: function (props) {
- var a = props.attributes, s = props.setAttributes;
- var particles = [];
- for (var i = 1; i <= 8; i++) {
- particles.push(el('div', { key: 'p' + i, className: 'hero-particle hero-particle--' + i }));
- }
- return el(Frag, null,
- el(IC, null,
- el(PB, { title: 'Settings' },
- el(TC, { label: 'Label (optional)', value: a.label, onChange: function(v){s({label:v});} })
- )
- ),
- el('section', { className: 'page-hero page-hero-animated' },
- el('div', { className: 'hero-particles', 'aria-hidden': 'true' }, particles),
- el('div', { className: 'hero-animated__glow' }),
- el('div', { className: 'hero-overlay' }),
- el('div', { className: 'container' },
- a.label ? el('span', { className: 'hero-label' }, a.label) : null,
- el(RT, { tagName: 'h1', value: a.title, onChange: function(v){s({title:v});}, placeholder: 'Page title...' }),
- el(RT, { tagName: 'p', className: 'lead', value: a.description, onChange: function(v){s({description:v});}, placeholder: 'Description...' })
- )
- )
- );
- },
- save: function () { return null; }
-});
-
-/* ═══════════════════════════════════════════════════════════════════════
- TEMPLATE-PART HELPER BLOCKS
- ═══════════════════════════════════════════════════════════════════════ */
-
-reg('oribi/site-header', {
- title: 'Oribi Site Header',
- icon: 'admin-home',
- category: 'oribi',
- supports: { html: false, multiple: false, reusable: false },
- edit: function () {
- return el('div', {
- style: { background: '#111111', color: '#fff', padding: '20px 24px', borderRadius: '8px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }
+ );
},
- el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } },
- el('strong', { style: { fontSize: '1.2rem' } }, 'Oribi'),
- el('span', { style: { fontSize: '1.2rem', fontWeight: 300 } }, 'Tech')
- ),
- el('div', { style: { display: 'flex', gap: '1.5rem', fontSize: '.9rem', opacity: 0.7 } },
- el('span', null, 'Services'),
- el('span', null, 'About'),
- el('span', null, 'FAQ'),
- el('span', null, 'Contact')
- )
- );
- },
- save: function () { return null; }
-});
+ save: function () { return null; }
+ });
-reg('oribi/site-footer', {
- title: 'Oribi Site Footer',
- icon: 'admin-home',
- category: 'oribi',
- supports: { html: false, multiple: false, reusable: false },
- edit: function () {
- return el('div', {
- style: { background: '#111111', color: '#fff', padding: '24px', borderRadius: '8px', textAlign: 'center' }
+ /* ANIMATED PAGE HERO ──────────────────────────────────────────────────── */
+ reg('oribi/page-hero-animated', {
+ title: 'Animated Page Hero',
+ icon: 'flag',
+ category: 'oribi',
+ supports: { align: ['full'], html: false },
+ attributes: {
+ align: { type: 'string', default: 'full' },
+ label: { type: 'string', default: '' },
+ title: { type: 'string', default: '' },
+ description: { type: 'string', default: '' },
},
- el('strong', { style: { fontSize: '1.1rem' } }, 'OTS Theme - Site Footer'),
- el('p', { style: { opacity: 0.5, margin: '8px 0 0', fontSize: '.85rem' } }, 'Brand · Service Links · Company Links · Connect · Copyright')
- );
- },
- save: function () { return null; }
-});
+ edit: function (props) {
+ var a = props.attributes, s = props.setAttributes;
+ var particles = [];
+ for (var i = 1; i <= 8; i++) {
+ particles.push(el('div', { key: 'p' + i, className: 'hero-particle hero-particle--' + i }));
+ }
+ return el(Frag, null,
+ el(IC, null,
+ el(PB, { title: 'Settings' },
+ el(TC, { label: 'Label (optional)', value: a.label, onChange: function (v) { s({ label: v }); } })
+ )
+ ),
+ el('section', { className: 'page-hero page-hero-animated' },
+ el('div', { className: 'hero-particles', 'aria-hidden': 'true' }, particles),
+ el('div', { className: 'hero-animated__glow' }),
+ el('div', { className: 'hero-overlay' }),
+ el('div', { className: 'container' },
+ a.label ? el('span', { className: 'hero-label' }, a.label) : null,
+ el(RT, { tagName: 'h1', value: a.title, onChange: function (v) { s({ title: v }); }, placeholder: 'Page title...' }),
+ el(RT, { tagName: 'p', className: 'lead', value: a.description, onChange: function (v) { s({ description: v }); }, placeholder: 'Description...' })
+ )
+ )
+ );
+ },
+ save: function () { return null; }
+ });
+
+ /* ═══════════════════════════════════════════════════════════════════════
+ TEMPLATE-PART HELPER BLOCKS
+ ═══════════════════════════════════════════════════════════════════════ */
+
+ reg('oribi/site-header', {
+ title: 'Oribi Site Header',
+ icon: 'admin-home',
+ category: 'oribi',
+ supports: { html: false, multiple: false, reusable: false },
+ edit: function () {
+ return el('div', {
+ style: { background: '#111111', color: '#fff', padding: '20px 24px', borderRadius: '8px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }
+ },
+ el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } },
+ el('strong', { style: { fontSize: '1.2rem' } }, 'Oribi'),
+ el('span', { style: { fontSize: '1.2rem', fontWeight: 300 } }, 'Tech')
+ ),
+ el('div', { style: { display: 'flex', gap: '1.5rem', fontSize: '.9rem', opacity: 0.7 } },
+ el('span', null, 'Services'),
+ el('span', null, 'About'),
+ el('span', null, 'FAQ'),
+ el('span', null, 'Contact')
+ )
+ );
+ },
+ save: function () { return null; }
+ });
+
+ reg('oribi/site-footer', {
+ title: 'Oribi Site Footer',
+ icon: 'admin-home',
+ category: 'oribi',
+ supports: { html: false, multiple: false, reusable: false },
+ edit: function () {
+ return el('div', {
+ style: { background: '#111111', color: '#fff', padding: '24px', borderRadius: '8px', textAlign: 'center' }
+ },
+ el('strong', { style: { fontSize: '1.1rem' } }, 'OTS Theme - Site Footer'),
+ el('p', { style: { opacity: 0.5, margin: '8px 0 0', fontSize: '.85rem' } }, 'Brand · Service Links · Company Links · Connect · Copyright')
+ );
+ },
+ save: function () { return null; }
+ });
})(window.wp);
diff --git a/theme/blocks/index.php b/theme/blocks/index.php
index 27aef9e..051abc8 100644
--- a/theme/blocks/index.php
+++ b/theme/blocks/index.php
@@ -339,6 +339,7 @@ add_action('init', function () {
'description' => ['type' => 'string', 'default' => ''],
'visual' => ['type' => 'string', 'default' => ''],
'reversed' => ['type' => 'boolean', 'default' => false],
+ 'cloudAnim' => ['type' => 'boolean', 'default' => false],
'imgId' => ['type' => 'number', 'default' => 0],
'imgUrl' => ['type' => 'string', 'default' => ''],
'imgAlt' => ['type' => 'string', 'default' => ''],
@@ -972,7 +973,20 @@ function oribi_render_intro_section($a)
- >
+ >
+ ';
+ echo '
';
+ echo '
';
+ echo '
';
+ echo '
';
+ }
+ else {
+ echo wp_kses_post($a['visual']);
+ }
+?>
+
@@ -1650,8 +1664,7 @@ function oribi_render_camera_animation()
0:00
-
-HTML;
+HTML;
}
function oribi_render_platform_row($a)