Initial commit
This commit is contained in:
147
layout/layout.tsx
Normal file
147
layout/layout.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
'use client';
|
||||
import React, { useCallback, useEffect, useRef, useContext } from 'react';
|
||||
import { classNames, DomHandler } from 'primereact/utils';
|
||||
import { usePathname, useSearchParams } from 'next/navigation';
|
||||
import { LayoutContext } from './context/layoutcontext';
|
||||
import { useEventListener, useMountEffect, useResizeListener, useUnmountEffect } from 'primereact/hooks';
|
||||
import AppTopbar from './AppTopbar';
|
||||
import AppConfig from './AppConfig';
|
||||
import AppBreadCrumb from './AppBreadCrumb';
|
||||
import { PrimeReactContext } from 'primereact/api';
|
||||
import { Tooltip } from 'primereact/tooltip';
|
||||
import { ChildContainerProps } from '@/types';
|
||||
import { Toast } from 'primereact/toast';
|
||||
import AppProfileMenu from './AppProfileMenu';
|
||||
import AppSidebar from './AppSidebar';
|
||||
import GlobalErrorHandler from '../components/GlobalErrorHandler';
|
||||
|
||||
const Layout = (props: ChildContainerProps) => {
|
||||
const { layoutConfig, layoutState, setLayoutState, isSlim, isSlimPlus, isHorizontal, isDesktop } = useContext(LayoutContext);
|
||||
const { setRipple } = useContext(PrimeReactContext);
|
||||
const topbarRef = useRef(null);
|
||||
const sidebarRef = useRef(null);
|
||||
const copyTooltipRef = useRef(null);
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const [bindMenuOutsideClickListener, unbindMenuOutsideClickListener] = useEventListener({
|
||||
type: 'click',
|
||||
listener: (event) => {
|
||||
const isOutsideClicked = !(sidebarRef.current.isSameNode(event.target) || sidebarRef.current.contains(event.target) || topbarRef.current.menubutton.isSameNode(event.target) || topbarRef.current.menubutton.contains(event.target));
|
||||
|
||||
if (isOutsideClicked) {
|
||||
hideMenu();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const [bindDocumentResizeListener, unbindDocumentResizeListener] = useResizeListener({
|
||||
listener: () => {
|
||||
if (isDesktop() && !DomHandler.isTouchDevice()) {
|
||||
hideMenu();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const hideMenu = useCallback(() => {
|
||||
setLayoutState((prevLayoutState) => ({
|
||||
...prevLayoutState,
|
||||
overlayMenuActive: false,
|
||||
overlaySubmenuActive: false,
|
||||
staticMenuMobileActive: false,
|
||||
menuHoverActive: false,
|
||||
menuClick: false,
|
||||
resetMenu: (isSlim() || isSlimPlus() || isHorizontal()) && isDesktop()
|
||||
}));
|
||||
}, [isSlim, isHorizontal, isDesktop, setLayoutState]);
|
||||
|
||||
const blockBodyScroll = () => {
|
||||
if (document.body.classList) {
|
||||
document.body.classList.add('blocked-scroll');
|
||||
} else {
|
||||
document.body.className += ' blocked-scroll';
|
||||
}
|
||||
};
|
||||
|
||||
const unblockBodyScroll = () => {
|
||||
if (document.body.classList) {
|
||||
document.body.classList.remove('blocked-scroll');
|
||||
} else {
|
||||
document.body.className = document.body.className.replace(new RegExp('(^|\\b)' + 'blocked-scroll'.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
|
||||
}
|
||||
};
|
||||
useMountEffect(() => {
|
||||
setRipple(layoutConfig.ripple);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (layoutState.overlayMenuActive || layoutState.staticMenuMobileActive || layoutState.overlaySubmenuActive) {
|
||||
bindMenuOutsideClickListener();
|
||||
}
|
||||
|
||||
if (layoutState.staticMenuMobileActive) {
|
||||
blockBodyScroll();
|
||||
(isSlim() || isSlimPlus() || isHorizontal()) && bindDocumentResizeListener();
|
||||
}
|
||||
|
||||
return () => {
|
||||
unbindMenuOutsideClickListener();
|
||||
unbindDocumentResizeListener();
|
||||
unblockBodyScroll();
|
||||
};
|
||||
}, [layoutState.overlayMenuActive, layoutState.staticMenuMobileActive, layoutState.overlaySubmenuActive]);
|
||||
|
||||
useEffect(() => {
|
||||
const onRouteChange = () => {
|
||||
hideMenu();
|
||||
};
|
||||
onRouteChange();
|
||||
}, [pathname, searchParams]);
|
||||
|
||||
useUnmountEffect(() => {
|
||||
unbindMenuOutsideClickListener();
|
||||
});
|
||||
|
||||
const containerClassName = classNames('layout-wrapper', {
|
||||
'layout-light': layoutConfig.colorScheme === 'light',
|
||||
'layout-dark': layoutConfig.colorScheme === 'dark',
|
||||
'layout-overlay': layoutConfig.menuMode === 'overlay',
|
||||
'layout-static': layoutConfig.menuMode === 'static',
|
||||
'layout-slim': layoutConfig.menuMode === 'slim',
|
||||
'layout-slim-plus': layoutConfig.menuMode === 'slim-plus',
|
||||
'layout-horizontal': layoutConfig.menuMode === 'horizontal',
|
||||
'layout-reveal': layoutConfig.menuMode === 'reveal',
|
||||
'layout-drawer': layoutConfig.menuMode === 'drawer',
|
||||
'layout-static-inactive': layoutState.staticMenuDesktopInactive && layoutConfig.menuMode === 'static',
|
||||
'layout-overlay-active': layoutState.overlayMenuActive,
|
||||
'layout-mobile-active': layoutState.staticMenuMobileActive,
|
||||
'p-ripple-disabled': !layoutConfig.ripple,
|
||||
'layout-sidebar-active': layoutState.sidebarActive,
|
||||
'layout-sidebar-anchored': layoutState.anchored
|
||||
});
|
||||
|
||||
return (
|
||||
<GlobalErrorHandler>
|
||||
<div className={classNames('layout-container', containerClassName)} data-theme={layoutConfig.colorScheme}>
|
||||
<Tooltip ref={copyTooltipRef} target=".block-action-copy" position="bottom" content="Copied to clipboard" event="focus" />
|
||||
|
||||
<AppSidebar sidebarRef={sidebarRef} />
|
||||
|
||||
<div className="layout-content-wrapper">
|
||||
<AppTopbar ref={topbarRef} sidebarRef={sidebarRef} />
|
||||
<div className="content-breadcrumb">
|
||||
<AppBreadCrumb />
|
||||
</div>
|
||||
|
||||
<div className="layout-content">{props.children}</div>
|
||||
<div className="layout-mask"></div>
|
||||
</div>
|
||||
<AppProfileMenu />
|
||||
<AppConfig />
|
||||
|
||||
<Toast></Toast>
|
||||
</div>
|
||||
</GlobalErrorHandler>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
Reference in New Issue
Block a user