2
0

Sidebar.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import React, {
  2. memo, useCallback, useEffect, useState,
  3. } from 'react';
  4. import dynamic from 'next/dynamic';
  5. import { scheduleToPut } 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 toggleDrawerMode = useCallback((bool) => {
  26. const isStateModified = isResizeDisabled !== bool;
  27. if (!isStateModified) {
  28. return;
  29. }
  30. // Drawer <-- Dock
  31. if (bool) {
  32. // disable resize
  33. mutateSidebarResizeDisabled(true, false);
  34. }
  35. // Drawer --> Dock
  36. else {
  37. // enable resize
  38. mutateSidebarResizeDisabled(false, false);
  39. }
  40. }, [isResizeDisabled, mutateSidebarResizeDisabled]);
  41. const resizeHandler = useCallback((newWidth: number) => {
  42. setResizableAreaWidth(newWidth);
  43. }, []);
  44. const resizeDoneHandler = useCallback((newWidth: number) => {
  45. mutateProductNavWidth(newWidth, false);
  46. scheduleToPut({ preferCollapsedModeByUser: false, currentProductNavWidth: newWidth });
  47. }, [mutateProductNavWidth]);
  48. const collapsedByResizableAreaHandler = useCallback(() => {
  49. mutateSidebarCollapsed(true);
  50. mutateProductNavWidth(sidebarMinWidth, false);
  51. scheduleToPut({ preferCollapsedModeByUser: true, currentProductNavWidth: sidebarMinWidth });
  52. }, [mutateProductNavWidth, mutateSidebarCollapsed]);
  53. useEffect(() => {
  54. toggleDrawerMode(isDrawerMode);
  55. }, [isDrawerMode, toggleDrawerMode]);
  56. // open/close resizable container when drawer mode
  57. useEffect(() => {
  58. if (isDrawerMode) {
  59. setResizableAreaWidth(sidebarFixedWidthInDrawerMode);
  60. }
  61. else if (isCollapsed) {
  62. setResizableAreaWidth(sidebarCollapsedWidth);
  63. }
  64. else {
  65. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  66. setResizableAreaWidth(currentProductNavWidth!);
  67. }
  68. }, [currentProductNavWidth, isCollapsed, isDrawerMode]);
  69. const disableResizing = isResizeDisabled || isDrawerMode || isCollapsed;
  70. return (
  71. <div className="grw-navigation-wrap">
  72. <SidebarNav />
  73. <ResizableArea
  74. width={resizableAreaWidth}
  75. minWidth={sidebarMinWidth}
  76. disabled={disableResizing}
  77. onResize={resizeHandler}
  78. onResizeDone={resizeDoneHandler}
  79. onCollapsed={collapsedByResizableAreaHandler}
  80. >
  81. <div className="sidebar-contents-container">
  82. <SidebarContents />
  83. </div>
  84. </ResizableArea>
  85. </div>
  86. );
  87. });
  88. export const Sidebar = (): JSX.Element => {
  89. const { data: isDrawerMode } = useDrawerMode();
  90. const { data: isDrawerOpened } = useDrawerOpened();
  91. // css styles
  92. const grwSidebarClass = `grw-sidebar ${styles['grw-sidebar']}`;
  93. const sidebarModeClass = `${isDrawerMode ? 'grw-sidebar-drawer' : 'grw-sidebar-dock'}`;
  94. const isOpenClass = `${isDrawerOpened ? 'open' : ''}`;
  95. return (
  96. <div className={`${grwSidebarClass} ${sidebarModeClass} ${isOpenClass} d-print-none`} data-testid="grw-sidebar">
  97. <SidebarSubstance />
  98. </div>
  99. );
  100. };