PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.11
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.11
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-search / frontend.js

frontend.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.11, at blocks/faq-search/frontend.js

162 lines 6.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 wp.domReady(function () {
2 function typoCssVarsForEl(typo, prefix, el) {
3 if (!typo || typeof typo !== 'object') return;
4 var m = {
5 family: 'font-family', weight: 'font-weight',
6 transform: 'text-transform', style: 'font-style', decoration: 'text-decoration'
7 };
8 Object.keys(m).forEach(function (k) {
9 if (typo[k]) el.style.setProperty(prefix + m[k], typo[k]);
10 });
11 var r = {
12 size: 'font-size', lineHeight: 'line-height',
13 letterSpacing: 'letter-spacing', wordSpacing: 'word-spacing'
14 };
15 Object.keys(r).forEach(function (k) {
16 ['Desktop', 'Tablet', 'Mobile'].forEach(function (d, i) {
17 var v = typo[k + d];
18 if (v === undefined || v === '') return;
19 var suffix = ['-d', '-t', '-m'][i];
20 var unit = typo[k + 'Unit'] || ('size' === k ? 'px' : (k === 'lineHeight' ? '' : 'px'));
21 el.style.setProperty(prefix + r[k] + suffix, v + unit);
22 });
23 });
24 }
25
26 document.querySelectorAll('.bkbg-fs-app').forEach(function (app) {
27 var opts = {};
28 try { opts = JSON.parse(app.getAttribute('data-opts') || '{}'); } catch (e) {}
29
30 var items = opts.items || [];
31 var itemStyle = opts.itemStyle || 'bordered';
32
33 var wrap = document.createElement('div');
34 wrap.className = 'bkbg-fs-wrap';
35 if (opts.bgColor) wrap.style.background = opts.bgColor;
36 wrap.style.paddingTop = (opts.paddingTop || 48) + 'px';
37 wrap.style.paddingBottom = (opts.paddingBottom || 48) + 'px';
38
39 var inner = document.createElement('div');
40 inner.className = 'bkbg-fs-inner';
41 inner.style.maxWidth = (opts.maxWidth || 800) + 'px';
42 inner.style.setProperty('--bkbg-fs-accent', opts.accentColor || '#7c3aed');
43 inner.style.setProperty('--bkbg-fs-border', opts.borderColor || '#e5e7eb');
44 inner.style.setProperty('--bkbg-fs-radius', (opts.borderRadius || 10) + 'px');
45 typoCssVarsForEl(opts.typoQuestion, '--bkbg-fsrch-qt-', wrap);
46 typoCssVarsForEl(opts.typoAnswer, '--bkbg-fsrch-an-', wrap);
47
48 // Search bar
49 var searchInput;
50 if (opts.showSearch !== false) {
51 var searchWrap = document.createElement('div');
52 searchWrap.className = 'bkbg-fs-search-wrap';
53
54 var iconEl = document.createElement('span');
55 iconEl.className = 'bkbg-fs-search-icon';
56 iconEl.textContent = '🔍';
57
58 searchInput = document.createElement('input');
59 searchInput.type = 'search';
60 searchInput.className = 'bkbg-fs-search-input';
61 searchInput.placeholder = opts.searchPlaceholder || 'Search FAQs…';
62 if (opts.searchBg) searchInput.style.background = opts.searchBg;
63 if (opts.searchBorderColor) searchInput.style.borderColor = opts.searchBorderColor;
64
65 searchWrap.appendChild(iconEl);
66 searchWrap.appendChild(searchInput);
67 inner.appendChild(searchWrap);
68 }
69
70 // No results
71 var noResults = document.createElement('div');
72 noResults.className = 'bkbg-fs-no-results';
73 noResults.textContent = opts.noResultsText || 'No FAQs match your search.';
74 inner.appendChild(noResults);
75
76 // FAQ items
77 var faqEls = [];
78
79 items.forEach(function (item, i) {
80 var faqEl = document.createElement('div');
81 faqEl.className = 'bkbg-fs-item bkbg-fs-item--' + itemStyle;
82 if (opts.itemBg && itemStyle !== 'plain') faqEl.style.background = opts.itemBg;
83
84 var btn = document.createElement('button');
85 btn.className = 'bkbg-fs-question-btn';
86 btn.setAttribute('aria-expanded', 'false');
87
88 var qText = document.createElement('span');
89 qText.className = 'bkbg-fs-question-text';
90 qText.style.color = opts.questionColor || '#111827';
91 qText.textContent = item.question;
92
93 var iconSpan = document.createElement('span');
94 iconSpan.className = 'bkbg-fs-icon';
95 iconSpan.textContent = '+';
96 iconSpan.setAttribute('aria-hidden', 'true');
97
98 btn.appendChild(qText);
99 btn.appendChild(iconSpan);
100
101 var answerWrap = document.createElement('div');
102 answerWrap.className = 'bkbg-fs-answer-wrap';
103
104 var answerEl = document.createElement('div');
105 answerEl.className = 'bkbg-fs-answer';
106 answerEl.style.color = opts.answerColor || '#4b5563';
107 answerEl.innerHTML = item.answer;
108
109 answerWrap.appendChild(answerEl);
110 faqEl.appendChild(btn);
111 faqEl.appendChild(answerWrap);
112
113 // Toggle logic
114 btn.addEventListener('click', function () {
115 var isOpen = faqEl.classList.contains('bkbg-fs-item--open');
116
117 if (!opts.allowMultiple) {
118 faqEls.forEach(function (el) {
119 el.classList.remove('bkbg-fs-item--open');
120 el.querySelector('.bkbg-fs-question-btn').setAttribute('aria-expanded', 'false');
121 });
122 }
123
124 if (!isOpen) {
125 faqEl.classList.add('bkbg-fs-item--open');
126 btn.setAttribute('aria-expanded', 'true');
127 }
128 });
129
130 faqEls.push(faqEl);
131 inner.appendChild(faqEl);
132 });
133
134 // Open first
135 if (opts.openFirst && faqEls.length > 0) {
136 faqEls[0].classList.add('bkbg-fs-item--open');
137 faqEls[0].querySelector('.bkbg-fs-question-btn').setAttribute('aria-expanded', 'true');
138 }
139
140 // Search filter
141 if (searchInput) {
142 searchInput.addEventListener('input', function () {
143 var query = searchInput.value.trim().toLowerCase();
144 var visibleCount = 0;
145
146 faqEls.forEach(function (el, i) {
147 var item = items[i];
148 var text = ((item.question || '') + ' ' + (item.answer || '')).toLowerCase();
149 var match = !query || text.includes(query);
150 el.classList.toggle('bkbg-fs-item--hidden', !match);
151 if (match) visibleCount++;
152 });
153
154 noResults.classList.toggle('bkbg-fs-no-results--visible', visibleCount === 0);
155 });
156 }
157
158 wrap.appendChild(inner);
159 app.parentNode.replaceChild(wrap, app);
160 });
161 });
162