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

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

526 lines 26.5 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 PanelBody = wp.components.PanelBody;
11 var RangeControl = wp.components.RangeControl;
12 var SelectControl = wp.components.SelectControl;
13 var TextControl = wp.components.TextControl;
14 var TextareaControl = wp.components.TextareaControl;
15 var ToggleControl = wp.components.ToggleControl;
16 var Button = wp.components.Button;
17 var ColorPicker = wp.components.ColorPicker;
18 var Popover = wp.components.Popover;
19
20 var _TypographyControl, _typoCssVars;
21 function getTypographyControl() { return _TypographyControl || (_TypographyControl = window.bkbgTypographyControl); }
22 function getTypoCssVars() { return _typoCssVars || (_typoCssVars = window.bkbgTypoCssVars); }
23
24 var PRIORITIES = {
25 high: { label: 'High', color: '#ef4444' },
26 medium: { label: 'Medium', color: '#f59e0b' },
27 low: { label: 'Low', color: '#10b981' }
28 };
29
30 function uid() {
31 return 'id-' + Math.random().toString(36).slice(2, 8);
32 }
33
34 // Single Kanban Card
35 function KanbanCard(props) {
36 var card = props.card;
37 var attrs = props.attrs;
38 var cardStyle = {
39 background: attrs.cardBg,
40 borderRadius: attrs.cardRadius + 'px',
41 padding: attrs.cardPadding + 'px',
42 boxShadow: attrs.cardShadow ? '0 1px 4px rgba(0,0,0,0.10)' : 'none',
43 marginBottom: '8px'
44 };
45
46 return el('div', { className: 'bkk-card', style: cardStyle },
47 el('div', { className: 'bkk-card-header' },
48 attrs.showTags && card.tag && el('span', {
49 className: 'bkk-tag',
50 style: { background: (card.tagColor || '#e5e7eb') + '22', color: card.tagColor || '#374151', borderRadius: '4px', padding: '2px 8px', fontSize: '11px', fontWeight: 600, letterSpacing: '0.02em' }
51 }, card.tag),
52 attrs.showPriority && el('span', {
53 className: 'bkk-priority bkk-priority--' + (card.priority || 'medium'),
54 title: (PRIORITIES[card.priority] || PRIORITIES.medium).label,
55 style: {
56 width: '8px', height: '8px', borderRadius: '50%',
57 background: (PRIORITIES[card.priority] || PRIORITIES.medium).color,
58 display: 'inline-block', marginLeft: '6px', flexShrink: 0
59 }
60 })
61 ),
62 el('div', {
63 className: 'bkk-card-title',
64 style: { color: attrs.cardTitleColor, marginTop: '6px' }
65 }, card.title || __('Card title', 'blockenberg')),
66 attrs.showDesc && card.desc && el('div', {
67 className: 'bkk-card-desc',
68 style: { color: attrs.cardDescColor, marginTop: '4px' }
69 }, card.desc)
70 );
71 }
72
73 // Single Kanban Column
74 function KanbanColumn(props) {
75 var col = props.col;
76 var attrs = props.attrs;
77 var colStyle = {
78 background: attrs.columnBg,
79 borderRadius: attrs.columnRadius + 'px',
80 padding: attrs.columnPadding + 'px',
81 minWidth: attrs.columnMinWidth + 'px',
82 flex: '1 1 ' + attrs.columnMinWidth + 'px'
83 };
84
85 return el('div', { className: 'bkk-column', style: colStyle },
86 el('div', { className: 'bkk-col-header', style: { marginBottom: '12px' } },
87 attrs.showColorBar && el('div', {
88 className: 'bkk-col-bar',
89 style: {
90 height: attrs.colorBarHeight + 'px',
91 background: col.color || '#6b7280',
92 borderRadius: '3px',
93 marginBottom: '10px'
94 }
95 }),
96 el('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' } },
97 el('span', {
98 className: 'bkk-col-title',
99 style: { color: attrs.columnTitleColor }
100 }, col.title || __('Column', 'blockenberg')),
101 attrs.showCardCount && el('span', {
102 className: 'bkk-count',
103 style: { fontSize: '11px', background: '#e5e7eb', borderRadius: '999px', padding: '1px 7px', color: '#6b7280', fontWeight: 600 }
104 }, (col.cards || []).length)
105 )
106 ),
107 el('div', { className: 'bkk-cards' },
108 (col.cards || []).map(function (card) {
109 return el(KanbanCard, { key: card.id, card: card, attrs: attrs });
110 })
111 )
112 );
113 }
114
115 // Column editor panel
116 function ColumnEditor(props) {
117 var col = props.col;
118 var colIdx = props.colIdx;
119 var onUpdateCol = props.onUpdateCol;
120 var onRemoveCol = props.onRemoveCol;
121 var onAddCard = props.onAddCard;
122 var onUpdateCard = props.onUpdateCard;
123 var onRemoveCard = props.onRemoveCard;
124
125 return el(PanelBody, {
126 title: (col.title || __('Column', 'blockenberg')) + ' (' + (col.cards || []).length + ')',
127 initialOpen: colIdx === 0
128 },
129 el(TextControl, {
130 label: __('Column title', 'blockenberg'),
131 value: col.title,
132 onChange: function (v) { onUpdateCol(colIdx, 'title', v); }
133 }),
134 el(BkbgColorSwatch, {
135 label: __('Column color (hex)', 'blockenberg'),
136 value: col.color,
137 onChange: function (v) { onUpdateCol(colIdx, 'color', v); }
138 }),
139
140 // Cards
141 (col.cards || []).map(function (card, ci) {
142 return el(PanelBody, {
143 key: card.id,
144 title: card.title || (__('Card', 'blockenberg') + ' ' + (ci + 1)),
145 initialOpen: false
146 },
147 el(TextControl, {
148 label: __('Card title', 'blockenberg'),
149 value: card.title,
150 onChange: function (v) { onUpdateCard(colIdx, ci, 'title', v); }
151 }),
152 el(TextareaControl, {
153 label: __('Description', 'blockenberg'),
154 rows: 2,
155 value: card.desc,
156 onChange: function (v) { onUpdateCard(colIdx, ci, 'desc', v); }
157 }),
158 el(TextControl, {
159 label: __('Tag label', 'blockenberg'),
160 value: card.tag,
161 onChange: function (v) { onUpdateCard(colIdx, ci, 'tag', v); }
162 }),
163 el(BkbgColorSwatch, {
164 label: __('Tag color (hex)', 'blockenberg'),
165 value: card.tagColor,
166 onChange: function (v) { onUpdateCard(colIdx, ci, 'tagColor', v); }
167 }),
168 el(SelectControl, {
169 label: __('Priority', 'blockenberg'),
170 value: card.priority || 'medium',
171 options: [
172 { label: 'High', value: 'high' },
173 { label: 'Medium', value: 'medium' },
174 { label: 'Low', value: 'low' }
175 ],
176 onChange: function (v) { onUpdateCard(colIdx, ci, 'priority', v); }
177 }),
178 el(Button, {
179 variant: 'secondary', isDestructive: true, isSmall: true,
180 onClick: function () { onRemoveCard(colIdx, ci); }
181 }, __('Remove card', 'blockenberg'))
182 );
183 }),
184
185 el(Button, {
186 variant: 'secondary', isSmall: true,
187 style: { marginTop: '8px', width: '100%', justifyContent: 'center' },
188 onClick: function () { onAddCard(colIdx); }
189 }, __('+ Add card', 'blockenberg')),
190
191 el('hr', { style: { margin: '12px 0', borderColor: '#e5e7eb' } }),
192 el(Button, {
193 variant: 'secondary', isDestructive: true, isSmall: true,
194 onClick: function () { onRemoveCol(colIdx); }
195 }, __('Remove column', 'blockenberg'))
196 );
197 }
198
199 var BkbgColorSwatch = function (props) {
200 var _st = useState(false); var isOpen = _st[0]; var setOpen = _st[1];
201 return el(Fragment, {},
202 el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '8px' } },
203 el('span', { style: { fontSize: '11px', fontWeight: 500, textTransform: 'uppercase', color: '#1e1e1e' } }, props.label),
204 el('button', {
205 type: 'button',
206 onClick: function () { setOpen(!isOpen); },
207 style: { width: '28px', height: '28px', borderRadius: '4px', border: '1px solid #ccc', background: props.value || '#ffffff', cursor: 'pointer', padding: 0 }
208 })
209 ),
210 isOpen && el(Popover, { onClose: function () { setOpen(false); } },
211 el('div', { style: { padding: '8px' } },
212 el(ColorPicker, { color: props.value, onChangeComplete: function (c) { props.onChange(c.hex); }, enableAlpha: true })
213 )
214 )
215 );
216 };
217
218 registerBlockType('blockenberg/kanban-board', {
219
220 edit: function (props) {
221 var attrs = props.attributes;
222 var setAttr = props.setAttributes;
223 var cols = attrs.columns || [];
224
225 function updateCol(ci, key, val) {
226 var next = cols.map(function (c, i) {
227 if (i !== ci) return c;
228 var u = Object.assign({}, c); u[key] = val; return u;
229 });
230 setAttr({ columns: next });
231 }
232
233 function removeCol(ci) {
234 setAttr({ columns: cols.filter(function (_, i) { return i !== ci; }) });
235 }
236
237 function addCol() {
238 if (cols.length >= 8) return;
239 setAttr({ columns: cols.concat([{ id: uid(), title: 'New Column', color: '#6b7280', cards: [] }]) });
240 }
241
242 function addCard(ci) {
243 var next = cols.map(function (c, i) {
244 if (i !== ci) return c;
245 var newCard = { id: uid(), title: 'New card', desc: '', tag: '', tagColor: '#6c3fb5', priority: 'medium' };
246 return Object.assign({}, c, { cards: (c.cards || []).concat([newCard]) });
247 });
248 setAttr({ columns: next });
249 }
250
251 function updateCard(ci, ki, key, val) {
252 var next = cols.map(function (c, i) {
253 if (i !== ci) return c;
254 var newCards = (c.cards || []).map(function (card, j) {
255 if (j !== ki) return card;
256 var u = Object.assign({}, card); u[key] = val; return u;
257 });
258 return Object.assign({}, c, { cards: newCards });
259 });
260 setAttr({ columns: next });
261 }
262
263 function removeCard(ci, ki) {
264 var next = cols.map(function (c, i) {
265 if (i !== ci) return c;
266 return Object.assign({}, c, { cards: (c.cards || []).filter(function (_, j) { return j !== ki; }) });
267 });
268 setAttr({ columns: next });
269 }
270
271 var wrapStyle = {
272 paddingTop: attrs.paddingTop + 'px',
273 paddingBottom: attrs.paddingBottom + 'px'
274 };
275 if (attrs.bgColor) wrapStyle.background = attrs.bgColor;
276 var _tv = getTypoCssVars();
277 Object.assign(wrapStyle, _tv(attrs.columnTitleTypo, '--bkk-ct-'));
278 Object.assign(wrapStyle, _tv(attrs.cardTitleTypo, '--bkk-cdt-'));
279 Object.assign(wrapStyle, _tv(attrs.cardDescTypo, '--bkk-cdd-'));
280
281 var blockProps = useBlockProps({ className: 'bkk-wrap', style: wrapStyle });
282
283 return el(Fragment, null,
284 el(InspectorControls, null,
285
286 el(PanelBody, { title: __('Board Settings', 'blockenberg'), initialOpen: true },
287 el(RangeControl, {
288 label: __('Column min-width (px)', 'blockenberg'),
289 value: attrs.columnMinWidth, min: 160, max: 400,
290 onChange: function (v) { setAttr({ columnMinWidth: v }); }
291 }),
292 el(RangeControl, {
293 label: __('Gap (px)', 'blockenberg'),
294 value: attrs.gap, min: 4, max: 48,
295 onChange: function (v) { setAttr({ gap: v }); }
296 }),
297 el(RangeControl, {
298 label: __('Column radius (px)', 'blockenberg'),
299 value: attrs.columnRadius, min: 0, max: 24,
300 onChange: function (v) { setAttr({ columnRadius: v }); }
301 }),
302 el(RangeControl, {
303 label: __('Card radius (px)', 'blockenberg'),
304 value: attrs.cardRadius, min: 0, max: 24,
305 onChange: function (v) { setAttr({ cardRadius: v }); }
306 }),
307 el(RangeControl, {
308 label: __('Card padding (px)', 'blockenberg'),
309 value: attrs.cardPadding, min: 8, max: 32,
310 onChange: function (v) { setAttr({ cardPadding: v }); }
311 }),
312 el(RangeControl, {
313 label: __('Column padding (px)', 'blockenberg'),
314 value: attrs.columnPadding, min: 8, max: 32,
315 onChange: function (v) { setAttr({ columnPadding: v }); }
316 }),
317 el(ToggleControl, {
318 label: __('Show color bar', 'blockenberg'),
319 checked: attrs.showColorBar,
320 onChange: function (v) { setAttr({ showColorBar: v }); },
321 __nextHasNoMarginBottom: true
322 }),
323 attrs.showColorBar && el(RangeControl, {
324 label: __('Color bar height (px)', 'blockenberg'),
325 value: attrs.colorBarHeight, min: 2, max: 12,
326 onChange: function (v) { setAttr({ colorBarHeight: v }); }
327 }),
328 el(ToggleControl, {
329 label: __('Show card count badge', 'blockenberg'),
330 checked: attrs.showCardCount,
331 onChange: function (v) { setAttr({ showCardCount: v }); },
332 __nextHasNoMarginBottom: true
333 }),
334 el(ToggleControl, {
335 label: __('Show priority dots', 'blockenberg'),
336 checked: attrs.showPriority,
337 onChange: function (v) { setAttr({ showPriority: v }); },
338 __nextHasNoMarginBottom: true
339 }),
340 el(ToggleControl, {
341 label: __('Show tags', 'blockenberg'),
342 checked: attrs.showTags,
343 onChange: function (v) { setAttr({ showTags: v }); },
344 __nextHasNoMarginBottom: true
345 }),
346 el(ToggleControl, {
347 label: __('Show description', 'blockenberg'),
348 checked: attrs.showDesc,
349 onChange: function (v) { setAttr({ showDesc: v }); },
350 __nextHasNoMarginBottom: true
351 }),
352 el(ToggleControl, {
353 label: __('Card shadow', 'blockenberg'),
354 checked: attrs.cardShadow,
355 onChange: function (v) { setAttr({ cardShadow: v }); },
356 __nextHasNoMarginBottom: true
357 })
358 ),
359
360 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
361 el(getTypographyControl(), { label: __('Column Title', 'blockenberg'), value: attrs.columnTitleTypo, onChange: function (v) { setAttr({ columnTitleTypo: v }); } }),
362 el(getTypographyControl(), { label: __('Card Title', 'blockenberg'), value: attrs.cardTitleTypo, onChange: function (v) { setAttr({ cardTitleTypo: v }); } }),
363 el(getTypographyControl(), { label: __('Card Description', 'blockenberg'), value: attrs.cardDescTypo, onChange: function (v) { setAttr({ cardDescTypo: v }); } })
364 ),
365
366 el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: false },
367 el(RangeControl, {
368 label: __('Padding Top (px)', 'blockenberg'),
369 value: attrs.paddingTop, min: 0, max: 200,
370 onChange: function (v) { setAttr({ paddingTop: v }); }
371 }),
372 el(RangeControl, {
373 label: __('Padding Bottom (px)', 'blockenberg'),
374 value: attrs.paddingBottom, min: 0, max: 200,
375 onChange: function (v) { setAttr({ paddingBottom: v }); }
376 })
377 ),
378
379 el(PanelColorSettings, {
380 title: __('Colors', 'blockenberg'),
381 initialOpen: false,
382 colorSettings: [
383 { label: __('Column Background', 'blockenberg'), value: attrs.columnBg, onChange: function (v) { setAttr({ columnBg: v || '#f3f4f6' }); } },
384 { label: __('Card Background', 'blockenberg'), value: attrs.cardBg, onChange: function (v) { setAttr({ cardBg: v || '#ffffff' }); } },
385 { label: __('Column Title', 'blockenberg'), value: attrs.columnTitleColor, onChange: function (v) { setAttr({ columnTitleColor: v || '#1f2937' }); } },
386 { label: __('Card Title', 'blockenberg'), value: attrs.cardTitleColor, onChange: function (v) { setAttr({ cardTitleColor: v || '#111827' }); } },
387 { label: __('Card Description', 'blockenberg'), value: attrs.cardDescColor, onChange: function (v) { setAttr({ cardDescColor: v || '#6b7280' }); } },
388 { label: __('Board Background', 'blockenberg'), value: attrs.bgColor, onChange: function (v) { setAttr({ bgColor: v || '' }); } }
389 ]
390 }),
391
392 // Columns editor
393 el(PanelBody, { title: __('Columns & Cards', 'blockenberg'), initialOpen: false },
394 cols.map(function (col, ci) {
395 return el(ColumnEditor, {
396 key: col.id,
397 col: col,
398 colIdx: ci,
399 onUpdateCol: updateCol,
400 onRemoveCol: removeCol,
401 onAddCard: addCard,
402 onUpdateCard: updateCard,
403 onRemoveCard: removeCard
404 });
405 }),
406 cols.length < 8 && el(Button, {
407 variant: 'primary', isSmall: true,
408 style: { marginTop: '12px', width: '100%', justifyContent: 'center' },
409 onClick: addCol
410 }, __('+ Add column', 'blockenberg'))
411 )
412 ),
413
414 el('div', blockProps,
415 el('div', {
416 className: 'bkk-board',
417 style: {
418 display: 'flex',
419 flexWrap: 'wrap',
420 gap: attrs.gap + 'px',
421 alignItems: 'flex-start'
422 }
423 },
424 cols.map(function (col) {
425 return el(KanbanColumn, { key: col.id, col: col, attrs: attrs });
426 })
427 )
428 )
429 );
430 },
431
432 save: function (props) {
433 var a = props.attributes;
434 var cols = a.columns || [];
435
436 var wrapStyle = {
437 paddingTop: a.paddingTop + 'px',
438 paddingBottom: a.paddingBottom + 'px'
439 };
440 if (a.bgColor) wrapStyle.background = a.bgColor;
441 var _tv = getTypoCssVars();
442 Object.assign(wrapStyle, _tv(a.columnTitleTypo, '--bkk-ct-'));
443 Object.assign(wrapStyle, _tv(a.cardTitleTypo, '--bkk-cdt-'));
444 Object.assign(wrapStyle, _tv(a.cardDescTypo, '--bkk-cdd-'));
445
446 var blockProps = wp.blockEditor.useBlockProps.save({ className: 'bkk-wrap', style: wrapStyle });
447
448 return el('div', blockProps,
449 el('div', {
450 className: 'bkk-board',
451 style: { display: 'flex', flexWrap: 'wrap', gap: a.gap + 'px', alignItems: 'flex-start' }
452 },
453 cols.map(function (col) {
454 return el('div', {
455 key: col.id,
456 className: 'bkk-column',
457 style: {
458 background: a.columnBg,
459 borderRadius: a.columnRadius + 'px',
460 padding: a.columnPadding + 'px',
461 minWidth: a.columnMinWidth + 'px',
462 flex: '1 1 ' + a.columnMinWidth + 'px'
463 }
464 },
465 el('div', { className: 'bkk-col-header' },
466 a.showColorBar && el('div', {
467 className: 'bkk-col-bar',
468 style: { height: a.colorBarHeight + 'px', background: col.color || '#6b7280', borderRadius: '3px', marginBottom: '10px' }
469 }),
470 el('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' } },
471 el('span', {
472 className: 'bkk-col-title',
473 style: { color: a.columnTitleColor }
474 }, col.title),
475 a.showCardCount && el('span', {
476 className: 'bkk-count',
477 style: { fontSize: '11px', background: '#e5e7eb', borderRadius: '999px', padding: '1px 7px', color: '#6b7280', fontWeight: 600 }
478 }, (col.cards || []).length)
479 )
480 ),
481 el('div', { className: 'bkk-cards', style: { marginTop: '12px' } },
482 (col.cards || []).map(function (card) {
483 return el('div', {
484 key: card.id,
485 className: 'bkk-card',
486 style: {
487 background: a.cardBg,
488 borderRadius: a.cardRadius + 'px',
489 padding: a.cardPadding + 'px',
490 boxShadow: a.cardShadow ? '0 1px 4px rgba(0,0,0,0.10)' : 'none',
491 marginBottom: '8px'
492 }
493 },
494 el('div', { className: 'bkk-card-header', style: { display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: '6px' } },
495 a.showTags && card.tag && el('span', {
496 className: 'bkk-tag',
497 style: { background: (card.tagColor || '#e5e7eb') + '22', color: card.tagColor || '#374151', borderRadius: '4px', padding: '2px 8px', fontSize: '11px', fontWeight: 600 }
498 }, card.tag),
499 a.showPriority && el('span', {
500 className: 'bkk-priority bkk-priority--' + (card.priority || 'medium'),
501 style: {
502 width: '8px', height: '8px', borderRadius: '50%',
503 background: (PRIORITIES[card.priority] || PRIORITIES.medium).color,
504 display: 'inline-block', flexShrink: 0
505 }
506 })
507 ),
508 el('div', {
509 className: 'bkk-card-title',
510 style: { color: a.cardTitleColor, marginTop: '6px' }
511 }, card.title),
512 a.showDesc && card.desc && el('div', {
513 className: 'bkk-card-desc',
514 style: { color: a.cardDescColor, marginTop: '4px' }
515 }, card.desc)
516 );
517 })
518 )
519 );
520 })
521 )
522 );
523 }
524 });
525 }() );
526