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

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

502 lines 27.4 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 RichText = wp.blockEditor.RichText;
10 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
11 var PanelBody = wp.components.PanelBody;
12 var ToggleControl = wp.components.ToggleControl;
13 var RangeControl = wp.components.RangeControl;
14 var SelectControl = wp.components.SelectControl;
15 var TextControl = wp.components.TextControl;
16 var TextareaControl = wp.components.TextareaControl;
17 var Button = wp.components.Button;
18
19 var _TC, _tv;
20 Object.defineProperty(window, '_bkbgCLgetTC', { get: function () { return _TC || (_TC = window.bkbgTypographyControl); } });
21 Object.defineProperty(window, '_bkbgCLgetTV', { get: function () { return _tv || (_tv = window.bkbgTypoCssVars); } });
22
23 var LOCK_TYPE_OPTIONS = [
24 { label: 'Email Opt-in', value: 'email' },
25 { label: 'Password', value: 'password' },
26 { label: 'Click to Reveal', value: 'click' },
27 ];
28
29 var LOCK_STYLE_OPTIONS = [
30 { label: 'Blur preview', value: 'blur' },
31 { label: 'Hide completely', value: 'hide' },
32 { label: 'Fade out', value: 'fade' },
33 ];
34
35 registerBlockType('blockenberg/content-lock', {
36 title: __('Content Lock', 'blockenberg'),
37 icon: 'lock',
38 category: 'bkbg-marketing',
39 description: __('Gate content behind an email opt-in, password, or click-reveal.', 'blockenberg'),
40
41 edit: function (props) {
42 var a = props.attributes;
43 var set = props.setAttributes;
44 var TC = window._bkbgCLgetTC;
45 var tv = window._bkbgCLgetTV || function () { return {}; };
46 var previewState = useState('locked');
47 var previewMode = previewState[0];
48 var setPreviewMode = previewState[1];
49
50 var blockProps = useBlockProps();
51
52 var gateStyle = Object.assign({
53 background: a.gateBg,
54 borderRadius: a.borderRadius + 'px',
55 padding: a.padding + 'px',
56 maxWidth: a.maxWidth + 'px',
57 margin: '0 auto',
58 textAlign: 'center',
59 display: 'flex',
60 flexDirection: 'column',
61 alignItems: 'center',
62 gap: 16,
63 boxShadow: '0 4px 24px rgba(0,0,0,0.10)',
64 }, tv(a.typoHeading, '--bkcl-head-'), tv(a.typoButton, '--bkcl-btn-'));
65
66 var contentStyle = {
67 filter: a.lockStyle === 'blur' ? 'blur(' + a.blurAmount + 'px)' : 'none',
68 userSelect: 'none',
69 pointerEvents: 'none',
70 position: 'relative',
71 };
72
73 return el(Fragment, null,
74 el(InspectorControls, null,
75 // Lock Type Panel
76 el(PanelBody, { title: 'Lock Type', initialOpen: true },
77 el(SelectControl, {
78 label: 'Gate Method',
79 value: a.lockType,
80 options: LOCK_TYPE_OPTIONS,
81 onChange: function (v) { set({ lockType: v }); },
82 __nextHasNoMarginBottom: true,
83 }),
84 el('div', { style: { height: 12 } }),
85 el(SelectControl, {
86 label: 'Content Lock Style',
87 value: a.lockStyle,
88 options: LOCK_STYLE_OPTIONS,
89 onChange: function (v) { set({ lockStyle: v }); },
90 __nextHasNoMarginBottom: true,
91 }),
92 a.lockStyle === 'blur' && el(Fragment, null,
93 el('div', { style: { height: 12 } }),
94 el(RangeControl, {
95 label: 'Blur Amount (px)',
96 value: a.blurAmount,
97 min: 1, max: 20,
98 onChange: function (v) { set({ blurAmount: v }); },
99 __nextHasNoMarginBottom: true,
100 }),
101 el('div', { style: { height: 12 } }),
102 el(RangeControl, {
103 label: 'Visible preview lines',
104 value: a.teaserLines,
105 min: 1, max: 10,
106 onChange: function (v) { set({ teaserLines: v }); },
107 __nextHasNoMarginBottom: true,
108 })
109 ),
110 el('div', { style: { height: 12 } }),
111 a.lockType === 'email' && el(Fragment, null,
112 el(ToggleControl, {
113 label: 'Remember unlock (localStorage)',
114 checked: a.rememberUnlock,
115 onChange: function (v) { set({ rememberUnlock: v }); },
116 __nextHasNoMarginBottom: true,
117 }),
118 el('div', { style: { height: 8 } }),
119 el(TextControl, {
120 label: 'Storage Key (unique per block)',
121 value: a.storageKey,
122 placeholder: 'e.g. guide-2024',
123 onChange: function (v) { set({ storageKey: v }); },
124 help: 'Unique ID so each lock is remembered separately.',
125 __nextHasNoMarginBottom: true,
126 }),
127 el('div', { style: { height: 8 } }),
128 el(TextControl, {
129 label: 'Webhook URL (optional)',
130 value: a.webhookUrl,
131 placeholder: 'https://hooks.zapier.com/...',
132 onChange: function (v) { set({ webhookUrl: v }); },
133 help: 'POST email to this URL (Zapier, Make, etc.)',
134 __nextHasNoMarginBottom: true,
135 })
136 ),
137 a.lockType === 'password' && el(Fragment, null,
138 el(TextControl, {
139 label: 'Password',
140 value: a.password,
141 type: 'text',
142 onChange: function (v) { set({ password: v }); },
143 help: 'Password is stored in HTML. Not for sensitive content.',
144 __nextHasNoMarginBottom: true,
145 })
146 )
147 ),
148
149 // Locked Content Panel
150 el(PanelBody, { title: 'Locked Content', initialOpen: true },
151 el('p', { style: { fontSize: 12, color: '#6b7280', margin: '0 0 8px' } },
152 'Paste or type the content that will be locked. HTML is supported.'
153 ),
154 el(TextareaControl, {
155 label: 'Locked Content (HTML)',
156 value: a.lockedContent,
157 rows: 6,
158 onChange: function (v) { set({ lockedContent: v }); },
159 __nextHasNoMarginBottom: true,
160 })
161 ),
162
163 // Gate UI Panel
164 el(PanelBody, { title: 'Gate Appearance', initialOpen: false },
165 el(ToggleControl, {
166 label: 'Show Icon',
167 checked: a.showIcon,
168 onChange: function (v) { set({ showIcon: v }); },
169 __nextHasNoMarginBottom: true,
170 }),
171 a.showIcon && el(TextControl, {
172 label: 'Icon (emoji)',
173 value: a.icon,
174 onChange: function (v) { set({ icon: v }); },
175 __nextHasNoMarginBottom: true,
176 }),
177 el('div', { style: { height: 10 } }),
178 el(ToggleControl, {
179 label: 'Show Eyebrow Label',
180 checked: a.showEyebrow,
181 onChange: function (v) { set({ showEyebrow: v }); },
182 __nextHasNoMarginBottom: true,
183 }),
184 a.showEyebrow && el(TextControl, {
185 label: 'Eyebrow Text',
186 value: a.eyebrow,
187 onChange: function (v) { set({ eyebrow: v }); },
188 __nextHasNoMarginBottom: true,
189 }),
190 el('div', { style: { height: 10 } }),
191 el(TextControl, {
192 label: 'Heading',
193 value: a.heading,
194 onChange: function (v) { set({ heading: v }); },
195 __nextHasNoMarginBottom: true,
196 }),
197 el('div', { style: { height: 10 } }),
198 el(TextControl, {
199 label: 'Sub-text',
200 value: a.subText,
201 onChange: function (v) { set({ subText: v }); },
202 __nextHasNoMarginBottom: true,
203 }),
204 el('div', { style: { height: 12 } }),
205 el(RangeControl, {
206 label: 'Max Width (px)',
207 value: a.maxWidth,
208 min: 300, max: 900,
209 onChange: function (v) { set({ maxWidth: v }); },
210 __nextHasNoMarginBottom: true,
211 }),
212 el('div', { style: { height: 12 } }),
213 el(RangeControl, {
214 label: 'Padding (px)',
215 value: a.padding,
216 min: 16, max: 80,
217 onChange: function (v) { set({ padding: v }); },
218 __nextHasNoMarginBottom: true,
219 }),
220 el('div', { style: { height: 12 } }),
221 el(RangeControl, {
222 label: 'Border Radius (px)',
223 value: a.borderRadius,
224 min: 0, max: 40,
225 onChange: function (v) { set({ borderRadius: v }); },
226 __nextHasNoMarginBottom: true,
227 }),
228 el('div', { style: { height: 12 } }),
229 el(RangeControl, {
230 label: 'Input Border Radius (px)',
231 value: a.inputRadius,
232 min: 0, max: 32,
233 onChange: function (v) { set({ inputRadius: v }); },
234 __nextHasNoMarginBottom: true,
235 })
236 ),
237
238 // Form fields Panel
239 el(PanelBody, { title: 'Form Labels', initialOpen: false },
240 a.lockType === 'email' && el(Fragment, null,
241 el(TextControl, {
242 label: 'Email Placeholder',
243 value: a.emailPlaceholder,
244 onChange: function (v) { set({ emailPlaceholder: v }); },
245 __nextHasNoMarginBottom: true,
246 }),
247 el('div', { style: { height: 8 } }),
248 el(TextControl, {
249 label: 'Submit Button Label',
250 value: a.submitLabel,
251 onChange: function (v) { set({ submitLabel: v }); },
252 __nextHasNoMarginBottom: true,
253 }),
254 el('div', { style: { height: 8 } }),
255 el(ToggleControl, {
256 label: 'Show Privacy Note',
257 checked: a.showPrivacy,
258 onChange: function (v) { set({ showPrivacy: v }); },
259 __nextHasNoMarginBottom: true,
260 }),
261 a.showPrivacy && el(TextControl, {
262 label: 'Privacy Note',
263 value: a.privacyNote,
264 onChange: function (v) { set({ privacyNote: v }); },
265 __nextHasNoMarginBottom: true,
266 }),
267 el('div', { style: { height: 8 } }),
268 el(TextControl, {
269 label: 'Success Heading',
270 value: a.successHeading,
271 onChange: function (v) { set({ successHeading: v }); },
272 __nextHasNoMarginBottom: true,
273 }),
274 el('div', { style: { height: 8 } }),
275 el(TextControl, {
276 label: 'Success Text',
277 value: a.successText,
278 onChange: function (v) { set({ successText: v }); },
279 __nextHasNoMarginBottom: true,
280 })
281 ),
282 a.lockType === 'password' && el(Fragment, null,
283 el(TextControl, {
284 label: 'Password Input Placeholder',
285 value: a.passwordPlaceholder,
286 onChange: function (v) { set({ passwordPlaceholder: v }); },
287 __nextHasNoMarginBottom: true,
288 }),
289 el('div', { style: { height: 8 } }),
290 el(TextControl, {
291 label: 'Submit Button Label',
292 value: a.passwordSubmitLabel,
293 onChange: function (v) { set({ passwordSubmitLabel: v }); },
294 __nextHasNoMarginBottom: true,
295 }),
296 el('div', { style: { height: 8 } }),
297 el(TextControl, {
298 label: 'Error Message',
299 value: a.passwordErrorMsg,
300 onChange: function (v) { set({ passwordErrorMsg: v }); },
301 __nextHasNoMarginBottom: true,
302 })
303 ),
304 a.lockType === 'click' && el(Fragment, null,
305 el(TextControl, {
306 label: 'Reveal Button Label',
307 value: a.clickButtonLabel,
308 onChange: function (v) { set({ clickButtonLabel: v }); },
309 __nextHasNoMarginBottom: true,
310 }),
311 el('div', { style: { height: 8 } }),
312 el(TextControl, {
313 label: 'Button Icon (emoji)',
314 value: a.clickButtonIcon,
315 onChange: function (v) { set({ clickButtonIcon: v }); },
316 __nextHasNoMarginBottom: true,
317 })
318 )
319 ),
320
321 // Colors Panel
322 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
323 TC && el(TC, { label: __('Heading', 'blockenberg'), value: a.typoHeading, onChange: function (v) { set({ typoHeading: v }); } }),
324 TC && el(TC, { label: __('Button', 'blockenberg'), value: a.typoButton, onChange: function (v) { set({ typoButton: v }); } }),
325 el(RangeControl, { label: __('Eyebrow Size (px)', 'blockenberg'), value: a.eyebrowSize, min: 10, max: 24, __nextHasNoMarginBottom: true, onChange: function (v) { set({ eyebrowSize: v }); } }),
326 el(RangeControl, { label: __('Sub-text Size (px)', 'blockenberg'), value: a.subTextSize, min: 12, max: 36, __nextHasNoMarginBottom: true, onChange: function (v) { set({ subTextSize: v }); } })
327 ),
328 el(PanelColorSettings, {
329 title: 'Colors',
330 initialOpen: false,
331 colorSettings: [
332 { label: 'Gate Card Background', value: a.gateBg, onChange: function (v) { set({ gateBg: v || '#ffffff' }); } },
333 { label: 'Eyebrow Color', value: a.eyebrowColor, onChange: function (v) { set({ eyebrowColor: v || '#6366f1' }); } },
334 { label: 'Heading Color', value: a.headingColor, onChange: function (v) { set({ headingColor: v || '#111827' }); } },
335 { label: 'Text Color', value: a.textColor, onChange: function (v) { set({ textColor: v || '#6b7280' }); } },
336 { label: 'Input Background', value: a.inputBg, onChange: function (v) { set({ inputBg: v || '#f9fafb' }); } },
337 { label: 'Input Border', value: a.inputBorder, onChange: function (v) { set({ inputBorder: v || '#e5e7eb' }); } },
338 { label: 'Input Focus Border', value: a.inputFocusBorder, onChange: function (v) { set({ inputFocusBorder: v || '#6366f1' }); } },
339 { label: 'Button Background', value: a.btnBg, onChange: function (v) { set({ btnBg: v || '#6366f1' }); } },
340 { label: 'Button Text Color', value: a.btnColor, onChange: function (v) { set({ btnColor: v || '#ffffff' }); } },
341 { label: 'Privacy Note Color', value: a.privacyColor, onChange: function (v) { set({ privacyColor: v || '#9ca3af' }); } },
342 ]
343 })
344 ),
345
346 // Editor Preview
347 el('div', blockProps,
348 // Preview toggle
349 el('div', { style: { display: 'flex', gap: 8, marginBottom: 12 } },
350 el(Button, {
351 onClick: function () { setPreviewMode('locked'); },
352 variant: previewMode === 'locked' ? 'primary' : 'secondary',
353 size: 'small',
354 __nextHasNoMarginBottom: true,
355 }, '🔒 Locked view'),
356 el(Button, {
357 onClick: function () { setPreviewMode('unlocked'); },
358 variant: previewMode === 'unlocked' ? 'primary' : 'secondary',
359 size: 'small',
360 __nextHasNoMarginBottom: true,
361 }, '🔓 Unlocked view')
362 ),
363
364 // Locked view
365 previewMode === 'locked' && el('div', { className: 'bkbg-cl-locked-preview', style: { position: 'relative' } },
366 // Blurred content behind
367 a.lockStyle !== 'hide' && el('div', { style: contentStyle },
368 el('div', { dangerouslySetInnerHTML: { __html: a.lockedContent } })
369 ),
370 // Gate overlay
371 el('div', {
372 style: {
373 position: a.lockStyle !== 'hide' ? 'absolute' : 'static',
374 inset: a.lockStyle !== 'hide' ? '0' : 'auto',
375 display: 'flex',
376 alignItems: 'center',
377 justifyContent: 'center',
378 padding: a.lockStyle !== 'hide' ? '20px' : '0',
379 background: a.lockStyle !== 'hide' ? 'linear-gradient(transparent 0%, rgba(255,255,255,0.95) 40%)' : 'transparent',
380 }
381 },
382 el('div', { style: gateStyle },
383 a.showIcon && a.icon && el('div', { style: { fontSize: 40 } }, a.icon),
384 a.showEyebrow && a.eyebrow && el('div', {
385 style: {
386 fontSize: (a.eyebrowSize || 11),
387 fontWeight: 700,
388 letterSpacing: '0.08em',
389 textTransform: 'uppercase',
390 color: a.eyebrowColor,
391 }
392 }, a.eyebrow),
393 el('h3', { className: 'bkbg-cl-heading', style: { margin: 0, color: a.headingColor } }, a.heading),
394 a.subText && el('p', { style: { margin: 0, fontSize: (a.subTextSize || 14), color: a.textColor, lineHeight: 1.6 } }, a.subText),
395 // Form preview (readonly)
396 a.lockType === 'email' && el('div', { style: { width: '100%', display: 'flex', flexDirection: 'column', gap: 10 } },
397 el('input', {
398 type: 'email',
399 placeholder: a.emailPlaceholder,
400 disabled: true,
401 style: {
402 width: '100%',
403 padding: '12px 16px',
404 borderRadius: a.inputRadius + 'px',
405 border: '1px solid ' + a.inputBorder,
406 background: a.inputBg,
407 fontSize: 15,
408 boxSizing: 'border-box',
409 }
410 }),
411 el('button', {
412 disabled: true,
413 className: 'bkbg-cl-btn',
414 style: {
415 padding: '12px 24px',
416 borderRadius: a.inputRadius + 'px',
417 background: a.btnBg,
418 color: a.btnColor,
419 border: 'none',
420 cursor: 'not-allowed',
421 }
422 }, a.submitLabel),
423 a.showPrivacy && el('p', { style: { margin: 0, fontSize: 12, color: a.privacyColor } }, a.privacyNote)
424 ),
425 a.lockType === 'password' && el('div', { style: { width: '100%', display: 'flex', flexDirection: 'column', gap: 10 } },
426 el('input', {
427 type: 'password',
428 placeholder: a.passwordPlaceholder,
429 disabled: true,
430 style: {
431 width: '100%',
432 padding: '12px 16px',
433 borderRadius: a.inputRadius + 'px',
434 border: '1px solid ' + a.inputBorder,
435 background: a.inputBg,
436 fontSize: 15,
437 boxSizing: 'border-box',
438 }
439 }),
440 el('button', {
441 disabled: true,
442 className: 'bkbg-cl-btn',
443 style: {
444 padding: '12px 24px',
445 borderRadius: a.inputRadius + 'px',
446 background: a.btnBg,
447 color: a.btnColor,
448 border: 'none',
449 cursor: 'not-allowed',
450 }
451 }, a.passwordSubmitLabel)
452 ),
453 a.lockType === 'click' && el('button', {
454 disabled: true,
455 className: 'bkbg-cl-btn',
456 style: {
457 padding: '14px 28px',
458 borderRadius: a.inputRadius + 'px',
459 background: a.btnBg,
460 color: a.btnColor,
461 border: 'none',
462 cursor: 'not-allowed',
463 display: 'flex',
464 alignItems: 'center',
465 gap: 8,
466 }
467 }, a.clickButtonIcon + ' ' + a.clickButtonLabel)
468 )
469 )
470 ),
471
472 // Unlocked view
473 previewMode === 'unlocked' && el('div', null,
474 el('div', {
475 style: {
476 background: '#f0fdf4',
477 border: '1px solid #86efac',
478 borderRadius: 8,
479 padding: '8px 14px',
480 marginBottom: 12,
481 fontSize: 13,
482 color: '#166534',
483 }
484 }, '�
485 ' + a.successHeading + '' + a.successText),
486 el('div', { dangerouslySetInnerHTML: { __html: a.lockedContent } })
487 )
488 )
489 );
490 },
491
492 save: function (props) {
493 return el('div', useBlockProps.save(),
494 el('div', {
495 className: 'bkbg-cl-app',
496 'data-opts': JSON.stringify(props.attributes),
497 })
498 );
499 }
500 });
501 }() );
502