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 / content-flip-box / index.js

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

377 lines 24.1 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 __ = wp.i18n.__;
5 var useState = wp.element.useState;
6 var registerBlockType = wp.blocks.registerBlockType;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var useBlockProps = wp.blockEditor.useBlockProps;
9 var PanelBody = wp.components.PanelBody;
10 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
11 var ToggleControl = wp.components.ToggleControl;
12 var RangeControl = wp.components.RangeControl;
13 var SelectControl = wp.components.SelectControl;
14 var TextControl = wp.components.TextControl;
15 var Button = wp.components.Button;
16 var IP = function () { return window.bkbgIconPicker; };
17
18 var _TC, _tv;
19 Object.defineProperty(window, '_bkbgCFBgetTC', { get: function () { return _TC || (_TC = window.bkbgTypographyControl); } });
20 Object.defineProperty(window, '_bkbgCFBgetTV', { get: function () { return _tv || (_tv = window.bkbgTypoCssVars); } });
21
22 function genId() {
23 return 'cfb_' + Math.random().toString(36).substr(2, 9);
24 }
25
26 var defaultItem = function (n) {
27 return {
28 id: genId(),
29 frontIcon: '', frontIconType: 'custom-char', frontIconDashicon: '', frontIconImageUrl: '',
30 frontTitle: 'Feature ' + n, frontText: 'A brief front description.',
31 frontBg: '#6c3fb5', frontColor: '#ffffff',
32 backIcon: '🔥', backIconType: 'custom-char', backIconDashicon: '', backIconImageUrl: '',
33 backTitle: 'Learn More', backText: 'This is the back side with more details about this feature.',
34 backBg: '#4f2d8a', backColor: '#ffffff',
35 backBtnText: 'Explore', backBtnUrl: '#', backBtnBg: '#ffffff', backBtnColor: '#4f2d8a'
36 };
37 };
38
39 registerBlockType('blockenberg/content-flip-box', {
40 title: __('Content Flip Box', 'blockenberg'),
41 icon: 'image-rotate',
42 category: 'bkbg-effects',
43 description: __('Grid of cards that flip on hover or click to reveal a styled back face.', 'blockenberg'),
44
45 edit: function (props) {
46 var a = props.attributes;
47 var setAttributes = props.setAttributes;
48 var TC = window._bkbgCFBgetTC;
49 var tv = window._bkbgCFBgetTV || function () { return {}; };
50 var activeState = useState(null);
51 var activeId = activeState[0];
52 var setActiveId = activeState[1];
53 // flippedIds: set of item IDs showing back face in editor
54 var flippedState = useState({});
55 var flipped = flippedState[0];
56 var setFlipped = flippedState[1];
57
58 var activeItem = activeId ? a.items.find(function (it) { return it.id === activeId; }) : null;
59
60 function updateItem(id, field, value) {
61 setAttributes({
62 items: a.items.map(function (it) {
63 if (it.id !== id) return it;
64 var u = Object.assign({}, it);
65 u[field] = value;
66 return u;
67 })
68 });
69 }
70
71 function removeItem(id) {
72 if (a.items.length <= 1) return;
73 setAttributes({ items: a.items.filter(function (it) { return it.id !== id; }) });
74 if (activeId === id) setActiveId(null);
75 }
76
77 function addItem() {
78 var it = defaultItem(a.items.length + 1);
79 setAttributes({ items: a.items.concat([it]) });
80 setActiveId(it.id);
81 }
82
83 function moveItem(index, dir) {
84 var items = a.items.slice();
85 var t = index + dir;
86 if (t < 0 || t >= items.length) return;
87 var tmp = items[index]; items[index] = items[t]; items[t] = tmp;
88 setAttributes({ items: items });
89 }
90
91 function toggleFlip(id) {
92 var nf = Object.assign({}, flipped);
93 nf[id] = !nf[id];
94 setFlipped(nf);
95 }
96
97 var flipDirOptions = [
98 { label: __('Horizontal (Y-axis)', 'blockenberg'), value: 'horizontal' },
99 { label: __('Vertical (X-axis)', 'blockenberg'), value: 'vertical' },
100 { label: __('Fade', 'blockenberg'), value: 'fade' }
101 ];
102 var flipTriggerOptions = [
103 { label: __('On Hover', 'blockenberg'), value: 'hover' },
104 { label: __('On Click', 'blockenberg'), value: 'click' }
105 ];
106 var alignOptions = [
107 { label: __('Left', 'blockenberg'), value: 'left' },
108 { label: __('Center', 'blockenberg'), value: 'center' },
109 { label: __('Right', 'blockenberg'), value: 'right' }
110 ];
111
112 var inspector = el(InspectorControls, {},
113 // Items list
114 el(PanelBody, { title: __('Items', 'blockenberg'), initialOpen: true },
115 a.items.map(function (item, idx) {
116 var isActive = item.id === activeId;
117 return el('div', {
118 key: item.id,
119 style: {
120 marginBottom: '8px', padding: '8px 10px',
121 background: isActive ? '#ede9fe' : '#f8fafc',
122 border: '1px solid ' + (isActive ? '#c4b5fd' : '#e2e8f0'),
123 borderRadius: '6px', cursor: 'pointer'
124 },
125 onClick: function () { setActiveId(isActive ? null : item.id); }
126 },
127 el('div', { style: { display: 'flex', alignItems: 'center', gap: '6px' } },
128 el('span', { style: { fontSize: '18px' } }, item.frontIcon),
129 el('span', { style: { flex: 1, fontSize: '13px', fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, item.frontTitle),
130 el('div', { style: { display: 'flex', gap: '2px' } },
131 el(Button, { isSmall: true, variant: 'tertiary', onClick: function (e) { e.stopPropagation(); moveItem(idx, -1); }, disabled: idx === 0 }, ''),
132 el(Button, { isSmall: true, variant: 'tertiary', onClick: function (e) { e.stopPropagation(); moveItem(idx, 1); }, disabled: idx === a.items.length - 1 }, ''),
133 el(Button, { isSmall: true, variant: 'tertiary', isDestructive: true, onClick: function (e) { e.stopPropagation(); removeItem(item.id); }, disabled: a.items.length <= 1 }, '')
134 )
135 )
136 );
137 }),
138 el('div', { style: { marginTop: '8px' } },
139 el(Button, { variant: 'secondary', onClick: addItem, style: { width: '100%', justifyContent: 'center' } },
140 '+ ' + __('Add Card', 'blockenberg')
141 )
142 )
143 ),
144
145 // Active item editor
146 activeItem && el(PanelBody, { title: '' + __('Edit Card', 'blockenberg') + ': ' + activeItem.frontTitle, initialOpen: true },
147 el('p', { style: { fontSize: '11px', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.5px', color: '#6c3fb5', margin: '0 0 8px' } }, __('Front Face', 'blockenberg')),
148 el(IP().IconPickerControl, {
149 iconType: activeItem.frontIconType, customChar: activeItem.frontIcon, dashicon: activeItem.frontIconDashicon, imageUrl: activeItem.frontIconImageUrl,
150 onChangeType: function (v) { updateItem(activeId, 'frontIconType', v); },
151 onChangeChar: function (v) { updateItem(activeId, 'frontIcon', v); },
152 onChangeDashicon: function (v) { updateItem(activeId, 'frontIconDashicon', v); },
153 onChangeImageUrl: function (v) { updateItem(activeId, 'frontIconImageUrl', v); }
154 }),
155 el('div', { style: { marginTop: '8px' } },
156 el(TextControl, { label: __('Title', 'blockenberg'), value: activeItem.frontTitle, onChange: function (v) { updateItem(activeId, 'frontTitle', v); }, __nextHasNoMarginBottom: true })
157 ),
158 el('div', { style: { marginTop: '8px' } },
159 el(TextControl, { label: __('Text', 'blockenberg'), value: activeItem.frontText, onChange: function (v) { updateItem(activeId, 'frontText', v); }, __nextHasNoMarginBottom: true })
160 ),
161 el(PanelColorSettings, {
162 title: __('Front Colors', 'blockenberg'),
163 initialOpen: false,
164 colorSettings: [
165 { value: activeItem.frontBg, onChange: function (c) { updateItem(activeId, 'frontBg', c || ''); }, label: __('Background', 'blockenberg') },
166 { value: activeItem.frontColor, onChange: function (c) { updateItem(activeId, 'frontColor', c || ''); }, label: __('Text Color', 'blockenberg') }
167 ]
168 }),
169 el('hr', { style: { margin: '12px 0', border: 'none', borderTop: '1px solid #e2e8f0' } }),
170 el('p', { style: { fontSize: '11px', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.5px', color: '#2563eb', margin: '0 0 8px' } }, __('Back Face', 'blockenberg')),
171 el(IP().IconPickerControl, {
172 iconType: activeItem.backIconType, customChar: activeItem.backIcon, dashicon: activeItem.backIconDashicon, imageUrl: activeItem.backIconImageUrl,
173 onChangeType: function (v) { updateItem(activeId, 'backIconType', v); },
174 onChangeChar: function (v) { updateItem(activeId, 'backIcon', v); },
175 onChangeDashicon: function (v) { updateItem(activeId, 'backIconDashicon', v); },
176 onChangeImageUrl: function (v) { updateItem(activeId, 'backIconImageUrl', v); }
177 }),
178 el('div', { style: { marginTop: '8px' } },
179 el(TextControl, { label: __('Title', 'blockenberg'), value: activeItem.backTitle, onChange: function (v) { updateItem(activeId, 'backTitle', v); }, __nextHasNoMarginBottom: true })
180 ),
181 el('div', { style: { marginTop: '8px' } },
182 el(TextControl, { label: __('Text', 'blockenberg'), value: activeItem.backText, onChange: function (v) { updateItem(activeId, 'backText', v); }, __nextHasNoMarginBottom: true })
183 ),
184 el('div', { style: { marginTop: '8px' } },
185 el(TextControl, { label: __('Button Text', 'blockenberg'), value: activeItem.backBtnText, onChange: function (v) { updateItem(activeId, 'backBtnText', v); }, __nextHasNoMarginBottom: true })
186 ),
187 el('div', { style: { marginTop: '8px' } },
188 el(TextControl, { label: __('Button URL', 'blockenberg'), value: activeItem.backBtnUrl, onChange: function (v) { updateItem(activeId, 'backBtnUrl', v); }, __nextHasNoMarginBottom: true })
189 ),
190 el(PanelColorSettings, {
191 title: __('Back Colors', 'blockenberg'),
192 initialOpen: false,
193 colorSettings: [
194 { value: activeItem.backBg, onChange: function (c) { updateItem(activeId, 'backBg', c || ''); }, label: __('Background', 'blockenberg') },
195 { value: activeItem.backColor, onChange: function (c) { updateItem(activeId, 'backColor', c || ''); }, label: __('Text Color', 'blockenberg') },
196 { value: activeItem.backBtnBg, onChange: function (c) { updateItem(activeId, 'backBtnBg', c || ''); }, label: __('Button Background', 'blockenberg') },
197 { value: activeItem.backBtnColor, onChange: function (c) { updateItem(activeId, 'backBtnColor', c || ''); }, label: __('Button Text', 'blockenberg') }
198 ]
199 })
200 ),
201
202 // Grid settings
203 el(PanelBody, { title: __('Grid & Layout', 'blockenberg'), initialOpen: false },
204 el(RangeControl, { label: __('Columns', 'blockenberg'), value: a.columns, min: 1, max: 6, onChange: function (v) { setAttributes({ columns: v }); } }),
205 el(RangeControl, { label: __('Gap', 'blockenberg'), value: a.gap, min: 0, max: 60, onChange: function (v) { setAttributes({ gap: v }); } }),
206 el(RangeControl, { label: __('Card Height (px)', 'blockenberg'), value: a.cardHeight, min: 160, max: 600, onChange: function (v) { setAttributes({ cardHeight: v }); } }),
207 el(RangeControl, { label: __('Border Radius', 'blockenberg'), value: a.borderRadius, min: 0, max: 40, onChange: function (v) { setAttributes({ borderRadius: v }); } }),
208 el(SelectControl, { label: __('Text Align', 'blockenberg'), value: a.textAlign, options: alignOptions, onChange: function (v) { setAttributes({ textAlign: v }); } })
209 ),
210
211 // Flip settings
212 el(PanelBody, { title: __('Flip Settings', 'blockenberg'), initialOpen: false },
213 el(SelectControl, { label: __('Flip Direction', 'blockenberg'), value: a.flipDirection, options: flipDirOptions, onChange: function (v) { setAttributes({ flipDirection: v }); } }),
214 el(SelectControl, { label: __('Flip Trigger', 'blockenberg'), value: a.flipTrigger, options: flipTriggerOptions, onChange: function (v) { setAttributes({ flipTrigger: v }); } }),
215 el(RangeControl, { label: __('Flip Speed (ms)', 'blockenberg'), value: a.flipSpeed, min: 200, max: 1200, step: 50, onChange: function (v) { setAttributes({ flipSpeed: v }); } })
216 ),
217
218 // Typography
219 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
220 el(RangeControl, { label: __('Icon Size', 'blockenberg'), value: a.iconSize, min: 20, max: 80, onChange: function (v) { setAttributes({ iconSize: v }); } }),
221 TC && el(TC, { label: __('Title', 'blockenberg'), value: a.typoTitle, onChange: function (v) { setAttributes({ typoTitle: v }); } }),
222 TC && el(TC, { label: __('Text', 'blockenberg'), value: a.typoText, onChange: function (v) { setAttributes({ typoText: v }); } }),
223 el(ToggleControl, { label: __('Show Front Text', 'blockenberg'), checked: a.showFrontText, onChange: function (v) { setAttributes({ showFrontText: v }); }, __nextHasNoMarginBottom: true }),
224 el(ToggleControl, { label: __('Show Back Button', 'blockenberg'), checked: a.showBackBtn, onChange: function (v) { setAttributes({ showBackBtn: v }); }, __nextHasNoMarginBottom: true }),
225 el(RangeControl, { label: __('Button Font Size', 'blockenberg'), value: a.btnFontSize, min: 11, max: 20, onChange: function (v) { setAttributes({ btnFontSize: v }); } })
226 ),
227
228 // Button
229 el(PanelBody, { title: __('Button Style', 'blockenberg'), initialOpen: false },
230 el(RangeControl, { label: __('Button Border Radius', 'blockenberg'), value: a.btnRadius, min: 0, max: 50, onChange: function (v) { setAttributes({ btnRadius: v }); } }),
231 el(RangeControl, { label: __('Button Padding H', 'blockenberg'), value: a.btnPadding, min: 6, max: 40, onChange: function (v) { setAttributes({ btnPadding: v }); } }),
232 )
233 );
234
235 var wrapStyle = Object.assign({
236 '--bkbg-cfb-cols': a.columns,
237 '--bkbg-cfb-gap': a.gap + 'px',
238 '--bkbg-cfb-height': a.cardHeight + 'px',
239 '--bkbg-cfb-radius': a.borderRadius + 'px',
240 '--bkbg-cfb-speed': (a.flipSpeed / 1000) + 's',
241 '--bkbg-cfb-icon-size': a.iconSize + 'px',
242 '--bkbg-cfb-title-size': a.titleSize + 'px',
243 '--bkbg-cfb-text-size': a.textSize + 'px',
244 '--bkbg-cfb-btn-radius': a.btnRadius + 'px',
245 '--bkbg-cfb-btn-padding': a.btnPadding + 'px',
246 '--bkbg-cfb-btn-font': a.btnFontSize + 'px'
247 }, tv(a.typoTitle, '--bkcfb-title-'), tv(a.typoText, '--bkcfb-text-'));
248
249 function renderFace(item, face, isBack) {
250 var bg = isBack ? item.backBg : item.frontBg;
251 var color = isBack ? item.backColor : item.frontColor;
252 var icon = isBack ? item.backIcon : item.frontIcon;
253 var iconType = isBack ? (item.backIconType || 'custom-char') : (item.frontIconType || 'custom-char');
254 var iconDash = isBack ? item.backIconDashicon : item.frontIconDashicon;
255 var iconImg = isBack ? item.backIconImageUrl : item.frontIconImageUrl;
256 var iconDashColor = isBack ? item.backIconDashiconColor : item.frontIconDashiconColor;
257 var title = isBack ? item.backTitle : item.frontTitle;
258 var text = isBack ? item.backText : item.frontText;
259 var faceClass = 'bkbg-cfb-face bkbg-cfb-' + (isBack ? 'back' : 'front');
260
261 return el('div', {
262 className: faceClass,
263 style: { background: bg, color: color, textAlign: a.textAlign }
264 },
265 icon && el('div', { className: 'bkbg-cfb-icon' },
266 iconType !== 'custom-char' ? IP().buildEditorIcon(iconType, icon, iconDash, iconImg, iconDashColor) : icon
267 ),
268 el('div', { className: 'bkbg-cfb-title' }, title),
269 (!isBack && a.showFrontText && text) && el('div', { className: 'bkbg-cfb-text' }, text),
270 (isBack && text) && el('div', { className: 'bkbg-cfb-text' }, text),
271 (isBack && a.showBackBtn && item.backBtnText) && el('a', {
272 className: 'bkbg-cfb-btn',
273 href: '#',
274 onClick: function (e) { e.preventDefault(); },
275 style: {
276 background: item.backBtnBg,
277 color: item.backBtnColor,
278 borderRadius: a.btnRadius + 'px',
279 padding: '8px ' + a.btnPadding + 'px',
280 fontSize: a.btnFontSize + 'px'
281 }
282 }, item.backBtnText)
283 );
284 }
285
286 var blockProps = useBlockProps({ className: 'bkbg-editor-wrap', 'data-block-label': 'Content Flip Box' });
287
288 return el('div', blockProps,
289 inspector,
290 el('div', { className: 'bkbg-cfb-grid bkbg-editor-flip-grid', style: wrapStyle },
291 a.items.map(function (item) {
292 var isFlippedInEditor = !!flipped[item.id];
293 var isActive = item.id === activeId;
294 return el('div', {
295 key: item.id,
296 className: 'bkbg-cfb-card' + (isActive ? ' bkbg-cfb-card--active' : ''),
297 style: { height: a.cardHeight + 'px', borderRadius: a.borderRadius + 'px', overflow: 'hidden', position: 'relative', cursor: 'pointer' },
298 onClick: function () { setActiveId(isActive ? null : item.id); }
299 },
300 // Flip toggle button
301 el('button', {
302 className: 'bkbg-cfb-editor-flip-btn',
303 title: isFlippedInEditor ? __('Show Front', 'blockenberg') : __('Show Back', 'blockenberg'),
304 onClick: function (e) { e.stopPropagation(); toggleFlip(item.id); }
305 }, isFlippedInEditor ? '' : ''),
306 // Active indicator
307 isActive && el('div', { className: 'bkbg-cfb-editor-active-badge' }, ''),
308 // Show either front or back face in editor
309 renderFace(item, 'front', isFlippedInEditor)
310 );
311 })
312 )
313 );
314 },
315
316 save: function (props) {
317 var a = props.attributes;
318 var tv = window._bkbgCFBgetTV || function () { return {}; };
319
320 var wrapStyle = Object.assign({
321 '--bkbg-cfb-cols': a.columns,
322 '--bkbg-cfb-gap': a.gap + 'px',
323 '--bkbg-cfb-height': a.cardHeight + 'px',
324 '--bkbg-cfb-radius': a.borderRadius + 'px',
325 '--bkbg-cfb-speed': (a.flipSpeed / 1000) + 's',
326 '--bkbg-cfb-icon-size': a.iconSize + 'px',
327 '--bkbg-cfb-title-size': a.titleSize + 'px',
328 '--bkbg-cfb-text-size': a.textSize + 'px',
329 '--bkbg-cfb-btn-radius': a.btnRadius + 'px',
330 '--bkbg-cfb-btn-padding': a.btnPadding + 'px',
331 '--bkbg-cfb-btn-font': a.btnFontSize + 'px'
332 }, tv(a.typoTitle, '--bkcfb-title-'), tv(a.typoText, '--bkcfb-text-'));
333
334 return el('div', {
335 className: 'bkbg-cfb-grid',
336 style: wrapStyle,
337 'data-trigger': a.flipTrigger,
338 'data-direction': a.flipDirection
339 },
340 a.items.map(function (item, idx) {
341 return el('div', { key: idx, className: 'bkbg-cfb-card' },
342 el('div', { className: 'bkbg-cfb-inner' },
343 // Front face
344 el('div', { className: 'bkbg-cfb-face bkbg-cfb-front', style: { background: item.frontBg, color: item.frontColor, textAlign: a.textAlign } },
345 item.frontIcon && el('div', { className: 'bkbg-cfb-icon' },
346 (item.frontIconType || 'custom-char') !== 'custom-char' ? IP().buildSaveIcon(item.frontIconType, item.frontIcon, item.frontIconDashicon, item.frontIconImageUrl, item.frontIconDashiconColor) : item.frontIcon
347 ),
348 el('div', { className: 'bkbg-cfb-title' }, item.frontTitle),
349 (a.showFrontText && item.frontText) && el('div', { className: 'bkbg-cfb-text' }, item.frontText)
350 ),
351 // Back face
352 el('div', { className: 'bkbg-cfb-face bkbg-cfb-back', style: { background: item.backBg, color: item.backColor, textAlign: a.textAlign } },
353 item.backIcon && el('div', { className: 'bkbg-cfb-icon' },
354 (item.backIconType || 'custom-char') !== 'custom-char' ? IP().buildSaveIcon(item.backIconType, item.backIcon, item.backIconDashicon, item.backIconImageUrl, item.backIconDashiconColor) : item.backIcon
355 ),
356 el('div', { className: 'bkbg-cfb-title' }, item.backTitle),
357 item.backText && el('div', { className: 'bkbg-cfb-text' }, item.backText),
358 (a.showBackBtn && item.backBtnText) && el('a', {
359 className: 'bkbg-cfb-btn',
360 href: item.backBtnUrl || '#',
361 style: {
362 background: item.backBtnBg,
363 color: item.backBtnColor,
364 borderRadius: a.btnRadius + 'px',
365 padding: '8px ' + a.btnPadding + 'px',
366 fontSize: a.btnFontSize + 'px'
367 }
368 }, item.backBtnText)
369 )
370 )
371 );
372 })
373 );
374 }
375 });
376 }() );
377