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

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

250 lines 20.9 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 registerBlockType = wp.blocks.registerBlockType;
5 var __ = wp.i18n.__;
6 var InspectorControls = wp.blockEditor.InspectorControls;
7 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
8 var useBlockProps = wp.blockEditor.useBlockProps;
9 var MediaUpload = wp.blockEditor.MediaUpload;
10 var MediaUploadCheck = wp.blockEditor.MediaUploadCheck;
11 var PanelBody = wp.components.PanelBody;
12 var RangeControl = wp.components.RangeControl;
13 var ToggleControl = wp.components.ToggleControl;
14 var TextControl = wp.components.TextControl;
15 var SelectControl = wp.components.SelectControl;
16 var Button = wp.components.Button;
17
18 var _fstTC, _fstTV;
19 function _tc() { return _fstTC || (_fstTC = window.bkbgTypographyControl); }
20 function _tv() { return _fstTV || (_fstTV = window.bkbgTypoCssVars); }
21
22 var POSITION_OPTIONS = [
23 { label: 'Top left', value: 'top-left' },
24 { label: 'Top right', value: 'top-right' },
25 { label: 'Middle left', value: 'middle-left' },
26 { label: 'Middle right', value: 'middle-right' },
27 { label: 'Bottom left', value: 'bottom-left' },
28 { label: 'Bottom right', value: 'bottom-right' },
29 ];
30
31 var CARD_STYLE_OPTIONS = [
32 { label: 'Shadow card', value: 'shadow' },
33 { label: 'Glass (frosted)', value: 'glass' },
34 { label: 'Solid / flat', value: 'solid' },
35 ];
36
37 var ASPECT_OPTIONS = [
38 { label: '4:5 (Portrait)', value: '4:5' },
39 { label: '1:1 (Square)', value: '1:1' },
40 { label: '16:9 (Landscape)', value: '16:9' },
41 { label: '3:4', value: '3:4' },
42 ];
43
44 var ICON_SVG = {
45 star: el('svg', { width: 20, height: 20, viewBox: '0 0 24 24', fill: 'currentColor' }, el('path', { d: 'M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 21 12 17.77 5.82 21 7 14.14 2 9.27l6.91-1.01L12 2z' })),
46 bolt: el('svg', { width: 20, height: 20, viewBox: '0 0 24 24', fill: 'currentColor' }, el('path', { d: 'M13 2L3 14h9l-1 8 10-12h-9l1-8z' })),
47 heart: el('svg', { width: 20, height: 20, viewBox: '0 0 24 24', fill: 'currentColor' }, el('path', { d: 'M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 0 0 0-7.78z' })),
48 check: el('svg', { width: 20, height: 20, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2 }, el('polyline', { points: '20 6 9 17 4 12' })),
49 chart: el('svg', { width: 20, height: 20, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2 }, el('line', { x1: 18, y1: 20, x2: 18, y2: 10 }), el('line', { x1: 12, y1: 20, x2: 12, y2: 4 }), el('line', { x1: 6, y1: 20, x2: 6, y2: 14 })),
50 users: el('svg', { width: 20, height: 20, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2 }, el('path', { d: 'M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2' }), el('circle', { cx: 9, cy: 7, r: 4 }), el('path', { d: 'M23 21v-2a4 4 0 0 0-3-3.87' }), el('path', { d: 'M16 3.13a4 4 0 0 1 0 7.75' })),
51 award: el('svg', { width: 20, height: 20, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2 }, el('circle', { cx: 12, cy: 8, r: 6 }), el('path', { d: 'M15.477 12.89L17 22l-5-3-5 3 1.523-9.11' })),
52 shield: el('svg', { width: 20, height: 20, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2 }, el('path', { d: 'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z' })),
53 };
54
55 var ICON_OPTIONS = Object.keys(ICON_SVG).map(function (k) { return { label: k.charAt(0).toUpperCase() + k.slice(1), value: k }; });
56 ICON_OPTIONS.unshift({ label: 'None', value: '' });
57
58 function makeId() { return 's' + Math.random().toString(36).substr(2, 6); }
59
60 function positionToStyle(pos, pad) {
61 var OFFSET = (-pad - 8) + 'px';
62 var map = {
63 'top-left': { top: '10%', left: OFFSET, transform: 'translateX(-50%)' },
64 'top-right': { top: '10%', right: OFFSET, transform: 'translateX(50%)' },
65 'middle-left': { top: '50%', left: OFFSET, transform: 'translate(-50%, -50%)' },
66 'middle-right': { top: '50%', right: OFFSET, transform: 'translate(50%, -50%)' },
67 'bottom-left': { bottom: '10%', left: OFFSET, transform: 'translateX(-50%)' },
68 'bottom-right': { bottom: '10%', right: OFFSET, transform: 'translateX(50%)' },
69 };
70 return map[pos] || map['top-right'];
71 }
72
73 function getCardBg(card, style) {
74 if (style === 'glass') return 'rgba(255,255,255,0.75)';
75 return card.bgColor || '#ffffff';
76 }
77 function getCardShadow(style) {
78 if (style === 'shadow') return '0 8px 32px rgba(0,0,0,0.12)';
79 if (style === 'glass') return '0 4px 24px rgba(0,0,0,0.08)';
80 return 'none';
81 }
82 function getCardBorder(style) {
83 if (style === 'glass') return '1px solid rgba(255,255,255,0.6)';
84 return 'none';
85 }
86
87 registerBlockType('blockenberg/floating-stats', {
88 edit: function (props) {
89 var attributes = props.attributes;
90 var setAttributes = props.setAttributes;
91 var cards = attributes.cards;
92
93 var blockProps = useBlockProps({
94 style: Object.assign({ paddingTop: attributes.paddingTop + 'px', paddingBottom: attributes.paddingBottom + 'px', backgroundColor: attributes.bgColor || undefined, display: 'flex', justifyContent: 'center' },
95 _tv()(attributes.typoValue, '--bkbg-fst-vl-'),
96 _tv()(attributes.typoLabel, '--bkbg-fst-lb-')
97 )
98 });
99
100 function setCard(id, patch) {
101 setAttributes({ cards: cards.map(function (c) { return c.id === id ? Object.assign({}, c, patch) : c; }) });
102 }
103 function addCard() {
104 setAttributes({ cards: cards.concat([{ id: makeId(), value: '1,000+', label: 'New metric', icon: 'star', position: 'bottom-right', bgColor: '#ffffff', textColor: '#111827', valueColor: '#6c3fb5' }]) });
105 }
106 function removeCard(id) {
107 if (cards.length <= 1) return;
108 setAttributes({ cards: cards.filter(function (c) { return c.id !== id; }) });
109 }
110
111 var aspectParts = attributes.imageAspectRatio.split(':');
112 var aspectNum = parseFloat(aspectParts[1]) / parseFloat(aspectParts[0]);
113
114 return el(Fragment, null,
115 el(InspectorControls, null,
116 el(PanelBody, { title: __('Image', 'blockenberg'), initialOpen: true },
117 el(MediaUploadCheck, null,
118 el(MediaUpload, {
119 onSelect: function (media) { setAttributes({ imageUrl: media.url, imageId: media.id, imageAlt: media.alt || '' }); },
120 allowedTypes: ['image'],
121 value: attributes.imageId,
122 render: function (ref) {
123 return el(Button, { onClick: ref.open, variant: 'secondary', style: { marginBottom: '8px' } },
124 attributes.imageUrl ? __('Change image', 'blockenberg') : __('Upload image', 'blockenberg')
125 );
126 }
127 })
128 ),
129 attributes.imageUrl && el(Button, { onClick: function () { setAttributes({ imageUrl: '', imageId: 0 }); }, variant: 'tertiary', isDestructive: true, size: 'compact', style: { display: 'block', marginBottom: '8px' } }, __('Remove image', 'blockenberg')),
130 el(SelectControl, { label: __('Aspect ratio', 'blockenberg'), value: attributes.imageAspectRatio, options: ASPECT_OPTIONS, onChange: function (v) { setAttributes({ imageAspectRatio: v }); } }),
131 el(RangeControl, { label: __('Image border radius (px)', 'blockenberg'), value: attributes.imageRadius, min: 0, max: 48, onChange: function (v) { setAttributes({ imageRadius: v }); } }),
132 el(ToggleControl, { label: __('Image drop shadow', 'blockenberg'), checked: attributes.imageShadow, onChange: function (v) { setAttributes({ imageShadow: v }); }, __nextHasNoMarginBottom: true }),
133 el(RangeControl, { label: __('Max width (px)', 'blockenberg'), value: attributes.wrapMaxWidth, min: 200, max: 900, onChange: function (v) { setAttributes({ wrapMaxWidth: v }); } })
134 ),
135 el(PanelBody, { title: __('Cards Style', 'blockenberg'), initialOpen: false },
136 el(SelectControl, { label: __('Card style preset', 'blockenberg'), value: attributes.cardStyle, options: CARD_STYLE_OPTIONS, onChange: function (v) { setAttributes({ cardStyle: v }); } }),
137 el(RangeControl, { label: __('Card padding (px)', 'blockenberg'), value: attributes.cardPadding, min: 8, max: 40, onChange: function (v) { setAttributes({ cardPadding: v }); } }),
138 el(RangeControl, { label: __('Card border radius (px)', 'blockenberg'), value: attributes.cardRadius, min: 0, max: 32, onChange: function (v) { setAttributes({ cardRadius: v }); } }),
139 el(ToggleControl, { label: __('Show icon', 'blockenberg'), checked: attributes.showIcon, onChange: function (v) { setAttributes({ showIcon: v }); }, __nextHasNoMarginBottom: true }),
140 attributes.showIcon && el(RangeControl, { label: __('Icon size (px)', 'blockenberg'), value: attributes.iconSize, min: 12, max: 48, onChange: function (v) { setAttributes({ iconSize: v }); } }),
141 el(ToggleControl, { label: __('Count-up animation', 'blockenberg'), checked: attributes.countUpAnimation, onChange: function (v) { setAttributes({ countUpAnimation: v }); }, __nextHasNoMarginBottom: true })
142 ),
143
144 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
145 _tc()({ label: __('Value', 'blockenberg'), value: attributes.typoValue, onChange: function (v) { setAttributes({ typoValue: v }); } }),
146 _tc()({ label: __('Label', 'blockenberg'), value: attributes.typoLabel, onChange: function (v) { setAttributes({ typoLabel: v }); } })
147 ),
148 el(PanelColorSettings, {
149 title: __('Default card colors', 'blockenberg'),
150 initialOpen: false,
151 colorSettings: [
152 { value: attributes.globalCardBg, onChange: function (v) { setAttributes({ globalCardBg: v || '' }); }, label: __('Card background', 'blockenberg') },
153 { value: attributes.globalCardColor, onChange: function (v) { setAttributes({ globalCardColor: v || '' }); }, label: __('Card text', 'blockenberg') },
154 { value: attributes.bgColor, onChange: function (v) { setAttributes({ bgColor: v || '' }); }, label: __('Section background', 'blockenberg') },
155 ]
156 }),
157 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
158 el(RangeControl, { label: __('Padding top (px)', 'blockenberg'), value: attributes.paddingTop, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingTop: v }); } }),
159 el(RangeControl, { label: __('Padding bottom (px)', 'blockenberg'), value: attributes.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingBottom: v }); } })
160 ),
161 el(PanelBody, { title: __('Stat Cards', 'blockenberg'), initialOpen: false },
162 cards.map(function (card, idx) {
163 return el(PanelBody, { key: card.id, title: (card.label || 'Card') + ' #' + (idx + 1), initialOpen: false },
164 el(TextControl, { label: __('Value', 'blockenberg'), value: card.value, placeholder: '10,000+', onChange: function (v) { setCard(card.id, { value: v }); } }),
165 el(TextControl, { label: __('Label', 'blockenberg'), value: card.label, onChange: function (v) { setCard(card.id, { label: v }); } }),
166 el(SelectControl, { label: __('Icon', 'blockenberg'), value: card.icon, options: ICON_OPTIONS, onChange: function (v) { setCard(card.id, { icon: v }); } }),
167 el(SelectControl, { label: __('Position', 'blockenberg'), value: card.position, options: POSITION_OPTIONS, onChange: function (v) { setCard(card.id, { position: v }); } }),
168 el(PanelColorSettings, {
169 title: __('Card colors', 'blockenberg'),
170 initialOpen: false,
171 colorSettings: [
172 { value: card.bgColor, onChange: function (v) { setCard(card.id, { bgColor: v || '' }); }, label: __('Background', 'blockenberg') },
173 { value: card.textColor, onChange: function (v) { setCard(card.id, { textColor: v || '' }); }, label: __('Label text', 'blockenberg') },
174 { value: card.valueColor, onChange: function (v) { setCard(card.id, { valueColor: v || '' }); }, label: __('Value color', 'blockenberg') },
175 ]
176 }),
177 el(Button, { onClick: function () { removeCard(card.id); }, variant: 'tertiary', isDestructive: true, size: 'compact' }, __('Remove card', 'blockenberg'))
178 );
179 }),
180 el(Button, { onClick: addCard, variant: 'primary', style: { marginTop: '8px' } }, __('+ Add Card', 'blockenberg'))
181 )
182 ),
183 el('div', blockProps,
184 el('div', {
185 className: 'bkbg-floating-stats',
186 style: { position: 'relative', maxWidth: attributes.wrapMaxWidth + 'px', width: '100%', margin: '0 auto' }
187 },
188 el('div', { className: 'bkbg-floating-stats__image-wrap', style: { position: 'relative', borderRadius: attributes.imageRadius + 'px', overflow: 'hidden', aspectRatio: attributes.imageAspectRatio.replace(':', '/'), boxShadow: attributes.imageShadow ? '0 32px 80px rgba(0,0,0,0.18)' : 'none', background: '#f3f4f6' } },
189 attributes.imageUrl
190 ? el('img', { src: attributes.imageUrl, alt: attributes.imageAlt, style: { width: '100%', height: '100%', objectFit: 'cover', display: 'block' } })
191 : el('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%', color: '#9ca3af', fontSize: '14px', minHeight: '300px' } }, __('Upload an image ↑', 'blockenberg'))
192 ),
193 cards.map(function (card) {
194 var posStyle = positionToStyle(card.position, attributes.cardPadding);
195 var cardBg = getCardBg(card, attributes.cardStyle);
196 var cardShadow = getCardShadow(attributes.cardStyle);
197 var cardBorder = getCardBorder(attributes.cardStyle);
198 return el('div', {
199 key: card.id,
200 className: 'bkbg-floating-card bkbg-floating-card--' + card.position,
201 style: Object.assign({ position: 'absolute', zIndex: 2, background: cardBg, color: card.textColor || attributes.globalCardColor, borderRadius: attributes.cardRadius + 'px', padding: attributes.cardPadding + 'px', boxShadow: cardShadow, border: cardBorder, backdropFilter: attributes.cardStyle === 'glass' ? 'blur(12px)' : undefined, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '4px', minWidth: '90px', textAlign: 'center', whiteSpace: 'nowrap' }, posStyle)
202 },
203 attributes.showIcon && card.icon && ICON_SVG[card.icon] && el('span', { style: { color: card.valueColor || '#6c3fb5', width: attributes.iconSize + 'px', height: attributes.iconSize + 'px', display: 'flex', alignItems: 'center', justifyContent: 'center' } }, ICON_SVG[card.icon]),
204 el('span', { className: 'bkbg-floating-card__value', style: { color: card.valueColor || '#6c3fb5' } }, card.value),
205 el('span', { className: 'bkbg-floating-card__label', style: { color: card.textColor || attributes.globalCardColor, opacity: 0.75 } }, card.label)
206 );
207 })
208 )
209 )
210 );
211 },
212
213 save: function (props) {
214 var attributes = props.attributes;
215 var cards = attributes.cards;
216 var blockProps = wp.blockEditor.useBlockProps.save({ className: 'bkbg-floating-stats-wrap' });
217
218 return el('div', Object.assign({}, blockProps, { style: Object.assign({ paddingTop: attributes.paddingTop + 'px', paddingBottom: attributes.paddingBottom + 'px', backgroundColor: attributes.bgColor || undefined, display: 'flex', justifyContent: 'center' },
219 _tv()(attributes.typoValue, '--bkbg-fst-vl-'),
220 _tv()(attributes.typoLabel, '--bkbg-fst-lb-')
221 ) }),
222 el('div', { className: 'bkbg-floating-stats', 'data-count-up': attributes.countUpAnimation ? '1' : '0', style: { position: 'relative', maxWidth: attributes.wrapMaxWidth + 'px', width: '100%', margin: '0 auto' } },
223 el('div', { className: 'bkbg-floating-stats__image-wrap', style: { position: 'relative', borderRadius: attributes.imageRadius + 'px', overflow: 'hidden', aspectRatio: attributes.imageAspectRatio.replace(':', '/'), boxShadow: attributes.imageShadow ? '0 32px 80px rgba(0,0,0,0.18)' : 'none', background: '#f3f4f6' } },
224 attributes.imageUrl && el('img', { src: attributes.imageUrl, alt: attributes.imageAlt, style: { width: '100%', height: '100%', objectFit: 'cover', display: 'block' } })
225 ),
226 cards.map(function (card) {
227 var posStyle = positionToStyle(card.position, attributes.cardPadding);
228 var cardBg = getCardBg(card, attributes.cardStyle);
229 var cardShadow = getCardShadow(attributes.cardStyle);
230 var cardBorder = getCardBorder(attributes.cardStyle);
231 var iconEl = attributes.showIcon && card.icon && ICON_SVG[card.icon]
232 ? el('span', { className: 'bkbg-floating-card__icon', style: { color: card.valueColor || '#6c3fb5', width: attributes.iconSize + 'px', height: attributes.iconSize + 'px', display: 'flex', alignItems: 'center', justifyContent: 'center' } }, ICON_SVG[card.icon])
233 : null;
234 return el('div', {
235 key: card.id,
236 className: 'bkbg-floating-card bkbg-floating-card--' + card.position,
237 'data-value': card.value,
238 style: Object.assign({ position: 'absolute', zIndex: 2, background: cardBg, color: card.textColor || attributes.globalCardColor, borderRadius: attributes.cardRadius + 'px', padding: attributes.cardPadding + 'px', boxShadow: cardShadow, border: cardBorder, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '4px', minWidth: '90px', textAlign: 'center', whiteSpace: 'nowrap' }, posStyle)
239 },
240 iconEl,
241 el('span', { className: 'bkbg-floating-card__value', style: { color: card.valueColor || '#6c3fb5' } }, card.value),
242 el('span', { className: 'bkbg-floating-card__label', style: { color: card.textColor || attributes.globalCardColor, opacity: 0.75 } }, card.label)
243 );
244 })
245 )
246 );
247 }
248 });
249 }());
250