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

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

286 lines 16.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 __ = wp.i18n.__;
4 var useState = wp.element.useState;
5 var registerBlockType = wp.blocks.registerBlockType;
6 var InspectorControls = wp.blockEditor.InspectorControls;
7 var RichText = wp.blockEditor.RichText;
8 var useBlockProps = wp.blockEditor.useBlockProps;
9 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
10 var PanelBody = wp.components.PanelBody;
11 var ToggleControl = wp.components.ToggleControl;
12 var RangeControl = wp.components.RangeControl;
13 var SelectControl = wp.components.SelectControl;
14 var TextControl = wp.components.TextControl;
15 var Button = wp.components.Button;
16
17 var _fgTC, _fgTV;
18 function _tc() { return _fgTC || (_fgTC = window.bkbgTypographyControl); }
19 function _tv(o, p) { if (!_fgTV) _fgTV = window.bkbgTypoCssVars; return _fgTV ? _fgTV(o, p) : {}; }
20
21 registerBlockType('blockenberg/faq-grid', {
22 title: __('FAQ Grid', 'blockenberg'),
23 icon: 'editor-help',
24 category: 'bkbg-business',
25
26 edit: function (props) {
27 var a = props.attributes;
28 var set = props.setAttributes;
29
30 var expandedState = useState(null);
31 var expanded = expandedState[0];
32 var setExpanded = expandedState[1];
33
34 function wrapStyle(a) {
35 return Object.assign({
36 '--bkbg-fg-accent': a.accentColor,
37 '--bkbg-fg-bg': a.bgColor,
38 '--bkbg-fg-text': a.textColor,
39 '--bkbg-fg-heading-c': a.headingColor,
40 '--bkbg-fg-sub-c': a.subColor,
41 '--bkbg-fg-q-c': a.questionColor,
42 '--bkbg-fg-a-c': a.answerColor,
43 '--bkbg-fg-card-bg': a.cardBg,
44 '--bkbg-fg-card-border': a.cardBorder,
45 '--bkbg-fg-card-p': a.cardPadding + 'px',
46 '--bkbg-fg-card-r': a.cardRadius + 'px',
47 '--bkbg-fg-gap': a.gap + 'px',
48 '--bkbg-fg-cols': a.columns,
49 '--bkbg-fg-num-c': a.numberColor,
50 '--bkbg-fg-sect-gap': a.sectionGap + 'px',
51 '--bkbg-fg-pt': a.paddingTop + 'px',
52 '--bkbg-fg-pb': a.paddingBottom + 'px',
53 },
54 _tv(a.typoHeading, '--bkbg-fg-hd-'),
55 _tv(a.typoSubheading, '--bkbg-fg-sh-'),
56 _tv(a.typoQuestion, '--bkbg-fg-qt-'),
57 _tv(a.typoAnswer, '--bkbg-fg-an-'));
58 }
59
60 function updateItem(index, key, value) {
61 var arr = a.items.slice();
62 arr[index] = Object.assign({}, arr[index]);
63 arr[index][key] = value;
64 set({ items: arr });
65 }
66
67 function addItem() {
68 set({ items: a.items.concat([{ question: __('Your question here?', 'blockenberg'), answer: __('Your answer here. Keep it concise and helpful for your visitors.', 'blockenberg') }]) });
69 }
70
71 function removeItem(idx) {
72 set({ items: a.items.filter(function (_, i) { return i !== idx; }) });
73 }
74
75 function moveItem(idx, dir) {
76 var ni = idx + dir;
77 if (ni < 0 || ni >= a.items.length) return;
78 var arr = a.items.slice();
79 var tmp = arr[idx]; arr[idx] = arr[ni]; arr[ni] = tmp;
80 set({ items: arr });
81 }
82
83 var styleOptions = [
84 { label: __('Card', 'blockenberg'), value: 'card' },
85 { label: __('Bordered', 'blockenberg'), value: 'bordered' },
86 { label: __('Flat', 'blockenberg'), value: 'flat' },
87 { label: __('Gradient', 'blockenberg'), value: 'gradient' },
88 { label: __('Dark', 'blockenberg'), value: 'dark' },
89 ];
90
91 var alignOptions = [
92 { label: __('Left', 'blockenberg'), value: 'left' },
93 { label: __('Center', 'blockenberg'), value: 'center' },
94 ];
95
96 var weightOpts = [
97 { label: '400', value: 400 }, { label: '500', value: 500 },
98 { label: '600', value: 600 }, { label: '700', value: 700 }, { label: '800', value: 800 }
99 ];
100
101 var inspector = el(InspectorControls, {},
102
103 el(PanelBody, { title: __('Section Header', 'blockenberg'), initialOpen: true },
104 el(ToggleControl, {
105 label: __('Show Heading', 'blockenberg'), checked: a.showHeading, __nextHasNoMarginBottom: true,
106 onChange: function (v) { set({ showHeading: v }); }
107 }),
108 a.showHeading && el(TextControl, { label: __('Heading', 'blockenberg'), value: a.heading, onChange: function (v) { set({ heading: v }); } }),
109 el(ToggleControl, {
110 label: __('Show Subheading', 'blockenberg'), checked: a.showSubheading, __nextHasNoMarginBottom: true,
111 onChange: function (v) { set({ showSubheading: v }); }
112 }),
113 a.showSubheading && el(TextControl, { label: __('Subheading', 'blockenberg'), value: a.subheading, onChange: function (v) { set({ subheading: v }); } }),
114 el(SelectControl, { label: __('Heading Align', 'blockenberg'), value: a.headingAlign, options: alignOptions, onChange: function (v) { set({ headingAlign: v }); } }),
115 el(RangeControl, { label: __('Section Gap', 'blockenberg'), value: a.sectionGap, onChange: function (v) { set({ sectionGap: v }); }, min: 16, max: 80 })
116 ),
117
118 el(PanelBody, { title: __('Grid & Style', 'blockenberg'), initialOpen: false },
119 el(SelectControl, {
120 label: __('Card Style', 'blockenberg'), value: a.style,
121 options: styleOptions, onChange: function (v) { set({ style: v }); }
122 }),
123 el(RangeControl, { label: __('Columns', 'blockenberg'), value: a.columns, onChange: function (v) { set({ columns: v }); }, min: 1, max: 4 }),
124 el(ToggleControl, {
125 label: __('Show Number', 'blockenberg'), checked: a.showNumber, __nextHasNoMarginBottom: true,
126 onChange: function (v) { set({ showNumber: v }); }
127 }),
128 el(ToggleControl, {
129 label: __('Show Divider', 'blockenberg'), checked: a.showDivider, __nextHasNoMarginBottom: true,
130 onChange: function (v) { set({ showDivider: v }); }
131 }),
132 el(RangeControl, { label: __('Card Padding', 'blockenberg'), value: a.cardPadding, onChange: function (v) { set({ cardPadding: v }); }, min: 12, max: 60 }),
133 el(RangeControl, { label: __('Border Radius', 'blockenberg'), value: a.cardRadius, onChange: function (v) { set({ cardRadius: v }); }, min: 0, max: 32 }),
134 el(RangeControl, { label: __('Gap', 'blockenberg'), value: a.gap, onChange: function (v) { set({ gap: v }); }, min: 8, max: 48 })
135 ),
136
137 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
138 _tc() && _tc()({ label: __('Heading', 'blockenberg'), typo: a.typoHeading, onChange: function (v) { set({ typoHeading: v }); } }),
139 _tc() && _tc()({ label: __('Subheading', 'blockenberg'), typo: a.typoSubheading, onChange: function (v) { set({ typoSubheading: v }); } }),
140 _tc() && _tc()({ label: __('Question', 'blockenberg'), typo: a.typoQuestion, onChange: function (v) { set({ typoQuestion: v }); } }),
141 _tc() && _tc()({ label: __('Answer', 'blockenberg'), typo: a.typoAnswer, onChange: function (v) { set({ typoAnswer: v }); } })
142 ),
143
144 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
145 el(RangeControl, { label: __('Padding Top', 'blockenberg'), value: a.paddingTop, onChange: function (v) { set({ paddingTop: v }); }, min: 0, max: 200 }),
146 el(RangeControl, { label: __('Padding Bottom', 'blockenberg'), value: a.paddingBottom, onChange: function (v) { set({ paddingBottom: v }); }, min: 0, max: 200 })
147 ),
148
149 el(PanelBody, { title: __('FAQ Items', 'blockenberg'), initialOpen: false },
150 a.items.map(function (item, idx) {
151 var isOpen = expanded === idx;
152 return el('div', { key: idx, className: 'bkbg-fg-item-ctrl' + (isOpen ? ' bkbg-fg-item-ctrl--open' : '') },
153 el('div', {
154 className: 'bkbg-fg-item-head',
155 onClick: function () { setExpanded(isOpen ? null : idx); }
156 },
157 el('strong', {}, '#' + (idx + 1) + ' ' + (item.question ? item.question.substring(0, 28) + (item.question.length > 28 ? '' : '') : '')),
158 el('div', { className: 'bkbg-fg-item-actions' },
159 el(Button, { icon: 'arrow-up-alt2', size: 'small', disabled: idx === 0, onClick: function (e) { e.stopPropagation(); moveItem(idx, -1); } }),
160 el(Button, { icon: 'arrow-down-alt2', size: 'small', disabled: idx === a.items.length - 1, onClick: function (e) { e.stopPropagation(); moveItem(idx, 1); } }),
161 el(Button, { icon: 'trash', size: 'small', isDestructive: true, onClick: function (e) { e.stopPropagation(); removeItem(idx); } })
162 )
163 ),
164 isOpen && el('div', { className: 'bkbg-fg-item-body' },
165 el(TextControl, { label: __('Question', 'blockenberg'), value: item.question, onChange: function (v) { updateItem(idx, 'question', v); } }),
166 el('label', { style: { display: 'block', marginBottom: 4, fontWeight: 500, fontSize: 11, textTransform: 'uppercase' } }, __('Answer', 'blockenberg')),
167 el('textarea', {
168 style: { width: '100%', minHeight: 80, padding: 8, borderRadius: 4, border: '1px solid #e2e8f0', resize: 'vertical' },
169 value: item.answer,
170 onChange: function (e) { updateItem(idx, 'answer', e.target.value); }
171 })
172 )
173 );
174 }),
175 el(Button, { variant: 'secondary', onClick: addItem }, __('+ Add FAQ Item', 'blockenberg'))
176 ),
177
178 el(PanelColorSettings, {
179 title: __('Colors', 'blockenberg'), initialOpen: false,
180 colorSettings: [
181 { value: a.accentColor, onChange: function (v) { set({ accentColor: v || '#6c3fb5' }); }, label: __('Accent Color', 'blockenberg') },
182 { value: a.bgColor, onChange: function (v) { set({ bgColor: v || '#ffffff' }); }, label: __('Section Background', 'blockenberg') },
183 { value: a.headingColor, onChange: function (v) { set({ headingColor: v || '#0f172a' }); }, label: __('Heading Color', 'blockenberg') },
184 { value: a.subColor, onChange: function (v) { set({ subColor: v || '#64748b' }); }, label: __('Subheading Color', 'blockenberg') },
185 { value: a.questionColor, onChange: function (v) { set({ questionColor: v || '#0f172a' }); }, label: __('Question Color', 'blockenberg') },
186 { value: a.answerColor, onChange: function (v) { set({ answerColor: v || '#475569' }); }, label: __('Answer Color', 'blockenberg') },
187 { value: a.cardBg, onChange: function (v) { set({ cardBg: v || '#ffffff' }); }, label: __('Card Background', 'blockenberg') },
188 { value: a.cardBorder, onChange: function (v) { set({ cardBorder: v || '#e2e8f0' }); }, label: __('Card Border', 'blockenberg') },
189 { value: a.numberColor, onChange: function (v) { set({ numberColor: v || '#6c3fb5' }); }, label: __('Number Color', 'blockenberg') },
190 ]
191 })
192 );
193
194 var blockProps = useBlockProps({
195 className: 'bkbg-fg-wrap bkbg-fg-style--' + a.style,
196 style: wrapStyle(a)
197 });
198
199 return el('div', blockProps,
200 inspector,
201 (a.showHeading || a.showSubheading) && el('div', {
202 className: 'bkbg-fg-header',
203 style: { textAlign: a.headingAlign }
204 },
205 a.showHeading && el(RichText, {
206 tagName: 'h2', className: 'bkbg-fg-heading',
207 value: a.heading, placeholder: __('FAQ Heading…', 'blockenberg'),
208 onChange: function (v) { set({ heading: v }); }
209 }),
210 a.showSubheading && el(RichText, {
211 tagName: 'p', className: 'bkbg-fg-subheading',
212 value: a.subheading, placeholder: __('Subheading…', 'blockenberg'),
213 onChange: function (v) { set({ subheading: v }); }
214 })
215 ),
216 el('div', { className: 'bkbg-fg-grid' },
217 a.items.map(function (item, idx) {
218 return el('div', { key: idx, className: 'bkbg-fg-card' },
219 a.showNumber && el('div', { className: 'bkbg-fg-num' }, (idx + 1) + '.'),
220 el('div', { className: 'bkbg-fg-q' }, item.question),
221 a.showDivider && el('div', { className: 'bkbg-fg-divider' }),
222 el('div', { className: 'bkbg-fg-a' }, item.answer)
223 );
224 })
225 )
226 );
227 },
228
229 save: function (props) {
230 var a = props.attributes;
231 var el = wp.element.createElement;
232
233 function wrapStyle(a) {
234 return Object.assign({
235 '--bkbg-fg-accent': a.accentColor,
236 '--bkbg-fg-bg': a.bgColor,
237 '--bkbg-fg-text': a.textColor,
238 '--bkbg-fg-heading-c': a.headingColor,
239 '--bkbg-fg-sub-c': a.subColor,
240 '--bkbg-fg-q-c': a.questionColor,
241 '--bkbg-fg-a-c': a.answerColor,
242 '--bkbg-fg-card-bg': a.cardBg,
243 '--bkbg-fg-card-border': a.cardBorder,
244 '--bkbg-fg-card-p': a.cardPadding + 'px',
245 '--bkbg-fg-card-r': a.cardRadius + 'px',
246 '--bkbg-fg-gap': a.gap + 'px',
247 '--bkbg-fg-cols': a.columns,
248 '--bkbg-fg-num-c': a.numberColor,
249 '--bkbg-fg-sect-gap': a.sectionGap + 'px',
250 '--bkbg-fg-pt': a.paddingTop + 'px',
251 '--bkbg-fg-pb': a.paddingBottom + 'px',
252 },
253 _tv(a.typoHeading, '--bkbg-fg-hd-'),
254 _tv(a.typoSubheading, '--bkbg-fg-sh-'),
255 _tv(a.typoQuestion, '--bkbg-fg-qt-'),
256 _tv(a.typoAnswer, '--bkbg-fg-an-'));
257 }
258
259 var blockProps = wp.blockEditor.useBlockProps.save({
260 className: 'bkbg-fg-wrap bkbg-fg-style--' + a.style,
261 style: wrapStyle(a)
262 });
263
264 return el('div', blockProps,
265 (a.showHeading || a.showSubheading) && el('div', {
266 className: 'bkbg-fg-header',
267 style: { textAlign: a.headingAlign }
268 },
269 a.showHeading && el(RichText.Content, { tagName: 'h2', className: 'bkbg-fg-heading', value: a.heading }),
270 a.showSubheading && el(RichText.Content, { tagName: 'p', className: 'bkbg-fg-subheading', value: a.subheading })
271 ),
272 el('div', { className: 'bkbg-fg-grid' },
273 a.items.map(function (item, idx) {
274 return el('div', { key: idx, className: 'bkbg-fg-card' },
275 a.showNumber && el('div', { className: 'bkbg-fg-num' }, (idx + 1) + '.'),
276 el('div', { className: 'bkbg-fg-q' }, item.question),
277 a.showDivider && el('div', { className: 'bkbg-fg-divider' }),
278 el('div', { className: 'bkbg-fg-a' }, item.answer)
279 );
280 })
281 )
282 );
283 }
284 });
285 }() );
286