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

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

246 lines 13.4 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 useBlockProps = wp.blockEditor.useBlockProps;
9 var useState = wp.element.useState;
10 var PanelBody = wp.components.PanelBody;
11 var TextControl = wp.components.TextControl;
12 var ToggleControl = wp.components.ToggleControl;
13 var RangeControl = wp.components.RangeControl;
14 var SelectControl = wp.components.SelectControl;
15 var Button = wp.components.Button;
16 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
17 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
18
19 // ── helpers ────────────────────────────────────────────────────
20 function upd(arr, idx, field, val) {
21 return arr.map(function (e, i) {
22 if (i !== idx) return e;
23 var u = {}; u[field] = val;
24 return Object.assign({}, e, u);
25 });
26 }
27
28 var LAYOUT_OPTIONS = [
29 { value: 'buttons', label: 'Pill buttons (GitHub style)' },
30 { value: 'compact', label: 'Compact row' },
31 { value: 'cards', label: 'Cards grid' },
32 ];
33
34 // ── reaction item renderer ─────────────────────────────────────
35 function renderReactionItem(r, a, isActive, layout) {
36 var isCards = layout === 'cards';
37 var isCompact = layout === 'compact';
38
39 // Common base styles
40 var itemStyle = {
41 display: 'inline-flex',
42 alignItems: 'center',
43 justifyContent: isCards ? 'center' : 'flex-start',
44 flexDirection: isCards ? 'column' : 'row',
45 gap: isCards ? '6px' : '6px',
46 padding: isCards ? '16px 12px' : isCompact ? '4px 12px' : '7px 14px',
47 borderRadius: (a.itemRadius || 100) + 'px',
48 border: '1.5px solid ' + (isActive ? a.activeItemBorder : a.itemBorderColor),
49 background: isActive ? a.activeItemBg : a.itemBg,
50 cursor: 'pointer',
51 userSelect: 'none',
52 transition: 'all .15s ease',
53 flexShrink: '0'
54 };
55 if (isCards) {
56 itemStyle.borderRadius = '12px';
57 itemStyle.minWidth = '90px';
58 }
59
60 var emojiEl = el('span', { style: { fontSize: a.emojiSize + 'px', lineHeight: '1' } }, r.emoji);
61 var countEl = a.showCount ? el('span', {
62 className: 'bkrab-count',
63 style: { color: isActive ? a.activeCountColor : a.countColor }
64 }, String(r.count)) : null;
65 var labelEl = (a.showLabel && !isCompact) ? el('span', {
66 className: 'bkrab-label',
67 style: { color: a.labelColor }
68 }, r.label) : null;
69
70 return el('div', { style: itemStyle },
71 emojiEl,
72 el('div', { style: { display: 'flex', flexDirection: isCards ? 'column' : 'row', alignItems: 'center', gap: '4px' } },
73 countEl, labelEl
74 )
75 );
76 }
77
78 // ── edit ──────────────────────────────────────────────────────
79 function Edit(props) {
80 var a = props.attributes;
81 var set = props.setAttributes;
82 var TC = getTypoControl();
83 var activeIdx = useState(0)[0];
84
85 var total = a.reactions.reduce(function (s, r) { return s + (r.count || 0); }, 0);
86
87 var colorSettings = [
88 { label: __('Background'), value: a.bgColor, onChange: function (v) { set({ bgColor: v || '#ffffff' }); } },
89 { label: __('Border'), value: a.borderColor, onChange: function (v) { set({ borderColor: v || '#e5e7eb' }); } },
90 { label: __('Title'), value: a.titleColor, onChange: function (v) { set({ titleColor: v || '#111827' }); } },
91 { label: __('Item BG'), value: a.itemBg, onChange: function (v) { set({ itemBg: v || '#f9fafb' }); } },
92 { label: __('Item Border'), value: a.itemBorderColor, onChange: function (v) { set({ itemBorderColor: v || '#e5e7eb' }); } },
93 { label: __('Count'), value: a.countColor, onChange: function (v) { set({ countColor: v || '#374151' }); } },
94 { label: __('Label'), value: a.labelColor, onChange: function (v) { set({ labelColor: v || '#6b7280' }); } },
95 { label: __('Total count'), value: a.totalColor, onChange: function (v) { set({ totalColor: v || '#9ca3af' }); } },
96 { label: __('Active BG'), value: a.activeItemBg, onChange: function (v) { set({ activeItemBg: v || '#eff6ff' }); } },
97 { label: __('Active Border'), value: a.activeItemBorder, onChange: function (v) { set({ activeItemBorder: v || '#bfdbfe' }); } },
98 { label: __('Active Count'), value: a.activeCountColor, onChange: function (v) { set({ activeCountColor: v || '#1d4ed8' }); } },
99 ];
100
101 var inspector = el(InspectorControls, {},
102 // Settings
103 el(PanelBody, { title: __('Settings'), initialOpen: true },
104 el(TextControl, {
105 label: __('Title'), value: a.title, __nextHasNoMarginBottom: true,
106 onChange: function (v) { set({ title: v }); }
107 }),
108 el(ToggleControl, {
109 label: __('Show title'), checked: a.showTitle, __nextHasNoMarginBottom: true,
110 onChange: function (v) { set({ showTitle: v }); }
111 }),
112 el(SelectControl, {
113 label: __('Layout'), value: a.layout, options: LAYOUT_OPTIONS, __nextHasNoMarginBottom: true,
114 onChange: function (v) { set({ layout: v }); }
115 }),
116 el(ToggleControl, {
117 label: __('Show count'), checked: a.showCount, __nextHasNoMarginBottom: true,
118 onChange: function (v) { set({ showCount: v }); }
119 }),
120 el(ToggleControl, {
121 label: __('Show label'), checked: a.showLabel, __nextHasNoMarginBottom: true,
122 onChange: function (v) { set({ showLabel: v }); }
123 }),
124 el(ToggleControl, {
125 label: __('Show total'), checked: a.showTotal, __nextHasNoMarginBottom: true,
126 onChange: function (v) { set({ showTotal: v }); }
127 }),
128 a.showTotal ? el(TextControl, {
129 label: __('Total label'), value: a.totalLabel, __nextHasNoMarginBottom: true,
130 onChange: function (v) { set({ totalLabel: v }); }
131 }) : null
132 ),
133 // Typography
134 el(PanelBody, { title: __('Typography'), initialOpen: false },
135 TC && el(TC, { label: __('Title', 'blockenberg'), value: a.titleTypo || {}, onChange: function(v) { set({ titleTypo: v }); } }),
136 TC && el(TC, { label: __('Count / Label', 'blockenberg'), value: a.countTypo || {}, onChange: function(v) { set({ countTypo: v }); } }),
137 el(RangeControl, { label: __('Emoji size'), value: a.emojiSize, min: 14, max: 40, __nextHasNoMarginBottom: true, onChange: function (v) { set({ emojiSize: v }); } })
138 ),
139 // Appearance
140 el(PanelBody, { title: __('Appearance'), initialOpen: false },
141 el(RangeControl, {
142 label: __('Card radius'), value: a.borderRadius, min: 0, max: 40, __nextHasNoMarginBottom: true,
143 onChange: function (v) { set({ borderRadius: v }); }
144 }),
145 el(RangeControl, {
146 label: __('Item radius'), value: a.itemRadius, min: 0, max: 100, __nextHasNoMarginBottom: true,
147 onChange: function (v) { set({ itemRadius: v }); }
148 })
149 ),
150 // Reactions editor
151 el(PanelBody, { title: __('Reactions (' + a.reactions.length + ')'), initialOpen: false },
152 a.reactions.map(function (r, idx) {
153 return el(PanelBody, {
154 key: idx,
155 title: r.emoji + ' ' + r.label + ' (' + r.count + ')',
156 initialOpen: false
157 },
158 el(TextControl, {
159 label: __('Emoji'), value: r.emoji, __nextHasNoMarginBottom: true,
160 onChange: function (v) { set({ reactions: upd(a.reactions, idx, 'emoji', v) }); }
161 }),
162 el(TextControl, {
163 label: __('Label'), value: r.label, __nextHasNoMarginBottom: true,
164 onChange: function (v) { set({ reactions: upd(a.reactions, idx, 'label', v) }); }
165 }),
166 el(TextControl, {
167 label: __('Count'), value: String(r.count), __nextHasNoMarginBottom: true,
168 onChange: function (v) { var n = parseInt(v, 10); if (!isNaN(n) && n >= 0) set({ reactions: upd(a.reactions, idx, 'count', n) }); }
169 }),
170 el(Button, {
171 variant: 'secondary', isDestructive: true, __nextHasNoMarginBottom: true,
172 onClick: function () { var n = a.reactions.slice(); n.splice(idx, 1); set({ reactions: n }); }
173 }, __('Remove'))
174 );
175 }),
176 a.reactions.length < 12 ? el(Button, {
177 variant: 'primary', __nextHasNoMarginBottom: true,
178 onClick: function () {
179 set({ reactions: a.reactions.concat([{ emoji: '', label: 'Star', count: 0 }]) });
180 }
181 }, __('+ Add reaction')) : null
182 ),
183 el(PanelColorSettings, {
184 title: __('Colors'),
185 initialOpen: false,
186 colorSettings: colorSettings
187 })
188 );
189
190 // ── Preview ───────────────────────────────────────────────
191 var total = a.reactions.reduce(function (s, r) { return s + (r.count || 0); }, 0);
192 var isCards = a.layout === 'cards';
193
194 var titleRow = a.showTitle ? el('div', {
195 className: 'bkrab-title',
196 style: { color: a.titleColor, marginBottom: '14px' }
197 }, a.title) : null;
198
199 var reactionEls = el('div', {
200 style: {
201 display: isCards ? 'grid' : 'flex',
202 gridTemplateColumns: isCards ? 'repeat(auto-fill, minmax(90px, 1fr))' : undefined,
203 flexWrap: isCards ? undefined : 'wrap',
204 gap: '8px'
205 }
206 },
207 a.reactions.map(function (r, idx) {
208 return el('div', { key: idx }, renderReactionItem(r, a, idx === activeIdx, a.layout));
209 })
210 );
211
212 var totalEl = (a.showTotal) ? el('div', {
213 className: 'bkrab-total',
214 style: { marginTop: '12px', color: a.totalColor }
215 }, total + ' ' + a.totalLabel) : null;
216
217 return el(Fragment, {},
218 inspector,
219 el('div', useBlockProps((function() {
220 var _tvFn = getTypoCssVars();
221 var s = {
222 background: a.bgColor,
223 border: '1px solid ' + a.borderColor,
224 borderRadius: a.borderRadius + 'px',
225 padding: '20px 24px',
226 fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'
227 };
228 if (_tvFn) {
229 Object.assign(s, _tvFn(a.titleTypo || {}, '--bkrab-tt-'));
230 Object.assign(s, _tvFn(a.countTypo || {}, '--bkrab-ct-'));
231 }
232 return { style: s };
233 })()), titleRow, reactionEls, totalEl)
234 );
235 }
236
237 registerBlockType('blockenberg/reaction-bar', {
238 edit: Edit,
239 save: function (props) {
240 return el('div', useBlockProps.save(),
241 el('div', { className: 'bkbg-reaction-bar-app', 'data-opts': JSON.stringify(props.attributes) })
242 );
243 }
244 });
245 })();
246