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

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

260 lines 12.8 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 useBlockProps = wp.blockEditor.useBlockProps;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
9 var PanelBody = wp.components.PanelBody;
10 var TextControl = wp.components.TextControl;
11 var TextareaControl = wp.components.TextareaControl;
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 __ = wp.i18n.__;
17
18 var _fnTC, _fnTV;
19 function _tc() { return _fnTC || (_fnTC = window.bkbgTypographyControl); }
20 function _tv() { return _fnTV || (_fnTV = window.bkbgTypoCssVars); }
21
22 // ── helpers ────────────────────────────────────────────────────────────────
23 function updateNote(notes, idx, val) {
24 return notes.map(function (n, i) {
25 if (i !== idx) return n;
26 return Object.assign({}, n, { text: val });
27 });
28 }
29
30 var MARKER_LABELS = { number: '1, 2, 3…', letter: 'a, b, c…', roman: 'i, ii, iii…', symbol: '*, †, ‡…' };
31 var SYMBOLS = ['*', '', '', '§', '', '', '#', '**', '††', '‡‡'];
32
33 function getMarker(style, i) {
34 if (style === 'letter') return String.fromCharCode(97 + i);
35 if (style === 'roman') {
36 var nums = [1,4,5,9,10,40,50,90,100,400,500,900,1000];
37 var syms = ['i','iv','v','ix','x','xl','l','xc','c','cd','d','cm','m'];
38 var n = i + 1, out = '';
39 for (var k = nums.length - 1; k >= 0; k--) {
40 while (n >= nums[k]) { out += syms[k]; n -= nums[k]; }
41 }
42 return out;
43 }
44 if (style === 'symbol') return SYMBOLS[i % SYMBOLS.length];
45 return String(i + 1);
46 }
47
48 // ── FootnotesPreview ────────────────────────────────────────────────────────
49 function FootnotesPreview(props) {
50 var a = props.attributes;
51
52 var markerStyle = {
53 background: a.markerBg,
54 color: a.markerColor,
55 borderRadius: '3px',
56 fontSize: '11px',
57 fontWeight: '700',
58 padding: '1px 5px',
59 cursor: 'default',
60 display: 'inline-block',
61 minWidth: '20px',
62 textAlign: 'center',
63 flexShrink: '0'
64 };
65
66 return el('div', {
67 className: 'bkbg-fn-block',
68 style: { background: a.bgColor, borderRadius: a.borderRadius + 'px' }
69 },
70 a.dividerEnabled && el('div', { className: 'bkbg-fn-divider', style: { borderTopColor: a.dividerColor } }),
71 a.showTitle && el('div', {
72 className: 'bkbg-fn-title',
73 style: { color: a.titleColor }
74 }, a.title),
75 el('ol', { className: 'bkbg-fn-list bkbg-fn-list-' + a.listStyle },
76 a.notes.map(function (note, i) {
77 return el('li', {
78 key: i,
79 className: 'bkbg-fn-item',
80 style: { color: a.textColor, borderColor: a.borderColor }
81 },
82 el('span', { className: 'bkbg-fn-marker', style: markerStyle },
83 getMarker(a.markerStyle, i)
84 ),
85 el('span', { className: 'bkbg-fn-text' }, note.text)
86 );
87 })
88 )
89 );
90 }
91
92 // ── NoteEditor ──────────────────────────────────────────────────────────────
93 function NoteEditor(props) {
94 var notes = props.notes;
95 var setAttributes = props.setAttributes;
96 var markerStyle = props.markerStyle;
97 var markerColor = props.markerColor;
98
99 var openState = useState(notes.map(function () { return false; }));
100 var open = openState[0];
101 var setOpen = openState[1];
102
103 function toggle(i) {
104 setOpen(open.map(function (v, j) { return j === i ? !v : v; }));
105 }
106
107 function remove(i) {
108 var newNotes = notes.filter(function (_, j) { return j !== i; })
109 .map(function (n, j) { return Object.assign({}, n, { id: j + 1 }); });
110 setAttributes({ notes: newNotes });
111 setOpen(open.filter(function (_, j) { return j !== i; }));
112 }
113
114 function add() {
115 var newId = notes.length + 1;
116 setAttributes({ notes: notes.concat([{ id: newId, text: 'New footnote text.' }]) });
117 setOpen(open.concat([true]));
118 }
119
120 return el('div', null,
121 notes.map(function (note, i) {
122 return el('div', { key: i, className: 'bkbg-fn-nota-editor' },
123 el('div', {
124 className: 'bkbg-fn-nota-header',
125 onClick: function () { toggle(i); },
126 style: { borderLeftColor: markerColor }
127 },
128 el('span', null, getMarker(markerStyle, i) + '' + note.text.slice(0, 40) + (note.text.length > 40 ? '' : '')),
129 el('span', null, open[i] ? '' : '')
130 ),
131 open[i] && el('div', { className: 'bkbg-fn-nota-fields' },
132 el(TextareaControl, {
133 label: __('Footnote text'),
134 value: note.text,
135 rows: 3,
136 __nextHasNoMarginBottom: true,
137 onChange: function (v) { setAttributes({ notes: updateNote(notes, i, v) }); }
138 }),
139 el(Button, {
140 variant: 'link',
141 isDestructive: true,
142 onClick: function () { remove(i); }
143 }, __('Remove'))
144 )
145 );
146 }),
147 el(Button, {
148 variant: 'secondary',
149 onClick: add,
150 style: { marginTop: '8px' }
151 }, __('+ Add Footnote'))
152 );
153 }
154
155 // ── register ────────────────────────────────────────────────────────────────
156 registerBlockType('blockenberg/footnotes', {
157 edit: function (props) {
158 var a = props.attributes;
159 var setAttributes = props.setAttributes;
160
161 return el(Fragment, null,
162 el(InspectorControls, null,
163 el(PanelBody, { title: __('Footnotes'), initialOpen: true },
164 el(NoteEditor, {
165 notes: a.notes,
166 setAttributes: setAttributes,
167 markerStyle: a.markerStyle,
168 markerColor: a.markerColor
169 })
170 ),
171 el(PanelBody, { title: __('Settings'), initialOpen: false },
172 el(TextControl, {
173 label: __('Section title'),
174 value: a.title,
175 __nextHasNoMarginBottom: true,
176 onChange: function (v) { setAttributes({ title: v }); }
177 }),
178 el(ToggleControl, {
179 label: __('Show title'),
180 checked: a.showTitle,
181 __nextHasNoMarginBottom: true,
182 onChange: function (v) { setAttributes({ showTitle: v }); }
183 }),
184 el(ToggleControl, {
185 label: __('Show divider line'),
186 checked: a.dividerEnabled,
187 __nextHasNoMarginBottom: true,
188 onChange: function (v) { setAttributes({ dividerEnabled: v }); }
189 }),
190 el(ToggleControl, {
191 label: __('Show tooltip on hover'),
192 checked: a.showTooltip,
193 __nextHasNoMarginBottom: true,
194 onChange: function (v) { setAttributes({ showTooltip: v }); }
195 }),
196 el(SelectControl, {
197 label: __('Marker style'),
198 value: a.markerStyle,
199 __nextHasNoMarginBottom: true,
200 options: Object.keys(MARKER_LABELS).map(function (k) {
201 return { value: k, label: MARKER_LABELS[k] };
202 }),
203 onChange: function (v) { setAttributes({ markerStyle: v }); }
204 }),
205 el(SelectControl, {
206 label: __('List style'),
207 value: a.listStyle,
208 __nextHasNoMarginBottom: true,
209 options: [
210 { value: 'default', label: 'Default (clean rows)' },
211 { value: 'card', label: 'Card (bordered)' },
212 { value: 'compact', label: 'Compact' }
213 ],
214 onChange: function (v) { setAttributes({ listStyle: v }); }
215 }),
216 el(RangeControl, {
217 label: __('Border radius (px)'),
218 value: a.borderRadius,
219 min: 0, max: 24,
220 __nextHasNoMarginBottom: true,
221 onChange: function (v) { setAttributes({ borderRadius: v }); }
222 })
223 ),
224 el(PanelBody, { title: __('Typography'), initialOpen: false },
225 _tc()({ label: __('Title', 'blockenberg'), value: a.typoTitle, onChange: function (v) { setAttributes({ typoTitle: v }); } }),
226 _tc()({ label: __('Note Text', 'blockenberg'), value: a.typoNote, onChange: function (v) { setAttributes({ typoNote: v }); } })
227 ),
228 el(PanelColorSettings, {
229 title: __('Colors'),
230 initialOpen: false,
231 colorSettings: [
232 { label: __('Background'), value: a.bgColor, onChange: function (v) { setAttributes({ bgColor: v || '#f8fafc' }); } },
233 { label: __('Border'), value: a.borderColor, onChange: function (v) { setAttributes({ borderColor: v || '#e2e8f0' }); } },
234 { label: __('Title'), value: a.titleColor, onChange: function (v) { setAttributes({ titleColor: v || '#0f172a' }); } },
235 { label: __('Text'), value: a.textColor, onChange: function (v) { setAttributes({ textColor: v || '#475569' }); } },
236 { label: __('Marker text'), value: a.markerColor, onChange: function (v) { setAttributes({ markerColor: v || '#3b82f6' }); } },
237 { label: __('Marker background'), value: a.markerBg, onChange: function (v) { setAttributes({ markerBg: v || '#eff6ff' }); } },
238 { label: __('Divider'), value: a.dividerColor, onChange: function (v) { setAttributes({ dividerColor: v || '#e2e8f0' }); } },
239 { label: __('Tooltip background'), value: a.tooltipBg, onChange: function (v) { setAttributes({ tooltipBg: v || '#1e293b' }); } },
240 { label: __('Tooltip text'), value: a.tooltipColor, onChange: function (v) { setAttributes({ tooltipColor: v || '#f1f5f9' }); } }
241 ]
242 })
243 ),
244 el('div', useBlockProps({ style: Object.assign({}, _tv()(a.typoTitle, '--bkbg-fn-tt-'), _tv()(a.typoNote, '--bkbg-fn-nt-')) }),
245 el(FootnotesPreview, { attributes: a })
246 )
247 );
248 },
249
250 save: function (props) {
251 return el('div', useBlockProps.save(),
252 el('div', {
253 className: 'bkbg-fn-app',
254 'data-opts': JSON.stringify(props.attributes)
255 })
256 );
257 }
258 });
259 }() );
260