@pagamio/frontend-commons-lib
Version:
Pagamio library for Frontend reusable components like the form engine and table container
88 lines (87 loc) • 7 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { Sidebar, TextInput } from 'flowbite-react';
import { HiSearch } from 'react-icons/hi';
import { twMerge } from 'tailwind-merge';
import React, { useEffect, useState } from 'react';
import { useAppSidebarContext } from '../../context';
import { useLibTranslations, useTranslation } from '../../translations';
const AppSidebarMenu = () => {
const { pages } = useAppSidebarContext();
return (_jsx(Sidebar.Items, { children: _jsx(Sidebar.ItemGroup, { className: "mt-0 border-t-0 pb-1 pt-0", children: pages.map((item) => (_jsx(AppSidebarItem, { ...item }, item.label))) }) }));
};
const AppSidebarItem = ({ href, target, icon, label, items, badge, forceDropdown }) => {
const { pathname, linkComponent: Link } = useAppSidebarContext();
const { t } = useTranslation();
// Check if current path matches this item or any of its descendants
const isParentActive = href ? pathname === href || pathname.startsWith(`${href}/`) : false;
// Recursive function to check if any nested child is active
const hasActiveChild = (children = []) => {
return children.some((child) => {
if (child.href && pathname.startsWith(child.href))
return true;
if (child.items)
return hasActiveChild(child.items);
return false;
});
};
// If there's exactly one item, render it as a direct link instead of a dropdown
if (items?.length === 1 && !forceDropdown) {
const singleItem = items[0];
return (_jsx(Sidebar.Item, { as: Link, href: singleItem.href, target: target, icon: icon, label: badge && t(badge), className: twMerge('text-gray-600 hover:text-primary-700 hover:bg-primary-50/70', 'dark:text-gray-400 dark:hover:text-primary-300 dark:hover:bg-primary-900/30', pathname === singleItem.href &&
'text-primary-700 bg-primary-100/80 hover:bg-primary-100/80 dark:text-primary-300 dark:bg-primary-900/40 dark:hover:bg-primary-900/40'), children: t(label) }));
}
if (items?.length) {
const isOpen = isParentActive || hasActiveChild(items);
return (_jsx(Sidebar.Collapse, { icon: icon, label: t(label), open: isOpen, className: twMerge('text-gray-600 hover:text-primary-700 hover:bg-primary-50/70', 'dark:text-gray-400 dark:hover:text-primary-300 dark:hover:bg-primary-900/30',
// Parent styling when its child is active
hasActiveChild(items) && 'text-primary-700 dark:text-primary-300',
// Parent styling when it's directly active
isParentActive &&
!hasActiveChild(items) &&
'text-primary-700 bg-primary-100/80 hover:bg-primary-100/80 dark:text-primary-300 dark:bg-primary-900/40 dark:hover:bg-primary-900/40'), theme: { list: 'space-y-2 py-2 [&>li>div]:w-full' }, children: items.map((child) => (_jsx(React.Fragment, { children: child.items?.length ? (
// Recursively render nested items
_jsx("div", { className: "pl-3", children: _jsx(AppSidebarItem, { ...child }) })) : (
// Render leaf item
_jsx(Sidebar.Item, { as: Link, href: child.href, target: child.target, icon: child.icon, className: twMerge('justify-center [&>*]:font-normal', 'text-gray-600 hover:text-primary-700 hover:bg-primary-50/70', 'dark:text-gray-400 dark:hover:text-primary-300 dark:hover:bg-primary-900/30', pathname === child.href &&
'text-primary-700 bg-primary-100/80 hover:bg-primary-100/80 dark:text-primary-300 dark:bg-primary-900/40 dark:hover:bg-primary-900/40'), children: t(child.label) })) }, child.label))) }));
}
// Render leaf item
return (_jsx(Sidebar.Item, { as: Link, href: href, target: target, icon: icon, label: badge && t(badge), className: twMerge('text-gray-600 hover:text-primary-700 hover:bg-primary-50/70', 'dark:text-gray-400 dark:hover:text-primary-300 dark:hover:bg-primary-900/30', isParentActive &&
'text-primary-700 bg-primary-100/80 hover:bg-primary-100/80 dark:text-primary-300 dark:bg-primary-900/40 dark:hover:bg-primary-900/40'), children: t(label) }));
};
const AppMobileSidebar = () => {
const { mobile: { isOpen, close }, sidebarHeader, } = useAppSidebarContext();
const { t } = useTranslation();
const { tLib } = useLibTranslations();
if (!isOpen)
return null;
return (_jsxs(_Fragment, { children: [_jsx(Sidebar, { "aria-label": t('sidebar.mobileAriaLabel', 'Sidebar with multi-level dropdown example'), className: twMerge('fixed inset-y-0 left-0 z-20 hidden h-full shrink-0 flex-col border-r border-gray-200 pt-16 dark:border-gray-700 md:flex', isOpen && 'flex'), id: "sidebar", children: _jsx("div", { className: "flex h-full flex-col justify-between", children: _jsxs("div", { className: "py-2", children: [sidebarHeader && _jsx("div", { className: "mb-4 px-3", children: sidebarHeader }), _jsx("form", { className: "pb-3", children: _jsx(TextInput, { icon: HiSearch, type: "search", placeholder: tLib('sidebar.searchPlaceholder', 'Search'), required: true, size: 32 }) }), _jsx(AppSidebarMenu, {})] }) }) }), _jsx("div", { onClick: close, "aria-hidden": "true", className: "fixed inset-0 z-10 h-full w-full bg-gray-900/50 pt-16 dark:bg-gray-900/90" })] }));
};
const AppDesktopSidebar = () => {
const { desktop: { isCollapsed, setCollapsed }, sidebarHeader, } = useAppSidebarContext();
const [isPreview, setIsPreview] = useState(isCollapsed);
const { tLib } = useLibTranslations();
useEffect(() => {
if (isCollapsed)
setIsPreview(false);
}, [isCollapsed]);
const preview = {
enable() {
if (!isCollapsed)
return;
setIsPreview(true);
setCollapsed(false);
},
disable() {
if (!isPreview)
return;
setCollapsed(true);
},
};
return (_jsx(Sidebar, { onMouseEnter: preview.enable, onMouseLeave: preview.disable, "aria-label": tLib('sidebar.desktopAriaLabel', 'Sidebar with multi-level dropdown example'), collapsed: isCollapsed, className: twMerge('fixed inset-y-0 left-0 z-20 flex h-full shrink-0 flex-col border-r border-gray-200 pt-16 duration-75 dark:border-gray-700', isCollapsed && 'hidden w-16'), id: "sidebar", children: _jsx("div", { className: "flex h-full flex-col justify-between", children: _jsxs("div", { className: "py-2", children: [sidebarHeader && _jsx("div", { className: "mb-4 px-3", children: sidebarHeader }), _jsx(AppSidebarMenu, {})] }) }) }));
};
const AppDashboardSidebar = () => {
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "md:hidden", children: _jsx(AppMobileSidebar, {}) }), _jsx("div", { className: "hidden md:block", children: _jsx(AppDesktopSidebar, {}) })] }));
};
export default AppDashboardSidebar;
export { AppSidebarMenu, AppMobileSidebar, AppDesktopSidebar, AppDashboardSidebar };