PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.14
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.14
2.0.14 2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / use-case-section / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.14, at blocks/use-case-section/index.js

263 lines 18.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* ====================================================
2 Use Case Section — editor (index.js)
3 Block: blockenberg/use-case-section
4 ==================================================== */
5 ( function () {
6 var el = wp.element.createElement;
7 var useState = wp.element.useState;
8 var Fragment = wp.element.Fragment;
9 var RichText = wp.blockEditor.RichText;
10 var registerBlockType = wp.blocks.registerBlockType;
11 var InspectorControls = wp.blockEditor.InspectorControls;
12 var useBlockProps = wp.blockEditor.useBlockProps;
13 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
14 var PanelBody = wp.components.PanelBody;
15 var RangeControl = wp.components.RangeControl;
16 var SelectControl = wp.components.SelectControl;
17 var ToggleControl = wp.components.ToggleControl;
18 var TextControl = wp.components.TextControl;
19 var Button = wp.components.Button;
20 var ColorPicker = wp.components.ColorPicker;
21 var Popover = wp.components.Popover;
22 var __ = wp.i18n.__;
23
24 // Resolve the shared components lazily without defining globals for each block.
25 function _tc(label, key, attrs, setA) {
26 var Control = window.bkbgTypographyControl;
27 return Control ? el(Control, {
28 label: label,
29 value: attrs[key] || {},
30 onChange: function (value) { var update = {}; update[key] = value; setA(update); }
31 }) : null;
32 }
33 function _tvf(vars, key, attrs, prefix) {
34 var cssVars = window.bkbgTypoCssVars;
35 if (cssVars) Object.assign(vars, cssVars(attrs[key] || {}, prefix));
36 return vars;
37 }
38 function getTypoControl(label, key, attrs, setA) { return _tc(label, key, attrs, setA); }
39 function getTypoCssVars(attrs) {
40 var v = {};
41 _tvf(v, 'titleTypo', attrs, '--bkusec-tt-');
42 _tvf(v, 'descTypo', attrs, '--bkusec-ds-');
43 return v;
44 }
45 var IP = function () { return window.bkbgIconPicker; };
46
47 function uid() { return Math.random().toString(36).slice(2,9); }
48
49 function wrapStyle(a) {
50 var s = {
51 '--bkbg-usec-pt': a.paddingTop + 'px',
52 '--bkbg-usec-pb': a.paddingBottom + 'px',
53 '--bkbg-usec-sec-bg': a.sectionBg,
54 '--bkbg-usec-card-bg':a.cardBg,
55 '--bkbg-usec-card-bd':a.cardBorder,
56 '--bkbg-usec-title-c':a.titleColor,
57 '--bkbg-usec-desc-c': a.descColor,
58 '--bkbg-usec-feat-c': a.featureColor,
59 '--bkbg-usec-chk-c': a.checkColor,
60 '--bkbg-usec-ey-bg': a.eyebrowBg,
61 '--bkbg-usec-ey-c': a.eyebrowColor,
62 '--bkbg-usec-sec-ttl':a.sectionTitleColor,
63 '--bkbg-usec-sec-sub':a.sectionSubColor,
64 '--bkbg-usec-icon-sz':a.iconSize + 'px',
65 '--bkbg-usec-r': a.cardRadius + 'px',
66 '--bkbg-usec-p': a.cardPadding + 'px',
67 '--bkbg-usec-gap': a.gap + 'px',
68 '--bkbg-usec-cols': a.columns,
69 '--bkbg-usec-header-gap': a.headerGap + 'px',
70 };
71 var _tv = getTypoCssVars(a);
72 Object.assign(s, _tv);
73 return s;
74 }
75
76 /* ----- Inspector: one expandable case row ----- */
77 function CaseRow(props) {
78 var c = props.caseItem;
79 var idx = props.index;
80 var total = props.total;
81 var onUpdate = props.onUpdate;
82 var onDelete = props.onDelete;
83 var onMove = props.onMove;
84 var open = useState(idx === 0);
85 var isOpen = open[0]; var setOpen = open[1];
86
87 return el('div', { className:'bkbg-inspector-row', style:{ borderBottom:'1px solid #e2e8f0', marginBottom:4 } },
88 el('div', { style:{ display:'flex', alignItems:'center', cursor:'pointer', padding:'6px 0' }, onClick:function(){ setOpen(!isOpen); } },
89 el('span', { style:{ flex:1, fontWeight:600, fontSize:12 } }, '#'+(idx+1)+' '+((c.iconType || 'custom-char') === 'custom-char' ? c.icon : '●')+' '+(c.title||'Case')),
90 el('span', null, isOpen ? '▲' : '▼')
91 ),
92 !isOpen ? null : el('div', { style:{ paddingBottom:8 } },
93 el(IP().IconPickerControl, IP().iconPickerProps(c, function(patch) { onUpdate(idx, patch); }, { label:__('Icon (emoji or symbol)','blockenberg'), charAttr:'icon', typeAttr:'iconType', dashiconAttr:'iconDashicon', imageUrlAttr:'iconImageUrl' })),
94 el(TextControl, { label:__('Title','blockenberg'), value:c.title, onChange:function(v){ onUpdate(idx,{title:v}); } }),
95 el(TextControl, { label:__('Description','blockenberg'), value:c.description, onChange:function(v){ onUpdate(idx,{description:v}); }, __nextHasNoMarginBottom:false }),
96 el(BkbgColorSwatch, { label:__('Accent color','blockenberg'), value:c.accentColor, onChange:function(v){ onUpdate(idx,{accentColor:v}); } }),
97 el('p', { style:{ fontWeight:600, fontSize:11, margin:'8px 0 4px' } }, __('Features','blockenberg')),
98 c.features.map(function(f, fi) {
99 return el('div', { key:f.id, style:{ display:'flex', gap:4, marginBottom:4 } },
100 el(TextControl, { value:f.text, onChange:function(v){ var feats=[].concat(c.features); feats[fi]=Object.assign({},f,{text:v}); onUpdate(idx,{features:feats}); }, placeholder:'Feature…' }),
101 el(Button, { isSmall:true, isDestructive:true, onClick:function(){ var feats=c.features.filter(function(_,i){ return i!==fi; }); onUpdate(idx,{features:feats}); } }, '✕')
102 );
103 }),
104 el(Button, { isSmall:true, variant:'tertiary', onClick:function(){ onUpdate(idx,{features:c.features.concat([{id:uid(),text:''}])}); } }, __('+ Feature','blockenberg')),
105 el(TextControl, { label:__('CTA label','blockenberg'), value:c.ctaLabel, onChange:function(v){ onUpdate(idx,{ctaLabel:v}); } }),
106 el(TextControl, { label:__('CTA URL','blockenberg'), value:c.ctaUrl, onChange:function(v){ onUpdate(idx,{ctaUrl:v}); } }),
107 el('div', { style:{ display:'flex', gap:4, marginTop:8 } },
108 el(Button, { isSmall:true, variant:'secondary', disabled:idx===0, onClick:function(){ onMove(idx,idx-1); } }, '↑'),
109 el(Button, { isSmall:true, variant:'secondary', disabled:idx===total-1, onClick:function(){ onMove(idx,idx+1); } }, '↓'),
110 el(Button, { isSmall:true, isDestructive:true, onClick:function(){ onDelete(idx); } }, __('Delete','blockenberg'))
111 )
112 )
113 );
114 }
115
116 var BkbgColorSwatch = function (props) {
117 var _st = useState(false); var isOpen = _st[0]; var setOpen = _st[1];
118 return el(Fragment, {},
119 el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '8px' } },
120 el('span', { style: { fontSize: '11px', fontWeight: 500, textTransform: 'uppercase', color: '#1e1e1e' } }, props.label),
121 el('button', {
122 type: 'button',
123 onClick: function () { setOpen(!isOpen); },
124 style: { width: '28px', height: '28px', borderRadius: '4px', border: '1px solid #ccc', background: props.value || '#ffffff', cursor: 'pointer', padding: 0 }
125 })
126 ),
127 isOpen && el(Popover, { onClose: function () { setOpen(false); } },
128 el('div', { style: { padding: '8px' } },
129 el(ColorPicker, { color: props.value, onChangeComplete: function (c) { props.onChange(c.hex); }, enableAlpha: true })
130 )
131 )
132 );
133 };
134
135 registerBlockType('blockenberg/use-case-section', {
136 edit: function (props) {
137 var a = props.attributes;
138 var setAttr = props.setAttributes;
139
140 function updateCase(idx, patch) {
141 var arr = a.cases.map(function(c,i){ return i===idx ? Object.assign({},c,patch) : c; });
142 setAttr({ cases: arr });
143 }
144 function deleteCase(idx) { setAttr({ cases: a.cases.filter(function(_,i){ return i!==idx; }) }); }
145 function moveCase(from, to) {
146 var arr = a.cases.slice();
147 arr.splice(to, 0, arr.splice(from, 1)[0]);
148 setAttr({ cases: arr });
149 }
150 function addCase() {
151 setAttr({ cases: a.cases.concat([{ id:uid(), icon:'⚡', iconType:'custom-char', iconDashicon:'', iconImageUrl:'', title:'New Use Case', description:'Describe who benefits from this.', features:[{id:uid(),text:'Key feature'}], ctaLabel:'Learn more', ctaUrl:'#', accentColor:'#6c3fb5' }]) });
152 }
153
154 var blockProps = useBlockProps({ className:'bkbg-usec-wrap', style:wrapStyle(a) });
155
156 var inspector = el(InspectorControls, null,
157 el(PanelBody, { title:__('Cases','blockenberg'), initialOpen:true },
158 a.cases.map(function(c,i){ return el(CaseRow, { key:c.id, caseItem:c, index:i, total:a.cases.length, onUpdate:updateCase, onDelete:deleteCase, onMove:moveCase }); }),
159 el(Button, { variant:'primary', onClick:addCase, style:{marginTop:8} }, __('+ Add case','blockenberg'))
160 ),
161 el(PanelBody, { title:__('Display','blockenberg'), initialOpen:false },
162 el(SelectControl, { label:__('Display style','blockenberg'), value:a.displayStyle, options:[{label:'Cards',value:'cards'},{label:'Tabs',value:'tabs'}], onChange:function(v){ setAttr({displayStyle:v}); } }),
163 el(RangeControl, { label:__('Columns','blockenberg'), value:a.columns, min:1, max:4, onChange:function(v){ setAttr({columns:v}); } }),
164 el(RangeControl, { label:__('Gap (px)','blockenberg'), value:a.gap, min:0, max:64, onChange:function(v){ setAttr({gap:v}); } }),
165 el(RangeControl, { label:__('Card radius (px)','blockenberg'), value:a.cardRadius, min:0, max:32, onChange:function(v){ setAttr({cardRadius:v}); } }),
166 el(RangeControl, { label:__('Card padding (px)','blockenberg'), value:a.cardPadding, min:0, max:64, onChange:function(v){ setAttr({cardPadding:v}); } }),
167 el(RangeControl, { label:__('Icon size (px)','blockenberg'), value:a.iconSize, min:16, max:72, onChange:function(v){ setAttr({iconSize:v}); } }),
168 el(ToggleControl, { label:__('Show features','blockenberg'), checked:a.showFeatures, onChange:function(v){ setAttr({showFeatures:v}); } }),
169 el(ToggleControl, { label:__('Show CTA links','blockenberg'), checked:a.showCta, onChange:function(v){ setAttr({showCta:v}); } })
170 ),
171 el(PanelBody, { title:__('Section header','blockenberg'), initialOpen:false },
172 el(ToggleControl, { label:__('Show header','blockenberg'), checked:a.showHeader, onChange:function(v){ setAttr({showHeader:v}); } }),
173 el(ToggleControl, { label:__('Show eyebrow','blockenberg'), checked:a.showEyebrow, onChange:function(v){ setAttr({showEyebrow:v}); } }),
174 el(TextControl, { label:__('Eyebrow text','blockenberg'), value:a.eyebrow, onChange:function(v){ setAttr({eyebrow:v}); } }),
175 el(SelectControl, { label:__('Header align','blockenberg'), value:a.headerAlign, options:[{label:'Center',value:'center'},{label:'Left',value:'left'}], onChange:function(v){ setAttr({headerAlign:v}); } }),
176 el(RangeControl, { label:__('Header gap (px)','blockenberg'), value:a.headerGap, min:8, max:96, onChange:function(v){ setAttr({headerGap:v}); } })
177 ),
178 el(PanelBody, { title:__('Typography','blockenberg'), initialOpen:false },
179 getTypoControl(__('Card Title', 'blockenberg'), 'titleTypo', a, setAttr),
180 getTypoControl(__('Card Description', 'blockenberg'), 'descTypo', a, setAttr)
181 ),
182 el(PanelBody, { title:__('Spacing','blockenberg'), initialOpen:false },
183 el(RangeControl, { label:__('Padding top (px)','blockenberg'), value:a.paddingTop, min:0, max:200, onChange:function(v){ setAttr({paddingTop:v}); } }),
184 el(RangeControl, { label:__('Padding bottom (px)','blockenberg'), value:a.paddingBottom, min:0, max:200, onChange:function(v){ setAttr({paddingBottom:v}); } })
185 ),
186 el(PanelColorSettings, { title:__('Colors','blockenberg'), initialOpen:false, colorSettings:[
187 {label:__('Section bg','blockenberg'), value:a.sectionBg, onChange:function(v){ setAttr({sectionBg:v||''}); }},
188 {label:__('Card bg','blockenberg'), value:a.cardBg, onChange:function(v){ setAttr({cardBg:v||''}); }},
189 {label:__('Card border','blockenberg'), value:a.cardBorder, onChange:function(v){ setAttr({cardBorder:v||''}); }},
190 {label:__('Title','blockenberg'), value:a.titleColor, onChange:function(v){ setAttr({titleColor:v||''}); }},
191 {label:__('Description','blockenberg'), value:a.descColor, onChange:function(v){ setAttr({descColor:v||''}); }},
192 {label:__('Feature text','blockenberg'), value:a.featureColor, onChange:function(v){ setAttr({featureColor:v||''}); }},
193 {label:__('Check icon','blockenberg'), value:a.checkColor, onChange:function(v){ setAttr({checkColor:v||''}); }},
194 {label:__('Eyebrow bg','blockenberg'), value:a.eyebrowBg, onChange:function(v){ setAttr({eyebrowBg:v||''}); }},
195 {label:__('Eyebrow text','blockenberg'), value:a.eyebrowColor, onChange:function(v){ setAttr({eyebrowColor:v||''}); }},
196 {label:__('Section title','blockenberg'), value:a.sectionTitleColor,onChange:function(v){ setAttr({sectionTitleColor:v||''}); }},
197 {label:__('Section subtitle','blockenberg'), value:a.sectionSubColor, onChange:function(v){ setAttr({sectionSubColor:v||''}); }},
198 ] })
199 );
200
201 /* render a single card in the editor canvas */
202 function renderCard(c) {
203 var _iType = c.iconType || 'custom-char';
204 var _iconContent = (_iType !== 'custom-char' && IP()) ? IP().buildEditorIcon(_iType, c.icon, c.iconDashicon, c.iconImageUrl, c.iconDashiconColor) : c.icon;
205 return el('div', { key:c.id, className:'bkbg-usec-card', style:{'--bkbg-usec-accent': c.accentColor} },
206 el('div', { className:'bkbg-usec-icon-wrap' }, el('span', { className:'bkbg-usec-icon' }, _iconContent)),
207 el('div', { className:'bkbg-usec-title' }, c.title),
208 el('div', { className:'bkbg-usec-desc' }, c.description),
209 a.showFeatures && c.features.length ? el('ul', { className:'bkbg-usec-features' },
210 c.features.map(function(f){ return el('li', { key:f.id }, el('span', { className:'bkbg-usec-check' }, '✓'), f.text); })
211 ) : null,
212 a.showCta ? el('span', { className:'bkbg-usec-cta' }, c.ctaLabel, el('span', { className:'bkbg-usec-cta-arrow' }, ' →')) : null
213 );
214 }
215
216 return el(Fragment, null,
217 inspector,
218 el('div', blockProps,
219 a.showHeader ? el('div', { className:'bkbg-usec-header bkbg-usec-header--' + a.headerAlign },
220 a.showEyebrow ? el('span', { className:'bkbg-usec-eyebrow' }, a.eyebrow) : null,
221 el(RichText, { tagName:'h2', className:'bkbg-usec-section-title', value:a.sectionTitle, onChange:function(v){ setAttr({sectionTitle:v}); }, placeholder:__('Section title…','blockenberg') }),
222 el(RichText, { tagName:'p', className:'bkbg-usec-section-sub', value:a.sectionSubtitle, onChange:function(v){ setAttr({sectionSubtitle:v}); }, placeholder:__('Section subtitle…','blockenberg') })
223 ) : null,
224 el('div', { className:'bkbg-usec-grid' },
225 a.cases.map(renderCard)
226 )
227 )
228 );
229 },
230
231 save: function (props) {
232 var a = props.attributes;
233 var blockProps = wp.blockEditor.useBlockProps.save({
234 className: 'bkbg-usec-wrap',
235 style: wrapStyle(a),
236 'data-display-style': a.displayStyle
237 });
238 return el('div', blockProps,
239 a.showHeader ? el('div', { className:'bkbg-usec-header bkbg-usec-header--' + a.headerAlign },
240 a.showEyebrow ? el('span', { className:'bkbg-usec-eyebrow' }, a.eyebrow) : null,
241 el(RichText.Content, { tagName:'h2', className:'bkbg-usec-section-title', value:a.sectionTitle }),
242 el(RichText.Content, { tagName:'p', className:'bkbg-usec-section-sub', value:a.sectionSubtitle })
243 ) : null,
244 el('div', { className:'bkbg-usec-grid' + (a.displayStyle === 'tabs' ? ' bkbg-usec-grid--tabs' : '') },
245 a.cases.map(function(c) {
246 var _iType = c.iconType || 'custom-char';
247 var _iconContent = (_iType !== 'custom-char' && IP()) ? IP().buildSaveIcon(_iType, c.icon, c.iconDashicon, c.iconImageUrl, c.iconDashiconColor) : c.icon;
248 return el('div', { key:c.id, className:'bkbg-usec-card', style:{'--bkbg-usec-accent': c.accentColor}, 'data-tab-label': c.title },
249 el('div', { className:'bkbg-usec-icon-wrap' }, el('span', { className:'bkbg-usec-icon' }, _iconContent)),
250 el('div', { className:'bkbg-usec-title' }, c.title),
251 el('div', { className:'bkbg-usec-desc' }, c.description),
252 a.showFeatures && c.features.length ? el('ul', { className:'bkbg-usec-features' },
253 c.features.map(function(f){ return el('li', { key:f.id }, el('span', { className:'bkbg-usec-check' }, '✓'), f.text); })
254 ) : null,
255 a.showCta ? el('a', { href:c.ctaUrl, className:'bkbg-usec-cta' }, c.ctaLabel, el('span', { className:'bkbg-usec-cta-arrow' }, ' →')) : null
256 );
257 })
258 )
259 );
260 }
261 });
262 }() );
263