PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
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 / card-cta-grid / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/card-cta-grid/index.js

193 lines 13.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* ====================================================
2 Card CTA Grid — editor (index.js)
3 Block: blockenberg/card-cta-grid
4 ==================================================== */
5 ( function () {
6 var el = wp.element.createElement;
7 var useState = wp.element.useState;
8 var Fragment = wp.element.Fragment;
9 var registerBlockType = wp.blocks.registerBlockType;
10 var InspectorControls = wp.blockEditor.InspectorControls;
11 var useBlockProps = wp.blockEditor.useBlockProps;
12 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
13 var PanelBody = wp.components.PanelBody;
14 var RangeControl = wp.components.RangeControl;
15 var SelectControl = wp.components.SelectControl;
16 var ToggleControl = wp.components.ToggleControl;
17 var TextControl = wp.components.TextControl;
18 var Button = wp.components.Button;
19 var ColorPicker = wp.components.ColorPicker;
20 var Popover = wp.components.Popover;
21 var __ = wp.i18n.__;
22 var IP = function () { return window.bkbgIconPicker; };
23
24 function getTypographyControl() { return (window.bkbgTypographyControl || function () { return null; }); }
25 function getTypoCssVars() { return (window.bkbgTypoCssVars || function () { return {}; }); }
26 function _tv(typo, prefix) { var fn = getTypoCssVars(); return fn(typo || {}, prefix); }
27
28 function uid() { return Math.random().toString(36).slice(2,9); }
29
30 function wrapStyle(a) {
31 return Object.assign({
32 '--bkbg-ccg-pt': a.paddingTop + 'px',
33 '--bkbg-ccg-pb': a.paddingBottom + 'px',
34 '--bkbg-ccg-sec-bg': a.sectionBg || 'transparent',
35 '--bkbg-ccg-card-bg': a.cardBg,
36 '--bkbg-ccg-card-bd': a.cardBorder,
37 '--bkbg-ccg-title-c': a.titleColor,
38 '--bkbg-ccg-desc-c': a.descColor,
39 '--bkbg-ccg-icon-sz': a.iconSize + 'px',
40 '--bkbg-ccg-r': a.cardRadius + 'px',
41 '--bkbg-ccg-gap': a.gap + 'px',
42 '--bkbg-ccg-cols': a.columns,
43 }, _tv(a.typoTitle, '--bkbg-ccg-tt-'), _tv(a.typoDesc, '--bkbg-ccg-td-'), _tv(a.typoCta, '--bkbg-ccg-tc-'));
44 }
45
46 /* Inspector row for one card */
47 function CardRow(props) {
48 var c = props.card; var idx = props.index; var total = props.total;
49 var onUpdate = props.onUpdate; var onDelete = props.onDelete; var onMove = props.onMove;
50 var open = useState(idx === 0); var isOpen = open[0]; var setOpen = open[1];
51 return el('div', { style:{ borderBottom:'1px solid #e2e8f0', marginBottom:4 } },
52 el('div', { style:{ display:'flex', alignItems:'center', cursor:'pointer', padding:'6px 0' }, onClick:function(){ setOpen(!isOpen); } },
53 el('span', { style:{ flex:1, fontWeight:600, fontSize:12 } }, '#'+(idx+1)+' '+c.icon+' '+(c.title||'Card')),
54 el('span', null, isOpen ? '' : '')
55 ),
56 !isOpen ? null : el('div', { style:{ paddingBottom:8 } },
57 el(IP().IconPickerControl, {
58 iconType: c.iconType, customChar: c.icon, dashicon: c.iconDashicon, imageUrl: c.iconImageUrl,
59 onChangeType: function(v){ onUpdate(idx,{iconType:v}); },
60 onChangeChar: function(v){ onUpdate(idx,{icon:v}); },
61 onChangeDashicon: function(v){ onUpdate(idx,{iconDashicon:v}); },
62 onChangeImageUrl: function(v){ onUpdate(idx,{iconImageUrl:v}); }
63 }),
64 el(TextControl, { label:__('Title','blockenberg'), value:c.title, onChange:function(v){ onUpdate(idx,{title:v}); } }),
65 el(TextControl, { label:__('Description','blockenberg'), value:c.description, onChange:function(v){ onUpdate(idx,{description:v}); } }),
66 el(TextControl, { label:__('CTA label','blockenberg'), value:c.ctaLabel, onChange:function(v){ onUpdate(idx,{ctaLabel:v}); } }),
67 el(TextControl, { label:__('CTA URL','blockenberg'), value:c.ctaUrl, onChange:function(v){ onUpdate(idx,{ctaUrl:v}); } }),
68 el(SelectControl, { label:__('CTA target','blockenberg'), value:c.ctaTarget, options:[{label:'Same tab',value:'_self'},{label:'New tab',value:'_blank'}], onChange:function(v){ onUpdate(idx,{ctaTarget:v}); } }),
69 el(BkbgColorSwatch, { label:__('Accent color','blockenberg'), value:c.accentColor, onChange:function(v){ onUpdate(idx,{accentColor:v}); } }),
70 el('div', { style:{ display:'flex', gap:4, marginTop:8 } },
71 el(Button, { isSmall:true, variant:'secondary', disabled:idx===0, onClick:function(){ onMove(idx,idx-1); } }, ''),
72 el(Button, { isSmall:true, variant:'secondary', disabled:idx===total-1, onClick:function(){ onMove(idx,idx+1); } }, ''),
73 el(Button, { isSmall:true, isDestructive:true, onClick:function(){ onDelete(idx); } }, __('Delete','blockenberg'))
74 )
75 )
76 );
77 }
78
79 var BkbgColorSwatch = function (props) {
80 var _st = useState(false); var isOpen = _st[0]; var setOpen = _st[1];
81 return el(Fragment, {},
82 el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '8px' } },
83 el('span', { style: { fontSize: '11px', fontWeight: 500, textTransform: 'uppercase', color: '#1e1e1e' } }, props.label),
84 el('button', {
85 type: 'button',
86 onClick: function () { setOpen(!isOpen); },
87 style: { width: '28px', height: '28px', borderRadius: '4px', border: '1px solid #ccc', background: props.value || '#ffffff', cursor: 'pointer', padding: 0 }
88 })
89 ),
90 isOpen && el(Popover, { onClose: function () { setOpen(false); } },
91 el('div', { style: { padding: '8px' } },
92 el(ColorPicker, { color: props.value, onChangeComplete: function (c) { props.onChange(c.hex); }, enableAlpha: true })
93 )
94 )
95 );
96 };
97
98 registerBlockType('blockenberg/card-cta-grid', {
99 edit: function (props) {
100 var a = props.attributes;
101 var setAttr = props.setAttributes;
102
103 function updateCard(idx, patch) {
104 setAttr({ cards: a.cards.map(function(c,i){ return i===idx ? Object.assign({},c,patch) : c; }) });
105 }
106 function deleteCard(idx) { setAttr({ cards: a.cards.filter(function(_,i){ return i!==idx; }) }); }
107 function moveCard(from, to) {
108 var arr = a.cards.slice(); arr.splice(to, 0, arr.splice(from, 1)[0]); setAttr({ cards: arr });
109 }
110 function addCard() {
111 setAttr({ cards: a.cards.concat([{ id:uid(), icon:'', iconType:'custom-char', iconDashicon:'', iconImageUrl:'', title:'New card', description:'Describe what happens when someone clicks this.', ctaLabel:'Learn more →', ctaUrl:'#', ctaTarget:'_self', accentColor:'#6c3fb5' }]) });
112 }
113
114 var blockProps = useBlockProps({ className:'bkbg-ccg-wrap bkbg-ccg-layout--' + a.layout + ' bkbg-ccg-style--' + a.cardStyle, style:wrapStyle(a) });
115
116 var inspector = el(InspectorControls, null,
117 el(PanelBody, { title:__('Cards','blockenberg'), initialOpen:true },
118 a.cards.map(function(c,i){ return el(CardRow, { key:c.id, card:c, index:i, total:a.cards.length, onUpdate:updateCard, onDelete:deleteCard, onMove:moveCard }); }),
119 el(Button, { variant:'primary', onClick:addCard, style:{marginTop:8} }, __('+ Add card','blockenberg'))
120 ),
121 el(PanelBody, { title:__('Layout','blockenberg'), initialOpen:false },
122 el(SelectControl, { label:__('Layout','blockenberg'), value:a.layout, options:[{label:'Grid',value:'grid'},{label:'Flex row',value:'flex'}], onChange:function(v){ setAttr({layout:v}); } }),
123 el(SelectControl, { label:__('Card style','blockenberg'), value:a.cardStyle, options:[{label:'Border',value:'border'},{label:'Shadow',value:'shadow'},{label:'Filled accent',value:'filled'},{label:'Flat',value:'flat'}], onChange:function(v){ setAttr({cardStyle:v}); } }),
124 el(RangeControl, { label:__('Columns','blockenberg'), value:a.columns, min:1, max:5, onChange:function(v){ setAttr({columns:v}); } }),
125 el(RangeControl, { label:__('Gap (px)','blockenberg'), value:a.gap, min:0, max:64, onChange:function(v){ setAttr({gap:v}); } }),
126 el(RangeControl, { label:__('Card radius (px)','blockenberg'), value:a.cardRadius, min:0, max:32, onChange:function(v){ setAttr({cardRadius:v}); } }),
127 el(RangeControl, { label:__('Icon size (px)','blockenberg'), value:a.iconSize, min:16, max:72, onChange:function(v){ setAttr({iconSize:v}); } }),
128 el(ToggleControl, { label:__('Show icon','blockenberg'), checked:a.showIcon, onChange:function(v){ setAttr({showIcon:v}); } }),
129 el(ToggleControl, { label:__('Show description','blockenberg'), checked:a.showDesc, onChange:function(v){ setAttr({showDesc:v}); } })
130 ),
131 el(PanelBody, { title:__('Typography','blockenberg'), initialOpen:false },
132 el(getTypographyControl(), { label: __('Title', 'blockenberg'), value: a.typoTitle, onChange: function (v) { setAttr({ typoTitle: v }); } }),
133 el(getTypographyControl(), { label: __('Description', 'blockenberg'), value: a.typoDesc, onChange: function (v) { setAttr({ typoDesc: v }); } }),
134 el(getTypographyControl(), { label: __('CTA', 'blockenberg'), value: a.typoCta, onChange: function (v) { setAttr({ typoCta: v }); } })
135 ),
136 el(PanelBody, { title:__('Spacing','blockenberg'), initialOpen:false },
137 el(RangeControl, { label:__('Padding top (px)','blockenberg'), value:a.paddingTop, min:0, max:160, onChange:function(v){ setAttr({paddingTop:v}); } }),
138 el(RangeControl, { label:__('Padding bottom (px)','blockenberg'), value:a.paddingBottom, min:0, max:160, onChange:function(v){ setAttr({paddingBottom:v}); } })
139 ),
140 el(PanelColorSettings, { title:__('Colors','blockenberg'), initialOpen:false, colorSettings:[
141 {label:__('Section bg','blockenberg'), value:a.sectionBg, onChange:function(v){ setAttr({sectionBg:v||''}); }},
142 {label:__('Card bg','blockenberg'), value:a.cardBg, onChange:function(v){ setAttr({cardBg:v||''}); }},
143 {label:__('Card border','blockenberg'), value:a.cardBorder, onChange:function(v){ setAttr({cardBorder:v||''}); }},
144 {label:__('Title','blockenberg'), value:a.titleColor, onChange:function(v){ setAttr({titleColor:v||''}); }},
145 {label:__('Description','blockenberg'), value:a.descColor, onChange:function(v){ setAttr({descColor:v||''}); }},
146 ] })
147 );
148
149 function renderCard(c) {
150 return el('div', { key:c.id, className:'bkbg-ccg-card', style:{'--bkbg-ccg-accent': c.accentColor} },
151 a.showIcon ? el('div', { className:'bkbg-ccg-icon' }, (c.iconType || 'custom-char') !== 'custom-char' ? IP().buildEditorIcon(c.iconType, c.icon, c.iconDashicon, c.iconImageUrl, c.iconDashiconColor) : c.icon) : null,
152 el('div', { className:'bkbg-ccg-body' },
153 el('div', { className:'bkbg-ccg-title' }, c.title),
154 a.showDesc ? el('div', { className:'bkbg-ccg-desc' }, c.description) : null
155 ),
156 el('span', { className:'bkbg-ccg-cta' }, c.ctaLabel)
157 );
158 }
159
160 return el(Fragment, null,
161 inspector,
162 el('div', blockProps,
163 el('div', { className:'bkbg-ccg-grid' },
164 a.cards.map(renderCard)
165 )
166 )
167 );
168 },
169
170 save: function (props) {
171 var a = props.attributes;
172 var blockProps = wp.blockEditor.useBlockProps.save({
173 className: 'bkbg-ccg-wrap bkbg-ccg-layout--' + a.layout + ' bkbg-ccg-style--' + a.cardStyle,
174 style: wrapStyle(a)
175 });
176 return el('div', blockProps,
177 el('div', { className:'bkbg-ccg-grid' },
178 a.cards.map(function(c) {
179 return el('a', { key:c.id, href:c.ctaUrl, target:c.ctaTarget, rel:c.ctaTarget==='_blank'?'noopener noreferrer':undefined, className:'bkbg-ccg-card', style:{'--bkbg-ccg-accent': c.accentColor} },
180 a.showIcon ? el('div', { className:'bkbg-ccg-icon' }, (c.iconType || 'custom-char') !== 'custom-char' ? IP().buildSaveIcon(c.iconType, c.icon, c.iconDashicon, c.iconImageUrl, c.iconDashiconColor) : c.icon) : null,
181 el('div', { className:'bkbg-ccg-body' },
182 el('div', { className:'bkbg-ccg-title' }, c.title),
183 a.showDesc ? el('div', { className:'bkbg-ccg-desc' }, c.description) : null
184 ),
185 el('span', { className:'bkbg-ccg-cta' }, c.ctaLabel)
186 );
187 })
188 )
189 );
190 }
191 });
192 }() );
193