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

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

232 lines 13.9 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 useBlockProps = wp.blockEditor.useBlockProps;
8 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
9 var PanelBody = wp.components.PanelBody;
10 var ToggleControl = wp.components.ToggleControl;
11 var RangeControl = wp.components.RangeControl;
12 var SelectControl = wp.components.SelectControl;
13 var TextControl = wp.components.TextControl;
14 var Button = wp.components.Button;
15 var Fragment = wp.element.Fragment;
16 var IP = function () { return window.bkbgIconPicker; };
17
18 var _TC, _tv;
19 Object.defineProperty(window, '_bkbgCMgetTC', { get: function () { return _TC || (_TC = window.bkbgTypographyControl); } });
20 Object.defineProperty(window, '_bkbgCMgetTV', { get: function () { return _tv || (_tv = window.bkbgTypoCssVars); } });
21
22 registerBlockType('blockenberg/content-menu', {
23 edit: function (props) {
24 var attr = props.attributes;
25 var set = props.setAttributes;
26 var TC = window._bkbgCMgetTC;
27 var tv = window._bkbgCMgetTV || function () { return {}; };
28 var links = attr.links || [];
29
30 var activeState = useState(0);
31 var activeIdx = activeState[0];
32 var setActiveIdx = activeState[1];
33
34 function updateLink(idx, field, val) {
35 var updated = links.map(function (lk, i) {
36 if (i !== idx) return lk;
37 var p = {}; p[field] = val;
38 return Object.assign({}, lk, p);
39 });
40 set({ links: updated });
41 }
42
43 function addLink() {
44 set({ links: links.concat([{ label: 'New Section', anchor: 'section-' + (links.length + 1), icon: '📌', iconType: 'custom-char', iconDashicon: '', iconImageUrl: '' }]) });
45 }
46
47 function removeLink(idx) {
48 set({ links: links.filter(function (_, i) { return i !== idx; }) });
49 }
50
51 var isVertical = attr.position !== 'inline' || attr.menuStyle === 'list' || attr.menuStyle === 'dots';
52 var isDots = attr.menuStyle === 'dots';
53
54 /* Style helpers */
55 function linkStyle(isActive) {
56 var base = { cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '8px', transition: 'all 0.2s', textDecoration: 'none' };
57 if (attr.menuStyle === 'pills') {
58 base.padding = '7px 16px';
59 base.borderRadius = attr.borderRadius + 'px';
60 base.background = isActive ? attr.activeBg : 'transparent';
61 base.color = isActive ? attr.activeColor : attr.linkColor;
62 } else if (attr.menuStyle === 'list') {
63 base.padding = '9px 14px';
64 base.borderLeft = isActive ? ('3px solid ' + attr.accentColor) : '3px solid transparent';
65 base.color = isActive ? attr.accentColor : attr.linkColor;
66 } else if (attr.menuStyle === 'tabs') {
67 base.padding = '9px 18px';
68 base.borderBottom = isActive ? ('2px solid ' + attr.accentColor) : '2px solid transparent';
69 base.color = isActive ? attr.accentColor : attr.linkColor;
70 } else if (attr.menuStyle === 'dots') {
71 base.padding = '4px';
72 base.justifyContent = 'center';
73 }
74 return base;
75 }
76
77 /* Inspector */
78 var inspector = el(InspectorControls, {},
79 el(PanelBody, { title: __('Menu Settings', 'blockenberg'), initialOpen: true },
80 el(SelectControl, {
81 label: __('Position', 'blockenberg'),
82 value: attr.position,
83 options: [
84 { label: 'Inline (inside content)', value: 'inline' },
85 { label: 'Fixed — Left', value: 'fixed-left' },
86 { label: 'Fixed — Right', value: 'fixed-right' }
87 ],
88 onChange: function (v) { set({ position: v }); },
89 __nextHasNoMarginBottom: true
90 }),
91 el(SelectControl, {
92 label: __('Style', 'blockenberg'),
93 value: attr.menuStyle,
94 options: [
95 { label: 'Pills (rounded buttons)', value: 'pills' },
96 { label: 'List (left accent line)', value: 'list' },
97 { label: 'Tabs (underline)', value: 'tabs' },
98 { label: 'Dots (compact)', value: 'dots' }
99 ],
100 onChange: function (v) { set({ menuStyle: v }); },
101 __nextHasNoMarginBottom: true
102 }),
103 el(ToggleControl, { label: __('Show Icons', 'blockenberg'), checked: attr.showIcons, onChange: function (v) { set({ showIcons: v }); }, __nextHasNoMarginBottom: true }),
104 el(ToggleControl, { label: __('Show Numbers', 'blockenberg'), checked: attr.showNumbers, onChange: function (v) { set({ showNumbers: v }); }, __nextHasNoMarginBottom: true }),
105 el(ToggleControl, { label: __('Smooth Scroll on Click', 'blockenberg'), checked: attr.animateScroll, onChange: function (v) { set({ animateScroll: v }); }, __nextHasNoMarginBottom: true }),
106 attr.position !== 'inline' && el(RangeControl, {
107 label: __('Vertical Position (vh %)', 'blockenberg'),
108 value: attr.fixedTop, min: 10, max: 90,
109 onChange: function (v) { set({ fixedTop: v }); },
110 __nextHasNoMarginBottom: true
111 }),
112 attr.position !== 'inline' && el(RangeControl, {
113 label: __('Edge Offset (px)', 'blockenberg'),
114 value: attr.fixedOffset, min: 8, max: 80,
115 onChange: function (v) { set({ fixedOffset: v }); },
116 __nextHasNoMarginBottom: true
117 }),
118 el(RangeControl, {
119 label: __('Menu Width (px)', 'blockenberg'),
120 value: attr.menuWidth, min: 100, max: 320,
121 onChange: function (v) { set({ menuWidth: v }); },
122 __nextHasNoMarginBottom: true
123 }),
124 el(RangeControl, {
125 label: __('Border Radius (px)', 'blockenberg'),
126 value: attr.borderRadius, min: 0, max: 24,
127 onChange: function (v) { set({ borderRadius: v }); },
128 __nextHasNoMarginBottom: true
129 }),
130 el(RangeControl, {
131 label: __('Padding Top (px)', 'blockenberg'),
132 value: attr.paddingTop, min: 0, max: 200,
133 onChange: function (v) { set({ paddingTop: v }); },
134 __nextHasNoMarginBottom: true
135 }),
136 el(RangeControl, {
137 label: __('Padding Bottom (px)', 'blockenberg'),
138 value: attr.paddingBottom, min: 0, max: 200,
139 onChange: function (v) { set({ paddingBottom: v }); },
140 __nextHasNoMarginBottom: true
141 })
142 ),
143 /* Links config */
144 el(PanelBody, { title: __('Links', 'blockenberg'), initialOpen: true },
145 links.map(function (lk, idx) {
146 return el('div', { key: idx, style: { borderBottom: '1px solid #e5e7eb', marginBottom: '10px', paddingBottom: '10px' } },
147 el(TextControl, { label: __('Label', 'blockenberg'), value: lk.label, onChange: function (v) { updateLink(idx, 'label', v); }, __nextHasNoMarginBottom: true }),
148 el(TextControl, { label: __('Anchor ID (no #)', 'blockenberg'), value: lk.anchor, onChange: function (v) { updateLink(idx, 'anchor', v.replace('#', '')); }, placeholder: 'section-id', __nextHasNoMarginBottom: true }),
149 attr.showIcons && el(IP().IconPickerControl, {
150 iconType: lk.iconType, customChar: lk.icon, dashicon: lk.iconDashicon, imageUrl: lk.iconImageUrl,
151 onChangeType: function (v) { updateLink(idx, 'iconType', v); },
152 onChangeChar: function (v) { updateLink(idx, 'icon', v); },
153 onChangeDashicon: function (v) { updateLink(idx, 'iconDashicon', v); },
154 onChangeImageUrl: function (v) { updateLink(idx, 'iconImageUrl', v); }
155 }),
156 el(Button, { onClick: function () { removeLink(idx); }, variant: 'link', isDestructive: true, isSmall: true, style: { marginTop: '4px' } }, __('Remove', 'blockenberg'))
157 );
158 }),
159 el(Button, { onClick: addLink, variant: 'primary', isSmall: true }, __('+ Add Link', 'blockenberg'))
160 ),
161 el(PanelColorSettings, {
162 title: __('Colors', 'blockenberg'), initialOpen: false,
163 colorSettings: [
164 { value: attr.bgColor, onChange: function (v) { set({ bgColor: v || '#ffffff' }); }, label: __('Menu Background', 'blockenberg') },
165 { value: attr.linkColor, onChange: function (v) { set({ linkColor: v || '#374151' }); }, label: __('Link Text', 'blockenberg') },
166 { value: attr.activeBg, onChange: function (v) { set({ activeBg: v || '#6366f1' }); }, label: __('Active Background', 'blockenberg') },
167 { value: attr.activeColor, onChange: function (v) { set({ activeColor: v || '#ffffff' }); }, label: __('Active Text', 'blockenberg') },
168 { value: attr.borderColor, onChange: function (v) { set({ borderColor: v || '#e5e7eb' }); }, label: __('Border', 'blockenberg') },
169 { value: attr.accentColor, onChange: function (v) { set({ accentColor: v || '#6366f1' }); }, label: __('Accent', 'blockenberg') }
170 ]
171 }),
172 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
173 TC && el(TC, { label: __('Link Text', 'blockenberg'), value: attr.typoLink, onChange: function (v) { set({ typoLink: v }); } })
174 )
175 );
176
177 /* nav container style */
178 var navStyle = Object.assign({
179 background: attr.bgColor,
180 border: '1px solid ' + attr.borderColor,
181 borderRadius: attr.borderRadius + 'px',
182 boxShadow: '0 2px 12px ' + attr.shadowColor,
183 overflow: 'hidden',
184 maxWidth: attr.menuWidth + 'px'
185 }, tv(attr.typoLink, '--bkcm-link-'));
186
187 return el(Fragment, {},
188 inspector,
189 el('div', useBlockProps({ style: { paddingTop: attr.paddingTop + 'px', paddingBottom: attr.paddingBottom + 'px' } }),
190 el('div', { style: { display: 'flex', flexDirection: 'column', gap: '8px', alignItems: 'flex-start' } },
191 attr.position !== 'inline' && el('div', { className: 'bkbg-cm-editor-note' },
192 '⚠️ ' + __('This menu will be FIXED on the page in the selected position. In the editor it is shown inline.', 'blockenberg')
193 ),
194 el('nav', { className: 'bkbg-cm-nav cm-' + attr.menuStyle, style: navStyle },
195 links.map(function (lk, idx) {
196 var isAct = idx === activeIdx;
197 if (attr.menuStyle === 'dots') {
198 return el('div', {
199 key: idx,
200 className: 'bkbg-cm-dot',
201 title: lk.label,
202 onClick: function () { setActiveIdx(idx); },
203 style: { width: isAct ? '22px' : '10px', height: '10px', borderRadius: '999px', background: isAct ? attr.activeBg : attr.borderColor, transition: 'all 0.2s', cursor: 'pointer' }
204 });
205 }
206 return el('div', {
207 key: idx,
208 className: 'bkbg-cm-link' + (isAct ? ' active' : ''),
209 onClick: function () { setActiveIdx(idx); },
210 style: linkStyle(isAct)
211 },
212 attr.showNumbers && el('span', { className: 'bkbg-cm-num' }, idx + 1 + '.'),
213 attr.showIcons && lk.icon && el('span', { className: 'bkbg-cm-link-icon' },
214 (lk.iconType || 'custom-char') !== 'custom-char' ? IP().buildEditorIcon(lk.iconType, lk.icon, lk.iconDashicon, lk.iconImageUrl, lk.iconDashiconColor) : lk.icon
215 ),
216 el('span', {}, lk.label)
217 );
218 })
219 )
220 )
221 )
222 );
223 },
224
225 save: function (props) {
226 return el('div', useBlockProps.save(),
227 el('div', { className: 'bkbg-cm-app', 'data-opts': JSON.stringify(props.attributes) })
228 );
229 }
230 });
231 }() );
232