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

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

351 lines 19.7 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 __ = wp.i18n.__;
4 var registerBlockType = wp.blocks.registerBlockType;
5 var InspectorControls = wp.blockEditor.InspectorControls;
6 var MediaUpload = wp.blockEditor.MediaUpload;
7 var MediaUploadCheck = wp.blockEditor.MediaUploadCheck;
8 var RichText = wp.blockEditor.RichText;
9 var useBlockProps = wp.blockEditor.useBlockProps;
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 Button = wp.components.Button;
17
18 var TAG_OPTIONS = [
19 { label: 'H2', value: 'h2' }, { label: 'H3', value: 'h3' },
20 { label: 'H4', value: 'h4' }, { label: 'H5', value: 'h5' },
21 { label: 'p', value: 'p' },
22 ];
23
24 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
25 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
26
27 function hexToRgba(hex, opacity) {
28 if (!hex) return 'rgba(139,92,246,' + opacity / 100 + ')';
29 hex = hex.replace('#', '');
30 if (hex.length === 3) hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
31 var r = parseInt(hex.substring(0,2), 16);
32 var g = parseInt(hex.substring(2,4), 16);
33 var b = parseInt(hex.substring(4,6), 16);
34 return 'rgba(' + r + ',' + g + ',' + b + ',' + (opacity / 100) + ')';
35 }
36
37 function buildCardStyle(a) {
38 var tv = getTypoCssVars();
39 var s = {
40 background: a.cardBg,
41 border: a.showBorder ? a.borderWidth + 'px solid ' + a.cardBorder : 'none',
42 borderRadius: a.cardRadius + 'px',
43 padding: a.cardPadding + 'px',
44 position: 'relative',
45 overflow: 'hidden',
46 cursor: 'default',
47 '--bkspot-color': hexToRgba(a.spotlightColor, a.spotlightOpacity),
48 '--bkspot-size': a.spotlightSize + 'px',
49 '--bkspot-hd-sz': a.headingSize + 'px',
50 '--bkspot-hd-w': String(a.headingFontWeight || '700'),
51 '--bkspot-hd-lh': String(a.headingLineHeight || 1.3),
52 '--bkspot-tx-sz': a.textSize + 'px',
53 '--bkspot-tx-lh': String(a.textLineHeight || 1.6),
54 };
55 Object.assign(s, tv(a.headingTypo, '--bkspot-hd-'));
56 Object.assign(s, tv(a.textTypo, '--bkspot-tx-'));
57 Object.assign(s, tv(a.linkTypo, '--bkspot-lk-'));
58 return s;
59 }
60
61 function CardPreview(a) {
62 return el('div', { className: 'bkspot-card', style: buildCardStyle(a) },
63 /* spotlight overlay - shown statically in editor */
64 el('div', {
65 style: {
66 position: 'absolute', inset: 0, pointerEvents: 'none', zIndex: 0,
67 background: 'radial-gradient(circle at 50% 30%, ' + hexToRgba(a.spotlightColor, a.spotlightOpacity) + ', transparent ' + a.spotlightSize + 'px)',
68 borderRadius: a.cardRadius + 'px',
69 opacity: 0.5,
70 }
71 }),
72 a.showBadge && a.badgeText && el('span', {
73 style: {
74 position: 'absolute', top: '16px', right: '16px', zIndex: 1,
75 background: a.badgeBg, color: a.badgeColor,
76 fontSize: '11px', fontWeight: 700, padding: '3px 8px', borderRadius: '4px',
77 }
78 }, a.badgeText),
79
80 a.showImage && a.imageUrl && el('div', {
81 style: {
82 backgroundImage: 'url(' + a.imageUrl + ')', backgroundSize: 'cover',
83 backgroundPosition: 'center', height: a.imageHeight + 'px',
84 borderRadius: (a.cardRadius - 4) + 'px', marginBottom: '16px', position: 'relative', zIndex: 1,
85 }
86 }),
87
88 el('div', { style: { position: 'relative', zIndex: 1 } },
89 a.showIcon && !a.showImage && el('span', {
90 className: 'dashicons dashicons-' + a.icon,
91 style: { fontSize: a.iconSize + 'px', width: a.iconSize + 'px', height: a.iconSize + 'px', lineHeight: 1, color: a.iconColor, marginBottom: '12px', display: 'block' }
92 }),
93 el(RichText.Content || 'div', null), /* placeholder for editor richtext */
94 el(a.tag || 'h3', { style: { margin: '0 0 8px', color: a.headingColor, fontSize: a.headingSize + 'px', fontWeight: 700, lineHeight: 1.3 } }, a.heading || __('Spotlight Card', 'blockenberg')),
95 el('p', { style: { margin: '0 0 16px', color: a.textColor, fontSize: a.textSize + 'px', lineHeight: 1.6 } }, a.text),
96 a.showLink && el('a', {
97 href: a.linkUrl,
98 style: { color: a.linkColor, fontWeight: 600, textDecoration: 'none', fontSize: a.textSize + 'px' }
99 }, a.linkLabel),
100 ),
101 );
102 }
103
104 registerBlockType('blockenberg/spotlight-card', {
105 edit: function (props) {
106 var a = props.attributes;
107 var set = props.setAttributes;
108 var blockProps = useBlockProps();
109
110 return el('div', blockProps,
111 el(InspectorControls, null,
112 el(PanelBody, { title: __('Content', 'blockenberg'), initialOpen: true },
113 el(SelectControl, {
114 label: __('Heading Tag'), value: a.tag, options: TAG_OPTIONS,
115 onChange: function (v) { set({ tag: v }); }
116 }),
117 ),
118 el(PanelBody, { title: __('Icon & Image', 'blockenberg'), initialOpen: false },
119 el(ToggleControl, {
120 label: __('Show Icon'), checked: a.showIcon,
121 onChange: function (v) { set({ showIcon: v, showImage: v ? false : a.showImage }); },
122 __nextHasNoMarginBottom: true
123 }),
124 a.showIcon && el(TextControl, {
125 label: __('Dashicon Name'), value: a.icon,
126 onChange: function (v) { set({ icon: v }); }
127 }),
128 a.showIcon && el(RangeControl, {
129 label: __('Icon Size (px)'), value: a.iconSize, min: 20, max: 80,
130 onChange: function (v) { set({ iconSize: v }); }
131 }),
132 el(ToggleControl, {
133 label: __('Show Image'), checked: a.showImage,
134 onChange: function (v) { set({ showImage: v, showIcon: v ? false : a.showIcon }); },
135 __nextHasNoMarginBottom: true
136 }),
137 a.showImage && el(MediaUploadCheck, null,
138 el(MediaUpload, {
139 onSelect: function (m) { set({ imageUrl: m.url, imageId: m.id }); },
140 allowedTypes: ['image'], value: a.imageId,
141 render: function (ref) {
142 return el(Button, {
143 onClick: ref.open, variant: 'secondary',
144 style: { width: '100%', justifyContent: 'center', marginBottom: '6px' }
145 }, a.imageUrl ? __('Change Image') : __('Select Image'));
146 }
147 })
148 ),
149 a.showImage && el(RangeControl, {
150 label: __('Image Height (px)'), value: a.imageHeight, min: 80, max: 400,
151 onChange: function (v) { set({ imageHeight: v }); }
152 }),
153 ),
154 el(PanelBody, { title: __('Badge & Link', 'blockenberg'), initialOpen: false },
155 el(ToggleControl, {
156 label: __('Show Badge'), checked: a.showBadge,
157 onChange: function (v) { set({ showBadge: v }); }, __nextHasNoMarginBottom: true
158 }),
159 a.showBadge && el(TextControl, {
160 label: __('Badge Text'), value: a.badgeText,
161 onChange: function (v) { set({ badgeText: v }); }
162 }),
163 el(ToggleControl, {
164 label: __('Show Link'), checked: a.showLink,
165 onChange: function (v) { set({ showLink: v }); }, __nextHasNoMarginBottom: true
166 }),
167 a.showLink && el(TextControl, {
168 label: __('Link Label'), value: a.linkLabel,
169 onChange: function (v) { set({ linkLabel: v }); }
170 }),
171 a.showLink && el(TextControl, {
172 label: __('Link URL'), value: a.linkUrl,
173 onChange: function (v) { set({ linkUrl: v }); }
174 }),
175 ),
176 el(PanelBody, { title: __('Spotlight Effect', 'blockenberg'), initialOpen: false },
177 el(RangeControl, {
178 label: __('Spotlight Size (px)'), value: a.spotlightSize, min: 100, max: 700,
179 onChange: function (v) { set({ spotlightSize: v }); }
180 }),
181 el(RangeControl, {
182 label: __('Spotlight Opacity %'), value: a.spotlightOpacity, min: 2, max: 60,
183 onChange: function (v) { set({ spotlightOpacity: v }); }
184 }),
185 ),
186 el(PanelBody, { title: __('Card Style', 'blockenberg'), initialOpen: false },
187 el(RangeControl, {
188 label: __('Border Radius (px)'), value: a.cardRadius, min: 0, max: 40,
189 onChange: function (v) { set({ cardRadius: v }); }
190 }),
191 el(RangeControl, {
192 label: __('Padding (px)'), value: a.cardPadding, min: 8, max: 64,
193 onChange: function (v) { set({ cardPadding: v }); }
194 }),
195 el(ToggleControl, {
196 label: __('Show Border'), checked: a.showBorder,
197 onChange: function (v) { set({ showBorder: v }); }, __nextHasNoMarginBottom: true
198 }),
199 a.showBorder && el(RangeControl, {
200 label: __('Border Width (px)'), value: a.borderWidth, min: 1, max: 4,
201 onChange: function (v) { set({ borderWidth: v }); }
202 }),
203 ),
204
205 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
206 getTypoControl()({ label: __('Heading', 'blockenberg'), value: a.headingTypo, onChange: function (v) { set({ headingTypo: v }); } }),
207 getTypoControl()({ label: __('Text', 'blockenberg'), value: a.textTypo, onChange: function (v) { set({ textTypo: v }); } }),
208 getTypoControl()({ label: __('Link', 'blockenberg'), value: a.linkTypo, onChange: function (v) { set({ linkTypo: v }); } })
209 ),
210 el(PanelColorSettings, {
211 title: __('Colors', 'blockenberg'), initialOpen: false,
212 colorSettings: [
213 { label: __('Spotlight'), value: a.spotlightColor, onChange: function (v) { set({ spotlightColor: v || '#8b5cf6' }); } },
214 { label: __('Card Background'), value: a.cardBg, onChange: function (v) { set({ cardBg: v || '#1e1b2e' }); } },
215 { label: __('Card Border'), value: a.cardBorder, onChange: function (v) { set({ cardBorder: v || '#2d2a4a' }); } },
216 { label: __('Heading'), value: a.headingColor, onChange: function (v) { set({ headingColor: v || '#f1f5f9' }); } },
217 { label: __('Body Text'), value: a.textColor, onChange: function (v) { set({ textColor: v || '#94a3b8' }); } },
218 { label: __('Icon'), value: a.iconColor, onChange: function (v) { set({ iconColor: v || '#6c3fb5' }); } },
219 { label: __('Link'), value: a.linkColor, onChange: function (v) { set({ linkColor: v || '#6c3fb5' }); } },
220 a.showBadge && { label: __('Badge Background'), value: a.badgeBg, onChange: function (v) { set({ badgeBg: v || '#6c3fb5' }); } },
221 a.showBadge && { label: __('Badge Text'), value: a.badgeColor, onChange: function (v) { set({ badgeColor: v || '#ffffff' }); } },
222 ].filter(Boolean)
223 }),
224 ),
225 /* Editor live preview */
226 el('div', { style: buildCardStyle(a), className: 'bkspot-card' },
227 el('div', {
228 style: {
229 position: 'absolute', inset: 0, pointerEvents: 'none',
230 background: 'radial-gradient(circle at 50% 30%, ' + hexToRgba(a.spotlightColor, a.spotlightOpacity) + ', transparent ' + a.spotlightSize + 'px)',
231 borderRadius: a.cardRadius + 'px', opacity: 0.7,
232 }
233 }),
234 a.showBadge && a.badgeText && el('span', {
235 style: {
236 position: 'absolute', top: '16px', right: '16px', zIndex: 1,
237 background: a.badgeBg, color: a.badgeColor,
238 fontSize: '11px', fontWeight: 700, padding: '3px 8px', borderRadius: '4px',
239 }
240 }, a.badgeText),
241 a.showImage && a.imageUrl && el('div', {
242 style: {
243 backgroundImage: 'url(' + a.imageUrl + ')', backgroundSize: 'cover',
244 backgroundPosition: 'center', height: a.imageHeight + 'px',
245 borderRadius: (a.cardRadius - 4) + 'px', marginBottom: '16px', position: 'relative', zIndex: 1,
246 }
247 }),
248 el('div', { style: { position: 'relative', zIndex: 1 } },
249 a.showIcon && !a.showImage && el('span', {
250 className: 'dashicons dashicons-' + a.icon,
251 style: { fontSize: a.iconSize + 'px', width: a.iconSize + 'px', height: a.iconSize + 'px', lineHeight: 1, color: a.iconColor, marginBottom: '12px', display: 'block' }
252 }),
253 el(RichText, {
254 tagName: a.tag,
255 value: a.heading,
256 onChange: function (v) { set({ heading: v }); },
257 placeholder: __('Heading…'),
258 className: 'bkspot-heading',
259 style: { margin: '0 0 8px', color: a.headingColor },
260 allowedFormats: ['core/bold', 'core/italic'],
261 }),
262 el(RichText, {
263 tagName: 'p',
264 value: a.text,
265 onChange: function (v) { set({ text: v }); },
266 placeholder: __('Card text…'),
267 className: 'bkspot-text',
268 style: { margin: '0 0 16px', color: a.textColor },
269 }),
270 a.showLink && el('a', {
271 href: a.linkUrl,
272 className: 'bkspot-link',
273 style: { color: a.linkColor }
274 }, a.linkLabel),
275 ),
276 ),
277 );
278 },
279
280 save: function (props) {
281 var a = props.attributes;
282 var tv = getTypoCssVars();
283 var h = a.spotlightColor ? a.spotlightColor.replace('#', '') : '8b5cf6';
284 if (h.length === 3) h = h[0]+h[0]+h[1]+h[1]+h[2]+h[2];
285 var r = parseInt(h.substring(0,2),16), g = parseInt(h.substring(2,4),16), b = parseInt(h.substring(4,6),16);
286 var rgba = 'rgba(' + r + ',' + g + ',' + b + ',' + (a.spotlightOpacity / 100) + ')';
287
288 var wrapStyle = {
289 background: a.cardBg,
290 border: a.showBorder ? a.borderWidth + 'px solid ' + a.cardBorder : 'none',
291 borderRadius: a.cardRadius + 'px',
292 padding: a.cardPadding + 'px',
293 position: 'relative',
294 overflow: 'hidden',
295 '--bkspot-color': rgba,
296 '--bkspot-size': a.spotlightSize + 'px',
297 '--bkspot-hd-sz': a.headingSize + 'px',
298 '--bkspot-hd-w': String(a.headingFontWeight || '700'),
299 '--bkspot-hd-lh': String(a.headingLineHeight || 1.3),
300 '--bkspot-tx-sz': a.textSize + 'px',
301 '--bkspot-tx-lh': String(a.textLineHeight || 1.6),
302 };
303 Object.assign(wrapStyle, tv(a.headingTypo, '--bkspot-hd-'));
304 Object.assign(wrapStyle, tv(a.textTypo, '--bkspot-tx-'));
305 Object.assign(wrapStyle, tv(a.linkTypo, '--bkspot-lk-'));
306
307 return el('div', {
308 className: 'bkspot-card',
309 style: wrapStyle
310 },
311 el('div', { className: 'bkspot-glow', 'aria-hidden': 'true' }),
312 a.showBadge && a.badgeText && el('span', {
313 className: 'bkspot-badge',
314 style: {
315 position: 'absolute', top: '16px', right: '16px', zIndex: 1,
316 background: a.badgeBg, color: a.badgeColor,
317 fontSize: '11px', fontWeight: 700, padding: '3px 8px', borderRadius: '4px',
318 }
319 }, a.badgeText),
320 a.showImage && a.imageUrl && el('div', {
321 className: 'bkspot-img',
322 style: {
323 backgroundImage: 'url(' + a.imageUrl + ')', backgroundSize: 'cover',
324 backgroundPosition: 'center', height: a.imageHeight + 'px',
325 borderRadius: (a.cardRadius - 4) + 'px', marginBottom: '16px', position: 'relative', zIndex: 1,
326 }
327 }),
328 el('div', { className: 'bkspot-body', style: { position: 'relative', zIndex: 1 } },
329 a.showIcon && !a.showImage && el('span', {
330 className: 'bkspot-icon dashicons dashicons-' + a.icon,
331 'aria-hidden': 'true',
332 style: { fontSize: a.iconSize + 'px', width: a.iconSize + 'px', height: a.iconSize + 'px', lineHeight: 1, color: a.iconColor, marginBottom: '12px', display: 'block' }
333 }),
334 el(RichText.Content, {
335 tagName: a.tag, value: a.heading, className: 'bkspot-heading',
336 style: { margin: '0 0 8px', color: a.headingColor }
337 }),
338 el(RichText.Content, {
339 tagName: 'p', value: a.text, className: 'bkspot-text',
340 style: { margin: '0 0 16px', color: a.textColor }
341 }),
342 a.showLink && el('a', {
343 href: a.linkUrl, className: 'bkspot-link',
344 style: { color: a.linkColor }
345 }, a.linkLabel),
346 ),
347 );
348 }
349 });
350 }() );
351