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 / creative-stats-waterfall / index.js

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

217 lines 14.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* ====================================================
2 Creative Stats Waterfall — editor (index.js)
3 Block: blockenberg/creative-stats-waterfall
4 ==================================================== */
5 ( function () {
6 var el = wp.element.createElement;
7 var Fragment = wp.element.Fragment;
8 var useState = wp.element.useState;
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
23 var _cswTC, _cswTV;
24 function _tc() { return _cswTC || (_cswTC = window.bkbgTypographyControl); }
25 function _tv(obj, prefix) { var fn = _cswTV || (_cswTV = window.bkbgTypoCssVars); return fn ? fn(obj, prefix) : {}; }
26
27 function uid() { return 'st' + Math.random().toString(36).slice(2,7); }
28 function move(arr, from, to) { var a=arr.slice(); a.splice(to,0,a.splice(from,1)[0]); return a; }
29
30 function wrapStyle(a) {
31 return Object.assign({
32 '--bkbg-csw-pt': a.paddingTop+'px',
33 '--bkbg-csw-pb': a.paddingBottom+'px',
34 '--bkbg-csw-num-c': a.numberColor || undefined,
35 '--bkbg-csw-ps-c': a.prefixSuffixColor || undefined,
36 '--bkbg-csw-label-c': a.labelColor,
37 '--bkbg-csw-desc-c': a.descColor,
38 '--bkbg-csw-div-c': a.dividerColor,
39 '--bkbg-csw-num-sz': a.numberSize+'px',
40 '--bkbg-csw-label-sz': a.labelSize+'px',
41 '--bkbg-csw-desc-sz': a.descSize+'px',
42 '--bkbg-csw-gap': a.gap+'px',
43 '--bkbg-csw-offset': a.waterfallOffset+'px',
44 background: a.sectionBg || undefined,
45 }, _tv(a.typoNumber, '--bkbg-csw-num-'), _tv(a.typoLabel, '--bkbg-csw-lbl-'), _tv(a.typoDesc, '--bkbg-csw-dsc-'));
46 }
47
48 function StatCard(props) {
49 var stat = props.stat;
50 var idx = props.idx;
51 var layout = props.layout;
52 var showDesc = props.showDesc;
53 var showDiv = props.showDiv;
54 var divStyle = props.divStyle;
55 var topOffset = layout === 'waterfall' ? (idx % 2 === 1 ? 'var(--bkbg-csw-offset)' : '0') : '0';
56 return el('div', {
57 className: 'bkbg-csw-stat',
58 style: { marginTop: topOffset, borderColor: stat.accentColor || undefined }
59 },
60 el('div', { className:'bkbg-csw-number-row' },
61 el('span', { className:'bkbg-csw-prefix' }, stat.prefix),
62 el('span', { className:'bkbg-csw-value', style:{color:stat.accentColor} }, stat.value),
63 el('span', { className:'bkbg-csw-suffix', style:{color:stat.accentColor} }, stat.suffix)
64 ),
65 el('div', { className:'bkbg-csw-label' }, stat.label),
66 showDesc ? el('div', { className:'bkbg-csw-desc' }, stat.description) : null,
67 showDiv && divStyle === 'line' ? el('div', { className:'bkbg-csw-divider' }) : null
68 );
69 }
70
71 var BkbgColorSwatch = function (props) {
72 var _st = useState(false); var isOpen = _st[0]; var setOpen = _st[1];
73 return el(Fragment, {},
74 el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '8px' } },
75 el('span', { style: { fontSize: '11px', fontWeight: 500, textTransform: 'uppercase', color: '#1e1e1e' } }, props.label),
76 el('button', {
77 type: 'button',
78 onClick: function () { setOpen(!isOpen); },
79 style: { width: '28px', height: '28px', borderRadius: '4px', border: '1px solid #ccc', background: props.value || '#ffffff', cursor: 'pointer', padding: 0 }
80 })
81 ),
82 isOpen && el(Popover, { onClose: function () { setOpen(false); } },
83 el('div', { style: { padding: '8px' } },
84 el(ColorPicker, { color: props.value, onChangeComplete: function (c) { props.onChange(c.hex); }, enableAlpha: true })
85 )
86 )
87 );
88 };
89
90 registerBlockType('blockenberg/creative-stats-waterfall', {
91 edit: function (props) {
92 var a = props.attributes;
93 var setAttr = props.setAttributes;
94 var stats = a.stats;
95
96 var _edit = useState(null);
97 var editId = _edit[0]; var setEditId = _edit[1];
98
99 function updateStat(id, patch) {
100 setAttr({ stats: stats.map(function(s){ return s.id===id ? Object.assign({},s,patch) : s; }) });
101 }
102
103 var blockProps = useBlockProps({
104 className: 'bkbg-csw-wrap bkbg-csw-layout--' + a.layout,
105 style: wrapStyle(a)
106 });
107
108 function statRow(stat, idx) {
109 var isEdit = editId === stat.id;
110 return el('div', { key:stat.id },
111 el('div', { style:{display:'flex',alignItems:'center',gap:'6px',background:isEdit?'#f3f0ff':'#f8f9fa',border:isEdit?'1px solid #6c3fb5':'1px solid #e2e8f0',borderRadius:'6px',padding:'6px 8px',marginBottom:'4px',cursor:'pointer'}, onClick:function(){ setEditId(isEdit?null:stat.id); } },
112 el('span', { style:{width:12,height:12,borderRadius:'50%',background:stat.accentColor,display:'inline-block',flexShrink:0} }),
113 el('span', { style:{flex:1,fontSize:'13px',fontWeight:500} }, stat.prefix + stat.value + stat.suffix + '' + stat.label),
114 el(Button, { icon:'arrow-up', isSmall:true, disabled:idx===0, onClick:function(e){ e.stopPropagation(); setAttr({stats:move(stats,idx,idx-1)}); } }),
115 el(Button, { icon:'arrow-down', isSmall:true, disabled:idx===stats.length-1, onClick:function(e){ e.stopPropagation(); setAttr({stats:move(stats,idx,idx+1)}); } }),
116 el(Button, { icon:'no-alt', isSmall:true, isDestructive:true, onClick:function(e){ e.stopPropagation(); setAttr({stats:stats.filter(function(_,i){ return i!==idx; })}); if(editId===stat.id) setEditId(null); } })
117 ),
118 isEdit ? el('div', { style:{padding:'10px',background:'#faf8ff',border:'1px solid #6c3fb5',borderTop:'none',borderRadius:'0 0 6px 6px',marginBottom:'4px'} },
119 el('div', { style:{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:'8px'} },
120 el(TextControl, { label:__('Prefix','blockenberg'), value:stat.prefix, onChange:function(v){ updateStat(stat.id,{prefix:v}); } }),
121 el(TextControl, { label:__('Value','blockenberg'), value:stat.value, onChange:function(v){ updateStat(stat.id,{value:v}); } }),
122 el(TextControl, { label:__('Suffix','blockenberg'), value:stat.suffix, onChange:function(v){ updateStat(stat.id,{suffix:v}); } })
123 ),
124 el(TextControl, { label:__('Label','blockenberg'), value:stat.label, onChange:function(v){ updateStat(stat.id,{label:v}); } }),
125 el(TextControl, { label:__('Description','blockenberg'), value:stat.description, onChange:function(v){ updateStat(stat.id,{description:v}); } }),
126 el(BkbgColorSwatch, { label:__('Accent color','blockenberg'),value:stat.accentColor, onChange:function(v){ updateStat(stat.id,{accentColor:v}); } })
127 ) : null
128 );
129 }
130
131 var inspector = el(InspectorControls, null,
132 el(PanelBody, { title:__('Stats','blockenberg'), initialOpen:true },
133 stats.map(function(s,i){ return statRow(s,i); }),
134 el(Button, { variant:'primary', style:{marginTop:'8px',width:'100%'},
135 onClick:function(){
136 var n={id:uid(),prefix:'',value:'0',suffix:'',label:'New Stat',description:'',accentColor:'#6c3fb5'};
137 setAttr({stats:stats.concat([n])});
138 setEditId(n.id);
139 }
140 }, __('+ Add Stat','blockenberg'))
141 ),
142 el(PanelBody, { title:__('Layout','blockenberg'), initialOpen:false },
143 el(SelectControl, { label:__('Layout style','blockenberg'), value:a.layout, options:[
144 {label:'Waterfall (offset)',value:'waterfall'},
145 {label:'Grid (uniform)', value:'grid'},
146 {label:'Horizontal row', value:'row'},
147 ], onChange:function(v){ setAttr({layout:v}); } }),
148 el(RangeControl, { label:__('Columns','blockenberg'), value:a.columns, min:2, max:6, onChange:function(v){ setAttr({columns:v}); } }),
149 el(RangeControl, { label:__('Waterfall offset (px)','blockenberg'), value:a.waterfallOffset, min:0, max:100, onChange:function(v){ setAttr({waterfallOffset:v}); } }),
150 el(RangeControl, { label:__('Gap (px)','blockenberg'), value:a.gap, min:0, max:80, onChange:function(v){ setAttr({gap:v}); } }),
151 el(ToggleControl, { label:__('Show descriptions','blockenberg'), checked:a.showDescription, onChange:function(v){ setAttr({showDescription:v}); } }),
152 el(ToggleControl, { label:__('Show dividers','blockenberg'), checked:a.showDivider, onChange:function(v){ setAttr({showDivider:v}); } }),
153 el(SelectControl, { label:__('Divider style','blockenberg'), value:a.dividerStyle, options:[
154 {label:'Line',value:'line'},
155 {label:'Dot',value:'dot'},
156 ], onChange:function(v){ setAttr({dividerStyle:v}); } })
157 ),
158 el(PanelBody, { title:__('Typography','blockenberg'), initialOpen:false },
159 _tc() && el(_tc(), { label: __('Number', 'blockenberg'), value: a.typoNumber, onChange: function (v) { setAttr({ typoNumber: v }); } }),
160 _tc() && el(_tc(), { label: __('Label', 'blockenberg'), value: a.typoLabel, onChange: function (v) { setAttr({ typoLabel: v }); } }),
161 _tc() && el(_tc(), { label: __('Description', 'blockenberg'), value: a.typoDesc, onChange: function (v) { setAttr({ typoDesc: v }); } })
162 ),
163 el(PanelBody, { title:__('Spacing','blockenberg'), initialOpen:false },
164 el(RangeControl, { label:__('Padding top (px)','blockenberg'), value:a.paddingTop, min:0, max:160, onChange:function(v){ setAttr({paddingTop:v}); } }),
165 el(RangeControl, { label:__('Padding bottom (px)','blockenberg'), value:a.paddingBottom, min:0, max:160, onChange:function(v){ setAttr({paddingBottom:v}); } })
166 ),
167 el(PanelColorSettings, { title:__('Colors','blockenberg'), initialOpen:false, colorSettings:[
168 {label:__('Section bg','blockenberg'), value:a.sectionBg, onChange:function(v){ setAttr({sectionBg:v||''}); }},
169 {label:__('Number color','blockenberg'), value:a.numberColor, onChange:function(v){ setAttr({numberColor:v||''}); }},
170 {label:__('Prefix / suffix','blockenberg'), value:a.prefixSuffixColor, onChange:function(v){ setAttr({prefixSuffixColor:v||''}); }},
171 {label:__('Label color','blockenberg'), value:a.labelColor, onChange:function(v){ setAttr({labelColor:v||''}); }},
172 {label:__('Description color','blockenberg'),value:a.descColor, onChange:function(v){ setAttr({descColor:v||''}); }},
173 {label:__('Divider color','blockenberg'), value:a.dividerColor, onChange:function(v){ setAttr({dividerColor:v||''}); }},
174 ] })
175 );
176
177 return el(Fragment, null,
178 inspector,
179 el('div', blockProps,
180 el('div', { className:'bkbg-csw-grid', style:{gridTemplateColumns:'repeat('+a.columns+',1fr)'} },
181 stats.map(function(stat, idx) {
182 return el(StatCard, { key:stat.id, stat:stat, idx:idx, layout:a.layout, showDesc:a.showDescription, showDiv:a.showDivider, divStyle:a.dividerStyle });
183 })
184 )
185 )
186 );
187 },
188
189 save: function (props) {
190 var a = props.attributes;
191 var blockProps = wp.blockEditor.useBlockProps.save({
192 className:'bkbg-csw-wrap bkbg-csw-layout--'+a.layout,
193 style: Object.assign({
194 '--bkbg-csw-pt':a.paddingTop+'px','--bkbg-csw-pb':a.paddingBottom+'px','--bkbg-csw-num-c':a.numberColor||undefined,'--bkbg-csw-ps-c':a.prefixSuffixColor||undefined,'--bkbg-csw-label-c':a.labelColor,'--bkbg-csw-desc-c':a.descColor,'--bkbg-csw-div-c':a.dividerColor,'--bkbg-csw-num-sz':a.numberSize+'px','--bkbg-csw-label-sz':a.labelSize+'px','--bkbg-csw-desc-sz':a.descSize+'px','--bkbg-csw-gap':a.gap+'px','--bkbg-csw-offset':a.waterfallOffset+'px',background:a.sectionBg||undefined,
195 }, _tv(a.typoNumber, '--bkbg-csw-num-'), _tv(a.typoLabel, '--bkbg-csw-lbl-'), _tv(a.typoDesc, '--bkbg-csw-dsc-'))
196 });
197 return el('div', blockProps,
198 el('div', { className:'bkbg-csw-grid', style:{gridTemplateColumns:'repeat('+a.columns+',1fr)'} },
199 a.stats.map(function(stat, idx) {
200 var topOffset = a.layout==='waterfall' ? (idx%2===1?'var(--bkbg-csw-offset)':'0') : '0';
201 return el('div', { key:stat.id, className:'bkbg-csw-stat', style:{marginTop:topOffset,borderColor:stat.accentColor||undefined} },
202 el('div', { className:'bkbg-csw-number-row' },
203 el('span', { className:'bkbg-csw-prefix' }, stat.prefix),
204 el('span', { className:'bkbg-csw-value', style:{color:stat.accentColor} }, stat.value),
205 el('span', { className:'bkbg-csw-suffix', style:{color:stat.accentColor} }, stat.suffix)
206 ),
207 el('div', { className:'bkbg-csw-label' }, stat.label),
208 a.showDescription ? el('div', { className:'bkbg-csw-desc' }, stat.description) : null,
209 a.showDivider && a.dividerStyle==='line' ? el('div', { className:'bkbg-csw-divider' }) : null
210 );
211 })
212 )
213 );
214 }
215 });
216 }() );
217