PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.11
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.11
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 / gradient-blob / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.11, at blocks/gradient-blob/index.js

281 lines 13.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 registerBlockType = wp.blocks.registerBlockType;
5 var __ = wp.i18n.__;
6 var InspectorControls = wp.blockEditor.InspectorControls;
7 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
8 var InnerBlocks = wp.blockEditor.InnerBlocks;
9 var useBlockProps = wp.blockEditor.useBlockProps;
10 var useInnerBlocksProps = wp.blockEditor.useInnerBlocksProps;
11 var PanelBody = wp.components.PanelBody;
12 var ToggleControl = wp.components.ToggleControl;
13 var RangeControl = wp.components.RangeControl;
14
15 var TEMPLATE = [
16 ['core/heading', { level: 2, placeholder: __('Section heading…', 'blockenberg'), textAlign: 'center' }],
17 ['core/paragraph', { placeholder: __('Add your content here…', 'blockenberg'), align: 'center' }],
18 ['core/buttons', { layout: { type: 'flex', justifyContent: 'center' } }, [
19 ['core/button', { text: __('Get started', 'blockenberg') }],
20 ]],
21 ];
22
23 // CSS for animated blob (editor preview)
24 var BLOB_ANIM = [
25 { top: '10%', left: '15%', animDelay: '0s' },
26 { top: '60%', left: '65%', animDelay: '-4s' },
27 { top: '35%', left: '50%', animDelay: '-7s' },
28 { top: '75%', left: '10%', animDelay: '-2s' },
29 { top: '20%', left: '75%', animDelay: '-9s' },
30 ];
31
32 function buildWrapStyle(a) {
33 return {
34 position: 'relative',
35 overflow: 'hidden',
36 minHeight: a.minHeight + 'px',
37 paddingTop: a.paddingTop + 'px',
38 paddingBottom: a.paddingBottom + 'px',
39 background: a.bgColor,
40 color: a.textColor || undefined,
41 };
42 }
43
44 function buildInnerStyle(a) {
45 return {
46 position: 'relative',
47 zIndex: 1,
48 maxWidth: a.contentMaxWidth + 'px',
49 margin: a.centerContent ? '0 auto' : undefined,
50 };
51 }
52
53 function buildBlobStyle(a, idx) {
54 var info = BLOB_ANIM[idx % BLOB_ANIM.length];
55 var colors = [a.color1, a.color2, a.color3];
56 var color = colors[idx % colors.length];
57 var size = a.blobSize;
58 return {
59 position: 'absolute',
60 top: info.top,
61 left: info.left,
62 width: size + '%',
63 height: size + '%',
64 background: color,
65 borderRadius: '60% 40% 30% 70% / 60% 30% 70% 40%',
66 opacity: (a.blobOpacity / 100),
67 filter: 'blur(' + a.blobBlur + 'px)',
68 willChange: 'transform, border-radius',
69 animationName: 'bkgb-morph',
70 animationDuration: a.animSpeed + 's',
71 animationDelay: info.animDelay,
72 animationTimingFunction: 'ease-in-out',
73 animationIterationCount: 'infinite',
74 animationPlayState: a.paused ? 'paused' : 'running',
75 transformOrigin: 'center',
76 pointerEvents: 'none',
77 };
78 }
79
80 registerBlockType('blockenberg/gradient-blob', {
81 title: __('Gradient Blob', 'blockenberg'),
82 description: __('Section with animated CSS blobs as background.', 'blockenberg'),
83 category: 'bkbg-effects',
84 icon: 'art',
85
86 edit: function (props) {
87 var attributes = props.attributes;
88 var setAttributes = props.setAttributes;
89 var numBlobs = Math.min(attributes.numBlobs || 3, 5);
90
91 var wrapStyle = buildWrapStyle(attributes);
92 var innerStyle = buildInnerStyle(attributes);
93
94 var blockProps = useBlockProps({ style: wrapStyle, className: 'bkgb-section' });
95 var innerBlocksProps = useInnerBlocksProps({ style: innerStyle, className: 'bkgb-inner' }, {
96 template: TEMPLATE,
97 templateLock: false,
98 });
99
100 return el(Fragment, null,
101 el(InspectorControls, null,
102 /* ── Blobs ──────────────────────────────────────────────── */
103 el(PanelBody, { title: __('Blobs', 'blockenberg'), initialOpen: true },
104 el(RangeControl, {
105 label: __('Number of blobs', 'blockenberg'),
106 value: attributes.numBlobs,
107 min: 1, max: 5,
108 onChange: function (v) { setAttributes({ numBlobs: v }); },
109 }),
110 el(RangeControl, {
111 label: __('Blob size (%)', 'blockenberg'),
112 value: attributes.blobSize,
113 min: 10, max: 120,
114 onChange: function (v) { setAttributes({ blobSize: v }); },
115 }),
116 el(RangeControl, {
117 label: __('Opacity (%)', 'blockenberg'),
118 value: attributes.blobOpacity,
119 min: 5, max: 100,
120 onChange: function (v) { setAttributes({ blobOpacity: v }); },
121 }),
122 el(RangeControl, {
123 label: __('Blur (px)', 'blockenberg'),
124 value: attributes.blobBlur,
125 min: 0, max: 200,
126 onChange: function (v) { setAttributes({ blobBlur: v }); },
127 }),
128 el(RangeControl, {
129 label: __('Animation speed (s)', 'blockenberg'),
130 value: attributes.animSpeed,
131 min: 3, max: 40,
132 onChange: function (v) { setAttributes({ animSpeed: v }); },
133 }),
134 el(ToggleControl, {
135 label: __('Pause animation', 'blockenberg'),
136 checked: attributes.paused,
137 onChange: function (v) { setAttributes({ paused: v }); },
138 __nextHasNoMarginBottom: true,
139 })
140 ),
141 /* ── Layout ─────────────────────────────────────────────── */
142 el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: false },
143 el(RangeControl, {
144 label: __('Min height (px)', 'blockenberg'),
145 value: attributes.minHeight,
146 min: 100, max: 1200,
147 onChange: function (v) { setAttributes({ minHeight: v }); },
148 }),
149 el(RangeControl, {
150 label: __('Padding top (px)', 'blockenberg'),
151 value: attributes.paddingTop,
152 min: 0, max: 200,
153 onChange: function (v) { setAttributes({ paddingTop: v }); },
154 }),
155 el(RangeControl, {
156 label: __('Padding bottom (px)', 'blockenberg'),
157 value: attributes.paddingBottom,
158 min: 0, max: 200,
159 onChange: function (v) { setAttributes({ paddingBottom: v }); },
160 }),
161 el(RangeControl, {
162 label: __('Content max width (px)', 'blockenberg'),
163 value: attributes.contentMaxWidth,
164 min: 200, max: 1400,
165 onChange: function (v) { setAttributes({ contentMaxWidth: v }); },
166 }),
167 el(ToggleControl, {
168 label: __('Center content', 'blockenberg'),
169 checked: attributes.centerContent,
170 onChange: function (v) { setAttributes({ centerContent: v }); },
171 __nextHasNoMarginBottom: true,
172 })
173 ),
174 /* ── Colors ─────────────────────────────────────────────── */
175 el(PanelColorSettings, {
176 title: __('Colors', 'blockenberg'),
177 initialOpen: false,
178 colorSettings: [
179 {
180 value: attributes.color1,
181 onChange: function (v) { setAttributes({ color1: v || '#c084fc' }); },
182 label: __('Blob color 1', 'blockenberg'),
183 },
184 {
185 value: attributes.color2,
186 onChange: function (v) { setAttributes({ color2: v || '#818cf8' }); },
187 label: __('Blob color 2', 'blockenberg'),
188 },
189 {
190 value: attributes.color3,
191 onChange: function (v) { setAttributes({ color3: v || '#f0abfc' }); },
192 label: __('Blob color 3', 'blockenberg'),
193 },
194 {
195 value: attributes.bgColor,
196 onChange: function (v) { setAttributes({ bgColor: v || '#faf5ff' }); },
197 label: __('Background color', 'blockenberg'),
198 },
199 {
200 value: attributes.textColor,
201 onChange: function (v) { setAttributes({ textColor: v || '' }); },
202 label: __('Text color', 'blockenberg'),
203 },
204 ],
205 })
206 ),
207 el('section', blockProps,
208 /* Blob layers */
209 Array.from({ length: numBlobs }, function (_, i) {
210 return el('div', {
211 key: i,
212 'aria-hidden': 'true',
213 className: 'bkgb-blob bkgb-blob-' + (i + 1),
214 style: buildBlobStyle(attributes, i),
215 });
216 }),
217 /* InnerBlocks content */
218 el('div', innerBlocksProps)
219 )
220 );
221 },
222
223 save: function (props) {
224 var a = props.attributes;
225 var numBlobs = Math.min(a.numBlobs || 3, 5);
226 var colors = [a.color1, a.color2, a.color3];
227 var blobPositions = [
228 { top: '10%', left: '15%' },
229 { top: '60%', left: '65%' },
230 { top: '35%', left: '50%' },
231 { top: '75%', left: '10%' },
232 { top: '20%', left: '75%' },
233 ];
234 var blobDelays = ['0s', '-4s', '-7s', '-2s', '-9s'];
235
236 return el('section', {
237 className: 'bkgb-section',
238 'data-speed': a.animSpeed,
239 'data-paused': a.paused ? 'true' : 'false',
240 style: {
241 position: 'relative',
242 overflow: 'hidden',
243 minHeight: a.minHeight + 'px',
244 paddingTop: a.paddingTop + 'px',
245 paddingBottom: a.paddingBottom + 'px',
246 background: a.bgColor,
247 color: a.textColor || undefined,
248 '--bkgb-speed': a.animSpeed + 's',
249 '--bkgb-blur': a.blobBlur + 'px',
250 '--bkgb-opacity': a.blobOpacity / 100,
251 '--bkgb-size': a.blobSize + '%',
252 },
253 },
254 Array.from({ length: numBlobs }, function (_, i) {
255 var pos = blobPositions[i % blobPositions.length];
256 return el('div', {
257 key: i,
258 'aria-hidden': 'true',
259 className: 'bkgb-blob bkgb-blob-' + (i + 1),
260 style: {
261 '--bkgb-c': colors[i % colors.length],
262 '--bkgb-delay': blobDelays[i % blobDelays.length],
263 top: pos.top,
264 left: pos.left,
265 },
266 });
267 }),
268 el('div', {
269 className: 'bkgb-inner',
270 style: {
271 position: 'relative',
272 zIndex: 1,
273 maxWidth: a.contentMaxWidth + 'px',
274 margin: a.centerContent ? '0 auto' : undefined,
275 },
276 }, el(InnerBlocks.Content))
277 );
278 },
279 });
280 }() );
281