import React, {
FC, useCallback, useEffect, useRef, useState,
} from 'react';
import { scheduleToPutUserUISettings } from '~/client/services/user-ui-settings';
import {
useDrawerMode, useDrawerOpened,
useSidebarCollapsed,
useCurrentSidebarContents,
useCurrentProductNavWidth,
useSidebarResizeDisabled,
} from '~/stores/ui';
import DrawerToggler from './Navbar/DrawerToggler';
import SidebarNav from './Sidebar/SidebarNav';
import SidebarContents from './Sidebar/SidebarContents';
import { NavigationResizeHexagon } from './Sidebar/NavigationResizeHexagon';
import StickyStretchableScroller from './StickyStretchableScroller';
const sidebarMinWidth = 240;
const sidebarMinimizeWidth = 20;
const GlobalNavigation = () => {
const { data: currentContents } = useCurrentSidebarContents();
const { data: isCollapsed, mutate: mutateSidebarCollapsed } = useSidebarCollapsed();
const itemSelectedHandler = useCallback((selectedContents) => {
let newValue = false;
// already selected
if (currentContents === selectedContents) {
// toggle collapsed
newValue = !isCollapsed;
}
mutateSidebarCollapsed(newValue, false);
scheduleToPutUserUISettings({ isSidebarCollapsed: newValue });
}, [currentContents, isCollapsed, mutateSidebarCollapsed]);
return ;
};
const SidebarContentsWrapper = () => {
const [resetKey, setResetKey] = useState(0);
const scrollTargetSelector = '#grw-sidebar-contents-scroll-target';
const calcViewHeight = useCallback(() => {
const scrollTargetElem = document.querySelector('#grw-sidebar-contents-scroll-target');
return scrollTargetElem != null
? window.innerHeight - scrollTargetElem?.getBoundingClientRect().top
: window.innerHeight;
}, []);
return (
<>
>
);
};
type Props = {
}
const Sidebar: FC = (props: Props) => {
const { data: isDrawerMode } = useDrawerMode();
const { data: isDrawerOpened, mutate: mutateDrawerOpened } = useDrawerOpened();
const { data: currentProductNavWidth, mutate: mutateProductNavWidth } = useCurrentProductNavWidth();
const { data: isCollapsed, mutate: mutateSidebarCollapsed } = useSidebarCollapsed();
const { data: isResizeDisabled, mutate: mutateSidebarResizeDisabled } = useSidebarResizeDisabled();
const [isTransitionEnabled, setTransitionEnabled] = useState(false);
const [isHover, setHover] = useState(false);
const [isDragging, setDrag] = useState(false);
const isResizableByDrag = !isResizeDisabled && !isDrawerMode && (!isCollapsed || isHover);
const toggleDrawerMode = useCallback((bool) => {
const isStateModified = isResizeDisabled !== bool;
if (!isStateModified) {
return;
}
// Drawer <-- Dock
if (bool) {
// disable resize
mutateSidebarResizeDisabled(true, false);
}
// Drawer --> Dock
else {
// enable resize
mutateSidebarResizeDisabled(false, false);
}
}, [isResizeDisabled, mutateSidebarResizeDisabled]);
const backdropClickedHandler = useCallback(() => {
mutateDrawerOpened(false, false);
}, [mutateDrawerOpened]);
useEffect(() => {
setTimeout(() => {
setTransitionEnabled(true);
}, 1000);
}, []);
useEffect(() => {
toggleDrawerMode(isDrawerMode);
}, [isDrawerMode, toggleDrawerMode]);
const resizableContainer = useRef(null);
const setContentWidth = useCallback((newWidth) => {
if (resizableContainer.current == null) {
return;
}
resizableContainer.current.style.width = `${newWidth}px`;
}, []);
const hoverOnResizableContainerHandler = useCallback(() => {
if (!isCollapsed || isDrawerMode || isDragging) {
return;
}
setHover(true);
setContentWidth(currentProductNavWidth);
}, [isCollapsed, isDrawerMode, isDragging, setContentWidth, currentProductNavWidth]);
const hoverOutHandler = useCallback(() => {
if (!isCollapsed || isDrawerMode || isDragging) {
return;
}
setHover(false);
setContentWidth(sidebarMinimizeWidth);
}, [isCollapsed, isDragging, isDrawerMode, setContentWidth]);
const toggleNavigationBtnClickHandler = useCallback(() => {
const newValue = !isCollapsed;
mutateSidebarCollapsed(newValue, false);
scheduleToPutUserUISettings({ isSidebarCollapsed: newValue });
}, [isCollapsed, mutateSidebarCollapsed]);
useEffect(() => {
if (isCollapsed) {
setContentWidth(sidebarMinimizeWidth);
}
else {
setContentWidth(currentProductNavWidth);
}
}, [currentProductNavWidth, isCollapsed, setContentWidth]);
const draggableAreaMoveHandler = useCallback((event: MouseEvent) => {
event.preventDefault();
const newWidth = event.pageX - 60;
if (resizableContainer.current != null) {
setContentWidth(newWidth);
resizableContainer.current.classList.add('dragging');
}
}, [setContentWidth]);
const dragableAreaMouseUpHandler = useCallback(() => {
if (resizableContainer.current == null) {
return;
}
setDrag(false);
if (resizableContainer.current.clientWidth < sidebarMinWidth) {
// force collapsed
mutateSidebarCollapsed(true);
mutateProductNavWidth(sidebarMinWidth, false);
scheduleToPutUserUISettings({ isSidebarCollapsed: true, currentProductNavWidth: sidebarMinWidth });
}
else {
const newWidth = resizableContainer.current.clientWidth;
mutateSidebarCollapsed(false);
mutateProductNavWidth(newWidth, false);
scheduleToPutUserUISettings({ isSidebarCollapsed: false, currentProductNavWidth: newWidth });
}
resizableContainer.current.classList.remove('dragging');
}, [mutateProductNavWidth, mutateSidebarCollapsed]);
const dragableAreaMouseDownHandler = useCallback((event: React.MouseEvent) => {
if (!isResizableByDrag) {
return;
}
event.preventDefault();
setDrag(true);
const removeEventListeners = () => {
document.removeEventListener('mousemove', draggableAreaMoveHandler);
document.removeEventListener('mouseup', dragableAreaMouseUpHandler);
document.removeEventListener('mouseup', removeEventListeners);
};
document.addEventListener('mousemove', draggableAreaMoveHandler);
document.addEventListener('mouseup', dragableAreaMouseUpHandler);
document.addEventListener('mouseup', removeEventListeners);
}, [dragableAreaMouseUpHandler, draggableAreaMoveHandler, isResizableByDrag]);
return (
<>
{ isResizableByDrag && (
) }
{ isDrawerOpened && (
) }
>
);
};
export default Sidebar;