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

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

390 lines 22.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 Fragment = wp.element.Fragment;
4 var useState = wp.element.useState;
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 RichText = wp.blockEditor.RichText;
11 var PanelBody = wp.components.PanelBody;
12 var RangeControl = wp.components.RangeControl;
13 var SelectControl = wp.components.SelectControl;
14 var TextControl = wp.components.TextControl;
15 var TextareaControl = wp.components.TextareaControl;
16 var ToggleControl = wp.components.ToggleControl;
17 var Button = wp.components.Button;
18
19 var _glTC, _glTV;
20 function _tc() { return _glTC || (_glTC = window.bkbgTypographyControl); }
21 function _tv() { return _glTV || (_glTV = window.bkbgTypoCssVars); }
22
23 var ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
24
25 function uid() {
26 return 'gl-' + Math.random().toString(36).slice(2, 9);
27 }
28
29 function groupByLetter(terms) {
30 var map = {};
31 (terms || []).forEach(function (t) {
32 var letter = (t.term || '?').charAt(0).toUpperCase();
33 if (!map[letter]) map[letter] = [];
34 map[letter].push(t);
35 });
36 return map;
37 }
38
39 function TermEditor(props) {
40 var term = props.term;
41 var onChange = props.onChange;
42 var onRemove = props.onRemove;
43 return el(PanelBody, {
44 title: (term.term || __('(empty term)', 'blockenberg')).slice(0, 32),
45 initialOpen: false
46 },
47 el(TextControl, {
48 label: __('Term', 'blockenberg'),
49 value: term.term,
50 onChange: function (v) { onChange({ term: v }); }
51 }),
52 el(TextareaControl, {
53 label: __('Definition', 'blockenberg'),
54 value: term.definition,
55 rows: 3,
56 onChange: function (v) { onChange({ definition: v }); }
57 }),
58 el(Button, {
59 isDestructive: true, isSmall: true,
60 style: { marginTop: '4px' },
61 onClick: onRemove
62 }, __('Remove term', 'blockenberg'))
63 );
64 }
65
66 registerBlockType('blockenberg/glossary', {
67 edit: function (props) {
68 var attrs = props.attributes;
69 var setAttr = function (obj) { props.setAttributes(obj); };
70
71 var terms = attrs.terms || [];
72
73 function addTerm() {
74 setAttr({ terms: terms.concat([{ id: uid(), term: '', definition: '' }]) });
75 }
76 function updateTerm(id, patch) {
77 setAttr({ terms: terms.map(function (t) { return t.id === id ? Object.assign({}, t, patch) : t; }) });
78 }
79 function removeTerm(id) {
80 setAttr({ terms: terms.filter(function (t) { return t.id !== id; }) });
81 }
82
83 var grouped = groupByLetter(terms);
84 var usedLetters = Object.keys(grouped).sort();
85
86 var wrapStyle = { paddingTop: attrs.paddingTop + 'px', paddingBottom: attrs.paddingBottom + 'px' };
87 if (attrs.bgColor) wrapStyle.background = attrs.bgColor;
88
89 var blockProps = useBlockProps({ style: Object.assign(wrapStyle, _tv()(attrs.typoTitle, '--bkbg-gl-tt-'), _tv()(attrs.typoTerm, '--bkbg-gl-tm-'), _tv()(attrs.typoDef, '--bkbg-gl-df-'), _tv()(attrs.typoLetterHead, '--bkbg-gl-lh-')) });
90
91 return el(Fragment, null,
92 el(InspectorControls, null,
93
94 el(PanelBody, { title: __('Terms', 'blockenberg'), initialOpen: true },
95 terms.map(function (t) {
96 return el(TermEditor, {
97 key: t.id,
98 term: t,
99 onChange: function (patch) { updateTerm(t.id, patch); },
100 onRemove: function () { removeTerm(t.id); }
101 });
102 }),
103 el(Button, {
104 variant: 'primary', isSmall: true,
105 style: { marginTop: '12px', width: '100%', justifyContent: 'center' },
106 onClick: addTerm
107 }, __('+ Add Term', 'blockenberg'))
108 ),
109
110 el(PanelBody, { title: __('Display', 'blockenberg'), initialOpen: false },
111 el(ToggleControl, {
112 label: __('Show title', 'blockenberg'),
113 checked: attrs.showTitle,
114 onChange: function (v) { setAttr({ showTitle: v }); },
115 __nextHasNoMarginBottom: true
116 }),
117 el(ToggleControl, {
118 label: __('Show subtitle', 'blockenberg'),
119 checked: attrs.showSubtitle,
120 onChange: function (v) { setAttr({ showSubtitle: v }); },
121 __nextHasNoMarginBottom: true
122 }),
123 el(ToggleControl, {
124 label: __('A–Z navigation bar', 'blockenberg'),
125 checked: attrs.showAlphaNav,
126 onChange: function (v) { setAttr({ showAlphaNav: v }); },
127 __nextHasNoMarginBottom: true
128 }),
129 el(ToggleControl, {
130 label: __('Search box', 'blockenberg'),
131 checked: attrs.showSearch,
132 onChange: function (v) { setAttr({ showSearch: v }); },
133 __nextHasNoMarginBottom: true
134 }),
135 el(ToggleControl, {
136 label: __('Group by letter', 'blockenberg'),
137 checked: attrs.groupByLetter,
138 onChange: function (v) { setAttr({ groupByLetter: v }); },
139 __nextHasNoMarginBottom: true
140 }),
141 el(ToggleControl, {
142 label: __('Show letter headings', 'blockenberg'),
143 checked: attrs.showLetterHead,
144 onChange: function (v) { setAttr({ showLetterHead: v }); },
145 __nextHasNoMarginBottom: true
146 }),
147 el(ToggleControl, {
148 label: __('Expandable definitions (accordion)', 'blockenberg'),
149 checked: attrs.expandable,
150 onChange: function (v) { setAttr({ expandable: v }); },
151 __nextHasNoMarginBottom: true
152 }),
153 el(SelectControl, {
154 label: __('Columns', 'blockenberg'),
155 value: String(attrs.columns),
156 options: [
157 { label: '1', value: '1' },
158 { label: '2', value: '2' }
159 ],
160 onChange: function (v) { setAttr({ columns: parseInt(v, 10) }); }
161 })
162 ),
163
164 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
165 _tc()({ label: __('Title', 'blockenberg'), value: attrs.typoTitle, onChange: function (v) { setAttr({ typoTitle: v }); } }),
166 _tc()({ label: __('Term', 'blockenberg'), value: attrs.typoTerm, onChange: function (v) { setAttr({ typoTerm: v }); } }),
167 _tc()({ label: __('Definition', 'blockenberg'), value: attrs.typoDef, onChange: function (v) { setAttr({ typoDef: v }); } }),
168 _tc()({ label: __('Letter Heading', 'blockenberg'), value: attrs.typoLetterHead, onChange: function (v) { setAttr({ typoLetterHead: v }); } }),
169 el(RangeControl, {
170 label: __('Card radius (px)', 'blockenberg'),
171 value: attrs.cardRadius, min: 0, max: 24,
172 onChange: function (v) { setAttr({ cardRadius: v }); }
173 })
174 ),
175
176 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
177 el(RangeControl, {
178 label: __('Padding Top (px)', 'blockenberg'),
179 value: attrs.paddingTop, min: 0, max: 200,
180 onChange: function (v) { setAttr({ paddingTop: v }); }
181 }),
182 el(RangeControl, {
183 label: __('Padding Bottom (px)', 'blockenberg'),
184 value: attrs.paddingBottom, min: 0, max: 200,
185 onChange: function (v) { setAttr({ paddingBottom: v }); }
186 })
187 ),
188
189 el(PanelColorSettings, {
190 title: __('Colors', 'blockenberg'),
191 initialOpen: false,
192 colorSettings: [
193 { label: __('Accent', 'blockenberg'), value: attrs.accentColor, onChange: function (v) { setAttr({ accentColor: v || '#6c3fb5' }); } },
194 { label: __('Title', 'blockenberg'), value: attrs.titleColor, onChange: function (v) { setAttr({ titleColor: v || '#1e1b4b' }); } },
195 { label: __('Subtitle', 'blockenberg'), value: attrs.subtitleColor, onChange: function (v) { setAttr({ subtitleColor: v || '#6b7280' }); } },
196 { label: __('Term text', 'blockenberg'), value: attrs.termColor, onChange: function (v) { setAttr({ termColor: v || '#1e1b4b' }); } },
197 { label: __('Definition text', 'blockenberg'), value: attrs.defColor, onChange: function (v) { setAttr({ defColor: v || '#374151' }); } },
198 { label: __('Letter heading text', 'blockenberg'), value: attrs.letterHeadColor, onChange: function (v) { setAttr({ letterHeadColor: v || '#6c3fb5' }); } },
199 { label: __('Letter heading background', 'blockenberg'), value: attrs.letterHeadBg, onChange: function (v) { setAttr({ letterHeadBg: v || '#f5f3ff' }); } },
200 { label: __('Nav bar background', 'blockenberg'), value: attrs.navBg, onChange: function (v) { setAttr({ navBg: v || '#f3f4f6' }); } },
201 { label: __('Nav active button', 'blockenberg'), value: attrs.navActiveColor, onChange: function (v) { setAttr({ navActiveColor: v || '#ffffff' }); } },
202 { label: __('Item border', 'blockenberg'), value: attrs.itemBorder, onChange: function (v) { setAttr({ itemBorder: v || '#e5e7eb' }); } },
203 { label: __('Block background', 'blockenberg'), value: attrs.bgColor, onChange: function (v) { setAttr({ bgColor: v || '' }); } }
204 ]
205 })
206 ),
207
208 el('div', blockProps,
209 attrs.showTitle && el(RichText, {
210 tagName: 'h2',
211 className: 'bkbg-gl-title',
212 style: { color: attrs.titleColor, margin: '0 0 8px' },
213 value: attrs.title,
214 onChange: function (v) { setAttr({ title: v }); },
215 placeholder: __('Glossary title…', 'blockenberg')
216 }),
217 attrs.showSubtitle && el(RichText, {
218 tagName: 'p',
219 className: 'bkbg-gl-subtitle',
220 style: { color: attrs.subtitleColor, margin: '0 0 24px' },
221 value: attrs.subtitle,
222 onChange: function (v) { setAttr({ subtitle: v }); },
223 placeholder: __('Optional subtitle…', 'blockenberg')
224 }),
225
226 attrs.showSearch && el('div', { className: 'bkbg-gl-search-wrap', style: { marginBottom: '16px' } },
227 el('input', {
228 type: 'text',
229 className: 'bkbg-gl-search',
230 placeholder: __('Search terms…', 'blockenberg'),
231 style: { width: '100%', padding: '8px 12px', borderRadius: '6px', border: '1px solid ' + (attrs.searchBorder || '#d1d5db'), fontSize: '14px', boxSizing: 'border-box' },
232 readOnly: true
233 })
234 ),
235
236 attrs.showAlphaNav && el('div', {
237 className: 'bkbg-gl-alpha-nav',
238 style: { display: 'flex', flexWrap: 'wrap', gap: '4px', background: attrs.navBg || '#f3f4f6', borderRadius: '8px', padding: '8px', marginBottom: '24px' }
239 },
240 ALPHABET.map(function (letter) {
241 var active = grouped[letter] && grouped[letter].length > 0;
242 return el('button', {
243 key: letter,
244 type: 'button',
245 className: 'bkbg-gl-nav-btn' + (active ? ' active' : ''),
246 style: {
247 minWidth: '28px', height: '28px', borderRadius: '4px',
248 border: 'none', cursor: active ? 'pointer' : 'default',
249 background: active ? attrs.accentColor : 'transparent',
250 color: active ? (attrs.navActiveColor || '#fff') : '#9ca3af',
251 fontWeight: 600, fontSize: '13px'
252 }
253 }, letter);
254 })
255 ),
256
257 el('div', {
258 className: 'bkbg-gl-list',
259 style: { columns: attrs.columns > 1 ? attrs.columns : undefined, columnGap: '32px' }
260 },
261 terms.length === 0
262 ? el('p', { style: { color: '#9ca3af', textAlign: 'center', padding: '40px 0' } }, __('Add your first term in the sidebar →', 'blockenberg'))
263 : (attrs.groupByLetter
264 ? usedLetters.map(function (letter) {
265 return el('div', { key: letter, className: 'bkbg-gl-letter-section', style: { breakInside: 'avoid', marginBottom: '24px' } },
266 attrs.showLetterHead && el('div', {
267 className: 'bkbg-gl-letter-head',
268 style: { background: attrs.letterHeadBg || '#f5f3ff', color: attrs.letterHeadColor || '#6c3fb5', borderRadius: '6px', padding: '4px 12px', display: 'inline-block', marginBottom: '12px' }
269 }, letter),
270 (grouped[letter] || []).map(function (term) {
271 return el('div', {
272 key: term.id,
273 className: 'bkbg-gl-item',
274 style: { borderBottom: '1px solid ' + (attrs.itemBorder || '#e5e7eb'), padding: '10px 0' }
275 },
276 el('div', {
277 className: 'bkbg-gl-term',
278 style: { color: attrs.termColor || '#1e1b4b', marginBottom: '4px' }
279 }, term.term || __('(term)', 'blockenberg')),
280 el('div', {
281 className: 'bkbg-gl-def',
282 style: { color: attrs.defColor || '#374151' }
283 }, term.definition || __('(definition)', 'blockenberg'))
284 );
285 })
286 );
287 })
288 : terms.map(function (term) {
289 return el('div', {
290 key: term.id,
291 className: 'bkbg-gl-item',
292 style: { borderBottom: '1px solid ' + (attrs.itemBorder || '#e5e7eb'), padding: '10px 0' }
293 },
294 el('div', { className: 'bkbg-gl-term', style: { color: attrs.termColor || '#1e1b4b', marginBottom: '4px' } }, term.term || __('(term)', 'blockenberg')),
295 el('div', { className: 'bkbg-gl-def', style: { color: attrs.defColor || '#374151' } }, term.definition || __('(definition)', 'blockenberg'))
296 );
297 })
298 )
299 )
300 )
301 );
302 },
303
304 save: function (props) {
305 var a = props.attributes;
306 var terms = a.terms || [];
307 var grouped = groupByLetter(terms);
308 var usedLetters = Object.keys(grouped).sort();
309
310 var wrapStyle = { paddingTop: a.paddingTop + 'px', paddingBottom: a.paddingBottom + 'px' };
311 if (a.bgColor) wrapStyle.background = a.bgColor;
312
313 var blockProps = wp.blockEditor.useBlockProps.save({ style: Object.assign(wrapStyle, _tv()(a.typoTitle, '--bkbg-gl-tt-'), _tv()(a.typoTerm, '--bkbg-gl-tm-'), _tv()(a.typoDef, '--bkbg-gl-df-'), _tv()(a.typoLetterHead, '--bkbg-gl-lh-')) });
314
315 return el('div', blockProps,
316 a.showTitle && el('h2', {
317 className: 'bkbg-gl-title',
318 style: { color: a.titleColor, margin: '0 0 8px' },
319 dangerouslySetInnerHTML: { __html: a.title }
320 }),
321 a.showSubtitle && el('p', {
322 className: 'bkbg-gl-subtitle',
323 style: { color: a.subtitleColor, margin: '0 0 24px' },
324 dangerouslySetInnerHTML: { __html: a.subtitle }
325 }),
326
327 a.showSearch && el('div', { className: 'bkbg-gl-search-wrap', style: { marginBottom: '16px' } },
328 el('input', {
329 type: 'text',
330 className: 'bkbg-gl-search',
331 placeholder: __('Search terms…', 'blockenberg'),
332 style: { width: '100%', padding: '8px 12px', borderRadius: '6px', border: '1px solid ' + (a.searchBorder || '#d1d5db'), fontSize: '14px', boxSizing: 'border-box' }
333 })
334 ),
335
336 a.showAlphaNav && el('div', {
337 className: 'bkbg-gl-alpha-nav',
338 style: { display: 'flex', flexWrap: 'wrap', gap: '4px', background: a.navBg || '#f3f4f6', borderRadius: '8px', padding: '8px', marginBottom: '24px' }
339 },
340 ALPHABET.map(function (letter) {
341 var active = grouped[letter] && grouped[letter].length > 0;
342 return el('a', {
343 key: letter,
344 href: active ? '#gl-' + letter.toLowerCase() : undefined,
345 className: 'bkbg-gl-nav-btn' + (active ? ' active' : ''),
346 style: {
347 minWidth: '28px', height: '28px', lineHeight: '28px',
348 borderRadius: '4px', textAlign: 'center', display: 'inline-block',
349 textDecoration: 'none',
350 background: active ? a.accentColor : 'transparent',
351 color: active ? (a.navActiveColor || '#fff') : '#9ca3af',
352 fontWeight: 600, fontSize: '13px'
353 }
354 }, letter);
355 })
356 ),
357
358 el('div', {
359 className: 'bkbg-gl-list',
360 'data-opts': JSON.stringify({ expandable: a.expandable, showSearch: a.showSearch, columns: a.columns }),
361 style: { columns: a.columns > 1 ? a.columns : undefined, columnGap: '32px' }
362 },
363 (a.groupByLetter
364 ? usedLetters.map(function (letter) {
365 return el('div', { key: letter, id: 'gl-' + letter.toLowerCase(), className: 'bkbg-gl-letter-section', style: { breakInside: 'avoid', marginBottom: '24px' } },
366 a.showLetterHead && el('div', {
367 className: 'bkbg-gl-letter-head',
368 style: { background: a.letterHeadBg || '#f5f3ff', color: a.letterHeadColor || '#6c3fb5', borderRadius: '6px', padding: '4px 12px', display: 'inline-block', marginBottom: '12px' }
369 }, letter),
370 (grouped[letter] || []).map(function (term) {
371 return el('div', { key: term.id, className: 'bkbg-gl-item', 'data-term': (term.term || '').toLowerCase(), style: { borderBottom: '1px solid ' + (a.itemBorder || '#e5e7eb'), padding: '10px 0' } },
372 el('div', { className: 'bkbg-gl-term', style: { color: a.termColor || '#1e1b4b', marginBottom: '4px', cursor: a.expandable ? 'pointer' : undefined } }, term.term),
373 el('div', { className: 'bkbg-gl-def', style: { color: a.defColor || '#374151' } }, term.definition)
374 );
375 })
376 );
377 })
378 : terms.map(function (term) {
379 return el('div', { key: term.id, className: 'bkbg-gl-item', 'data-term': (term.term || '').toLowerCase(), style: { borderBottom: '1px solid ' + (a.itemBorder || '#e5e7eb'), padding: '10px 0' } },
380 el('div', { className: 'bkbg-gl-term', style: { color: a.termColor || '#1e1b4b', marginBottom: '4px' } }, term.term),
381 el('div', { className: 'bkbg-gl-def', style: { color: a.defColor || '#374151' } }, term.definition)
382 );
383 })
384 )
385 )
386 );
387 }
388 });
389 }() );
390