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

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

317 lines 18.0 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 useBlockProps = wp.blockEditor.useBlockProps;
9 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
10 var PanelBody = wp.components.PanelBody;
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
17 var _tc, _tv;
18 function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
19 function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
20
21 function updateItem(arr, idx, field, val) {
22 return arr.map(function (item, i) {
23 if (i !== idx) return item;
24 var p = {}; p[field] = val;
25 return Object.assign({}, item, p);
26 });
27 }
28
29 function moveItem(arr, from, to) {
30 var a = arr.slice();
31 var item = a.splice(from, 1)[0];
32 a.splice(to, 0, item);
33 return a;
34 }
35
36 /* ── BannerPreview – shows the active message ── */
37 function BannerPreview(props) {
38 var a = props.attributes;
39 var activeIdx = props.activeIdx;
40 var setActiveIdx = props.setActiveIdx;
41 var msgs = a.messages || [];
42
43 if (msgs.length === 0) {
44 return el('div', { style: { height: a.height + 'px', background: '#6366f1', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontSize: '13px' } }, 'Add a message in the sidebar');
45 }
46
47 var msg = msgs[Math.min(activeIdx, msgs.length - 1)];
48
49 return el('div', {
50 style: {
51 background: msg.bgColor || '#6366f1',
52 color: msg.textColor || '#fff',
53 height: a.height + 'px',
54 display: 'flex',
55 alignItems: 'center',
56 justifyContent: 'center',
57 position: 'relative',
58 overflow: 'hidden',
59 padding: '0 ' + (a.showArrows ? '48px' : '16px'),
60 boxSizing: 'border-box'
61 }
62 },
63 /* Left arrow */
64 a.showArrows && msgs.length > 1 && el('button', {
65 onClick: function () { setActiveIdx((activeIdx - 1 + msgs.length) % msgs.length); },
66 style: {
67 position: 'absolute', left: '8px',
68 background: a.arrowBg || 'rgba(0,0,0,0.15)',
69 color: a.arrowColor || '#fff',
70 border: 'none', borderRadius: '50%',
71 width: '28px', height: '28px',
72 cursor: 'pointer', fontSize: '16px', lineHeight: '28px',
73 display: 'flex', alignItems: 'center', justifyContent: 'center'
74 }
75 }, ''),
76
77 /* Message */
78 el('div', { style: { display: 'flex', alignItems: 'center', gap: '10px', flexWrap: 'wrap', justifyContent: 'center' } },
79 el('span', null, msg.text || ''),
80 msg.linkLabel && msg.linkUrl && a.linkStyle === 'inline' && el('a', {
81 href: msg.linkUrl, onClick: function (e) { e.preventDefault(); },
82 style: { color: 'inherit', fontWeight: '700', textDecoration: 'underline', whiteSpace: 'nowrap' }
83 }, msg.linkLabel),
84 msg.linkLabel && msg.linkUrl && a.linkStyle === 'button' && el('a', {
85 href: msg.linkUrl, onClick: function (e) { e.preventDefault(); },
86 style: { color: msg.bgColor || '#6366f1', background: msg.textColor || '#fff', padding: '3px 10px', borderRadius: '12px', fontWeight: '700', textDecoration: 'none', fontSize: (a.fontSize - 1) + 'px', whiteSpace: 'nowrap' }
87 }, msg.linkLabel)
88 ),
89
90 /* Dots */
91 a.showDots && msgs.length > 1 && el('div', {
92 style: { position: 'absolute', bottom: '4px', left: '50%', transform: 'translateX(-50%)', display: 'flex', gap: '4px' }
93 },
94 msgs.map(function (_, di) {
95 return el('div', {
96 key: di,
97 onClick: function () { setActiveIdx(di); },
98 style: {
99 width: '6px', height: '6px', borderRadius: '50%', cursor: 'pointer',
100 background: di === activeIdx ? (a.dotActiveColor || '#fff') : (a.dotColor || 'rgba(255,255,255,0.4)'),
101 transition: 'background 0.15s'
102 }
103 });
104 })
105 ),
106
107 /* Right arrow */
108 a.showArrows && msgs.length > 1 && el('button', {
109 onClick: function () { setActiveIdx((activeIdx + 1) % msgs.length); },
110 style: {
111 position: 'absolute', right: a.showClose ? '36px' : '8px',
112 background: a.arrowBg || 'rgba(0,0,0,0.15)',
113 color: a.arrowColor || '#fff',
114 border: 'none', borderRadius: '50%',
115 width: '28px', height: '28px',
116 cursor: 'pointer', fontSize: '16px', lineHeight: '28px',
117 display: 'flex', alignItems: 'center', justifyContent: 'center'
118 }
119 }, ''),
120
121 /* Close */
122 a.showClose && el('button', {
123 style: {
124 position: 'absolute', right: '8px',
125 background: a.closeBg || 'rgba(0,0,0,0.15)',
126 color: a.closeColor || '#fff',
127 border: 'none', borderRadius: '50%',
128 width: '24px', height: '24px',
129 cursor: 'pointer', fontSize: '14px',
130 display: 'flex', alignItems: 'center', justifyContent: 'center'
131 }
132 }, '×')
133 );
134 }
135
136 /* ── MessageEditor ── */
137 function MessageEditor(props) {
138 var msgs = props.messages;
139 var onChange = props.onChange;
140 var activeIdx = props.activeIdx;
141 var setActiveIdx = props.setActiveIdx;
142
143 function addMsg() {
144 var colors = ['#6366f1', '#0ea5e9', '#ef4444', '#f59e0b', '#10b981'];
145 var c = colors[msgs.length % colors.length];
146 onChange(msgs.concat([{ text: 'New announcement message', linkLabel: 'Learn More', linkUrl: '#', linkTarget: '_self', bgColor: c, textColor: '#ffffff', countdownTo: '' }]));
147 setActiveIdx(msgs.length);
148 }
149
150 return el(Fragment, null,
151 msgs.map(function (msg, idx) {
152 var isOpen = idx === activeIdx;
153 return el('div', {
154 key: idx,
155 style: {
156 border: '1px solid ' + (isOpen ? '#6366f1' : '#e5e7eb'),
157 borderRadius: '6px',
158 marginBottom: '6px',
159 overflow: 'hidden'
160 }
161 },
162 /* header row */
163 el('div', {
164 style: {
165 display: 'flex', alignItems: 'center', gap: '6px',
166 padding: '7px 10px',
167 background: isOpen ? '#f0f0ff' : '#f9fafb',
168 cursor: 'pointer'
169 },
170 onClick: function () { setActiveIdx(isOpen ? -1 : idx); }
171 },
172 el('div', { style: { width: '12px', height: '12px', borderRadius: '3px', background: msg.bgColor || '#6366f1', flexShrink: 0 } }),
173 el('span', { style: { flex: 1, fontSize: '12px', fontWeight: '600', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, msg.text ? msg.text.slice(0, 40) : 'Message ' + (idx + 1)),
174 el(Button, { icon: 'arrow-up-alt2', isSmall: true, disabled: idx === 0, onClick: function (e) { e.stopPropagation(); onChange(moveItem(msgs, idx, idx - 1)); setActiveIdx(idx - 1); } }),
175 el(Button, { icon: 'arrow-down-alt2', isSmall: true, disabled: idx === msgs.length - 1, onClick: function (e) { e.stopPropagation(); onChange(moveItem(msgs, idx, idx + 1)); setActiveIdx(idx + 1); } }),
176 el(Button, { icon: 'no-alt', isSmall: true, isDestructive: true, onClick: function (e) { e.stopPropagation(); var a = msgs.slice(); a.splice(idx, 1); onChange(a); setActiveIdx(-1); } })
177 ),
178
179 isOpen && el('div', { style: { padding: '10px', display: 'flex', flexDirection: 'column', gap: '8px' } },
180 el('div', null,
181 el('label', { style: { fontSize: '11px', fontWeight: '600', display: 'block', marginBottom: '6px' } }, __('Message Text', 'blockenberg')),
182 el('textarea', {
183 value: msg.text || '',
184 onChange: function (e) { onChange(updateItem(msgs, idx, 'text', e.target.value)); },
185 style: { width: '100%', minHeight: '60px', fontSize: '12px', padding: '6px', border: '1px solid #e5e7eb', borderRadius: '4px', boxSizing: 'border-box', resize: 'vertical' }
186 })
187 ),
188 el(TextControl, { label: __('Link Label', 'blockenberg'), value: msg.linkLabel || '', onChange: function (v) { onChange(updateItem(msgs, idx, 'linkLabel', v)); }, __nextHasNoMarginBottom: true }),
189 el(TextControl, { label: __('Link URL', 'blockenberg'), value: msg.linkUrl || '', onChange: function (v) { onChange(updateItem(msgs, idx, 'linkUrl', v)); }, __nextHasNoMarginBottom: true }),
190 el(SelectControl, {
191 label: __('Link Target', 'blockenberg'),
192 value: msg.linkTarget || '_self',
193 options: [{ value: '_self', label: 'Same tab' }, { value: '_blank', label: 'New tab' }],
194 onChange: function (v) { onChange(updateItem(msgs, idx, 'linkTarget', v)); },
195 __nextHasNoMarginBottom: true
196 }),
197 el('div', { style: { display: 'flex', gap: '10px' } },
198 el('div', { style: { flex: 1 } },
199 el('label', { style: { fontSize: '11px', fontWeight: '600', display: 'block', marginBottom: '4px' } }, __('Background', 'blockenberg')),
200 el('input', { type: 'color', value: msg.bgColor || '#6366f1', onChange: function (e) { onChange(updateItem(msgs, idx, 'bgColor', e.target.value)); }, style: { width: '100%', height: '32px', border: 'none', borderRadius: '4px', cursor: 'pointer' } })
201 ),
202 el('div', { style: { flex: 1 } },
203 el('label', { style: { fontSize: '11px', fontWeight: '600', display: 'block', marginBottom: '4px' } }, __('Text Color', 'blockenberg')),
204 el('input', { type: 'color', value: msg.textColor || '#ffffff', onChange: function (e) { onChange(updateItem(msgs, idx, 'textColor', e.target.value)); }, style: { width: '100%', height: '32px', border: 'none', borderRadius: '4px', cursor: 'pointer' } })
205 )
206 ),
207 el(TextControl, { label: __('Countdown To (ISO date, optional)', 'blockenberg'), value: msg.countdownTo || '', placeholder: '2025-12-31T23:59:59', onChange: function (v) { onChange(updateItem(msgs, idx, 'countdownTo', v)); }, __nextHasNoMarginBottom: true })
208 )
209 );
210 }),
211 el(Button, { variant: 'secondary', onClick: addMsg, style: { marginTop: '6px', width: '100%', justifyContent: 'center' } }, __('+ Add Message', 'blockenberg'))
212 );
213 }
214
215 registerBlockType('blockenberg/rotating-banner', {
216 edit: function (props) {
217 var a = props.attributes;
218 var set = props.setAttributes;
219 var msgIdxState = useState(0);
220 var msgIdx = msgIdxState[0];
221 var setMsgIdx = msgIdxState[1];
222 var editorIdxState = useState(-1);
223 var editorIdx = editorIdxState[0];
224 var setEditorIdx = editorIdxState[1];
225
226 var blockProps = useBlockProps((function () {
227 var _tv = getTypoCssVars();
228 var s = { overflow: 'hidden' };
229 if (_tv) {
230 Object.assign(s, _tv(a.messageTypo, '--bkrbnr-mt-'));
231 }
232 return { style: s };
233 })());
234
235 var inspector = el(InspectorControls, null,
236 el(PanelBody, { title: __('Messages', 'blockenberg'), initialOpen: true },
237 el(MessageEditor, {
238 messages: a.messages,
239 onChange: function (v) { set({ messages: v }); },
240 activeIdx: editorIdx,
241 setActiveIdx: setEditorIdx
242 })
243 ),
244
245 el(PanelBody, { title: __('Rotation & Behaviour', 'blockenberg'), initialOpen: false },
246 el(ToggleControl, { label: __('Auto-play', 'blockenberg'), checked: a.autoPlay, onChange: function (v) { set({ autoPlay: v }); }, __nextHasNoMarginBottom: true }),
247 a.autoPlay && el('div', { style: { marginTop: '8px' } },
248 el(RangeControl, { label: __('Interval (ms)', 'blockenberg'), value: a.interval, min: 1000, max: 15000, step: 500, onChange: function (v) { set({ interval: v }); }, __nextHasNoMarginBottom: true })
249 ),
250 el('div', { style: { marginTop: '8px' } },
251 el(SelectControl, {
252 label: __('Animation', 'blockenberg'),
253 value: a.animationType,
254 options: [{ value: 'slide', label: 'Slide' }, { value: 'fade', label: 'Fade' }],
255 onChange: function (v) { set({ animationType: v }); },
256 __nextHasNoMarginBottom: true
257 })
258 ),
259 el(ToggleControl, { label: __('Show Arrows', 'blockenberg'), checked: a.showArrows, onChange: function (v) { set({ showArrows: v }); }, __nextHasNoMarginBottom: true }),
260 el(ToggleControl, { label: __('Show Dot Indicators', 'blockenberg'), checked: a.showDots, onChange: function (v) { set({ showDots: v }); }, __nextHasNoMarginBottom: true }),
261 el(ToggleControl, { label: __('Show Close Button', 'blockenberg'), checked: a.showClose, onChange: function (v) { set({ showClose: v }); }, __nextHasNoMarginBottom: true }),
262 a.showClose && el('div', { style: { marginTop: '8px' } },
263 el(RangeControl, { label: __('Cookie Dismiss Duration (days)', 'blockenberg'), value: a.cookieDays, min: 0, max: 365, onChange: function (v) { set({ cookieDays: v }); }, __nextHasNoMarginBottom: true })
264 )
265 ),
266
267 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
268 getTypoControl() && el(getTypoControl(), {
269 label: __('Message Typography', 'blockenberg'),
270 value: a.messageTypo || {},
271 onChange: function (v) { set({ messageTypo: v }); }
272 })
273 ),
274
275 el(PanelBody, { title: __('Appearance', 'blockenberg'), initialOpen: false },
276 el(RangeControl, { label: __('Banner Height (px)', 'blockenberg'), value: a.height, min: 32, max: 120, onChange: function (v) { set({ height: v }); }, __nextHasNoMarginBottom: true }),
277 el('div', { style: { marginTop: '8px' } },
278 el(SelectControl, {
279 label: __('Link Style', 'blockenberg'),
280 value: a.linkStyle,
281 options: [{ value: 'inline', label: 'Inline underline' }, { value: 'button', label: 'Pill button' }, { value: 'none', label: 'No link' }],
282 onChange: function (v) { set({ linkStyle: v }); },
283 __nextHasNoMarginBottom: true
284 })
285 )
286 ),
287
288 el(PanelColorSettings, {
289 title: __('Navigation Colors', 'blockenberg'),
290 initialOpen: false,
291 colorSettings: [
292 { value: a.arrowBg, onChange: function (v) { set({ arrowBg: v }); }, label: __('Arrow Background', 'blockenberg') },
293 { value: a.arrowColor, onChange: function (v) { set({ arrowColor: v }); }, label: __('Arrow Color', 'blockenberg') },
294 { value: a.dotColor, onChange: function (v) { set({ dotColor: v }); }, label: __('Dot Color', 'blockenberg') },
295 { value: a.dotActiveColor, onChange: function (v) { set({ dotActiveColor: v }); }, label: __('Active Dot Color', 'blockenberg') },
296 { value: a.closeBg, onChange: function (v) { set({ closeBg: v }); }, label: __('Close Button Background', 'blockenberg') },
297 { value: a.closeColor, onChange: function (v) { set({ closeColor: v }); }, label: __('Close Button Color', 'blockenberg') }
298 ]
299 })
300 );
301
302 return el(Fragment, null,
303 inspector,
304 el('div', blockProps,
305 el(BannerPreview, { attributes: a, activeIdx: msgIdx, setActiveIdx: setMsgIdx })
306 )
307 );
308 },
309
310 save: function (props) {
311 return el('div', useBlockProps.save(),
312 el('div', { className: 'bkbg-rbnr-app', 'data-opts': JSON.stringify(props.attributes) })
313 );
314 }
315 });
316 }() );
317