فهرست منبع

migrate useSidebarMode

Yuki Takei 11 ماه پیش
والد
کامیت
b84d73cb13

+ 2 - 2
apps/app/src/client/components/Me/UISettings.tsx

@@ -5,8 +5,8 @@ import { UncontrolledTooltip } from 'reactstrap';
 
 import { updateUserUISettings } from '~/client/services/user-ui-settings';
 import { toastError, toastSuccess } from '~/client/util/toastr';
-import { usePreferCollapsedMode } from '~/states/ui';
-import { useCollapsedContentsOpened, useSidebarMode } from '~/stores/ui';
+import { usePreferCollapsedMode, useSidebarMode } from '~/states/ui';
+import { useCollapsedContentsOpened } from '~/stores/ui';
 
 import styles from './UISettings.module.scss';
 

+ 3 - 2
apps/app/src/client/components/PagePathNavSticky/PagePathNavSticky.tsx

@@ -7,8 +7,9 @@ import { pagePathUtils } from '@growi/core/dist/utils';
 import Sticky from 'react-stickynode';
 
 import LinkedPagePath from '~/models/linked-page-path';
+import { useSidebarMode } from '~/states/ui';
 import {
-  usePageControlsX, useCurrentProductNavWidth, useSidebarMode,
+  usePageControlsX, useCurrentProductNavWidth,
 } from '~/stores/ui';
 
 import { PagePathHierarchicalLink } from '../../../components/Common/PagePathHierarchicalLink';
@@ -29,7 +30,7 @@ export const PagePathNavSticky = (props: PagePathNavLayoutProps): JSX.Element =>
 
   const { data: pageControlsX } = usePageControlsX();
   const { data: sidebarWidth } = useCurrentProductNavWidth();
-  const { data: sidebarMode } = useSidebarMode();
+  const { sidebarMode } = useSidebarMode();
   const pagePathNavRef = useRef<HTMLDivElement>(null);
 
   const [navMaxWidth, setNavMaxWidth] = useState<number | undefined>();

+ 8 - 5
apps/app/src/client/components/Sidebar/Sidebar.tsx

@@ -13,12 +13,15 @@ import { EditorMode, useEditorMode } from '~/stores-universal/ui';
 import {
   useCollapsedContentsOpened,
   useCurrentProductNavWidth,
-  useSidebarMode,
   useSidebarScrollerRef,
   useIsDeviceLargerThanMd,
-  useIsDeviceLargerThanXl,
 } from '~/stores/ui';
-import { useDrawerOpened, usePreferCollapsedMode } from '~/states/ui';
+import {
+  useDrawerOpened,
+  usePreferCollapsedMode,
+  useSidebarMode,
+  useDeviceLargerThanXl,
+} from '~/states/ui';
 
 import { DrawerToggler } from '../Common/DrawerToggler';
 
