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 / awards / index.js

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

323 lines 22.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function () {
2 var el = wp.element.createElement;
3 var Fragment = wp.element.Fragment;
4 var useState = wp.element.useState;
5 var __ = wp.i18n.__;
6 var registerBlockType = wp.blocks.registerBlockType;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var RichText = wp.blockEditor.RichText;
9 var useBlockProps = wp.blockEditor.useBlockProps;
10 var MediaUpload = wp.blockEditor.MediaUpload;
11 var MediaUploadCheck = wp.blockEditor.MediaUploadCheck;
12 var PanelBody = wp.components.PanelBody;
13 var Button = wp.components.Button;
14 var ToggleControl = wp.components.ToggleControl;
15 var RangeControl = wp.components.RangeControl;
16 var SelectControl = wp.components.SelectControl;
17 var TextControl = wp.components.TextControl;
18 var TextareaControl = wp.components.TextareaControl;
19 var ColorPicker = wp.components.ColorPicker;
20 var Popover = wp.components.Popover;
21 var IP = function () { return window.bkbgIconPicker; };
22
23 function getTypographyControl() {
24 return (typeof window.bkbgTypographyControl !== 'undefined') ? window.bkbgTypographyControl : null;
25 }
26 function getTypoCssVars() {
27 return (typeof window.bkbgTypoCssVars !== 'undefined') ? window.bkbgTypoCssVars : function() { return {}; };
28 }
29
30 function makeId() { return 'aw' + Math.random().toString(36).substr(2, 5); }
31
32 function buildWrapStyle(a) {
33 var _tv = getTypoCssVars();
34 var s = {
35 '--bkbg-aw-accent': a.accentColor,
36 '--bkbg-aw-card-bg': a.cardBg,
37 '--bkbg-aw-card-border': a.cardBorder,
38 '--bkbg-aw-title-color': a.titleColor,
39 '--bkbg-aw-sect-title': a.sectionTitleColor,
40 '--bkbg-aw-sub-color': a.subtitleColor,
41 '--bkbg-aw-award-title': a.awardTitleColor,
42 '--bkbg-aw-issuer': a.issuerColor,
43 '--bkbg-aw-year': a.yearColor,
44 '--bkbg-aw-desc': a.descColor,
45 '--bkbg-aw-card-r': a.cardRadius + 'px',
46 '--bkbg-aw-icon-r': a.iconBgRadius + 'px',
47 '--bkbg-aw-gap': a.gap + 'px',
48 '--bkbg-aw-cols': a.columns,
49 '--bkbg-aw-title-sz': a.titleSize + 'px',
50 '--bkbg-aw-award-sz': a.awardTitleSize + 'px',
51 '--bkbg-aw-issuer-sz': a.issuerSize + 'px',
52 '--bkbg-aw-desc-sz': a.descSize + 'px',
53 '--bkbg-aw-icon-sz': a.iconSize + 'px',
54 paddingTop: a.paddingTop + 'px',
55 paddingBottom: a.paddingBottom + 'px',
56 backgroundColor: a.bgColor || undefined,
57 };
58 Object.assign(s, _tv(a.sectionTitleTypo || {}, '--bkbg-aw-stitle-'));
59 Object.assign(s, _tv(a.subtitleTypo || {}, '--bkbg-aw-sub-'));
60 Object.assign(s, _tv(a.awardTitleTypo || {}, '--bkbg-aw-atitle-'));
61 Object.assign(s, _tv(a.issuerTypo || {}, '--bkbg-aw-iss-'));
62 Object.assign(s, _tv(a.descTypo || {}, '--bkbg-aw-dsc-'));
63 return s;
64 }
65
66 function renderColorControl(key, label, value, onChange, openKey, setOpenKey) {
67 var isOpen = openKey === key;
68 return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } },
69 el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1, lineHeight: 1.4 } }, label),
70 el('div', { style: { position: 'relative', flexShrink: 0 } },
71 el('button', { type: 'button', onClick: function () { setOpenKey(isOpen ? null : key); }, style: { width: '28px', height: '28px', borderRadius: '4px', border: isOpen ? '2px solid #007cba' : '2px solid #ddd', cursor: 'pointer', padding: 0, background: value || '#ccc' } }),
72 isOpen && el(Popover, { position: 'bottom left', onClose: function () { setOpenKey(null); } },
73 el('div', { style: { padding: '8px' } },
74 el(ColorPicker, { color: value, enableAlpha: true, onChange: onChange })
75 )
76 )
77 )
78 );
79 }
80
81 /* ── Single award card ────────────────────────────────────────── */
82 function AwardCard(props) {
83 var award = props.award;
84 var a = props.a;
85 var iconBgColor = award.color || a.accentColor;
86
87 /* Luminance-based contrast for icon bg text */
88 function hexLuma(hex) {
89 var c = hex.replace('#','');
90 if (c.length === 3) c = c[0]+c[0]+c[1]+c[1]+c[2]+c[2];
91 var r = parseInt(c.substr(0,2),16), g = parseInt(c.substr(2,2),16), b = parseInt(c.substr(4,2),16);
92 return 0.299*r + 0.587*g + 0.114*b;
93 }
94 var iconTextColor = hexLuma(iconBgColor) > 140 ? '#333' : '#fff';
95
96 return el('div', { className: 'bkbg-aw-card', style: {
97 background: a.cardBg,
98 border: '1.5px solid ' + a.cardBorder,
99 borderRadius: a.cardRadius + 'px',
100 padding: '28px 22px',
101 display: 'flex',
102 flexDirection: 'column',
103 alignItems: 'flex-start',
104 gap: '12px',
105 transition: 'box-shadow 0.2s, transform 0.2s',
106 }},
107 /* Icon / image */
108 el('div', { style: {
109 width: a.iconSize + 'px', height: a.iconSize + 'px',
110 borderRadius: a.iconBgRadius + 'px',
111 background: iconBgColor,
112 display: 'flex', alignItems: 'center', justifyContent: 'center',
113 flexShrink: 0, fontSize: Math.round(a.iconSize * 0.52) + 'px',
114 overflow: 'hidden', color: iconTextColor,
115 }},
116 award.imageUrl
117 ? el('img', { src: award.imageUrl, alt: award.title, style: { width: '100%', height: '100%', objectFit: 'cover' } })
118 : (award.iconType || 'custom-char') !== 'custom-char'
119 ? IP().buildEditorIcon(award.iconType, award.icon, award.iconDashicon, award.iconImageUrl, award.iconDashiconColor)
120 : el('span', null, award.icon || '🏆')
121 ),
122
123 /* Content */
124 el('div', { style: { flex: 1, minWidth: 0, width: '100%' } },
125 el('div', { style: { display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: '8px', marginBottom: '6px' } },
126 el('p', { className: 'bkbg-aw-award-title', style: { margin: 0, color: a.awardTitleColor, flex: 1, minWidth: 0 } }, award.title),
127 a.showYear && award.year && el('span', { className: 'bkbg-aw-year', style: { color: a.yearColor, background: a.yearColor + '18', padding: '2px 8px', borderRadius: '99px', flexShrink: 0, whiteSpace: 'nowrap' } }, award.year)
128 ),
129 a.showIssuer && award.issuer && el('p', { className: 'bkbg-aw-issuer', style: { margin: '0 0 6px', color: a.issuerColor } }, award.issuer),
130 a.showDescription && award.description && el('p', { className: 'bkbg-aw-desc', style: { margin: 0, color: a.descColor } }, award.description)
131 )
132 );
133 }
134
135 registerBlockType('blockenberg/awards', {
136 title: __('Awards & Recognition', 'blockenberg'),
137 icon: 'awards',
138 category: 'bkbg-business',
139
140 edit: function (props) {
141 var a = props.attributes;
142 var setAttributes = props.setAttributes;
143
144 var openColorKeyState = useState(null);
145 var openColorKey = openColorKeyState[0];
146 var setOpenColorKey = openColorKeyState[1];
147
148 var editAwardState = useState(null);
149 var editAwardId = editAwardState[0];
150 var setEditAwardId = editAwardState[1];
151
152 var blockProps = useBlockProps({ style: buildWrapStyle(a) });
153
154 function cc(key, label, attrKey) {
155 return renderColorControl(key, label, a[attrKey], function (val) {
156 var upd = {}; upd[attrKey] = val; setAttributes(upd);
157 }, openColorKey, setOpenColorKey);
158 }
159
160 function updateAward(id, key, val) {
161 setAttributes({ awards: a.awards.map(function (aw) {
162 if (aw.id !== id) return aw;
163 var u = Object.assign({}, aw); u[key] = val; return u;
164 }) });
165 }
166
167 function removeAward(id) {
168 setAttributes({ awards: a.awards.filter(function (aw) { return aw.id !== id; }) });
169 }
170
171 function addAward() {
172 var newId = makeId();
173 setAttributes({ awards: a.awards.concat([{ id: newId, title: 'New Award', issuer: 'Organization', year: new Date().getFullYear().toString(), description: 'Award description.', icon: '🏆', iconType: 'custom-char', iconDashicon: '', iconImageUrl: '', imageUrl: '', imageId: 0, color: '', url: '' }]) });
174 setEditAwardId(newId);
175 }
176
177 /* Grid style for editor preview */
178 var gridStyle = {
179 display: 'grid',
180 gridTemplateColumns: 'repeat(' + a.columns + ', 1fr)',
181 gap: a.gap + 'px',
182 };
183
184 return el(Fragment, null,
185 el(InspectorControls, null,
186 el(PanelBody, { title: __('Awards', 'blockenberg'), initialOpen: true },
187 a.awards.map(function (aw) {
188 var isEdit = editAwardId === aw.id;
189 return el('div', { key: aw.id, style: { border: '1px solid #e0e0e0', borderRadius: '8px', marginBottom: '8px', overflow: 'hidden' } },
190 el('div', { onClick: function () { setEditAwardId(isEdit ? null : aw.id); },
191 style: { display: 'flex', alignItems: 'center', gap: '8px', padding: '8px 10px', cursor: 'pointer', background: isEdit ? '#f0e9ff' : '#fafafa' } },
192 el('span', { style: { fontSize: '20px', flexShrink: 0 } }, aw.icon || '🏆'),
193 el('div', { style: { flex: 1, overflow: 'hidden' } },
194 el('p', { style: { margin: 0, fontSize: '12px', fontWeight: 700, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, aw.title),
195 el('p', { style: { margin: 0, fontSize: '11px', color: '#888' } }, aw.issuer + (aw.year ? ' · ' + aw.year : ''))
196 )
197 ),
198 isEdit && el('div', { style: { padding: '10px', borderTop: '1px solid #e0e0e0' } },
199 el(TextControl, { label: __('Award title', 'blockenberg'), value: aw.title, onChange: function (v) { updateAward(aw.id, 'title', v); } }),
200 el(TextControl, { label: __('Issuer', 'blockenberg'), value: aw.issuer, onChange: function (v) { updateAward(aw.id, 'issuer', v); } }),
201 el(TextControl, { label: __('Year', 'blockenberg'), value: aw.year, onChange: function (v) { updateAward(aw.id, 'year', v); } }),
202 el(IP().IconPickerControl, {
203 iconType: aw.iconType, customChar: aw.icon, dashicon: aw.iconDashicon, imageUrl: aw.iconImageUrl,
204 onChangeType: function (v) { updateAward(aw.id, 'iconType', v); },
205 onChangeChar: function (v) { updateAward(aw.id, 'icon', v); },
206 onChangeDashicon: function (v) { updateAward(aw.id, 'iconDashicon', v); },
207 onChangeImageUrl: function (v) { updateAward(aw.id, 'iconImageUrl', v); }
208 }),
209 el(TextareaControl, { label: __('Description', 'blockenberg'), value: aw.description, onChange: function (v) { updateAward(aw.id, 'description', v); }, rows: 3 }),
210 el(TextControl, { label: __('Link URL (optional)', 'blockenberg'), value: aw.url, onChange: function (v) { updateAward(aw.id, 'url', v); } }),
211 el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '8px' } },
212 el('span', { style: { fontSize: '12px', fontWeight: 600 } }, __('Icon bg color:', 'blockenberg')),
213 el('input', { type: 'color', value: aw.color || a.accentColor, onChange: function (e) { updateAward(aw.id, 'color', e.target.value); }, style: { width: '32px', height: '28px', padding: 0, border: 'none', cursor: 'pointer', background: 'none' } })
214 ),
215 /* Image upload */
216 el(MediaUploadCheck, null,
217 el(MediaUpload, { onSelect: function (m) { updateAward(aw.id, 'imageUrl', m.url); updateAward(aw.id, 'imageId', m.id); }, allowedTypes: ['image'], value: aw.imageId,
218 render: function (mp) {
219 return el(Fragment, null,
220 aw.imageUrl && el('img', { src: aw.imageUrl, style: { width: '48px', height: '48px', borderRadius: aw.color ? a.iconBgRadius + 'px' : '50%', objectFit: 'cover', display: 'block', marginBottom: '6px' } }),
221 el(Button, { variant: 'secondary', size: 'compact', onClick: mp.open }, aw.imageUrl ? __('Change image', 'blockenberg') : __('Upload image', 'blockenberg')),
222 aw.imageUrl && el(Button, { variant: 'tertiary', size: 'compact', isDestructive: true, onClick: function () { updateAward(aw.id, 'imageUrl', ''); updateAward(aw.id, 'imageId', 0); }, style: { marginLeft: '6px' } }, __('Remove', 'blockenberg'))
223 );
224 }
225 })
226 ),
227 el('div', { style: { marginTop: '10px' } },
228 el(Button, { isDestructive: true, variant: 'tertiary', size: 'compact', onClick: function () { removeAward(aw.id); } }, __('Remove award', 'blockenberg'))
229 )
230 )
231 );
232 }),
233 el(Button, { variant: 'secondary', onClick: addAward, style: { width: '100%', justifyContent: 'center' } }, '+ ' + __('Add Award', 'blockenberg'))
234 ),
235 el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: false },
236 el(SelectControl, { label: __('Layout', 'blockenberg'), value: a.layout, options: [{ label: __('Grid', 'blockenberg'), value: 'grid' }, { label: __('List', 'blockenberg'), value: 'list' }], onChange: function (v) { setAttributes({ layout: v }); } }),
237 a.layout === 'grid' && el(RangeControl, { label: __('Columns', 'blockenberg'), value: a.columns, min: 1, max: 4, onChange: function (v) { setAttributes({ columns: v }); } }),
238 el(RangeControl, { label: __('Gap (px)', 'blockenberg'), value: a.gap, min: 8, max: 60, onChange: function (v) { setAttributes({ gap: v }); } })
239 ),
240 el(PanelBody, { title: __('Display', 'blockenberg'), initialOpen: false },
241 el(ToggleControl, { label: __('Show section title', 'blockenberg'), checked: a.showTitle, onChange: function (v) { setAttributes({ showTitle: v }); }, __nextHasNoMarginBottom: true }),
242 el(ToggleControl, { label: __('Show subtitle', 'blockenberg'), checked: a.showSubtitle, onChange: function (v) { setAttributes({ showSubtitle: v }); }, __nextHasNoMarginBottom: true }),
243 el(ToggleControl, { label: __('Show year', 'blockenberg'), checked: a.showYear, onChange: function (v) { setAttributes({ showYear: v }); }, __nextHasNoMarginBottom: true }),
244 el(ToggleControl, { label: __('Show issuer', 'blockenberg'), checked: a.showIssuer, onChange: function (v) { setAttributes({ showIssuer: v }); }, __nextHasNoMarginBottom: true }),
245 el(ToggleControl, { label: __('Show description', 'blockenberg'), checked: a.showDescription, onChange: function (v) { setAttributes({ showDescription: v }); }, __nextHasNoMarginBottom: true }),
246 el(RangeControl, { label: __('Icon size (px)', 'blockenberg'), value: a.iconSize, min: 24, max: 80, onChange: function (v) { setAttributes({ iconSize: v }); } })
247 ),
248 el(PanelBody, { title: __('Appearance', 'blockenberg'), initialOpen: false },
249 el(RangeControl, { label: __('Card radius (px)', 'blockenberg'), value: a.cardRadius, min: 0, max: 32, onChange: function (v) { setAttributes({ cardRadius: v }); } }),
250 el(RangeControl, { label: __('Icon bg radius (px)','blockenberg'), value: a.iconBgRadius, min: 0, max: 32, onChange: function (v) { setAttributes({ iconBgRadius: v }); } })
251 ),
252
253 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
254 (function () {
255 var TC = getTypographyControl();
256 if (!TC) return el('p', { style: { color: '#999', fontSize: '12px', padding: '8px 0' } }, __('Typography control loading…', 'blockenberg'));
257 return el(wp.element.Fragment, {},
258 el(TC, { label: __('Section Title', 'blockenberg'), value: a.sectionTitleTypo || {}, onChange: function (v) { setAttributes({ sectionTitleTypo: v }); } }),
259 el(TC, { label: __('Subtitle', 'blockenberg'), value: a.subtitleTypo || {}, onChange: function (v) { setAttributes({ subtitleTypo: v }); } }),
260 el(TC, { label: __('Award Title', 'blockenberg'), value: a.awardTitleTypo || {}, onChange: function (v) { setAttributes({ awardTitleTypo: v }); } }),
261 el(TC, { label: __('Issuer', 'blockenberg'), value: a.issuerTypo || {}, onChange: function (v) { setAttributes({ issuerTypo: v }); } }),
262 el(TC, { label: __('Description', 'blockenberg'), value: a.descTypo || {}, onChange: function (v) { setAttributes({ descTypo: v }); } })
263 );
264 })()
265 ),
266 el(PanelBody, { title: __('Colors', 'blockenberg'), initialOpen: false },
267 cc('accentColor', __('Accent', 'blockenberg'), 'accentColor'),
268 cc('cardBg', __('Card background', 'blockenberg'), 'cardBg'),
269 cc('cardBorder', __('Card border', 'blockenberg'), 'cardBorder'),
270 cc('titleColor', __('Section title', 'blockenberg'), 'titleColor'),
271 cc('sectionTitleColor',__('Section subtitle', 'blockenberg'), 'sectionTitleColor'),
272 cc('subtitleColor', __('Subtitle text', 'blockenberg'), 'subtitleColor'),
273 cc('awardTitleColor', __('Award title', 'blockenberg'), 'awardTitleColor'),
274 cc('issuerColor', __('Issuer text', 'blockenberg'), 'issuerColor'),
275 cc('yearColor', __('Year badge', 'blockenberg'), 'yearColor'),
276 cc('descColor', __('Description', 'blockenberg'), 'descColor'),
277 cc('bgColor', __('Section background','blockenberg'), 'bgColor')
278 ),
279 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
280 el(RangeControl, { label: __('Padding top', 'blockenberg'), value: a.paddingTop, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingTop: v }); } }),
281 el(RangeControl, { label: __('Padding bottom', 'blockenberg'), value: a.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingBottom: v }); } })
282 )
283 ),
284
285 el('div', blockProps,
286 /* Section header */
287 el('div', { style: { textAlign: 'center', marginBottom: '40px' } },
288 a.showTitle && el(RichText, { tagName: 'h2', className: 'bkbg-aw-title', value: a.title, onChange: function (v) { setAttributes({ title: v }); }, placeholder: __('Awards & Recognition', 'blockenberg'), style: { color: a.titleColor, margin: '0 0 10px' } }),
289 a.showSubtitle && el(RichText, { tagName: 'p', className: 'bkbg-aw-subtitle', value: a.subtitle, onChange: function (v) { setAttributes({ subtitle: v }); }, placeholder: __('Our achievements and certifications', 'blockenberg'), style: { color: a.subtitleColor, margin: '8px 0 0', maxWidth: '520px', marginLeft: 'auto', marginRight: 'auto' } })
290 ),
291
292 /* Grid */
293 el('div', { style: a.layout === 'list'
294 ? { display: 'flex', flexDirection: 'column', gap: a.gap + 'px' }
295 : gridStyle },
296 a.awards.map(function (aw) {
297 return el(AwardCard, { key: aw.id, award: aw, a: a });
298 })
299 )
300 )
301 );
302 },
303
304 save: function (props) {
305 var a = props.attributes;
306 return el('div', wp.blockEditor.useBlockProps.save({ className: 'bkbg-aw-wrapper', style: buildWrapStyle(a) }),
307 el('div', { className: 'bkbg-aw-header', style: { textAlign: 'center', marginBottom: '40px' } },
308 a.showTitle && el(RichText.Content, { tagName: 'h2', className: 'bkbg-aw-title', value: a.title }),
309 a.showSubtitle && el(RichText.Content, { tagName: 'p', className: 'bkbg-aw-subtitle', value: a.subtitle })
310 ),
311 el('div', {
312 className: 'bkbg-aw-grid',
313 'data-awards': JSON.stringify(a.awards),
314 'data-layout': a.layout,
315 'data-show-year': a.showYear ? '1' : '0',
316 'data-show-issuer': a.showIssuer ? '1' : '0',
317 'data-show-desc': a.showDescription ? '1' : '0',
318 })
319 );
320 }
321 });
322 }() );
323