2026-02-20 21:28:00 -05:00
|
|
|
/**
|
2026-02-20 22:06:53 -05:00
|
|
|
* OTS Theme - Custom Block Editor Scripts (InnerBlocks Architecture)
|
2026-02-20 21:28:00 -05:00
|
|
|
*
|
|
|
|
|
* 13 blocks: 5 standalone + 4 parent/child pairs.
|
|
|
|
|
* Parent blocks use InnerBlocks for child items.
|
|
|
|
|
* Child blocks are dynamic (save -> null) with inline RichText editing.
|
|
|
|
|
*/
|
|
|
|
|
(function (wp) {
|
|
|
|
|
'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;
|
|
|
|
|
|
|
|
|
|
/* ── 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.
|
2026-02-20 22:06:53 -05:00
|
|
|
* cssClass - the wrapper class, e.g. 'feature-icon' or 'value-icon'
|
|
|
|
|
* extraStyle - optional inline style object for the wrapper
|
2026-02-20 21:28:00 -05:00
|
|
|
*/
|
|
|
|
|
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 }); } }),
|
2026-02-20 22:06:53 -05:00
|
|
|
el(RC, { label: 'Height (px) - 0 = auto', value: imgH, min: 0, max: 600, step: 4,
|
2026-02-20 21:28:00 -05:00
|
|
|
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: allowedBlocks,
|
|
|
|
|
template: defaultTemplate,
|
|
|
|
|
templateLock: false
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 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 }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* ═══════════════════════════════════════════════════════════════════════
|
|
|
|
|
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(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 },
|
|
|
|
|
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: '' },
|
2026-02-21 00:53:13 -05:00
|
|
|
price: { type: 'string', default: '' },
|
|
|
|
|
pricePer: { type: 'string', default: '' },
|
2026-02-20 21:28:00 -05:00
|
|
|
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...' }),
|
2026-02-21 00:53:13 -05:00
|
|
|
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' })
|
|
|
|
|
),
|
2026-02-20 21:28:00 -05:00
|
|
|
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 },
|
|
|
|
|
},
|
|
|
|
|
edit: function (props) {
|
|
|
|
|
var a = props.attributes, s = props.setAttributes;
|
|
|
|
|
var imgW = a.imgWidth || 300;
|
|
|
|
|
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(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.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;
|
|
|
|
|
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('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
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
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 || [];
|
|
|
|
|
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('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 }, col); })
|
|
|
|
|
)
|
|
|
|
|
),
|
|
|
|
|
el('tbody', null,
|
|
|
|
|
rows.map(function(row, i) {
|
|
|
|
|
if (row.group) {
|
|
|
|
|
return el('tr', { key: i, className: 'comparison-group-row' },
|
|
|
|
|
el('td', { colSpan: cols.length + 1 }, row.group)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return el('tr', { key: i },
|
|
|
|
|
el('td', { className: 'comparison-feature-name' }, row.feature || ''),
|
|
|
|
|
(row.values || []).map(function(val, j) {
|
|
|
|
|
return el('td', { key: j, className: 'comparison-cell' },
|
|
|
|
|
val === true ? '\u2713' : val === false ? '\u2014' : String(val)
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
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: [] })
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
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', {
|
2026-02-20 22:06:53 -05:00
|
|
|
style: { background: '#111111', color: '#fff', padding: '20px 24px', borderRadius: '8px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }
|
2026-02-20 21:28:00 -05:00
|
|
|
},
|
|
|
|
|
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', {
|
2026-02-20 22:06:53 -05:00
|
|
|
style: { background: '#111111', color: '#fff', padding: '24px', borderRadius: '8px', textAlign: 'center' }
|
2026-02-20 21:28:00 -05:00
|
|
|
},
|
2026-02-20 22:06:53 -05:00
|
|
|
el('strong', { style: { fontSize: '1.1rem' } }, 'OTS Theme - Site Footer'),
|
2026-02-20 21:28:00 -05:00
|
|
|
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);
|