@@ -225,14 +228,14 @@ const DrawableContainer = memo((props: DrawableContainerProps): JSX.Element => {
 export const Sidebar = (): JSX.Element => {
 
   const {
-    data: sidebarMode,
+    sidebarMode,
     isDrawerMode, isCollapsedMode, isDockMode,
   } = useSidebarMode();
 
   const { data: isSearchPage } = useIsSearchPage();
   const { data: editorMode } = useEditorMode();
   const { data: isMdSize } = useIsDeviceLargerThanMd();
-  const { data: isXlSize } = useIsDeviceLargerThanXl();
+  const [isXlSize] = useDeviceLargerThanXl();
 
   const isEditorMode = editorMode === EditorMode.Editor;
   const shouldHideSiteName = isEditorMode && isXlSize;

+ 2 - 1
apps/app/src/client/components/Sidebar/SidebarContents.tsx

@@ -2,7 +2,8 @@ import React, { memo, useMemo } from 'react';
 
 import { AiAssistant } from '~/features/openai/client/components/AiAssistant/Sidebar/AiAssistant';
 import { SidebarContentsType } from '~/interfaces/ui';
-import { useCollapsedContentsOpened, useCurrentSidebarContents, useSidebarMode } from '~/stores/ui';
+import { useSidebarMode } from '~/states/ui';
+import { useCollapsedContentsOpened, useCurrentSidebarContents } from '~/stores/ui';
 
 
 import { Bookmarks } from './Bookmarks';

+ 4 - 2
apps/app/src/client/components/Sidebar/SidebarHead/ToggleCollapseButton.tsx

@@ -2,9 +2,11 @@ import {
   memo, useCallback, useMemo, type JSX,
 } from 'react';
 
-import { useDrawerOpened, usePreferCollapsedMode } from '~/states/ui';
 import {
-  useCollapsedContentsOpened, useSidebarMode,
+  useDrawerOpened, usePreferCollapsedMode, useSidebarMode,
+} from '~/states/ui';
+import {
+  useCollapsedContentsOpened,
 } from '~/stores/ui';
 
 

+ 2 - 2
apps/app/src/client/components/Sidebar/SidebarNav/PrimaryItems.tsx

@@ -4,7 +4,7 @@ import dynamic from 'next/dynamic';
 
 import { SidebarContentsType } from '~/interfaces/ui';
 import { useIsAiEnabled } from '~/stores-universal/context';
-import { useSidebarMode } from '~/stores/ui';
+import { useSidebarMode } from '~/states/ui';
 
 import { PrimaryItem } from './PrimaryItem';
 
@@ -22,7 +22,7 @@ type Props = {
 export const PrimaryItems = memo((props: Props) => {
   const { onItemHover } = props;
 
-  const { data: sidebarMode } = useSidebarMode();
+  const { sidebarMode } = useSidebarMode();
   const { data: isAiEnabled } = useIsAiEnabled();
 
   if (sidebarMode == null) {

+ 1 - 0
apps/app/src/pages/utils/commons.ts

@@ -185,6 +185,7 @@ export const generateCustomTitleForPage = (props: CommonProps, pagePath: string)
 export const useInitSidebarConfig = (sidebarConfig: ISidebarConfig, userUISettings?: IUserUISettings): void => {
   // UserUISettings
   const [, setPreferCollapsedMode] = usePreferCollapsedMode();
+  const value = userUISettings?.preferCollapsedModeByUser ?? sidebarConfig.isSidebarCollapsedMode;
   setPreferCollapsedMode(userUISettings?.preferCollapsedModeByUser ?? sidebarConfig.isSidebarCollapsedMode);
 
   useCurrentSidebarContents(userUISettings?.currentSidebarContents);

+ 86 - 3
apps/app/src/states/ui.ts

@@ -1,14 +1,97 @@
+import { useEffect } from 'react';
+
+
+import { isClient } from '@growi/core/dist/utils';
+import { Breakpoint } from '@growi/ui/dist/interfaces';
+import { addBreakpointListener, cleanupBreakpointListener } from '@growi/ui/dist/utils';
 import { atom, useAtom } from 'jotai';
 
-// Private atoms
+import { SidebarMode } from '~/interfaces/ui';
+import { EditorMode } from '~/stores-universal/ui';
+
 const isDrawerOpenedAtom = atom<boolean>(false);
-const preferCollapsedModeAtom = atom<boolean>(false);
 
-// Public hooks
 export const useDrawerOpened = () => {
   return useAtom(isDrawerOpenedAtom);
 };
 
+
+const preferCollapsedModeAtom = atom<boolean>(false);
+
 export const usePreferCollapsedMode = () => {
   return useAtom(preferCollapsedModeAtom);
 };
+
+
+// Device state atoms
+const isDeviceLargerThanXlAtom = atom<boolean>(false);
+
+export const useDeviceLargerThanXl = () => {
+  const [isLargerThanXl, setIsLargerThanXl] = useAtom(isDeviceLargerThanXlAtom);
+
+  useEffect(() => {
+    if (isClient()) {
+      const xlOrAboveHandler = function(this: MediaQueryList): void {
+        // lg -> xl: matches will be true
+        // xl -> lg: matches will be false
+        setIsLargerThanXl(this.matches);
+      };
+      const mql = addBreakpointListener(Breakpoint.XL, xlOrAboveHandler);
+
+      // initialize
+      setIsLargerThanXl(mql.matches);
+
+      return () => {
+        cleanupBreakpointListener(mql, xlOrAboveHandler);
+      };
+    }
+    return undefined;
+  }, [setIsLargerThanXl]);
+
+  return [isLargerThanXl, setIsLargerThanXl] as const;
+};
+
+
+const editorModeAtom = atom<EditorMode>(EditorMode.View);
+
+export const useEditorModeState = () => {
+  return useAtom(editorModeAtom);
+};
+
+
+// Sidebar mode atom
+const sidebarModeAtom = atom(
+  (get) => {
+    const isDeviceLargerThanXl = get(isDeviceLargerThanXlAtom);
+    const editorMode = get(editorModeAtom);
+    const isCollapsedModeUnderDockMode = get(preferCollapsedModeAtom);
+
+    if (!isDeviceLargerThanXl) {
+      return SidebarMode.DRAWER;
+    }
+    return (editorMode === EditorMode.Editor || isCollapsedModeUnderDockMode)
+      ? SidebarMode.COLLAPSED
+      : SidebarMode.DOCK;
+  },
+);
+
+type DetectSidebarModeUtils = {
+  isDrawerMode(): boolean
+  isCollapsedMode(): boolean
+  isDockMode(): boolean
+}
+
+export const useSidebarMode = (): { sidebarMode: SidebarMode } & DetectSidebarModeUtils => {
+  const [sidebarMode] = useAtom(sidebarModeAtom);
+
+  const isDrawerMode = () => sidebarMode === SidebarMode.DRAWER;
+  const isCollapsedMode = () => sidebarMode === SidebarMode.COLLAPSED;
+  const isDockMode = () => sidebarMode === SidebarMode.DOCK;
+
+  return {
+    sidebarMode,
+    isDrawerMode,
+    isCollapsedMode,
+    isDockMode,
+  };
+};

+ 0 - 72
apps/app/src/stores/ui.tsx

@@ -20,7 +20,6 @@ import { scheduleToPut } from '~/client/services/user-ui-settings';
 import type { IPageSelectedGrant } from '~/interfaces/page';
 import { SidebarContentsType, SidebarMode } from '~/interfaces/ui';
 import type { UpdateDescCountData } from '~/interfaces/websocket';
-import { usePreferCollapsedMode } from '~/states/ui';
 import {
   useIsEditable, useIsReadOnlyUser,
   useIsSharedUser, useIsIdenticalPath, useCurrentUser, useShareLinkId,
@@ -148,34 +147,6 @@ export const useIsDeviceLargerThanLg = (): SWRResponse<boolean, Error> => {
   return useSWRStatic(key);
 };
 
-export const useIsDeviceLargerThanXl = (): SWRResponse<boolean, Error> => {
-  const key: Key = isClient() ? 'isDeviceLargerThanXl' : null;
-
-  const { cache, mutate } = useSWRConfig();
-
-  useEffect(() => {
-    if (key != null) {
-      const xlOrAvobeHandler = function(this: MediaQueryList): void {
-        // lg -> xl: matches will be true
-        // xl -> lg: matches will be false
-        mutate(key, this.matches);
-      };
-      const mql = addBreakpointListener(Breakpoint.XL, xlOrAvobeHandler);
-
-      // initialize
-      if (cache.get(key)?.data == null) {
-        cache.set(key, { ...cache.get(key), data: mql.matches });
-      }
-
-      return () => {
-        cleanupBreakpointListener(mql, xlOrAvobeHandler);
-      };
-    }
-  }, [cache, key, mutate]);
-
-  return useSWRStatic(key);
-};
-
 
 type MutateAndSaveUserUISettings<Data> = (data: Data, opts?: boolean | MutatorOptions<Data>) => Promise<Data | undefined>;
 type MutateAndSaveUserUISettingsUtils<Data> = {
@@ -218,49 +189,6 @@ export const useCollapsedContentsOpened = (initialData?: boolean): SWRResponse<b
   return useSWRStatic('isCollapsedContentsOpened', initialData, { fallbackData: false });
 };
 
-type DetectSidebarModeUtils = {
-  isDrawerMode(): boolean
-  isCollapsedMode(): boolean
-  isDockMode(): boolean
-}
-
-export const useSidebarMode = (): SWRResponseWithUtils<DetectSidebarModeUtils, SidebarMode> => {
-  const { data: isDeviceLargerThanXl } = useIsDeviceLargerThanXl();
-  const { data: editorMode } = useEditorMode();
-  const [isCollapsedModeUnderDockMode] = usePreferCollapsedMode();
-
-  const condition = isDeviceLargerThanXl != null && editorMode != null && isCollapsedModeUnderDockMode != null;
-
-  const isEditorMode = editorMode === EditorMode.Editor;
-
-  const fetcher = useCallback((
-      [, isDeviceLargerThanXl, isEditorMode]: [Key, boolean | undefined, boolean | undefined, boolean|undefined],
-  ): SidebarMode => {
-    if (!isDeviceLargerThanXl) {
-      return SidebarMode.DRAWER;
-    }
-    return (isEditorMode || isCollapsedModeUnderDockMode) ? SidebarMode.COLLAPSED : SidebarMode.DOCK;
-  }, [isCollapsedModeUnderDockMode]);
-
-  const swrResponse = useSWRImmutable(
-    condition ? ['sidebarMode', isDeviceLargerThanXl, isEditorMode, isCollapsedModeUnderDockMode] : null,
-    // calcDrawerMode,
-    fetcher,
-    { fallbackData: fetcher(['sidebarMode', isDeviceLargerThanXl, isEditorMode, isCollapsedModeUnderDockMode]) },
-  );
-
-  const _isDrawerMode = useCallback(() => swrResponse.data === SidebarMode.DRAWER, [swrResponse.data]);
-  const _isCollapsedMode = useCallback(() => swrResponse.data === SidebarMode.COLLAPSED, [swrResponse.data]);
-  const _isDockMode = useCallback(() => swrResponse.data === SidebarMode.DOCK, [swrResponse.data]);
-
-  return {
-    ...swrResponse,
-    isDrawerMode: _isDrawerMode,
-    isCollapsedMode: _isCollapsedMode,
-    isDockMode: _isDockMode,
-  };
-};
-
 export const useSelectedGrant = (initialData?: Nullable<IPageSelectedGrant>): SWRResponse<Nullable<IPageSelectedGrant>, Error> => {
   return useSWRStatic<Nullable<IPageSelectedGrant>, Error>('selectedGrant', initialData, { fallbackData: { grant: PageGrant.GRANT_PUBLIC } });
 };