# blockenberg/2.0.7/blocks/side-menu/index.js

Blockenberg — 600+ Advanced Gutenberg Blocks &amp; AI Agent for WordPress Block Editor, version 2.0.7. 401 lines.

- Page: https://pluginprobe.com/plugins/blockenberg/2.0.7/code/blocks/side-menu/index.js
- Raw: https://pluginprobe.com/plugins/blockenberg/2.0.7/raw/blocks/side-menu/index.js
- Modified: 2026-03-06T12:32:40+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/blockenberg/2.0.7/code/blocks/side-menu/index.js#L10-L20`.

```javascript
( function () {
    var el = wp.element.createElement;
    var Fragment = wp.element.Fragment;
    var useState = wp.element.useState;
    var __ = wp.i18n.__;
    var registerBlockType = wp.blocks.registerBlockType;
    var InspectorControls = wp.blockEditor.InspectorControls;
    var useBlockProps = wp.blockEditor.useBlockProps;
    var PanelColorSettings = wp.blockEditor.PanelColorSettings;
    var PanelBody = wp.components.PanelBody;
    var ToggleControl = wp.components.ToggleControl;
    var RangeControl = wp.components.RangeControl;
    var SelectControl = wp.components.SelectControl;
    var TextControl = wp.components.TextControl;
    var Button = wp.components.Button;
    var ColorPicker = wp.components.ColorPicker;
    var Popover = wp.components.Popover;

    var _tc, _tv;
    function getTC() { return _tc || (_tc = window.bkbgTypographyControl); }
    function getTV() { return _tv || (_tv = window.bkbgTypoCssVars); }
    var IP = function () { return window.bkbgIconPicker; };

    /* ─── helpers ─── */
    function updateItem(arr, idx, field, val) {
        return arr.map(function (item, i) {
            if (i !== idx) return item;
            var p = {}; p[field] = val;
            return Object.assign({}, item, p);
        });
    }

    function moveItem(arr, from, to) {
        var a = arr.slice();
        var item = a.splice(from, 1)[0];
        a.splice(to, 0, item);
        return a;
    }

    /* ─── ItemEditor ─── */
    function ItemEditor(props) {
        var items = props.items;
        var onChange = props.onChange;
        var activeIdx = props.activeIdx;
        var setActiveIdx = props.setActiveIdx;

        var levelLabels = ['Level 0 — Section heading', 'Level 1 — Nav item', 'Level 2 — Nested item'];

        function addItem() {
            onChange(items.concat([{
                label: 'New Item', url: '#', icon: '', iconType: 'custom-char', iconDashicon: '', iconImageUrl: '', level: 1,
                badge: '', badgeColor: '#6366f1', dividerBefore: false
            }]));
        }

        return el(Fragment, null,
            items.map(function (item, idx) {
                var isActive = idx === activeIdx;
                var indent = item.level * 12;

                return el('div', {
                    key: idx,
                    style: {
                        marginBottom: '4px',
                        border: '1px solid ' + (isActive ? '#6366f1' : '#e5e7eb'),
                        borderRadius: '6px',
                        overflow: 'hidden'
                    }
                },
                    /* header row */
                    el('div', {
                        style: {
                            display: 'flex', alignItems: 'center', gap: '6px',
                            padding: '6px 8px', cursor: 'pointer',
                            background: isActive ? '#f0f0ff' : '#f9fafb',
                            paddingLeft: (8 + indent) + 'px'
                        },
                        onClick: function () { setActiveIdx(isActive ? -1 : idx); }
                    },
                        el('span', { style: { flex: 1, fontSize: '12px', fontWeight: '600', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } },
                            (item.icon && (item.iconType || 'custom-char') === 'custom-char' ? item.icon + ' ' : '') + (item.label || 'Item ' + (idx + 1))
                        ),
                        el('span', { style: { fontSize: '10px', color: '#9ca3af', flexShrink: 0 } }, 'L' + item.level),
                        el(Button, { icon: 'arrow-up-alt2', isSmall: true, disabled: idx === 0, onClick: function (e) { e.stopPropagation(); onChange(moveItem(items, idx, idx - 1)); setActiveIdx(idx - 1); } }),
                        el(Button, { icon: 'arrow-down-alt2', isSmall: true, disabled: idx === items.length - 1, onClick: function (e) { e.stopPropagation(); onChange(moveItem(items, idx, idx + 1)); setActiveIdx(idx + 1); } }),
                        el(Button, { icon: 'no-alt', isSmall: true, isDestructive: true, onClick: function (e) { e.stopPropagation(); var a = items.slice(); a.splice(idx, 1); onChange(a); setActiveIdx(-1); } })
                    ),

                    /* expanded fields */
                    isActive && el('div', { style: { padding: '10px', display: 'flex', flexDirection: 'column', gap: '8px', background: '#fff' } },
                        el(TextControl, { label: __('Label', 'blockenberg'), value: item.label, onChange: function (v) { onChange(updateItem(items, idx, 'label', v)); }, __nextHasNoMarginBottom: true }),
                        el(TextControl, { label: __('URL', 'blockenberg'), value: item.url, onChange: function (v) { onChange(updateItem(items, idx, 'url', v)); }, __nextHasNoMarginBottom: true }),
                        el(IP().IconPickerControl, IP().iconPickerProps(item, function (patch) { var newItems = items.slice(); newItems[idx] = Object.assign({}, item, patch); onChange(newItems); }, { label: __('Icon', 'blockenberg'), charAttr: 'icon', typeAttr: 'iconType', dashiconAttr: 'iconDashicon', imageUrlAttr: 'iconImageUrl' })),
                        el(SelectControl, {
                            label: __('Level', 'blockenberg'),
                            value: String(item.level),
                            options: [
                                { value: '0', label: 'Level 0 — Section heading' },
                                { value: '1', label: 'Level 1 — Nav item' },
                                { value: '2', label: 'Level 2 — Nested item' }
                            ],
                            onChange: function (v) { onChange(updateItem(items, idx, 'level', parseInt(v, 10))); },
                            __nextHasNoMarginBottom: true
                        }),
                        el(TextControl, { label: __('Badge Text', 'blockenberg'), value: item.badge || '', onChange: function (v) { onChange(updateItem(items, idx, 'badge', v)); }, __nextHasNoMarginBottom: true }),
                        item.badge && el(BkbgColorSwatch, { label: __('Badge Color', 'blockenberg'), value: item.badgeColor || '#6366f1', onChange: function (v) { onChange(updateItem(items, idx, 'badgeColor', v)); } }),
                        el(ToggleControl, { label: __('Divider Before', 'blockenberg'), checked: !!item.dividerBefore, onChange: function (v) { onChange(updateItem(items, idx, 'dividerBefore', v)); }, __nextHasNoMarginBottom: true })
                    )
                );
            }),

            el(Button, {
                variant: 'secondary',
                onClick: addItem,
                style: { marginTop: '8px', width: '100%', justifyContent: 'center' }
            }, __('+ Add Item', 'blockenberg'))
        );
    }

    /* ─── MenuPreview ─── */
    function MenuPreview(props) {
        var a = props.attributes;
        var onSetActive = props.onSetActive;
        var openSectionsState = useState(function () {
            var s = {};
            a.items.forEach(function (item, idx) { if (item.level === 0 && a.defaultExpanded) s[idx] = true; });
            return s;
        });
        var openSections = openSectionsState[0];
        var setOpenSections = openSectionsState[1];

        function toggleSection(idx) {
            var ns = Object.assign({}, openSections);
            ns[idx] = !ns[idx];
            setOpenSections(ns);
        }

        /* find the most recent L0 section for each item */
        var sectionMap = {};
        var lastL0 = -1;
        a.items.forEach(function (item, idx) {
            if (item.level === 0) { lastL0 = idx; sectionMap[idx] = idx; }
            else { sectionMap[idx] = lastL0; }
        });

        function isVisible(idx) {
            var item = a.items[idx];
            if (item.level === 0) return true;
            var secIdx = sectionMap[idx];
            if (secIdx < 0) return true;
            if (!a.collapsible) return true;
            return !!openSections[secIdx];
        }

        var menuStyle = {
            width: '100%',
            background: a.menuBg || '#fff',
            border: '1px solid ' + (a.menuBorder || '#e5e7eb'),
            borderRadius: (a.borderRadius || 8) + 'px',
            overflow: 'hidden',
            boxShadow: '0 1px 4px rgba(0,0,0,0.05)'
        };

        return el('div', { style: menuStyle },
            /* heading */
            a.showHeading && a.headingText && el('div', {
                style: {
                    padding: (a.itemPaddingV || 8) + 'px ' + (a.itemPaddingH || 14) + 'px',
                    fontWeight: a.headingFontWeight||700,
                    fontSize: (a.headingSize || 11) + 'px',
                    textTransform: 'uppercase',
                    letterSpacing: '0.07em',
                    color: a.headingColor || '#9ca3af',
                    borderBottom: '1px solid ' + (a.dividerColor || '#e5e7eb')
                }
            }, a.headingText),

            /* items */
            el('nav', { style: { padding: '6px 0' } },
                a.items.map(function (item, idx) {
                    if (!isVisible(idx)) return null;

                    var isSection = item.level === 0;
                    var isActive = idx === a.activeIndex;
                    var indent = item.level * 12;
                    var hasChildren = !isSection && false; /* computed below */

                    /* check if this L0 has children to show collapse arrow */
                    var hasChildItems = isSection && a.items.some(function (it, i) { return i > idx && it.level > 0 && sectionMap[i] === idx; });

                    var itemStyle = {
                        display: 'flex',
                        alignItems: 'center',
                        gap: '8px',
                        padding: (a.itemPaddingV || 8) + 'px ' + (a.itemPaddingH || 14) + 'px',
                        paddingLeft: ((a.itemPaddingH || 14) + indent) + 'px',
                        fontSize: (a.fontSize || 14) + 'px',
                        color: isActive ? (a.activeItemColor || '#6366f1') : (isSection ? (a.sectionHeadingColor || '#111827') : (a.itemColor || '#374151')),
                        background: isActive ? (a.activeItemBg || '#ede9fe') : 'transparent',
                        fontWeight: isSection ? String(a.fontWeight||700) : (isActive ? '600' : '400'),
                        cursor: 'pointer',
                        transition: 'background 0.15s, color 0.15s',
                        textDecoration: 'none',
                        borderLeft: isActive ? '3px solid ' + (a.activeIndicatorColor || '#6366f1') : '3px solid transparent',
                        boxSizing: 'border-box'
                    };

                    return el(Fragment, { key: idx },
                        item.dividerBefore && a.showDividers && el('div', {
                            style: {
                                height: '1px',
                                background: a.dividerColor || '#e5e7eb',
                                margin: '6px ' + (a.itemPaddingH || 14) + 'px'
                            }
                        }),

                        el('a', {
                            href: item.url || '#',
                            style: itemStyle,
                            onClick: function (e) { e.preventDefault(); if (onSetActive) onSetActive(idx); if (isSection && hasChildItems && a.collapsible) toggleSection(idx); }
                        },
                            a.showIcons && item.icon && el('span', { style: { flexShrink: 0, fontSize: '14px' } }, (item.iconType || 'custom-char') !== 'custom-char' ? IP().buildEditorIcon(item.iconType, item.icon, item.iconDashicon, item.iconImageUrl, item.iconDashiconColor) : item.icon),
                            el('span', { style: { flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, item.label),
                            a.showBadges && item.badge && el('span', {
                                style: {
                                    flexShrink: 0,
                                    background: item.badgeColor || (a.badgeBg || '#6366f1'),
                                    color: a.badgeColor || '#fff',
                                    fontSize: '10px',
                                    fontWeight: '700',
                                    padding: '1px 7px',
                                    borderRadius: '20px',
                                    lineHeight: '1.5'
                                }
                            }, item.badge),
                            isSection && hasChildItems && a.collapsible && el('span', {
                                style: {
                                    flexShrink: 0,
                                    color: a.arrowColor || '#9ca3af',
                                    fontSize: '10px',
                                    transition: 'transform 0.2s',
                                    transform: openSections[idx] ? 'rotate(180deg)' : 'rotate(0deg)',
                                    display: 'inline-block'
                                }
                            }, '▾')
                        )
                    );
                })
            )
        );
    }

    /* ─── register ─── */
    var BkbgColorSwatch = function (props) {
        var _st = useState(false); var isOpen = _st[0]; var setOpen = _st[1];
        return el(Fragment, {},
            el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '8px' } },
                el('span', { style: { fontSize: '11px', fontWeight: 500, textTransform: 'uppercase', color: '#1e1e1e' } }, props.label),
                el('button', {
                    type: 'button',
                    onClick: function () { setOpen(!isOpen); },
                    style: { width: '28px', height: '28px', borderRadius: '4px', border: '1px solid #ccc', background: props.value || '#ffffff', cursor: 'pointer', padding: 0 }
                })
            ),
            isOpen && el(Popover, { onClose: function () { setOpen(false); } },
                el('div', { style: { padding: '8px' } },
                    el(ColorPicker, { color: props.value, onChangeComplete: function (c) { props.onChange(c.hex); }, enableAlpha: true })
                )
            )
        );
    };

    registerBlockType('blockenberg/side-menu', {
        edit: function (props) {
            var a = props.attributes;
            var set = props.setAttributes;
            var itemIdxState = useState(-1);
            var itemIdx = itemIdxState[0];
            var setItemIdx = itemIdxState[1];

            var blockProps = useBlockProps((function () {
                var _tvf = getTV();
                var s = {
                    paddingTop: (a.paddingTop || 0) + 'px',
                    paddingBottom: (a.paddingBottom || 0) + 'px',
                    background: a.bgColor
                };
                if (_tvf) {
                    Object.assign(s, _tvf(a.headingTypo, '--bksmnu-ht-'));
                    Object.assign(s, _tvf(a.itemTypo, '--bksmnu-it-'));
                }
                return { style: s };
            })());

            var inspector = el(InspectorControls, null,
                /* Items */
                el(PanelBody, { title: __('Menu Items', 'blockenberg'), initialOpen: true },
                    el(ItemEditor, {
                        items: a.items,
                        onChange: function (v) { set({ items: v }); },
                        activeIdx: itemIdx,
                        setActiveIdx: setItemIdx
                    })
                ),

                /* Options */
                el(PanelBody, { title: __('Options', 'blockenberg'), initialOpen: false },
                    el(ToggleControl, { label: __('Show Heading', 'blockenberg'), checked: a.showHeading, onChange: function (v) { set({ showHeading: v }); }, __nextHasNoMarginBottom: true }),
                    a.showHeading && el('div', { style: { marginTop: '8px' } },
                        el(TextControl, { label: __('Heading Text', 'blockenberg'), value: a.headingText, onChange: function (v) { set({ headingText: v }); }, __nextHasNoMarginBottom: true })
                    ),
                    el('div', { style: { marginTop: '8px' } },
                        el(SelectControl, {
                            label: __('Style', 'blockenberg'),
                            value: a.menuStyle,
                            options: [
                                { value: 'default', label: 'Default' },
                                { value: 'pills', label: 'Pills' },
                                { value: 'bordered', label: 'Bordered' },
                                { value: 'minimal', label: 'Minimal' }
                            ],
                            onChange: function (v) { set({ menuStyle: v }); },
                            __nextHasNoMarginBottom: true
                        })
                    ),
                    el(ToggleControl, { label: __('Collapsible Sections', 'blockenberg'), checked: a.collapsible, onChange: function (v) { set({ collapsible: v }); }, __nextHasNoMarginBottom: true }),
                    a.collapsible && el(ToggleControl, { label: __('Default Expanded', 'blockenberg'), checked: a.defaultExpanded, onChange: function (v) { set({ defaultExpanded: v }); }, __nextHasNoMarginBottom: true }),
                    el(ToggleControl, { label: __('Show Icons', 'blockenberg'), checked: a.showIcons, onChange: function (v) { set({ showIcons: v }); }, __nextHasNoMarginBottom: true }),
                    el(ToggleControl, { label: __('Show Badges', 'blockenberg'), checked: a.showBadges, onChange: function (v) { set({ showBadges: v }); }, __nextHasNoMarginBottom: true }),
                    el(ToggleControl, { label: __('Show Dividers', 'blockenberg'), checked: a.showDividers, onChange: function (v) { set({ showDividers: v }); }, __nextHasNoMarginBottom: true })
                ),

                /* Appearance */
                el(PanelBody, { title: __('Appearance', 'blockenberg'), initialOpen: false },
                    el(RangeControl, { label: __('Menu Width (px)', 'blockenberg'), value: a.width, min: 160, max: 480, step: 10, onChange: function (v) { set({ width: v }); }, __nextHasNoMarginBottom: true }),
                    el('div', { style: { marginTop: '8px' } },
                        el(RangeControl, { label: __('Item Padding Vertical', 'blockenberg'), value: a.itemPaddingV, min: 4, max: 24, onChange: function (v) { set({ itemPaddingV: v }); }, __nextHasNoMarginBottom: true })
                    ),
                    el('div', { style: { marginTop: '8px' } },
                        el(RangeControl, { label: __('Item Padding Horizontal', 'blockenberg'), value: a.itemPaddingH, min: 8, max: 32, onChange: function (v) { set({ itemPaddingH: v }); }, __nextHasNoMarginBottom: true })
                    ),
                    el('div', { style: { marginTop: '8px' } },
                        el(RangeControl, { label: __('Border Radius', 'blockenberg'), value: a.borderRadius, min: 0, max: 24, onChange: function (v) { set({ borderRadius: v }); }, __nextHasNoMarginBottom: true })
                    ),
                    el('div', { style: { marginTop: '8px' } },
                        el(RangeControl, { label: __('Padding Top (px)', 'blockenberg'), value: a.paddingTop, min: 0, max: 120, step: 4, onChange: function (v) { set({ paddingTop: v }); }, __nextHasNoMarginBottom: true })
                    ),
                    el('div', { style: { marginTop: '8px' } },
                        el(RangeControl, { label: __('Padding Bottom (px)', 'blockenberg'), value: a.paddingBottom, min: 0, max: 120, step: 4, onChange: function (v) { set({ paddingBottom: v }); }, __nextHasNoMarginBottom: true })
                    )
                ),

                /* Colors */
                
                el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
                    el(getTC(), { label: 'Heading', value: a.headingTypo, onChange: function (v) { set({ headingTypo: v }); } }),
                    el(getTC(), { label: 'Menu Items', value: a.itemTypo, onChange: function (v) { set({ itemTypo: v }); } })
                ),
el(PanelColorSettings, {
                    title: __('Colors', 'blockenberg'),
                    initialOpen: false,
                    colorSettings: [
                        { value: a.bgColor, onChange: function (v) { set({ bgColor: v }); }, label: __('Page Background', 'blockenberg') },
                        { value: a.menuBg, onChange: function (v) { set({ menuBg: v }); }, label: __('Menu Background', 'blockenberg') },
                        { value: a.menuBorder, onChange: function (v) { set({ menuBorder: v }); }, label: __('Menu Border', 'blockenberg') },
                        { value: a.headingColor, onChange: function (v) { set({ headingColor: v }); }, label: __('Heading Text', 'blockenberg') },
                        { value: a.itemColor, onChange: function (v) { set({ itemColor: v }); }, label: __('Item Text', 'blockenberg') },
                        { value: a.itemHoverBg, onChange: function (v) { set({ itemHoverBg: v }); }, label: __('Item Hover Background', 'blockenberg') },
                        { value: a.activeItemBg, onChange: function (v) { set({ activeItemBg: v }); }, label: __('Active Item Background', 'blockenberg') },
                        { value: a.activeItemColor, onChange: function (v) { set({ activeItemColor: v }); }, label: __('Active Item Text', 'blockenberg') },
                        { value: a.activeIndicatorColor, onChange: function (v) { set({ activeIndicatorColor: v }); }, label: __('Active Indicator', 'blockenberg') },
                        { value: a.sectionHeadingColor, onChange: function (v) { set({ sectionHeadingColor: v }); }, label: __('Section Heading', 'blockenberg') },
                        { value: a.dividerColor, onChange: function (v) { set({ dividerColor: v }); }, label: __('Divider', 'blockenberg') },
                        { value: a.badgeBg, onChange: function (v) { set({ badgeBg: v }); }, label: __('Badge Background', 'blockenberg') },
                        { value: a.badgeColor, onChange: function (v) { set({ badgeColor: v }); }, label: __('Badge Text', 'blockenberg') },
                        { value: a.arrowColor, onChange: function (v) { set({ arrowColor: v }); }, label: __('Arrow Icon', 'blockenberg') }
                    ]
                })
            );

            return el(Fragment, null,
                inspector,
                el('div', blockProps,
                    el('div', { style: { maxWidth: (a.width || 260) + 'px' } },
                        el(MenuPreview, {
                            attributes: a,
                            onSetActive: function (idx) { set({ activeIndex: idx }); }
                        })
                    )
                )
            );
        },

        save: function (props) {
            return el('div', useBlockProps.save(),
                el('div', { className: 'bkbg-smnu-app', 'data-opts': JSON.stringify(props.attributes) })
            );
        }
    });
}() );

```
