|
@@ -1,24 +1,24 @@
|
|
|
import React, {
|
|
import React, {
|
|
|
- memo, useCallback, useEffect, useRef, useState,
|
|
|
|
|
|
|
+ type FC,
|
|
|
|
|
+ memo, useCallback, useEffect, useState,
|
|
|
} from 'react';
|
|
} from 'react';
|
|
|
|
|
|
|
|
import dynamic from 'next/dynamic';
|
|
import dynamic from 'next/dynamic';
|
|
|
|
|
|
|
|
-import { useUserUISettings } from '~/client/services/user-ui-settings';
|
|
|
|
|
|
|
+import { scheduleToPut } from '~/client/services/user-ui-settings';
|
|
|
|
|
+import { SidebarMode } from '~/interfaces/ui';
|
|
|
import {
|
|
import {
|
|
|
- useDrawerMode, useDrawerOpened,
|
|
|
|
|
- useSidebarCollapsed,
|
|
|
|
|
- useCurrentSidebarContents,
|
|
|
|
|
|
|
+ useDrawerOpened,
|
|
|
|
|
+ useCollapsedContentsOpened,
|
|
|
useCurrentProductNavWidth,
|
|
useCurrentProductNavWidth,
|
|
|
- useSidebarResizeDisabled,
|
|
|
|
|
- useSidebarScrollerRef,
|
|
|
|
|
|
|
+ usePreferCollapsedMode,
|
|
|
|
|
+ useSidebarMode,
|
|
|
} from '~/stores/ui';
|
|
} from '~/stores/ui';
|
|
|
|
|
|
|
|
-import DrawerToggler from '../Navbar/DrawerToggler';
|
|
|
|
|
-import { StickyStretchableScrollerProps } from '../StickyStretchableScroller';
|
|
|
|
|
-
|
|
|
|
|
-import { NavigationResizeHexagon } from './NavigationResizeHexagon';
|
|
|
|
|
-import { SidebarNav } from './SidebarNav';
|
|
|
|
|
|
|
+import { AppTitleOnSidebarHead, AppTitleOnSubnavigation } from './AppTitle/AppTitle';
|
|
|
|
|
+import { ResizableArea } from './ResizableArea/ResizableArea';
|
|
|
|
|
+import { SidebarHead } from './SidebarHead';
|
|
|
|
|
+import { SidebarNav, type SidebarNavProps } from './SidebarNav';
|
|
|
|
|
|
|
|
import styles from './Sidebar.module.scss';
|
|
import styles from './Sidebar.module.scss';
|
|
|
|
|
|
|
@@ -26,328 +26,178 @@ import styles from './Sidebar.module.scss';
|
|
|
const SidebarContents = dynamic(() => import('./SidebarContents').then(mod => mod.SidebarContents), { ssr: false });
|
|
const SidebarContents = dynamic(() => import('./SidebarContents').then(mod => mod.SidebarContents), { ssr: false });
|
|
|
|
|
|
|
|
|
|
|
|
|
-const StickyStretchableScroller = dynamic<StickyStretchableScrollerProps>(() => import('../StickyStretchableScroller')
|
|
|
|
|
- .then(mod => mod.StickyStretchableScroller), { ssr: false });
|
|
|
|
|
-
|
|
|
|
|
-const sidebarMinWidth = 240;
|
|
|
|
|
-const sidebarMinimizeWidth = 20;
|
|
|
|
|
-const sidebarFixedWidthInDrawerMode = 320;
|
|
|
|
|
-
|
|
|
|
|
-const GlobalNavigation = memo(() => {
|
|
|
|
|
- const { data: isDrawerMode } = useDrawerMode();
|
|
|
|
|
- const { data: currentContents } = useCurrentSidebarContents();
|
|
|
|
|
- const { data: isCollapsed, mutate: mutateSidebarCollapsed } = useSidebarCollapsed();
|
|
|
|
|
-
|
|
|
|
|
- const { scheduleToPut } = useUserUISettings();
|
|
|
|
|
-
|
|
|
|
|
- const itemSelectedHandler = useCallback((selectedContents) => {
|
|
|
|
|
- if (isDrawerMode) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- let newValue = false;
|
|
|
|
|
-
|
|
|
|
|
- // already selected
|
|
|
|
|
- if (currentContents === selectedContents) {
|
|
|
|
|
- // toggle collapsed
|
|
|
|
|
- newValue = !isCollapsed;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- mutateSidebarCollapsed(newValue, false);
|
|
|
|
|
- scheduleToPut({ isSidebarCollapsed: newValue });
|
|
|
|
|
-
|
|
|
|
|
- }, [currentContents, isCollapsed, isDrawerMode, mutateSidebarCollapsed, scheduleToPut]);
|
|
|
|
|
-
|
|
|
|
|
- return <SidebarNav onItemSelected={itemSelectedHandler} />;
|
|
|
|
|
-
|
|
|
|
|
-});
|
|
|
|
|
-GlobalNavigation.displayName = 'GlobalNavigation';
|
|
|
|
|
-
|
|
|
|
|
-const SidebarContentsWrapper = memo(() => {
|
|
|
|
|
- const { mutate: mutateSidebarScroller } = useSidebarScrollerRef();
|
|
|
|
|
|
|
+const resizableAreaMinWidth = 348;
|
|
|
|
|
+const sidebarNavCollapsedWidth = 48;
|
|
|
|
|
|
|
|
- const calcViewHeight = useCallback(() => {
|
|
|
|
|
- const elem = document.querySelector('#grw-sidebar-contents-wrapper');
|
|
|
|
|
- return elem != null
|
|
|
|
|
- ? window.innerHeight - elem?.getBoundingClientRect().top
|
|
|
|
|
- : window.innerHeight;
|
|
|
|
|
- }, []);
|
|
|
|
|
|
|
|
|
|
- return (
|
|
|
|
|
- <>
|
|
|
|
|
- <div id="grw-sidebar-contents-wrapper" style={{ minHeight: '100%' }}>
|
|
|
|
|
- <StickyStretchableScroller
|
|
|
|
|
- simplebarRef={mutateSidebarScroller}
|
|
|
|
|
- stickyElemSelector=".grw-sidebar"
|
|
|
|
|
- calcViewHeight={calcViewHeight}
|
|
|
|
|
- >
|
|
|
|
|
- <SidebarContents />
|
|
|
|
|
- </StickyStretchableScroller>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <DrawerToggler iconClass="icon-arrow-left" />
|
|
|
|
|
- </>
|
|
|
|
|
- );
|
|
|
|
|
-});
|
|
|
|
|
-SidebarContentsWrapper.displayName = 'SidebarContentsWrapper';
|
|
|
|
|
|
|
+type ResizableContainerProps = {
|
|
|
|
|
+ children?: React.ReactNode,
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
+const ResizableContainer = memo((props: ResizableContainerProps): JSX.Element => {
|
|
|
|
|
|
|
|
-export const Sidebar = memo((): JSX.Element => {
|
|
|
|
|
|
|
+ const { children } = props;
|
|
|
|
|
|
|
|
- const { data: isDrawerMode } = useDrawerMode();
|
|
|
|
|
- const { data: isDrawerOpened, mutate: mutateDrawerOpened } = useDrawerOpened();
|
|
|
|
|
|
|
+ const { isDrawerMode, isCollapsedMode, isDockMode } = useSidebarMode();
|
|
|
|
|
+ const { mutate: mutateDrawerOpened } = useDrawerOpened();
|
|
|
const { data: currentProductNavWidth, mutate: mutateProductNavWidth } = useCurrentProductNavWidth();
|
|
const { data: currentProductNavWidth, mutate: mutateProductNavWidth } = useCurrentProductNavWidth();
|
|
|
- const { data: isCollapsed, mutate: mutateSidebarCollapsed } = useSidebarCollapsed();
|
|
|
|
|
- const { data: isResizeDisabled, mutate: mutateSidebarResizeDisabled } = useSidebarResizeDisabled();
|
|
|
|
|
|
|
+ const { mutate: mutatePreferCollapsedMode } = usePreferCollapsedMode();
|
|
|
|
|
+ const { mutate: mutateCollapsedContentsOpened } = useCollapsedContentsOpened();
|
|
|
|
|
|
|
|
- const { scheduleToPut } = useUserUISettings();
|
|
|
|
|
|
|
+ const [resizableAreaWidth, setResizableAreaWidth] = useState<number|undefined>(undefined);
|
|
|
|
|
|
|
|
- const [isHover, setHover] = useState(false);
|
|
|
|
|
- const [isHoverOnResizableContainer, setHoverOnResizableContainer] = useState(false);
|
|
|
|
|
- const [isDragging, setDrag] = useState(false);
|
|
|
|
|
|
|
+ const resizeHandler = useCallback((newWidth: number) => {
|
|
|
|
|
+ setResizableAreaWidth(newWidth);
|
|
|
|
|
+ }, []);
|
|
|
|
|
|
|
|
- const resizableContainer = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
+ const resizeDoneHandler = useCallback((newWidth: number) => {
|
|
|
|
|
+ mutateProductNavWidth(newWidth, false);
|
|
|
|
|
+ scheduleToPut({ preferCollapsedModeByUser: false, currentProductNavWidth: newWidth });
|
|
|
|
|
+ }, [mutateProductNavWidth]);
|
|
|
|
|
|
|
|
- const timeoutIdRef = useRef<NodeJS.Timeout>();
|
|
|
|
|
|
|
+ const collapsedByResizableAreaHandler = useCallback(() => {
|
|
|
|
|
+ mutatePreferCollapsedMode(true);
|
|
|
|
|
+ mutateCollapsedContentsOpened(false);
|
|
|
|
|
+ scheduleToPut({ preferCollapsedModeByUser: true });
|
|
|
|
|
+ }, [mutateCollapsedContentsOpened, mutatePreferCollapsedMode]);
|
|
|
|
|
|
|
|
- const isResizableByDrag = !isResizeDisabled && !isDrawerMode && (!isCollapsed || isHover);
|
|
|
|
|
|
|
|
|
|
- const toggleDrawerMode = useCallback((bool) => {
|
|
|
|
|
- const isStateModified = isResizeDisabled !== bool;
|
|
|
|
|
- if (!isStateModified) {
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ // open/close resizable container when drawer mode
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ if (isDrawerMode()) {
|
|
|
|
|
+ setResizableAreaWidth(undefined);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // Drawer <-- Dock
|
|
|
|
|
- if (bool) {
|
|
|
|
|
- // disable resize
|
|
|
|
|
- mutateSidebarResizeDisabled(true, false);
|
|
|
|
|
|
|
+ else if (isCollapsedMode()) {
|
|
|
|
|
+ setResizableAreaWidth(sidebarNavCollapsedWidth);
|
|
|
}
|
|
}
|
|
|
- // Drawer --> Dock
|
|
|
|
|
else {
|
|
else {
|
|
|
- // enable resize
|
|
|
|
|
- mutateSidebarResizeDisabled(false, false);
|
|
|
|
|
- }
|
|
|
|
|
- }, [isResizeDisabled, mutateSidebarResizeDisabled]);
|
|
|
|
|
-
|
|
|
|
|
- const setContentWidth = useCallback((newWidth: number) => {
|
|
|
|
|
- if (resizableContainer.current == null) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- resizableContainer.current.style.width = `${newWidth}px`;
|
|
|
|
|
- }, []);
|
|
|
|
|
-
|
|
|
|
|
- const hoverOnHandler = useCallback(() => {
|
|
|
|
|
- if (!isCollapsed || isDrawerMode || isDragging) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- setHover(true);
|
|
|
|
|
- }, [isCollapsed, isDragging, isDrawerMode]);
|
|
|
|
|
-
|
|
|
|
|
- const hoverOutHandler = useCallback(() => {
|
|
|
|
|
- if (!isCollapsed || isDrawerMode || isDragging) {
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
|
|
|
+ setResizableAreaWidth(currentProductNavWidth!);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- setHover(false);
|
|
|
|
|
- }, [isCollapsed, isDragging, isDrawerMode]);
|
|
|
|
|
|
|
+ mutateDrawerOpened(false);
|
|
|
|
|
+ }, [currentProductNavWidth, isCollapsedMode, isDrawerMode, mutateDrawerOpened]);
|
|
|
|
|
|
|
|
- const hoverOnResizableContainerHandler = useCallback(() => {
|
|
|
|
|
- if (!isCollapsed || isDrawerMode || isDragging) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return (
|
|
|
|
|
+ <ResizableArea
|
|
|
|
|
+ className="flex-expand-vert"
|
|
|
|
|
+ width={resizableAreaWidth}
|
|
|
|
|
+ minWidth={resizableAreaMinWidth}
|
|
|
|
|
+ disabled={!isDockMode()}
|
|
|
|
|
+ onResize={resizeHandler}
|
|
|
|
|
+ onResizeDone={resizeDoneHandler}
|
|
|
|
|
+ onCollapsed={collapsedByResizableAreaHandler}
|
|
|
|
|
+ >
|
|
|
|
|
+ {children}
|
|
|
|
|
+ </ResizableArea>
|
|
|
|
|
+ );
|
|
|
|
|
|
|
|
- setHoverOnResizableContainer(true);
|
|
|
|
|
- }, [isCollapsed, isDrawerMode, isDragging]);
|
|
|
|
|
|
|
+});
|
|
|
|
|
|
|
|
- const hoverOutResizableContainerHandler = useCallback(() => {
|
|
|
|
|
- if (!isCollapsed || isDrawerMode || isDragging) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- setHoverOnResizableContainer(false);
|
|
|
|
|
- }, [isCollapsed, isDrawerMode, isDragging]);
|
|
|
|
|
|
|
+type CollapsibleContainerProps = {
|
|
|
|
|
+ Nav: FC<SidebarNavProps>,
|
|
|
|
|
+ className?: string,
|
|
|
|
|
+ children?: React.ReactNode,
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- const toggleNavigationBtnClickHandler = useCallback(() => {
|
|
|
|
|
- const newValue = !isCollapsed;
|
|
|
|
|
- mutateSidebarCollapsed(newValue, false);
|
|
|
|
|
- scheduleToPut({ isSidebarCollapsed: newValue });
|
|
|
|
|
- }, [isCollapsed, mutateSidebarCollapsed, scheduleToPut]);
|
|
|
|
|
|
|
+const CollapsibleContainer = memo((props: CollapsibleContainerProps): JSX.Element => {
|
|
|
|
|
|
|
|
- useEffect(() => {
|
|
|
|
|
- if (isCollapsed) {
|
|
|
|
|
- setContentWidth(sidebarMinimizeWidth);
|
|
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
|
|
|
- setContentWidth(currentProductNavWidth!);
|
|
|
|
|
- }
|
|
|
|
|
- }, [currentProductNavWidth, isCollapsed, setContentWidth]);
|
|
|
|
|
|
|
+ const { Nav, className, children } = props;
|
|
|
|
|
|
|
|
- const draggableAreaMoveHandler = useCallback((event: MouseEvent) => {
|
|
|
|
|
- event.preventDefault();
|
|
|
|
|
|
|
+ const { isCollapsedMode } = useSidebarMode();
|
|
|
|
|
+ const { data: currentProductNavWidth } = useCurrentProductNavWidth();
|
|
|
|
|
+ const { data: isCollapsedContentsOpened, mutate: mutateCollapsedContentsOpened } = useCollapsedContentsOpened();
|
|
|
|
|
|
|
|
- const newWidth = event.pageX - 60;
|
|
|
|
|
- if (resizableContainer.current != null) {
|
|
|
|
|
- setContentWidth(newWidth);
|
|
|
|
|
- resizableContainer.current.classList.add('dragging');
|
|
|
|
|
- }
|
|
|
|
|
- }, [setContentWidth]);
|
|
|
|
|
|
|
|
|
|
- const dragableAreaMouseUpHandler = useCallback(() => {
|
|
|
|
|
- if (resizableContainer.current == null) {
|
|
|
|
|
|
|
+ // open menu when collapsed mode
|
|
|
|
|
+ const primaryItemHoverHandler = useCallback(() => {
|
|
|
|
|
+ // reject other than collapsed mode
|
|
|
|
|
+ if (!isCollapsedMode()) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- setDrag(false);
|
|
|
|
|
-
|
|
|
|
|
- if (resizableContainer.current.clientWidth < sidebarMinWidth) {
|
|
|
|
|
- // force collapsed
|
|
|
|
|
- mutateSidebarCollapsed(true);
|
|
|
|
|
- mutateProductNavWidth(sidebarMinWidth, false);
|
|
|
|
|
- scheduleToPut({ isSidebarCollapsed: true, currentProductNavWidth: sidebarMinWidth });
|
|
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
- const newWidth = resizableContainer.current.clientWidth;
|
|
|
|
|
- mutateSidebarCollapsed(false);
|
|
|
|
|
- mutateProductNavWidth(newWidth, false);
|
|
|
|
|
- scheduleToPut({ isSidebarCollapsed: false, currentProductNavWidth: newWidth });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- resizableContainer.current.classList.remove('dragging');
|
|
|
|
|
-
|
|
|
|
|
- }, [mutateProductNavWidth, mutateSidebarCollapsed, scheduleToPut]);
|
|
|
|
|
|
|
+ mutateCollapsedContentsOpened(true);
|
|
|
|
|
+ }, [isCollapsedMode, mutateCollapsedContentsOpened]);
|
|
|
|
|
|
|
|
- const dragableAreaMouseDownHandler = useCallback((event: React.MouseEvent) => {
|
|
|
|
|
- if (!isResizableByDrag) {
|
|
|
|
|
|
|
+ // close menu when collapsed mode
|
|
|
|
|
+ const mouseLeaveHandler = useCallback(() => {
|
|
|
|
|
+ // reject other than collapsed mode
|
|
|
|
|
+ if (!isCollapsedMode()) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- event.preventDefault();
|
|
|
|
|
|
|
+ mutateCollapsedContentsOpened(false);
|
|
|
|
|
+ }, [isCollapsedMode, mutateCollapsedContentsOpened]);
|
|
|
|
|
|
|
|
- setDrag(true);
|
|
|
|
|
|
|
+ const openClass = `${isCollapsedContentsOpened ? 'open' : ''}`;
|
|
|
|
|
+ const collapsibleContentsWidth = isCollapsedMode() ? currentProductNavWidth : undefined;
|
|
|
|
|
|
|
|
- const removeEventListeners = () => {
|
|
|
|
|
- document.removeEventListener('mousemove', draggableAreaMoveHandler);
|
|
|
|
|
- document.removeEventListener('mouseup', dragableAreaMouseUpHandler);
|
|
|
|
|
- document.removeEventListener('mouseup', removeEventListeners);
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div className={`flex-expand-horiz ${className}`} onMouseLeave={mouseLeaveHandler}>
|
|
|
|
|
+ <Nav onPrimaryItemHover={primaryItemHoverHandler} />
|
|
|
|
|
+ <div className={`sidebar-contents-container flex-grow-1 overflow-y-auto ${openClass}`} style={{ width: collapsibleContentsWidth }}>
|
|
|
|
|
+ {children}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
|
|
|
- document.addEventListener('mousemove', draggableAreaMoveHandler);
|
|
|
|
|
- document.addEventListener('mouseup', dragableAreaMouseUpHandler);
|
|
|
|
|
- document.addEventListener('mouseup', removeEventListeners);
|
|
|
|
|
|
|
+});
|
|
|
|
|
|
|
|
- }, [dragableAreaMouseUpHandler, draggableAreaMoveHandler, isResizableByDrag]);
|
|
|
|
|
|
|
|
|
|
- useEffect(() => {
|
|
|
|
|
- toggleDrawerMode(isDrawerMode);
|
|
|
|
|
- }, [isDrawerMode, toggleDrawerMode]);
|
|
|
|
|
|
|
+type DrawableContainerProps = {
|
|
|
|
|
+ className?: string,
|
|
|
|
|
+ children?: React.ReactNode,
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- // open/close resizable container
|
|
|
|
|
- useEffect(() => {
|
|
|
|
|
- if (!isCollapsed) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+const DrawableContainer = memo((props: DrawableContainerProps): JSX.Element => {
|
|
|
|
|
|
|
|
- if (isHoverOnResizableContainer) {
|
|
|
|
|
- // schedule to open
|
|
|
|
|
- timeoutIdRef.current = setTimeout(() => {
|
|
|
|
|
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
|
|
|
- setContentWidth(currentProductNavWidth!);
|
|
|
|
|
- }, 70);
|
|
|
|
|
- }
|
|
|
|
|
- else if (timeoutIdRef.current != null) {
|
|
|
|
|
- // cancel schedule to open
|
|
|
|
|
- clearTimeout(timeoutIdRef.current);
|
|
|
|
|
- timeoutIdRef.current = undefined;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const { className, children } = props;
|
|
|
|
|
|
|
|
- // close
|
|
|
|
|
- if (!isHover) {
|
|
|
|
|
- setContentWidth(sidebarMinimizeWidth);
|
|
|
|
|
- timeoutIdRef.current = undefined;
|
|
|
|
|
- }
|
|
|
|
|
- }, [isCollapsed, isHover, isHoverOnResizableContainer, currentProductNavWidth, setContentWidth]);
|
|
|
|
|
|
|
+ const { data: isDrawerOpened } = useDrawerOpened();
|
|
|
|
|
|
|
|
- // open/close resizable container when drawer mode
|
|
|
|
|
- useEffect(() => {
|
|
|
|
|
- if (isDrawerMode) {
|
|
|
|
|
- setContentWidth(sidebarFixedWidthInDrawerMode);
|
|
|
|
|
- }
|
|
|
|
|
- else if (isCollapsed) {
|
|
|
|
|
- setContentWidth(sidebarMinimizeWidth);
|
|
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
|
|
|
- setContentWidth(currentProductNavWidth!);
|
|
|
|
|
- }
|
|
|
|
|
- }, [currentProductNavWidth, isCollapsed, isDrawerMode, setContentWidth]);
|
|
|
|
|
|
|
+ const openClass = `${isDrawerOpened ? 'open' : ''}`;
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div className={`${className} ${openClass}`}>
|
|
|
|
|
+ {children}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+});
|
|
|
|
|
|
|
|
|
|
|
|
|
- const showContents = isDrawerMode || isHover || !isCollapsed;
|
|
|
|
|
|
|
+export const Sidebar = (): JSX.Element => {
|
|
|
|
|
|
|
|
|
|
+ const { data: sidebarMode, isCollapsedMode } = useSidebarMode();
|
|
|
|
|
|
|
|
// css styles
|
|
// css styles
|
|
|
- const grwSidebarClass = `grw-sidebar ${styles['grw-sidebar']}`;
|
|
|
|
|
- const sidebarModeClass = `${isDrawerMode ? 'grw-sidebar-drawer' : 'grw-sidebar-dock'}`;
|
|
|
|
|
- const isOpenClass = `${isDrawerOpened ? 'open' : ''}`;
|
|
|
|
|
|
|
+ const grwSidebarClass = styles['grw-sidebar'];
|
|
|
|
|
+ // eslint-disable-next-line no-nested-ternary
|
|
|
|
|
+ let modeClass;
|
|
|
|
|
+ switch (sidebarMode) {
|
|
|
|
|
+ case SidebarMode.DRAWER:
|
|
|
|
|
+ modeClass = 'grw-sidebar-drawer';
|
|
|
|
|
+ break;
|
|
|
|
|
+ case SidebarMode.COLLAPSED:
|
|
|
|
|
+ modeClass = 'grw-sidebar-collapsed';
|
|
|
|
|
+ break;
|
|
|
|
|
+ case SidebarMode.DOCK:
|
|
|
|
|
+ modeClass = 'grw-sidebar-dock';
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return (
|
|
return (
|
|
|
<>
|
|
<>
|
|
|
- <div className={`${grwSidebarClass} ${sidebarModeClass} ${isOpenClass} d-print-none`} data-testid="grw-sidebar">
|
|
|
|
|
- <div className="data-layout-container">
|
|
|
|
|
- <div
|
|
|
|
|
- className="navigation transition-enabled"
|
|
|
|
|
- onMouseEnter={hoverOnHandler}
|
|
|
|
|
- onMouseLeave={hoverOutHandler}
|
|
|
|
|
- >
|
|
|
|
|
- <div className="grw-navigation-wrap">
|
|
|
|
|
- <div className="grw-global-navigation">
|
|
|
|
|
- <GlobalNavigation></GlobalNavigation>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div
|
|
|
|
|
- ref={resizableContainer}
|
|
|
|
|
- className="grw-contextual-navigation"
|
|
|
|
|
- onMouseEnter={hoverOnResizableContainerHandler}
|
|
|
|
|
- onMouseLeave={hoverOutResizableContainerHandler}
|
|
|
|
|
- style={{ width: isCollapsed ? sidebarMinimizeWidth : currentProductNavWidth }}
|
|
|
|
|
- >
|
|
|
|
|
- <div className={`grw-contextual-navigation-child ${showContents ? '' : 'd-none'}`} data-testid="grw-contextual-navigation-child">
|
|
|
|
|
- <SidebarContents />
|
|
|
|
|
- <DrawerToggler iconClass="icon-arrow-left" />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className="grw-navigation-draggable">
|
|
|
|
|
- { isResizableByDrag && (
|
|
|
|
|
- <div
|
|
|
|
|
- className="grw-navigation-draggable-hitarea"
|
|
|
|
|
- onMouseDown={dragableAreaMouseDownHandler}
|
|
|
|
|
- >
|
|
|
|
|
- <div className="grw-navigation-draggable-hitarea-child"></div>
|
|
|
|
|
- </div>
|
|
|
|
|
- ) }
|
|
|
|
|
- <button
|
|
|
|
|
- data-testid="grw-navigation-resize-button"
|
|
|
|
|
- className={`grw-navigation-resize-button ${!isDrawerMode ? 'resizable' : ''} ${isCollapsed ? 'collapsed' : ''} `}
|
|
|
|
|
- type="button"
|
|
|
|
|
- aria-expanded="true"
|
|
|
|
|
- aria-label="Toggle navigation"
|
|
|
|
|
- disabled={isDrawerMode}
|
|
|
|
|
- onClick={toggleNavigationBtnClickHandler}
|
|
|
|
|
- >
|
|
|
|
|
- <span className="hexagon-container" role="presentation">
|
|
|
|
|
- <NavigationResizeHexagon />
|
|
|
|
|
- </span>
|
|
|
|
|
- <span className="hitarea" role="presentation"></span>
|
|
|
|
|
- </button>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
|
|
+ { sidebarMode != null && isCollapsedMode() && <AppTitleOnSubnavigation /> }
|
|
|
|
|
+ <DrawableContainer className={`${grwSidebarClass} ${modeClass} border-end vh-100`} data-testid="grw-sidebar">
|
|
|
|
|
+ <ResizableContainer>
|
|
|
|
|
+ { sidebarMode != null && !isCollapsedMode() && <AppTitleOnSidebarHead /> }
|
|
|
|
|
+ <SidebarHead />
|
|
|
|
|
+ <CollapsibleContainer Nav={SidebarNav} className="border-top">
|
|
|
|
|
+ <SidebarContents />
|
|
|
|
|
+ </CollapsibleContainer>
|
|
|
|
|
+ </ResizableContainer>
|
|
|
|
|
+ </DrawableContainer>
|
|
|
</>
|
|
</>
|
|
|
);
|
|
);
|
|
|
-
|
|
|
|
|
-});
|
|
|
|
|
-Sidebar.displayName = 'Sidebar';
|
|
|
|
|
|
|
+};
|