PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.14
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.14
2.0.14 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 / typing-speed-test / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.14, at blocks/typing-speed-test/index.js

271 lines 14.6 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 useState = wp.element.useState;
4 var Fragment = wp.element.Fragment;
5 var registerBlockType = wp.blocks.registerBlockType;
6 var __ = wp.i18n.__;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
9 var useBlockProps = wp.blockEditor.useBlockProps;
10 var PanelBody = wp.components.PanelBody;
11 var RangeControl = wp.components.RangeControl;
12 var TextControl = wp.components.TextControl;
13 var ToggleControl = wp.components.ToggleControl;
14 var SelectControl = wp.components.SelectControl;
15
16 // Resolve the shared components lazily without defining globals for each block.
17 function _tc(label, key, attrs, setA) {
18 var Control = window.bkbgTypographyControl;
19 return Control ? el(Control, {
20 label: label,
21 value: attrs[key] || {},
22 onChange: function (value) { var update = {}; update[key] = value; setA(update); }
23 }) : null;
24 }
25 function _tvf(vars, key, attrs, prefix) {
26 var cssVars = window.bkbgTypoCssVars;
27 if (cssVars) Object.assign(vars, cssVars(attrs[key] || {}, prefix));
28 return vars;
29 }
30 function getTypoControl(label, key, attrs, setA) { return _tc(label, key, attrs, setA); }
31 function getTypoCssVars(attrs) {
32 var v = {};
33 _tvf(v, 'titleTypo', attrs, '--bktst-tt-');
34 _tvf(v, 'subtitleTypo', attrs, '--bktst-st-');
35 return v;
36 }
37
38 var SAMPLE_TEXT = 'The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs. How vexingly quick daft zebras jump.';
39
40 registerBlockType('blockenberg/typing-speed-test', {
41 edit: function (props) {
42 var a = props.attributes;
43 var setAttributes = props.setAttributes;
44 var blockProps = useBlockProps((function () { var _tv = getTypoCssVars(a); var s = {}; Object.assign(s, _tv); return { className: 'bkbg-tst-editor-wrap', style: s }; })());
45
46 var containerStyle = {
47 background: a.sectionBg,
48 borderRadius: '12px',
49 padding: '28px',
50 maxWidth: a.contentMaxWidth + 'px',
51 margin: '0 auto',
52 fontFamily: 'system-ui, sans-serif'
53 };
54
55 var cardStyle = {
56 background: a.cardBg,
57 borderRadius: '10px',
58 padding: '20px',
59 marginBottom: '16px',
60 boxShadow: '0 2px 8px rgba(0,0,0,0.06)'
61 };
62
63 var btnStyle = {
64 background: a.accentColor,
65 color: '#fff',
66 border: 'none',
67 borderRadius: '8px',
68 padding: '10px 24px',
69 cursor: 'pointer',
70 fontWeight: '600',
71 fontSize: '14px'
72 };
73
74 var statBoxStyle = {
75 textAlign: 'center',
76 flex: '1',
77 minWidth: '80px'
78 };
79
80 return el(
81 Fragment,
82 null,
83 el(
84 InspectorControls,
85 null,
86 el(
87 PanelBody,
88 { title: __('Content', 'blockenberg'), initialOpen: true },
89 el(TextControl, {
90 label: __('Title', 'blockenberg'),
91 value: a.title,
92 onChange: function (v) { setAttributes({ title: v }); }
93 }),
94 el(TextControl, {
95 label: __('Subtitle', 'blockenberg'),
96 value: a.subtitle,
97 onChange: function (v) { setAttributes({ subtitle: v }); }
98 }),
99 el(ToggleControl, {
100 label: __('Show Title', 'blockenberg'),
101 checked: a.showTitle,
102 onChange: function (v) { setAttributes({ showTitle: v }); },
103 __nextHasNoMarginBottom: true
104 }),
105 el(ToggleControl, {
106 label: __('Show Subtitle', 'blockenberg'),
107 checked: a.showSubtitle,
108 onChange: function (v) { setAttributes({ showSubtitle: v }); },
109 __nextHasNoMarginBottom: true
110 })
111 ),
112 el(
113 PanelBody,
114 { title: __('Test Settings', 'blockenberg'), initialOpen: false },
115 el(SelectControl, {
116 label: __('Test Duration', 'blockenberg'),
117 value: String(a.duration),
118 options: [
119 { value: '30', label: '30 seconds' },
120 { value: '60', label: '60 seconds' },
121 { value: '120', label: '2 minutes' },
122 { value: '180', label: '3 minutes' }
123 ],
124 onChange: function (v) { setAttributes({ duration: parseInt(v) }); }
125 }),
126 el(SelectControl, {
127 label: __('Default Difficulty', 'blockenberg'),
128 value: a.defaultDifficulty,
129 options: [
130 { value: 'easy', label: __('Easy', 'blockenberg') },
131 { value: 'medium', label: __('Medium', 'blockenberg') },
132 { value: 'hard', label: __('Hard', 'blockenberg') }
133 ],
134 onChange: function (v) { setAttributes({ defaultDifficulty: v }); }
135 }),
136 el(ToggleControl, {
137 label: __('Show Difficulty Buttons', 'blockenberg'),
138 checked: a.showDifficultyBtn,
139 onChange: function (v) { setAttributes({ showDifficultyBtn: v }); },
140 __nextHasNoMarginBottom: true
141 }),
142 el(ToggleControl, {
143 label: __('Show Live WPM', 'blockenberg'),
144 checked: a.showLiveWpm,
145 onChange: function (v) { setAttributes({ showLiveWpm: v }); },
146 __nextHasNoMarginBottom: true
147 }),
148 el(ToggleControl, {
149 label: __('Show Accuracy', 'blockenberg'),
150 checked: a.showAccuracy,
151 onChange: function (v) { setAttributes({ showAccuracy: v }); },
152 __nextHasNoMarginBottom: true
153 }),
154 el(ToggleControl, {
155 label: __('Show Error Count', 'blockenberg'),
156 checked: a.showErrors,
157 onChange: function (v) { setAttributes({ showErrors: v }); },
158 __nextHasNoMarginBottom: true
159 })
160 ),
161 el(
162 PanelBody,
163 { title: __('Typography', 'blockenberg'), initialOpen: false },
164 getTypoControl(__('Title', 'blockenberg'), 'titleTypo', a, setAttributes),
165 getTypoControl(__('Subtitle', 'blockenberg'), 'subtitleTypo', a, setAttributes)
166 ),
167 el(
168 PanelBody,
169 { title: __('Appearance', 'blockenberg'), initialOpen: false },
170 el(RangeControl, {
171 label: __('Max Width (px)', 'blockenberg'),
172 value: a.contentMaxWidth,
173 min: 320, max: 1200,
174 onChange: function (v) { setAttributes({ contentMaxWidth: v }); }
175 })
176 ),
177 el(
178 PanelColorSettings,
179 {
180 title: __('Colors', 'blockenberg'),
181 initialOpen: false,
182 colorSettings: [
183 { value: a.accentColor, onChange: function (v) { setAttributes({ accentColor: v || '#8b5cf6' }); }, label: __('Accent Color', 'blockenberg') },
184 { value: a.correctColor, onChange: function (v) { setAttributes({ correctColor: v || '#22c55e' }); }, label: __('Correct Letter Color', 'blockenberg') },
185 { value: a.errorColor, onChange: function (v) { setAttributes({ errorColor: v || '#ef4444' }); }, label: __('Error Color', 'blockenberg') },
186 { value: a.sectionBg, onChange: function (v) { setAttributes({ sectionBg: v || '#f5f3ff' }); }, label: __('Section Background', 'blockenberg') },
187 { value: a.cardBg, onChange: function (v) { setAttributes({ cardBg: v || '#ffffff' }); }, label: __('Card Background', 'blockenberg') },
188 { value: a.textAreaBg, onChange: function (v) { setAttributes({ textAreaBg: v || '#1e1b4b' }); }, label: __('Text Area Background', 'blockenberg') },
189 { value: a.textAreaColor, onChange: function (v) { setAttributes({ textAreaColor: v || '#c4b5fd' }); }, label: __('Text Area Text', 'blockenberg') },
190 { value: a.titleColor, onChange: function (v) { setAttributes({ titleColor: v || '#4c1d95' }); }, label: __('Title Color', 'blockenberg') },
191 { value: a.subtitleColor, onChange: function (v) { setAttributes({ subtitleColor: v || '#6b7280' }); }, label: __('Subtitle Color', 'blockenberg') },
192 { value: a.labelColor, onChange: function (v) { setAttributes({ labelColor: v || '#374151' }); }, label: __('Label Color', 'blockenberg') }
193 ]
194 }
195 )
196 ),
197 el(
198 'div',
199 blockProps,
200 el(
201 'div',
202 { style: containerStyle },
203 a.showTitle && el('div', { className: 'bkbg-tst-title', style: { color: a.titleColor } }, a.title),
204 a.showSubtitle && el('div', { className: 'bkbg-tst-subtitle', style: { color: a.subtitleColor } }, a.subtitle),
205
206 // Stats bar
207 el('div', { style: Object.assign({}, cardStyle, { display: 'flex', gap: '12px', justifyContent: 'space-between', flexWrap: 'wrap' }) },
208 [
209 { label: 'Time', value: a.duration + 's' },
210 a.showLiveWpm && { label: 'WPM', value: '–' },
211 a.showAccuracy && { label: 'Accuracy', value: '–' },
212 a.showErrors && { label: 'Errors', value: '–' }
213 ].filter(Boolean).map(function (s, i) {
214 return el('div', { key: i, style: statBoxStyle },
215 el('div', { style: { fontSize: '28px', fontWeight: '700', color: a.accentColor } }, s.value),
216 el('div', { style: { fontSize: '12px', color: a.subtitleColor, marginTop: '2px' } }, s.label)
217 );
218 })
219 ),
220
221 // Difficulty buttons
222 a.showDifficultyBtn && el('div', { style: { display: 'flex', gap: '8px', marginBottom: '14px', flexWrap: 'wrap' } },
223 ['easy', 'medium', 'hard'].map(function (d) {
224 var active = d === a.defaultDifficulty;
225 return el('button', {
226 key: d,
227 style: {
228 background: active ? a.accentColor : '#e5e7eb',
229 color: active ? '#fff' : '#374151',
230 border: 'none', borderRadius: '6px', padding: '6px 16px',
231 cursor: 'pointer', fontSize: '13px', fontWeight: '600', textTransform: 'capitalize'
232 }
233 }, d.charAt(0).toUpperCase() + d.slice(1));
234 })
235 ),
236
237 // Text display area
238 el('div', { style: Object.assign({}, cardStyle, { background: a.textAreaBg, fontFamily: 'monospace', fontSize: '17px', lineHeight: '1.9', color: a.textAreaColor, letterSpacing: '0.02em', minHeight: '100px', padding: '20px' }) },
239 SAMPLE_TEXT
240 ),
241
242 // Input area
243 el('textarea', {
244 placeholder: 'Click here and start typing...',
245 disabled: true,
246 style: {
247 width: '100%', borderRadius: '8px', padding: '14px',
248 fontSize: '15px', border: '2px solid ' + a.accentColor,
249 background: a.cardBg, color: a.labelColor,
250 resize: 'none', height: '80px', fontFamily: 'monospace',
251 boxSizing: 'border-box', marginTop: '4px'
252 }
253 }),
254
255 el('div', { style: { display: 'flex', justifyContent: 'center', marginTop: '14px' } },
256 el('button', { style: btnStyle }, '▶ Start Test')
257 )
258 )
259 )
260 );
261 },
262 save: function (props) {
263 var a = props.attributes;
264 var blockProps = wp.blockEditor.useBlockProps.save((function () { var _tv = getTypoCssVars(a); var s = {}; Object.assign(s, _tv); return { style: s }; })());
265 return el('div', blockProps,
266 el('div', { className: 'bkbg-tst-app', 'data-opts': JSON.stringify(a) })
267 );
268 }
269 });
270 }() );
271