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

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

309 lines 16.2 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 registerBlockType = wp.blocks.registerBlockType;
6 var useBlockProps = wp.blockEditor.useBlockProps;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
9 var PanelBody = wp.components.PanelBody;
10 var TextControl = wp.components.TextControl;
11 var TextareaControl = wp.components.TextareaControl;
12 var ToggleControl = wp.components.ToggleControl;
13 var RangeControl = wp.components.RangeControl;
14 var SelectControl = wp.components.SelectControl;
15 var Button = wp.components.Button;
16 var __ = wp.i18n.__;
17
18 var _tc, _tv;
19 function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
20 function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
21
22 function updateObj(list, idx, field, val) {
23 return list.map(function (o, i) {
24 if (i !== idx) return o;
25 var u = {}; u[field] = val;
26 return Object.assign({}, o, u);
27 });
28 }
29
30 // ── ObjectionPreview ────────────────────────────────────────────────────────
31 function ObjectionPreview(props) {
32 var a = props.attributes;
33 var setAttributes = props.setAttributes;
34
35 return el('div', {
36 className: 'bkbg-oh-block',
37 style: { background: a.bgColor }
38 },
39 a.showHeadline && el(Fragment, null,
40 el('h2', {
41 className: 'bkbg-oh-headline',
42 style: { color: a.headlineColor },
43 contentEditable: true,
44 suppressContentEditableWarning: true,
45 onBlur: function (e) { setAttributes({ headline: e.target.textContent }); }
46 }, a.headline),
47 a.subheadline && el('p', {
48 className: 'bkbg-oh-sub',
49 style: { color: a.subColor },
50 contentEditable: true,
51 suppressContentEditableWarning: true,
52 onBlur: function (e) { setAttributes({ subheadline: e.target.textContent }); }
53 }, a.subheadline)
54 ),
55 el('div', {
56 className: 'bkbg-oh-list bkbg-oh-layout-' + a.layout + ' bkbg-oh-style-' + a.style,
57 style: { gap: a.gap + 'px' }
58 },
59 a.objections.map(function (obj, i) {
60 return el('div', { key: i, className: 'bkbg-oh-pair', style: { borderRadius: a.borderRadius + 'px' } },
61 // Objection side
62 el('div', {
63 className: 'bkbg-oh-objection',
64 style: {
65 background: a.objectionBg,
66 color: a.objectionColor,
67 borderColor: a.objectionBorderColor,
68 borderRadius: (a.style === 'split' ? a.borderRadius + 'px 0 0 ' + a.borderRadius + 'px' : a.borderRadius + 'px')
69 }
70 },
71 el('div', { className: 'bkbg-oh-side-header' },
72 a.showIcon && el('span', { className: 'bkbg-oh-icon', style: { background: a.iconBg } }, obj.icon || ''),
73 el('span', { className: 'bkbg-oh-side-label', style: { color: a.labelColor } }, a.objectionLabel)
74 ),
75 el('p', { className: 'bkbg-oh-objection-text' }, '"' + obj.objection + '"')
76 ),
77 // Divider arrow (split style)
78 a.style === 'split' && el('div', { className: 'bkbg-oh-arrow', style: { color: a.responseBg } }, ''),
79 // Response side
80 el('div', {
81 className: 'bkbg-oh-response',
82 style: {
83 background: a.responseBg,
84 color: a.responseColor,
85 borderColor: a.responseBorderColor,
86 borderRadius: (a.style === 'split' ? '0 ' + a.borderRadius + 'px ' + a.borderRadius + 'px 0' : a.borderRadius + 'px')
87 }
88 },
89 el('div', { className: 'bkbg-oh-side-header' },
90 el('span', { className: 'bkbg-oh-check', style: { background: a.responseColor } }, ''),
91 el('span', { className: 'bkbg-oh-side-label', style: { color: a.labelColor } }, a.responseLabel)
92 ),
93 el('p', { className: 'bkbg-oh-response-text' }, obj.response)
94 )
95 );
96 })
97 )
98 );
99 }
100
101 // ── ObjectionEditor ─────────────────────────────────────────────────────────
102 function ObjectionEditor(props) {
103 var list = props.list;
104 var setAttributes = props.setAttributes;
105 var accentColor = props.accentColor;
106
107 var openState = useState(list.map(function () { return false; }));
108 var open = openState[0];
109 var setOpen = openState[1];
110
111 function toggle(i) {
112 setOpen(open.map(function (v, j) { return j === i ? !v : v; }));
113 }
114
115 function remove(i) {
116 setAttributes({ objections: list.filter(function (_, j) { return j !== i; }) });
117 setOpen(open.filter(function (_, j) { return j !== i; }));
118 }
119
120 function add() {
121 setAttributes({ objections: list.concat([{ objection: 'New concern or objection.', response: 'Your response addressing this concern.', icon: '💬' }]) });
122 setOpen(open.concat([true]));
123 }
124
125 return el('div', null,
126 list.map(function (obj, i) {
127 return el('div', { key: i, className: 'bkbg-oh-obj-editor' },
128 el('div', {
129 className: 'bkbg-oh-obj-header',
130 onClick: function () { toggle(i); },
131 style: { borderLeftColor: accentColor }
132 },
133 el('span', null, (obj.icon || '') + ' ' + obj.objection.slice(0, 40) + (obj.objection.length > 40 ? '' : '')),
134 el('span', null, open[i] ? '' : '')
135 ),
136 open[i] && el('div', { className: 'bkbg-oh-obj-fields' },
137 el(TextControl, {
138 label: __('Icon (emoji)'),
139 value: obj.icon,
140 __nextHasNoMarginBottom: true,
141 onChange: function (v) { setAttributes({ objections: updateObj(list, i, 'icon', v) }); }
142 }),
143 el(TextareaControl, {
144 label: __('Objection / Concern'),
145 value: obj.objection,
146 rows: 2,
147 __nextHasNoMarginBottom: true,
148 onChange: function (v) { setAttributes({ objections: updateObj(list, i, 'objection', v) }); }
149 }),
150 el(TextareaControl, {
151 label: __('Response'),
152 value: obj.response,
153 rows: 3,
154 __nextHasNoMarginBottom: true,
155 onChange: function (v) { setAttributes({ objections: updateObj(list, i, 'response', v) }); }
156 }),
157 el(Button, {
158 variant: 'link',
159 isDestructive: true,
160 onClick: function () { remove(i); }
161 }, __('Remove'))
162 )
163 );
164 }),
165 el(Button, {
166 variant: 'secondary',
167 onClick: add,
168 style: { marginTop: '8px' }
169 }, __('+ Add Objection'))
170 );
171 }
172
173 // ── register ────────────────────────────────────────────────────────────────
174 registerBlockType('blockenberg/objection-handler', {
175 edit: function (props) {
176 var a = props.attributes;
177 var setAttributes = props.setAttributes;
178
179 return el(Fragment, null,
180 el(InspectorControls, null,
181 el(PanelBody, { title: __('Objections'), initialOpen: true },
182 el(ObjectionEditor, {
183 list: a.objections,
184 setAttributes: setAttributes,
185 accentColor: a.objectionColor
186 })
187 ),
188 el(PanelBody, { title: __('Headline'), initialOpen: false },
189 el(ToggleControl, {
190 label: __('Show headline section'),
191 checked: a.showHeadline,
192 __nextHasNoMarginBottom: true,
193 onChange: function (v) { setAttributes({ showHeadline: v }); }
194 }),
195 el(TextControl, {
196 label: __('Headline'),
197 value: a.headline,
198 __nextHasNoMarginBottom: true,
199 onChange: function (v) { setAttributes({ headline: v }); }
200 }),
201 el(TextControl, {
202 label: __('Subheadline'),
203 value: a.subheadline,
204 __nextHasNoMarginBottom: true,
205 onChange: function (v) { setAttributes({ subheadline: v }); }
206 })
207 ),
208 el(PanelBody, { title: __('Layout & Style'), initialOpen: false },
209 el(SelectControl, {
210 label: __('Layout'),
211 value: a.layout,
212 __nextHasNoMarginBottom: true,
213 options: [
214 { value: 'stack', label: 'Stacked (one per row)' },
215 { value: 'grid', label: 'Grid (2 columns)' }
216 ],
217 onChange: function (v) { setAttributes({ layout: v }); }
218 }),
219 el(SelectControl, {
220 label: __('Pair style'),
221 value: a.style,
222 __nextHasNoMarginBottom: true,
223 options: [
224 { value: 'split', label: 'Split (side by side)' },
225 { value: 'card', label: 'Cards (stacked)' }
226 ],
227 onChange: function (v) { setAttributes({ style: v }); }
228 }),
229 el(ToggleControl, {
230 label: __('Show icon'),
231 checked: a.showIcon,
232 __nextHasNoMarginBottom: true,
233 onChange: function (v) { setAttributes({ showIcon: v }); }
234 }),
235 el(TextControl, {
236 label: __('Objection column label'),
237 value: a.objectionLabel,
238 __nextHasNoMarginBottom: true,
239 onChange: function (v) { setAttributes({ objectionLabel: v }); }
240 }),
241 el(TextControl, {
242 label: __('Response column label'),
243 value: a.responseLabel,
244 __nextHasNoMarginBottom: true,
245 onChange: function (v) { setAttributes({ responseLabel: v }); }
246 }),
247 el(RangeControl, {
248 label: __('Border radius (px)'),
249 value: a.borderRadius,
250 min: 0, max: 24,
251 __nextHasNoMarginBottom: true,
252 onChange: function (v) { setAttributes({ borderRadius: v }); }
253 }),
254 el(RangeControl, {
255 label: __('Gap between rows (px)'),
256 value: a.gap,
257 min: 4, max: 40,
258 __nextHasNoMarginBottom: true,
259 onChange: function (v) { setAttributes({ gap: v }); }
260 })
261 ),
262 el(PanelColorSettings, {
263 title: __('Colors'),
264 initialOpen: false,
265 colorSettings: [
266 { label: __('Background'), value: a.bgColor, onChange: function (v) { setAttributes({ bgColor: v || '#ffffff' }); } },
267 { label: __('Headline'), value: a.headlineColor, onChange: function (v) { setAttributes({ headlineColor: v || '#0f172a' }); } },
268 { label: __('Subheadline'), value: a.subColor, onChange: function (v) { setAttributes({ subColor: v || '#64748b' }); } },
269 { label: __('Objection bg'), value: a.objectionBg, onChange: function (v) { setAttributes({ objectionBg: v || '#fff7ed' }); } },
270 { label: __('Objection text'), value: a.objectionColor, onChange: function (v) { setAttributes({ objectionColor: v || '#9a3412' }); } },
271 { label: __('Objection border'), value: a.objectionBorderColor, onChange: function (v) { setAttributes({ objectionBorderColor: v || '#fed7aa' }); } },
272 { label: __('Response bg'), value: a.responseBg, onChange: function (v) { setAttributes({ responseBg: v || '#f0fdf4' }); } },
273 { label: __('Response text'), value: a.responseColor, onChange: function (v) { setAttributes({ responseColor: v || '#166534' }); } },
274 { label: __('Response border'), value: a.responseBorderColor, onChange: function (v) { setAttributes({ responseBorderColor: v || '#bbf7d0' }); } },
275 { label: __('Label color'), value: a.labelColor, onChange: function (v) { setAttributes({ labelColor: v || '#64748b' }); } }
276 ]
277 }),
278 el(PanelBody, { title: __('Typography'), initialOpen: false },
279 el(getTypoControl(), { label: __('Headline'), value: a.headlineTypo, onChange: function (v) { setAttributes({ headlineTypo: v }); } }),
280 el(getTypoControl(), { label: __('Body Text'), value: a.bodyTypo, onChange: function (v) { setAttributes({ bodyTypo: v }); } })
281 )
282 ),
283 el('div', (function () {
284 var bp = useBlockProps();
285 var _tvf = getTypoCssVars();
286 var s = {};
287 if (_tvf) {
288 Object.assign(s, _tvf(a.headlineTypo, '--bkbg-oh-hl-'));
289 Object.assign(s, _tvf(a.bodyTypo, '--bkbg-oh-bd-'));
290 }
291 bp.style = Object.assign(s, bp.style || {});
292 return bp;
293 }()),
294 el(ObjectionPreview, { attributes: a, setAttributes: setAttributes })
295 )
296 );
297 },
298
299 save: function (props) {
300 return el('div', useBlockProps.save(),
301 el('div', {
302 className: 'bkbg-oh-app',
303 'data-opts': JSON.stringify(props.attributes)
304 })
305 );
306 }
307 });
308 }() );
309