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

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

312 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 = window.wp.element.createElement;
3 var __ = function (s) { return s; };
4 var registerBlockType = window.wp.blocks.registerBlockType;
5 var InspectorControls = window.wp.blockEditor.InspectorControls;
6 var MediaUpload = window.wp.blockEditor.MediaUpload;
7 var MediaUploadCheck = window.wp.blockEditor.MediaUploadCheck;
8 var PanelBody = window.wp.components.PanelBody;
9 var ToggleControl = window.wp.components.ToggleControl;
10 var SelectControl = window.wp.components.SelectControl;
11 var RangeControl = window.wp.components.RangeControl;
12 var TextControl = window.wp.components.TextControl;
13 var Button = window.wp.components.Button;
14 var PanelColorSettings = window.wp.blockEditor.PanelColorSettings;
15
16 var _TypographyControl, _typoCssVars;
17 function getTypographyControl() { return _TypographyControl || (_TypographyControl = window.bkbgTypographyControl); }
18 function getTypoCssVars() { return _typoCssVars || (_typoCssVars = window.bkbgTypoCssVars); }
19
20 var shadowMap = {
21 none: 'none',
22 sm: '0 1px 3px rgba(0,0,0,0.12)',
23 md: '0 4px 12px rgba(0,0,0,0.18)',
24 lg: '0 10px 30px rgba(0,0,0,0.25)',
25 };
26
27 registerBlockType('blockenberg/image-box', {
28 title: __('Image Box'),
29 description: __('A clickable image card with overlay, hover effects, and a link.'),
30 category: 'bkbg-media',
31 icon: el('svg', { viewBox: '0 0 24 24', fill: 'currentColor', width: 24, height: 24 },
32 el('path', { d: 'M21 3H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H3V5h18v14zm-5.5-7l-3 3.86-2.5-2.5-3.5 4.64H19l-3.5-5z' })
33 ),
34
35 edit: function (props) {
36 var a = props.attributes;
37 var setA = props.setAttributes;
38
39 var ratioOptions = [
40 { label: '16:9', value: '56.25' },
41 { label: '4:3', value: '75' },
42 { label: '1:1', value: '100' },
43 { label: '3:4', value: '133' },
44 { label: '21:9', value: '42.85' },
45 ];
46
47 var inspector = el(InspectorControls, null,
48 el(PanelBody, { title: __('Image'), initialOpen: true },
49 el(MediaUploadCheck, null,
50 el(MediaUpload, {
51 onSelect: function (media) {
52 setA({ imageUrl: media.url, imageId: media.id, imageAlt: media.alt || '' });
53 },
54 allowedTypes: ['image'],
55 value: a.imageId,
56 render: function (ref) {
57 return el('div', null,
58 a.imageUrl && el('img', {
59 src: a.imageUrl,
60 alt: a.imageAlt,
61 style: { width: '100%', borderRadius: 6, marginBottom: 8 }
62 }),
63 el(Button, {
64 onClick: ref.open,
65 variant: a.imageId ? 'secondary' : 'primary',
66 style: { marginBottom: 8 },
67 }, a.imageId ? __('Replace Image') : __('Select Image')),
68 a.imageId && el(Button, {
69 onClick: function () { setA({ imageUrl: '', imageId: 0, imageAlt: '' }); },
70 variant: 'link',
71 isDestructive: true,
72 }, __('Remove Image'))
73 );
74 }
75 })
76 ),
77 el(SelectControl, {
78 label: __('Aspect Ratio'),
79 value: a.imageRatio,
80 options: ratioOptions,
81 onChange: function (v) { setA({ imageRatio: v }); },
82 })
83 ),
84 el(PanelBody, { title: __('Content'), initialOpen: true },
85 el(TextControl, {
86 label: __('Title'),
87 value: a.title,
88 onChange: function (v) { setA({ title: v }); },
89 }),
90 el(TextControl, {
91 label: __('Subtitle'),
92 value: a.subtitle,
93 onChange: function (v) { setA({ subtitle: v }); },
94 }),
95 el(TextControl, {
96 label: __('Link URL'),
97 value: a.linkUrl,
98 onChange: function (v) { setA({ linkUrl: v }); },
99 }),
100 el(SelectControl, {
101 label: __('Link Target'),
102 value: a.linkTarget,
103 options: [
104 { label: 'Same tab', value: '_self' },
105 { label: 'New tab', value: '_blank' },
106 ],
107 onChange: function (v) { setA({ linkTarget: v }); },
108 }),
109 el(SelectControl, {
110 label: __('Title Position'),
111 value: a.titlePosition,
112 options: [
113 { label: 'Overlay – Bottom', value: 'over-bottom' },
114 { label: 'Overlay – Center', value: 'over-center' },
115 { label: 'Below image', value: 'below' },
116 ],
117 onChange: function (v) { setA({ titlePosition: v }); },
118 }),
119 ),
120 el(PanelBody, { title: __('Style'), initialOpen: false },
121 el(SelectControl, {
122 label: __('Hover Effect'),
123 value: a.hoverEffect,
124 options: [
125 { label: 'Zoom', value: 'zoom' },
126 { label: 'Fade', value: 'fade' },
127 { label: 'Lift', value: 'lift' },
128 { label: 'Overlay', value: 'overlay' },
129 { label: 'None', value: 'none' },
130 ],
131 onChange: function (v) { setA({ hoverEffect: v }); },
132 }),
133 el(SelectControl, {
134 label: __('Box Shadow'),
135 value: a.shadow,
136 options: [
137 { label: 'None', value: 'none' },
138 { label: 'Small', value: 'sm' },
139 { label: 'Medium', value: 'md' },
140 { label: 'Large', value: 'lg' },
141 ],
142 onChange: function (v) { setA({ shadow: v }); },
143 }),
144 el(RangeControl, {
145 label: __('Border Radius'), value: a.borderRadius, min: 0, max: 40,
146 onChange: function (v) { setA({ borderRadius: v }); },
147 }),
148 el(RangeControl, {
149 label: __('Width (%)'), value: a.width, min: 20, max: 100, step: 5,
150 onChange: function (v) { setA({ width: v }); },
151 }),
152 el(ToggleControl, {
153 label: __('Show overlay'),
154 checked: a.overlay,
155 onChange: function (v) { setA({ overlay: v }); },
156 __nextHasNoMarginBottom: true,
157 }),
158 a.overlay && el(RangeControl, {
159 label: __('Overlay Hover Opacity (%)'), value: a.overlayHoverOpacity, min: 0, max: 100,
160 onChange: function (v) { setA({ overlayHoverOpacity: v }); },
161 })
162 ),
163
164 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
165 getTypographyControl() && el( getTypographyControl(), { label: __( 'Title' ), value: a.titleTypo || {}, onChange: function(v){ setA({ titleTypo: v }); } }),
166 getTypographyControl() && el( getTypographyControl(), { label: __( 'Subtitle' ), value: a.subtitleTypo || {}, onChange: function(v){ setA({ subtitleTypo: v }); } })
167 ),
168 el(PanelBody, { title: __('Colors'), initialOpen: false },
169 el(PanelColorSettings, {
170 title: __('Text Colors'),
171 initialOpen: false,
172 colorSettings: [
173 { label: __('Title Color'), value: a.titleColor, onChange: function (v) { setA({ titleColor: v || '#ffffff' }); } },
174 { label: __('Subtitle Color'), value: a.subtitleColor, onChange: function (v) { setA({ subtitleColor: v || 'rgba(255,255,255,0.85)' }); } },
175 ],
176 })
177 )
178 );
179
180 /* Editor preview */
181 var below = a.titlePosition === 'below';
182
183 var innerStyle = {
184 position: 'relative',
185 overflow: 'hidden',
186 borderRadius: a.borderRadius + 'px',
187 width: a.width + '%',
188 boxShadow: shadowMap[a.shadow] || 'none',
189 display: 'inline-block',
190 verticalAlign:'top',
191 cursor: a.linkUrl ? 'pointer' : 'default',
192 };
193
194 var ratioBox = {
195 paddingBottom: a.imageRatio + '%',
196 position: 'relative',
197 overflow: 'hidden',
198 background: a.imageUrl ? 'transparent' : '#e5e7eb',
199 };
200
201 var imgStyle = {
202 position: 'absolute', inset: 0,
203 width: '100%', height: '100%',
204 objectFit: 'cover',
205 };
206
207 var overlayStyle = a.overlay ? {
208 position: 'absolute', inset: 0,
209 background: a.overlayColor,
210 } : {};
211
212 var textJustify = a.titlePosition === 'over-center' ? 'center' : 'flex-start';
213 var textAlign = a.titlePosition === 'over-center' ? 'center' : 'left';
214
215 var textOverlayStyle = {
216 position: 'absolute',
217 left: 0, right: 0, padding: '16px',
218 display: 'flex', flexDirection: 'column',
219 justifyContent: textJustify,
220 alignItems: textJustify,
221 textAlign: textAlign,
222 };
223 if (a.titlePosition === 'over-bottom') {
224 textOverlayStyle.bottom = 0;
225 } else if (a.titlePosition === 'over-center') {
226 textOverlayStyle.top = '50%';
227 textOverlayStyle.transform = 'translateY(-50%)';
228 }
229
230 return el('div', { className: 'bkbg-imgb-editor', style: (function(){
231 var s = { maxWidth: '100%' };
232 if (a.titleSize) s['--bkbg-imgb-title-sz'] = a.titleSize + 'px';
233 if (a.titleWeight) s['--bkbg-imgb-title-w'] = String(a.titleWeight);
234 if (a.titleLineHeight) s['--bkbg-imgb-title-lh'] = String(a.titleLineHeight);
235 if (a.subtitleSize) s['--bkbg-imgb-sub-sz'] = a.subtitleSize + 'px';
236 if (a.subtitleFontWeight) s['--bkbg-imgb-sub-w'] = String(a.subtitleFontWeight);
237 if (a.subtitleLineHeight) s['--bkbg-imgb-sub-lh'] = String(a.subtitleLineHeight);
238 var _tv2 = getTypoCssVars();
239 if (_tv2) {
240 Object.assign(s, _tv2(a.titleTypo, '--bkbg-imgb-tt-'));
241 Object.assign(s, _tv2(a.subtitleTypo, '--bkbg-imgb-st-'));
242 }
243 return s;
244 })() },
245 inspector,
246 el('div', { style: innerStyle },
247 el('div', { style: ratioBox },
248 a.imageUrl
249 ? el('img', { src: a.imageUrl, alt: a.imageAlt, style: imgStyle })
250 : el('div', { style: Object.assign({}, imgStyle, { display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#9ca3af', fontSize: 13 }) }, __('Select an image in the sidebar')),
251 a.overlay && el('div', { style: overlayStyle }),
252 !below && el('div', { style: textOverlayStyle },
253 el('span', { className: 'bkbg-imgb-title', style: { color: a.titleColor, display: 'block' } }, a.title),
254 a.subtitle && el('span', { className: 'bkbg-imgb-subtitle', style: { color: a.subtitleColor, marginTop: 4 } }, a.subtitle)
255 )
256 ),
257 below && el('div', { style: { padding: '12px' } },
258 el('span', { className: 'bkbg-imgb-title', style: { color: '#111827', display: 'block' } }, a.title),
259 a.subtitle && el('span', { className: 'bkbg-imgb-subtitle', style: { color: '#6b7280', marginTop: 4, display: 'block' } }, a.subtitle)
260 )
261 )
262 );
263 },
264
265 save: function (props) {
266 var a = props.attributes;
267 var below = a.titlePosition === 'below';
268
269 var Tag = a.linkUrl ? 'a' : 'div';
270 var linkAttrs = a.linkUrl ? { href: a.linkUrl, target: a.linkTarget, rel: a.linkTarget === '_blank' ? 'noopener noreferrer' : undefined } : {};
271
272 var wrapProps = Object.assign({}, linkAttrs, {
273 className: 'bkbg-imgb-wrap bkbg-imgb-hover--' + a.hoverEffect + ' bkbg-imgb-shadow--' + a.shadow,
274 style: (function(){
275 var s = {
276 '--bkbg-imgb-radius': a.borderRadius + 'px',
277 '--bkbg-imgb-width': a.width + '%',
278 '--bkbg-imgb-hover-opa': a.overlayHoverOpacity / 100,
279 };
280 if (a.titleSize) s['--bkbg-imgb-title-sz'] = a.titleSize + 'px';
281 if (a.titleWeight) s['--bkbg-imgb-title-w'] = String(a.titleWeight);
282 if (a.titleLineHeight) s['--bkbg-imgb-title-lh'] = String(a.titleLineHeight);
283 if (a.subtitleSize) s['--bkbg-imgb-sub-sz'] = a.subtitleSize + 'px';
284 if (a.subtitleFontWeight) s['--bkbg-imgb-sub-w'] = String(a.subtitleFontWeight);
285 if (a.subtitleLineHeight) s['--bkbg-imgb-sub-lh'] = String(a.subtitleLineHeight);
286 var _tv2 = getTypoCssVars();
287 if (_tv2) {
288 Object.assign(s, _tv2(a.titleTypo, '--bkbg-imgb-tt-'));
289 Object.assign(s, _tv2(a.subtitleTypo, '--bkbg-imgb-st-'));
290 }
291 return s;
292 })()
293 });
294
295 return el(Tag, wrapProps,
296 el('div', { className: 'bkbg-imgb-media', style: { paddingBottom: a.imageRatio + '%' } },
297 a.imageUrl && el('img', { src: a.imageUrl, alt: a.imageAlt, className: 'bkbg-imgb-img', loading: 'lazy' }),
298 a.overlay && el('div', { className: 'bkbg-imgb-overlay', style: { background: a.overlayColor } }),
299 !below && el('div', { className: 'bkbg-imgb-text bkbg-imgb-text--' + a.titlePosition },
300 el('span', { className: 'bkbg-imgb-title', style: { color: a.titleColor } }, a.title),
301 a.subtitle && el('span', { className: 'bkbg-imgb-subtitle', style: { color: a.subtitleColor } }, a.subtitle)
302 )
303 ),
304 below && el('div', { className: 'bkbg-imgb-caption' },
305 el('span', { className: 'bkbg-imgb-title' }, a.title),
306 a.subtitle && el('span', { className: 'bkbg-imgb-subtitle' }, a.subtitle)
307 )
308 );
309 },
310 });
311 })();
312