Sidebar.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import React, {
  2. memo, useCallback, useEffect, useState,
  3. } from 'react';
  4. import dynamic from 'next/dynamic';
  5. import { useUserUISettings } from '~/client/services/user-ui-settings';
  6. import {
  7. useDrawerMode, useDrawerOpened,
  8. useSidebarCollapsed,
  9. useCurrentProductNavWidth,
  10. useSidebarResizeDisabled,
  11. } from '~/stores/ui';
  12. import { ResizableArea } from './ResizableArea/ResizableArea';
  13. import { SidebarNav } from './SidebarNav';
  14. import styles from './Sidebar.module.scss';
  15. const SidebarContents = dynamic(() => import('./SidebarContents').then(mod => mod.SidebarContents), { ssr: false });
  16. const sidebarMinWidth = 240;
  17. const sidebarCollapsedWidth = 0;
  18. const sidebarFixedWidthInDrawerMode = 320;
  19. export const SidebarSubstance = memo((): JSX.Element => {
  20. const { data: isDrawerMode } = useDrawerMode();
  21. const { data: currentProductNavWidth, mutate: mutateProductNavWidth } = useCurrentProductNavWidth();
  22. const { data: isCollapsed, mutate: mutateSidebarCollapsed } = useSidebarCollapsed();
  23. const { data: isResizeDisabled, mutate: mutateSidebarResizeDisabled } = useSidebarResizeDisabled();
  24. const [resizableAreaWidth, setResizableAreaWidth] = useState(0);
  25. const { scheduleToPut } = useUserUISettings();
  26. const toggleDrawerMode = useCallback((bool) => {
  27. const isStateModified = isResizeDisabled !== bool;
  28. if (!isStateModified) {
  29. return;
  30. }
  31. // Drawer <-- Dock
  32. if (bool) {
  33. // disable resize
  34. mutateSidebarResizeDisabled(true, false);
  35. }
  36. // Drawer --> Dock
  37. else {
  38. // enable resize
  39. mutateSidebarResizeDisabled(false, false);
  40. }
  41. }, [isResizeDisabled, mutateSidebarResizeDisabled]);
  42. const resizeHandler = useCallback((newWidth: number) => {
  43. setResizableAreaWidth(newWidth);
  44. }, []);
  45. const resizeDoneHandler = useCallback((newWidth: number) => {
  46. mutateProductNavWidth(newWidth, false);
  47. scheduleToPut({ isSidebarCollapsed: false, currentProductNavWidth: newWidth });
  48. }, [mutateProductNavWidth, scheduleToPut]);
  49. const collapsedByResizableAreaHandler = useCallback(() => {
  50. mutateSidebarCollapsed(true);
  51. mutateProductNavWidth(sidebarMinWidth, false);
  52. scheduleToPut({ isSidebarCollapsed: true, currentProductNavWidth: sidebarMinWidth });
  53. }, [mutateProductNavWidth, mutateSidebarCollapsed, scheduleToPut]);
  54. useEffect(() => {
  55. toggleDrawerMode(isDrawerMode);
  56. }, [isDrawerMode, toggleDrawerMode]);
  57. // open/close resizable container when drawer mode
  58. useEffect(() => {
  59. if (isDrawerMode) {
  60. setResizableAreaWidth(sidebarFixedWidthInDrawerMode);
  61. }
  62. else if (isCollapsed) {
  63. setResizableAreaWidth(sidebarCollapsedWidth);
  64. }
  65. else {
  66. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  67. setResizableAreaWidth(currentProductNavWidth!);
  68. }
  69. }, [currentProductNavWidth, isCollapsed, isDrawerMode]);
  70. const disableResizing = isResizeDisabled || isDrawerMode || isCollapsed;
  71. return (
  72. <div className="data-layout-container">
  73. <div className="navigation transition-enabled">
  74. <div className="grw-navigation-wrap">
  75. <SidebarNav />
  76. <ResizableArea
  77. width={resizableAreaWidth}
  78. minWidth={sidebarMinWidth}
  79. disabled={disableResizing}
  80. onResize={resizeHandler}
  81. onResizeDone={resizeDoneHandler}
  82. onCollapsed={collapsedByResizableAreaHandler}
  83. >
  84. <div className="sidebar-contents-container">
  85. <SidebarContents />
  86. </div>
  87. </ResizableArea>
  88. </div>
  89. </div>
  90. </div>
  91. );
  92. });
  93. export const Sidebar = (): JSX.Element => {
  94. const { data: isDrawerMode } = useDrawerMode();
  95. const { data: isDrawerOpened } = useDrawerOpened();
  96. // css styles
  97. const grwSidebarClass = `grw-sidebar ${styles['grw-sidebar']}`;
  98. const sidebarModeClass = `${isDrawerMode ? 'grw-sidebar-drawer' : 'grw-sidebar-dock'}`;
  99. const isOpenClass = `${isDrawerOpened ? 'open' : ''}`;
  100. return (
  101. <div className={`${grwSidebarClass} ${sidebarModeClass} ${isOpenClass} d-print-none`} data-testid="grw-sidebar">
  102. <SidebarSubstance />
  103. </div>
  104. );
  105. };