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

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

227 lines 16.3 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 registerBlockType = wp.blocks.registerBlockType;
6 var InspectorControls = wp.blockEditor.InspectorControls;
7 var useBlockProps = wp.blockEditor.useBlockProps;
8 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
9 var PanelBody = wp.components.PanelBody;
10 var ToggleControl = wp.components.ToggleControl;
11 var RangeControl = wp.components.RangeControl;
12 var SelectControl = wp.components.SelectControl;
13 var TextControl = wp.components.TextControl;
14 var Button = wp.components.Button;
15
16 var _tc, _tv;
17 function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
18 function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
19 var IP = function () { return window.bkbgIconPicker; };
20
21 var POSITION_OPTIONS = [
22 { label: 'Bottom Left', value: 'bottom-left' },
23 { label: 'Bottom Right', value: 'bottom-right' },
24 { label: 'Top Left', value: 'top-left' },
25 { label: 'Top Right', value: 'top-right' },
26 ];
27 var ANIMATE_OPTIONS = [
28 { label: 'Slide in', value: 'slide' },
29 { label: 'Fade in', value: 'fade' },
30 { label: 'Pop in', value: 'pop' },
31 ];
32 var STYLE_OPTIONS = [
33 { label: 'Shadow (elevated)', value: 'shadow' },
34 { label: 'Bordered', value: 'bordered' },
35 { label: 'Flat (minimal)', value: 'flat' },
36 ];
37
38 var BG_COLORS = ['#6366f1', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#0ea5e9', '#ec4899', '#14b8a6'];
39
40 function updateNotif(arr, idx, field, val) {
41 return arr.map(function (n, i) {
42 if (i !== idx) return n;
43 var p = {}; p[field] = val;
44 return Object.assign({}, n, p);
45 });
46 }
47
48 function initials(name) {
49 return (name || 'U').split(' ').map(function (w) { return w[0] || ''; }).join('').slice(0, 2).toUpperCase();
50 }
51
52 function buildToastPreview(notif, a) {
53 return el('div', {
54 style: {
55 display: 'flex', alignItems: 'center', gap: 10,
56 padding: '10px 14px',
57 background: a.toastBg,
58 borderRadius: a.borderRadius + 'px',
59 border: a.toastStyle === 'bordered' ? '1px solid ' + a.toastBorder : 'none',
60 boxShadow: (a.toastStyle === 'shadow' && a.toastShadow) ? '0 4px 18px rgba(0,0,0,0.12)' : 'none',
61 maxWidth: a.maxWidth + 'px',
62 }
63 },
64 a.showAvatar && el('div', {
65 style: {
66 width: a.avatarSize + 'px', height: a.avatarSize + 'px', borderRadius: '50%',
67 background: notif.avatarBg || '#6366f1', color: '#fff',
68 display: 'flex', alignItems: 'center', justifyContent: 'center',
69 fontSize: Math.round(a.avatarSize * 0.35) + 'px', fontWeight: 700, flexShrink: 0,
70 }
71 }, initials(notif.name)),
72 el('div', { style: { flex: 1, minWidth: 0 } },
73 el('div', { style: { display: 'flex', alignItems: 'center', gap: 4 } },
74 a.showIcon && el('span', { style: { fontSize: a.iconSize + 'px' } }, (notif.iconType || 'custom-char') !== 'custom-char' ? IP().buildEditorIcon(notif.iconType, notif.icon, notif.iconDashicon, notif.iconImageUrl, notif.iconDashiconColor) : (notif.icon || '🔔')),
75 el('span', { className: 'bkbg-ntst-name', style: { color: a.nameColor } }, notif.name || 'User')
76 ),
77 el('div', { className: 'bkbg-ntst-msg', style: { color: a.textColor, marginTop: 2, overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' } }, notif.text || 'notification text'),
78 a.showTimeAgo && el('div', { className: 'bkbg-ntst-time', style: { fontSize: a.timeSize + 'px', color: a.timeColor, marginTop: 2 } }, notif.timeAgo || 'just now')
79 )
80 );
81 }
82
83 registerBlockType('blockenberg/notification-toast', {
84 title: __('Notification Toast', 'blockenberg'),
85 icon: 'megaphone',
86 category: 'bkbg-effects',
87 description: __('Social-proof toast notifications that cycle in the page corner.', 'blockenberg'),
88
89 edit: function (props) {
90 var a = props.attributes;
91 var set = props.setAttributes;
92 var blockProps = useBlockProps((function () {
93 var _tvf = getTypoCssVars();
94 var s = {};
95 if (_tvf) { Object.assign(s, _tvf(a.nameTypo, '--bkbg-ntst-nm-')); Object.assign(s, _tvf(a.textTypo, '--bkbg-ntst-tx-')); }
96 return { style: s };
97 })());
98 var firstNotif = a.notifications[0] || { icon: '🎉', name: 'User', text: 'Notification text', timeAgo: 'just now', avatarBg: '#6366f1' };
99
100 return el(Fragment, null,
101 el(InspectorControls, null,
102
103 // Notifications list
104 el(PanelBody, { title: 'Notifications (' + a.notifications.length + ')', initialOpen: true },
105 a.notifications.map(function (n, i) {
106 return el('div', {
107 key: i,
108 style: { border: '1px solid #e5e7eb', borderRadius: 8, padding: 10, marginBottom: 8, background: '#fafafa' }
109 },
110 el('div', { style: { display: 'flex', alignItems: 'center', gap: 6, marginBottom: 8 } },
111 el('div', { style: { width: 28, height: 28, borderRadius: '50%', background: n.avatarBg || '#6366f1', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 10, fontWeight: 700 } }, initials(n.name)),
112 el('span', { style: { fontSize: 12, fontWeight: 600, color: '#374151' } }, n.name),
113 el('span', { style: { fontSize: 16 } }, (n.iconType || 'custom-char') !== 'custom-char' ? IP().buildEditorIcon(n.iconType, n.icon, n.iconDashicon, n.iconImageUrl, n.iconDashiconColor) : n.icon)
114 ),
115 el(TextControl, { label: 'Name', value: n.name, onChange: function (v) { set({ notifications: updateNotif(a.notifications, i, 'name', v) }); }, __nextHasNoMarginBottom: true }),
116 el('div', { style: { height: 6 } }),
117 el(IP().IconPickerControl, { iconType: n.iconType || 'custom-char', customChar: n.icon || '', dashicon: n.iconDashicon || '', imageUrl: n.iconImageUrl || '', onChangeType: function (v) { set({ notifications: updateNotif(a.notifications, i, 'iconType', v) }); }, onChangeChar: function (v) { set({ notifications: updateNotif(a.notifications, i, 'icon', v) }); }, onChangeDashicon: function (v) { set({ notifications: updateNotif(a.notifications, i, 'iconDashicon', v) }); }, onChangeImageUrl: function (v) { set({ notifications: updateNotif(a.notifications, i, 'iconImageUrl', v) }); } }),
118 el('div', { style: { height: 6 } }),
119 el(TextControl, { label: 'Message', value: n.text, onChange: function (v) { set({ notifications: updateNotif(a.notifications, i, 'text', v) }); }, __nextHasNoMarginBottom: true }),
120 el('div', { style: { height: 6 } }),
121 el(TextControl, { label: 'Time label', value: n.timeAgo, onChange: function (v) { set({ notifications: updateNotif(a.notifications, i, 'timeAgo', v) }); }, __nextHasNoMarginBottom: true }),
122 el('div', { style: { height: 6 } }),
123 el('p', { style: { fontSize: 11, color: '#6b7280', margin: '0 0 4px' } }, 'Avatar color:'),
124 el('div', { style: { display: 'flex', gap: 6, flexWrap: 'wrap' } },
125 BG_COLORS.map(function (c) {
126 return el('button', {
127 key: c,
128 onClick: function () { set({ notifications: updateNotif(a.notifications, i, 'avatarBg', c) }); },
129 style: { width: 24, height: 24, borderRadius: '50%', background: c, border: n.avatarBg === c ? '3px solid #374151' : '2px solid #e5e7eb', cursor: 'pointer' }
130 });
131 }),
132 el('input', {
133 type: 'color', value: n.avatarBg || '#6366f1',
134 onChange: function (e) { set({ notifications: updateNotif(a.notifications, i, 'avatarBg', e.target.value) }); },
135 style: { width: 24, height: 24, border: 'none', borderRadius: '50%', cursor: 'pointer', padding: 0 }
136 })
137 ),
138 el('div', { style: { height: 6 } }),
139 el(Button, { isDestructive: true, variant: 'link', size: 'small', onClick: function () { set({ notifications: a.notifications.filter(function (_, idx) { return idx !== i; }) }); }, __nextHasNoMarginBottom: true }, 'Remove')
140 );
141 }),
142 el(Button, {
143 variant: 'secondary',
144 onClick: function () { set({ notifications: a.notifications.concat([{ icon: '�
145 ', iconType: 'custom-char', iconDashicon: '', iconImageUrl: '', name: 'New User', text: 'just took an action', timeAgo: 'just now', avatarBg: '#6366f1' }]) }); },
146 style: { width: '100%', justifyContent: 'center' }, __nextHasNoMarginBottom: true
147 }, '+ Add Notification')
148 ),
149
150 // Behaviour
151 el(PanelBody, { title: 'Behaviour', initialOpen: false },
152 el(SelectControl, { label: 'Position', value: a.position, options: POSITION_OPTIONS, onChange: function (v) { set({ position: v }); }, __nextHasNoMarginBottom: true }),
153 el('div', { style: { height: 10 } }),
154 el(RangeControl, { label: 'Interval between toasts (s)', value: a.interval, min: 1, max: 20, onChange: function (v) { set({ interval: v }); }, __nextHasNoMarginBottom: true }),
155 el('div', { style: { height: 10 } }),
156 el(RangeControl, { label: 'Display duration (s)', value: a.displayDuration, min: 1, max: 10, onChange: function (v) { set({ displayDuration: v }); }, __nextHasNoMarginBottom: true }),
157 el('div', { style: { height: 10 } }),
158 el(SelectControl, { label: 'Animation', value: a.animateType, options: ANIMATE_OPTIONS, onChange: function (v) { set({ animateType: v }); }, __nextHasNoMarginBottom: true }),
159 el('div', { style: { height: 10 } }),
160 el(ToggleControl, { label: 'Loop notifications', checked: a.loop, onChange: function (v) { set({ loop: v }); }, __nextHasNoMarginBottom: true }),
161 el('div', { style: { height: 4 } }),
162 el(ToggleControl, { label: 'Show each session only once', checked: a.showOnce, onChange: function (v) { set({ showOnce: v }); }, __nextHasNoMarginBottom: true })
163 ),
164
165 // Appearance
166 el(PanelBody, { title: 'Appearance', initialOpen: false },
167 el(SelectControl, { label: 'Toast Style', value: a.toastStyle, options: STYLE_OPTIONS, onChange: function (v) { set({ toastStyle: v }); }, __nextHasNoMarginBottom: true }),
168 el('div', { style: { height: 10 } }),
169 el(RangeControl, { label: 'Max Width (px)', value: a.maxWidth, min: 200, max: 500, onChange: function (v) { set({ maxWidth: v }); }, __nextHasNoMarginBottom: true }),
170 el('div', { style: { height: 10 } }),
171 el(RangeControl, { label: 'Border Radius (px)', value: a.borderRadius, min: 0, max: 24, onChange: function (v) { set({ borderRadius: v }); }, __nextHasNoMarginBottom: true }),
172 el('div', { style: { height: 10 } }),
173 el(ToggleControl, { label: 'Show avatar', checked: a.showAvatar, onChange: function (v) { set({ showAvatar: v }); }, __nextHasNoMarginBottom: true }),
174 a.showAvatar && el(Fragment, null,
175 el('div', { style: { height: 8 } }),
176 el(RangeControl, { label: 'Avatar Size (px)', value: a.avatarSize, min: 28, max: 60, onChange: function (v) { set({ avatarSize: v }); }, __nextHasNoMarginBottom: true })
177 ),
178 el('div', { style: { height: 4 } }),
179 el(ToggleControl, { label: 'Show icon/emoji', checked: a.showIcon, onChange: function (v) { set({ showIcon: v }); }, __nextHasNoMarginBottom: true }),
180 el('div', { style: { height: 4 } }),
181 el(ToggleControl, { label: 'Show time label', checked: a.showTimeAgo, onChange: function (v) { set({ showTimeAgo: v }); }, __nextHasNoMarginBottom: true }),
182 el('div', { style: { height: 10 } }),
183 el('div', { style: { height: 10 } }),
184 ),
185
186 // Colors
187
188 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
189 getTypoControl() && el(getTypoControl(), { label: __('Name Typography', 'blockenberg'), value: a.nameTypo || {}, onChange: function (v) { set({ nameTypo: v }); } }),
190 getTypoControl() && el(getTypoControl(), { label: __('Text Typography', 'blockenberg'), value: a.textTypo || {}, onChange: function (v) { set({ textTypo: v }); } }),
191 el(RangeControl, { label: __('Icon Size (px)', 'blockenberg'), value: a.iconSize, min: 12, max: 40, __nextHasNoMarginBottom: true, onChange: function (v) { set({ iconSize: v }); } }),
192 el(RangeControl, { label: __('Time Size (px)', 'blockenberg'), value: a.timeSize, min: 8, max: 18, __nextHasNoMarginBottom: true, onChange: function (v) { set({ timeSize: v }); } })
193 ),
194 el(PanelColorSettings, {
195 title: 'Colors',
196 initialOpen: false,
197 colorSettings: [
198 { label: 'Toast Background', value: a.toastBg, onChange: function (v) { set({ toastBg: v || '#ffffff' }); } },
199 { label: 'Toast Border', value: a.toastBorder, onChange: function (v) { set({ toastBorder: v || '#e5e7eb' }); } },
200 { label: 'Name Color', value: a.nameColor, onChange: function (v) { set({ nameColor: v || '#111827' }); } },
201 { label: 'Message Color', value: a.textColor, onChange: function (v) { set({ textColor: v || '#6b7280' }); } },
202 { label: 'Time Color', value: a.timeColor, onChange: function (v) { set({ timeColor: v || '#9ca3af' }); } },
203 ]
204 })
205 ),
206
207 // ── Editor Preview ──
208 el('div', blockProps,
209 el('p', { style: { fontSize: 11, color: '#9ca3af', textAlign: 'center', margin: '0 0 12px' } },
210 'Notification Toast — appears fixed in the "' + a.position + '" corner on the frontend'
211 ),
212 el('div', { style: { display: 'flex', justifyContent: 'center' } },
213 buildToastPreview(firstNotif, a)
214 ),
215 a.notifications.length > 1 && el('p', { style: { fontSize: 11, color: '#9ca3af', textAlign: 'center', margin: '10px 0 0' } }, '+ ' + (a.notifications.length - 1) + ' more notifications cycling every ' + a.interval + 's')
216 )
217 );
218 },
219
220 save: function (props) {
221 return el('div', useBlockProps.save(),
222 el('div', { className: 'bkbg-ntst-app', 'data-opts': JSON.stringify(props.attributes) })
223 );
224 }
225 });
226 }() );
227