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

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

225 lines 13.3 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 __ = wp.i18n.__;
5 var registerBlockType = wp.blocks.registerBlockType;
6 var InspectorControls = wp.blockEditor.InspectorControls;
7 var useBlockProps = wp.blockEditor.useBlockProps;
8 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
9 var PanelBody = wp.components.PanelBody;
10 var TextControl = wp.components.TextControl;
11 var ToggleControl = wp.components.ToggleControl;
12 var RangeControl = wp.components.RangeControl;
13 var SelectControl = wp.components.SelectControl;
14 var useRef = wp.element.useRef;
15 var useEffect = wp.element.useEffect;
16
17 var _tc, _tv;
18 function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
19 function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
20
21 var CHAR_SETS = [
22 { label: 'Matrix (Katakana + digits)', value: 'matrix' },
23 { label: 'Binary (0 and 1)', value: 'binary' },
24 { label: 'Hexadecimal', value: 'hex' },
25 { label: 'Latin alphabet', value: 'latin' },
26 { label: 'Custom', value: 'custom' },
27 ];
28
29 var COLOR_STYLES = [
30 { label: '🟢 Classic Green / White head', value: 'classic-green' },
31 { label: '🔵 Cyan / White head', value: 'cyan' },
32 { label: '🔴 Red / Pink head', value: 'red' },
33 { label: '🟡 Gold / White head', value: 'gold' },
34 { label: '🟣 Purple / White head', value: 'purple' },
35 { label: '🌈 Rainbow columns', value: 'rainbow' },
36 { label: '🎨 Custom colors', value: 'custom' },
37 ];
38
39 var STYLE_COLORS = {
40 'classic-green': { primary: '#00ff41', head: '#ffffff', bg: '#000000' },
41 'cyan': { primary: '#00e5ff', head: '#ffffff', bg: '#000a0d' },
42 'red': { primary: '#ff0040', head: '#ffaaaa', bg: '#0d0000' },
43 'gold': { primary: '#ffcc00', head: '#ffffff', bg: '#080600' },
44 'purple': { primary: '#cc44ff', head: '#ffffff', bg: '#060008' },
45 'rainbow': { primary: '#00ff41', head: '#ffffff', bg: '#000000' },
46 'custom': null,
47 };
48
49 function applyStyle(val, set) {
50 var c = STYLE_COLORS[val];
51 if (c) set({ colorStyle: val, primaryColor: c.primary, headColor: c.head, bgColor: c.bg });
52 else set({ colorStyle: val });
53 }
54
55 /* live canvas preview in editor */
56 function MatrixCanvas(props) {
57 var a = props.attributes;
58 var canRef = useRef(null);
59
60 useEffect(function () {
61 var canvas = canRef.current;
62 if (!canvas) return;
63 var ctx = canvas.getContext('2d');
64 canvas.width = canvas.offsetWidth || 600;
65 canvas.height = a.height;
66
67 var cols = Math.floor(canvas.width / (a.fontSize || 16));
68 var drops = [];
69 for (var i = 0; i < cols; i++) {
70 drops[i] = a.randomStart ? Math.floor(Math.random() * -canvas.height / a.fontSize) : 0;
71 }
72
73 var chars = getChars(a);
74 var raf;
75 var lastTime = 0;
76
77 function draw(ts) {
78 var interval = 1000 / ((a.speed || 50) / 10 + 5);
79 if (ts - lastTime > interval) {
80 lastTime = ts;
81 ctx.fillStyle = hexToRgba(a.bgColor || '#000', (a.bgOpacity || 8) / 100);
82 ctx.fillRect(0, 0, canvas.width, canvas.height);
83 for (var i = 0; i < drops.length; i++) {
84 var ch = chars[Math.floor(Math.random() * chars.length)];
85 var y = drops[i] * (a.fontSize || 16);
86 if (y > 0) {
87 ctx.font = (a.fontSize || 16) + 'px monospace';
88 ctx.fillStyle = a.headColor || '#ffffff';
89 ctx.fillText(ch, i * (a.fontSize || 16), y);
90 }
91 if (Math.random() > 0.975) drops[i] = 0;
92 drops[i]++;
93 }
94 }
95 raf = requestAnimationFrame(draw);
96 }
97 raf = requestAnimationFrame(draw);
98 return function () { cancelAnimationFrame(raf); };
99 }, [a.height, a.fontSize, a.speed, a.bgColor, a.bgOpacity, a.primaryColor, a.headColor, a.charSet, a.customChars, a.randomStart]);
100
101 return el('canvas', { ref: canRef, style: { width: '100%', height: a.height + 'px', display: 'block', borderRadius: '0' } });
102 }
103
104 function getChars(a) {
105 if (a.charSet === 'binary') return ['0','1'];
106 if (a.charSet === 'hex') return '0123456789ABCDEF'.split('');
107 if (a.charSet === 'latin') return 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.split('');
108 if (a.charSet === 'custom') return (a.customChars || '01').split('');
109 /* matrix: katakana + digits */
110 var kata = 'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン';
111 return (kata + '0123456789').split('');
112 }
113
114 function hexToRgba(hex, alpha) {
115 var r = 0, g = 0, b = 0;
116 if (hex && hex.startsWith('#')) {
117 var h = hex.slice(1);
118 if (h.length === 3) h = h[0]+h[0]+h[1]+h[1]+h[2]+h[2];
119 r = parseInt(h.slice(0,2),16);
120 g = parseInt(h.slice(2,4),16);
121 b = parseInt(h.slice(4,6),16);
122 }
123 return 'rgba(' + r + ',' + g + ',' + b + ',' + alpha + ')';
124 }
125
126 registerBlockType('blockenberg/matrix-rain', {
127 edit: function (props) {
128 var a = props.attributes;
129 var set = props.setAttributes;
130
131 return el(Fragment, null,
132 el(InspectorControls, null,
133 /* Canvas */
134 el(PanelBody, { title: 'Canvas', initialOpen: true },
135 el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Height (px)', value: a.height, min: 100, max: 900, step: 20, onChange: function (v) { set({ height: v }); } }),
136 el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Speed', value: a.speed, min: 1, max: 100, onChange: function (v) { set({ speed: v }); } }),
137 el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Density (%)', value: a.density, min: 10, max: 100, onChange: function (v) { set({ density: v }); } }),
138 el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Fade trail length', value: a.fadeLength, min: 1, max: 80, onChange: function (v) { set({ fadeLength: v }); } }),
139 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Glow effect', checked: a.glowEffect, onChange: function (v) { set({ glowEffect: v }); } }),
140 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Random start positions', checked: a.randomStart, onChange: function (v) { set({ randomStart: v }); } }),
141 ),
142 /* Characters */
143 el(PanelBody, { title: 'Characters', initialOpen: false },
144 el(SelectControl, { __nextHasNoMarginBottom: true, label: 'Character set', value: a.charSet, options: CHAR_SETS, onChange: function (v) { set({ charSet: v }); } }),
145 a.charSet === 'custom' && el(TextControl, { __nextHasNoMarginBottom: true, label: 'Custom characters', value: a.customChars, onChange: function (v) { set({ customChars: v }); }, help: 'Type the characters to use (no spaces needed)' }),
146 ),
147 /* Colors */
148
149 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
150 el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Canvas font size (px)', value: a.fontSize, min: 8, max: 40, onChange: function (v) { set({ fontSize: v }); } }),
151 a.showOverlay && getTypoControl() && el(getTypoControl(), { label: 'Overlay Title', value: a.overlayTypo || {}, onChange: function (v) { set({ overlayTypo: v }); } }),
152 a.showOverlay && getTypoControl() && el(getTypoControl(), { label: 'Overlay Subtext', value: a.subtextTypo || {}, onChange: function (v) { set({ subtextTypo: v }); } })
153 ),
154 el(PanelBody, { title: 'Colors', initialOpen: false },
155 el(SelectControl, { __nextHasNoMarginBottom: true, label: 'Color preset', value: a.colorStyle, options: COLOR_STYLES, onChange: function (v) { applyStyle(v, set); } }),
156 el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Background opacity (fade trail)', value: a.bgOpacity, min: 1, max: 40, onChange: function (v) { set({ bgOpacity: v }); } }),
157 ),
158 el(PanelColorSettings, {
159 title: 'Custom Colors',
160 initialOpen: false,
161 colorSettings: [
162 { value: a.primaryColor, onChange: function (v) { set({ primaryColor: v || '#00ff41', colorStyle: 'custom' }); }, label: 'Rain color' },
163 { value: a.headColor, onChange: function (v) { set({ headColor: v || '#ffffff', colorStyle: 'custom' }); }, label: 'Head (leading char) color' },
164 { value: a.bgColor, onChange: function (v) { set({ bgColor: v || '#000000', colorStyle: 'custom' }); }, label: 'Background color' },
165 ],
166 }),
167 /* Overlay */
168 el(PanelBody, { title: 'Text Overlay', initialOpen: false },
169 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show text overlay', checked: a.showOverlay, onChange: function (v) { set({ showOverlay: v }); } }),
170 a.showOverlay && el(TextControl, { __nextHasNoMarginBottom: true, label: 'Main text', value: a.overlayText, onChange: function (v) { set({ overlayText: v }); } }),
171 a.showOverlay && el(TextControl, { __nextHasNoMarginBottom: true, label: 'Subtext', value: a.overlaySubtext, onChange: function (v) { set({ overlaySubtext: v }); } }),
172 ),
173 a.showOverlay && el(PanelColorSettings, {
174 title: 'Overlay Colors',
175 initialOpen: false,
176 colorSettings: [
177 { value: a.overlayTextColor, onChange: function (v) { set({ overlayTextColor: v || '#00ff41' }); }, label: 'Overlay text color' },
178 { value: a.overlayBg, onChange: function (v) { set({ overlayBg: v || 'rgba(0,0,0,0.35)' }); }, label: 'Overlay background' },
179 ],
180 }),
181 /* Interaction */
182 el(PanelBody, { title: 'Interaction', initialOpen: false },
183 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Click to pause/resume', checked: a.clickToPause, onChange: function (v) { set({ clickToPause: v }); } }),
184 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Pause on hover', checked: a.pauseOnHover, onChange: function (v) { set({ pauseOnHover: v }); } }),
185 ),
186 ),
187 el('div', useBlockProps((function () {
188 var tv = getTypoCssVars();
189 var s = { position: 'relative', overflow: 'hidden' };
190 Object.assign(s, tv(a.overlayTypo, '--bkbg-mr-ot-'));
191 Object.assign(s, tv(a.subtextTypo, '--bkbg-mr-os-'));
192 return { style: s };
193 })()),
194 el(MatrixCanvas, { attributes: a }),
195 a.showOverlay && el('div', {
196 className: 'bkbg-mr-overlay',
197 style: {
198 position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column',
199 alignItems: 'center', justifyContent: 'center',
200 background: a.overlayBg, pointerEvents: 'none',
201 },
202 },
203 el('h2', { className: 'bkbg-mr-overlay-title', style: { color: a.overlayTextColor, margin: '0 0 12px' } },
204 a.overlayText),
205 a.overlaySubtext && el('p', { className: 'bkbg-mr-overlay-sub', style: { color: a.overlayTextColor, opacity: 0.7, margin: 0 } },
206 a.overlaySubtext)
207 )
208 )
209 );
210 },
211 save: function (props) {
212 var a = props.attributes;
213 return el('div', useBlockProps.save((function () {
214 var tv = getTypoCssVars();
215 var s = {};
216 Object.assign(s, tv(a.overlayTypo, '--bkbg-mr-ot-'));
217 Object.assign(s, tv(a.subtextTypo, '--bkbg-mr-os-'));
218 return { style: s };
219 })()),
220 el('div', { className: 'bkbg-mr-app', 'data-opts': JSON.stringify(a) })
221 );
222 },
223 });
224 }() );
225