Просмотр исходного кода

Merge pull request #4670 from weseek/feat/enable-drawer-mode

feat: Enable drawer mode
Yuki Takei 4 лет назад
Родитель
Сommit
31b8a3193e

+ 12 - 0
packages/app/src/client/services/ContextExtractor.tsx

@@ -7,6 +7,9 @@ import {
   usePageId, usePageIdOnHackmd, usePageUser, useCurrentPagePath, useRevisionCreatedAt, useRevisionId, useRevisionIdHackmdSynced,
   usePageId, usePageIdOnHackmd, usePageUser, useCurrentPagePath, useRevisionCreatedAt, useRevisionId, useRevisionIdHackmdSynced,
   useShareLinkId, useShareLinksNumber, useTemplateTagData, useUpdatedAt, useCreator, useRevisionAuthor, useCurrentUser,
   useShareLinkId, useShareLinksNumber, useTemplateTagData, useUpdatedAt, useCreator, useRevisionAuthor, useCurrentUser,
 } from '../../stores/context';
 } from '../../stores/context';
+import {
+  useEditorMode, useIsDeviceSmallerThanMd, usePreferDrawerModeByUser, usePreferDrawerModeOnEditByUser,
+} from '~/stores/ui';
 
 
 const { isTrashPage: _isTrashPage } = pagePathUtils;
 const { isTrashPage: _isTrashPage } = pagePathUtils;
 
 
@@ -54,7 +57,16 @@ const ContextExtractor: FC = () => {
   /*
   /*
    * use static swr
    * use static swr
    */
    */
+  // App
   useCurrentUser(currentUser);
   useCurrentUser(currentUser);
+
+  // Navigation
+  useEditorMode();
+  usePreferDrawerModeByUser();
+  usePreferDrawerModeOnEditByUser();
+  useIsDeviceSmallerThanMd();
+
+  // Page
   useCreatedAt(createdAt);
   useCreatedAt(createdAt);
   useDeleteUsername(deleteUsername);
   useDeleteUsername(deleteUsername);
   useDeletedAt(deletedAt);
   useDeletedAt(deletedAt);

+ 8 - 5
packages/app/src/components/Navbar/PersonalDropdown.jsx

@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useCallback } from 'react';
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';
 
 
 import { withTranslation } from 'react-i18next';
 import { withTranslation } from 'react-i18next';
@@ -9,6 +9,7 @@ import { UserPicture } from '@growi/ui';
 import { withUnstatedContainers } from '../UnstatedUtils';
 import { withUnstatedContainers } from '../UnstatedUtils';
 import AppContainer from '~/client/services/AppContainer';
 import AppContainer from '~/client/services/AppContainer';
 import NavigationContainer from '~/client/services/NavigationContainer';
 import NavigationContainer from '~/client/services/NavigationContainer';
+import { usePreferDrawerModeByUser } from '~/stores/ui';
 
 
 import {
 import {
   isUserPreferenceExists,
   isUserPreferenceExists,
@@ -34,6 +35,8 @@ const PersonalDropdown = (props) => {
   const [useOsSettings, setOsSettings] = useState(!isUserPreferenceExists());
   const [useOsSettings, setOsSettings] = useState(!isUserPreferenceExists());
   const [isDarkMode, setIsDarkMode] = useState(isDarkModeByUtil());
   const [isDarkMode, setIsDarkMode] = useState(isDarkModeByUtil());
 
 
+  const { data: isPreferDrawerMode, mutate: mutatePreferDrawerMode } = usePreferDrawerModeByUser();
+
   const logoutHandler = () => {
   const logoutHandler = () => {
     const { interceptorManager } = appContainer;
     const { interceptorManager } = appContainer;
 
 
@@ -46,9 +49,9 @@ const PersonalDropdown = (props) => {
     window.location.href = '/logout';
     window.location.href = '/logout';
   };
   };
 
 
-  const preferDrawerModeSwitchModifiedHandler = (bool) => {
-    navigationContainer.setDrawerModePreference(bool);
-  };
+  const preferDrawerModeSwitchModifiedHandler = useCallback((bool) => {
+    mutatePreferDrawerMode(bool);
+  }, [mutatePreferDrawerMode]);
 
 
   const preferDrawerModeOnEditSwitchModifiedHandler = (bool) => {
   const preferDrawerModeOnEditSwitchModifiedHandler = (bool) => {
     navigationContainer.setDrawerModePreferenceOnEdit(bool);
     navigationContainer.setDrawerModePreferenceOnEdit(bool);
@@ -144,7 +147,7 @@ const PersonalDropdown = (props) => {
                   id="swSidebarMode"
                   id="swSidebarMode"
                   className="custom-control-input"
                   className="custom-control-input"
                   type="checkbox"
                   type="checkbox"
-                  checked={!preferDrawerModeByUser}
+                  checked={!isPreferDrawerMode}
                   onChange={e => preferDrawerModeSwitchModifiedHandler(!e.target.checked)}
                   onChange={e => preferDrawerModeSwitchModifiedHandler(!e.target.checked)}
                 />
                 />
                 <label className="custom-control-label" htmlFor="swSidebarMode"></label>
                 <label className="custom-control-label" htmlFor="swSidebarMode"></label>

+ 1 - 1
packages/app/src/components/Sidebar.tsx

@@ -3,7 +3,7 @@ import React, {
 } from 'react';
 } from 'react';
 
 
 import {
 import {
-  useDrawerMode, useDrawerOpened, usePreferDrawerModeByUser,
+  useDrawerMode, useDrawerOpened,
   useSidebarCollapsed,
   useSidebarCollapsed,
   useCurrentSidebarContents,
   useCurrentSidebarContents,
   useCurrentProductNavWidth,
   useCurrentProductNavWidth,

+ 61 - 31
packages/app/src/stores/ui.tsx

@@ -1,5 +1,5 @@
-import {
-  useSWRConfig, SWRResponse, Key,
+import useSWR, {
+  useSWRConfig, SWRResponse, Key, Fetcher, Middleware, mutate, SWRConfig,
 } from 'swr';
 } from 'swr';
 import useSWRImmutable from 'swr/immutable';
 import useSWRImmutable from 'swr/immutable';
 
 
@@ -35,6 +35,16 @@ export type EditorMode = typeof EditorMode[keyof typeof EditorMode];
  *                      for switching UI
  *                      for switching UI
  *********************************************************** */
  *********************************************************** */
 
 
+export const useSWRxUserUISettings = (): SWRResponse<IUserUISettings, Error> => {
+  const key = isServer ? null : 'userUISettings';
+
+  return useSWRImmutable(
+    key,
+    () => apiv3Get<IUserUISettings>('/user-ui-settings').then(response => response.data),
+  );
+};
+
+
 export const useIsMobile = (): SWRResponse<boolean|null, Error> => {
 export const useIsMobile = (): SWRResponse<boolean|null, Error> => {
   const key = isServer ? null : 'isMobile';
   const key = isServer ? null : 'isMobile';
 
 
@@ -49,9 +59,31 @@ export const useIsMobile = (): SWRResponse<boolean|null, Error> => {
   return useStaticSWR(key, null, configuration);
   return useStaticSWR(key, null, configuration);
 };
 };
 
 
+// drawer mode keys
+const IS_DRAWER_MODE: Key = 'isDrawerMode';
+
+export const mutateDrawerMode: Middleware = (useSWRNext) => {
+  return (...args) => {
+    const { mutate } = useSWRConfig();
+    const swrNext = useSWRNext(...args);
+    return {
+      ...swrNext,
+      mutate: (data, shouldRevalidate) => {
+        return swrNext.mutate(data, shouldRevalidate)
+          .then((value) => {
+            mutate(IS_DRAWER_MODE); // mutate isDrawerMode
+            return value;
+          });
+      },
+    };
+  };
+};
+
 export const useEditorMode = (editorMode?: EditorMode): SWRResponse<EditorMode, Error> => {
 export const useEditorMode = (editorMode?: EditorMode): SWRResponse<EditorMode, Error> => {
+  const key: Key = 'editorMode';
   const initialData = EditorMode.View;
   const initialData = EditorMode.View;
-  return useStaticSWR('editorMode', editorMode || null, { fallbackData: initialData });
+
+  return useStaticSWR(key, editorMode || null, { fallbackData: initialData, use: [mutateDrawerMode] });
 };
 };
 
 
 export const useIsDeviceSmallerThanMd = (): SWRResponse<boolean|null, Error> => {
 export const useIsDeviceSmallerThanMd = (): SWRResponse<boolean|null, Error> => {
@@ -75,37 +107,50 @@ export const useIsDeviceSmallerThanMd = (): SWRResponse<boolean|null, Error> =>
     }
     }
   }
   }
 
 
-  return useStaticSWR(key);
+  return useStaticSWR(key, null, { use: [mutateDrawerMode] });
 };
 };
 
 
 export const usePreferDrawerModeByUser = (isPrefered?: boolean): SWRResponse<boolean, Error> => {
 export const usePreferDrawerModeByUser = (isPrefered?: boolean): SWRResponse<boolean, Error> => {
-  const key = isServer ? null : 'preferDrawerModeByUser';
+  const key: Key = isServer ? null : 'preferDrawerModeByUser';
+  const initialData = localStorage?.preferDrawerModeByUser === 'true';
 
 
-  const initialData = false;
-  return useStaticSWR(key, isPrefered || null, { fallbackData: initialData, use: [sessionStorageMiddleware] });
+  return useStaticSWR(key, isPrefered || null, { fallbackData: initialData, use: [mutateDrawerMode, sessionStorageMiddleware] });
 };
 };
 
 
 export const usePreferDrawerModeOnEditByUser = (isPrefered?: boolean): SWRResponse<boolean, Error> => {
 export const usePreferDrawerModeOnEditByUser = (isPrefered?: boolean): SWRResponse<boolean, Error> => {
-  const key = isServer ? null : 'preferDrawerModeOnEditByUser';
+  const key: Key = isServer ? null : 'preferDrawerModeOnEditByUser';
+  const initialData = localStorage?.preferDrawerModeOnEditByUser == null || localStorage?.preferDrawerModeOnEditByUser === 'true';
 
 
-  const initialData = true;
-  return useStaticSWR(key, isPrefered || null, { fallbackData: initialData, use: [sessionStorageMiddleware] });
+  return useStaticSWR(key, isPrefered || null, { fallbackData: initialData, use: [mutateDrawerMode, sessionStorageMiddleware] });
 };
 };
 
 
 export const useDrawerMode = (): SWRResponse<boolean, Error> => {
 export const useDrawerMode = (): SWRResponse<boolean, Error> => {
-  const key = isServer ? null : 'isDrawerMode';
-
   const { data: editorMode } = useEditorMode();
   const { data: editorMode } = useEditorMode();
   const { data: preferDrawerModeByUser } = usePreferDrawerModeByUser();
   const { data: preferDrawerModeByUser } = usePreferDrawerModeByUser();
   const { data: preferDrawerModeOnEditByUser } = usePreferDrawerModeOnEditByUser();
   const { data: preferDrawerModeOnEditByUser } = usePreferDrawerModeOnEditByUser();
   const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
   const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
 
 
-  // get preference on view or edit
-  const preferDrawerMode = editorMode !== EditorMode.View ? preferDrawerModeOnEditByUser : preferDrawerModeByUser;
+  const condition = editorMode != null || preferDrawerModeByUser != null || preferDrawerModeOnEditByUser != null || isDeviceSmallerThanMd != null;
+
+  const calcDrawerMode: Fetcher<boolean> = (
+      key: Key, editorMode: EditorMode, preferDrawerModeByUser: boolean, preferDrawerModeOnEditByUser: boolean, isDeviceSmallerThanMd: boolean,
+  ): boolean => {
+
+    // get preference on view or edit
+    const preferDrawerMode = editorMode !== EditorMode.View ? preferDrawerModeOnEditByUser : preferDrawerModeByUser;
 
 
-  const isDrawerMode = isDeviceSmallerThanMd || preferDrawerMode;
+    return isDeviceSmallerThanMd || preferDrawerMode;
+  };
 
 
-  return useStaticSWR(key, isDrawerMode || null);
+  return useSWR(
+    condition ? [IS_DRAWER_MODE, editorMode, preferDrawerModeByUser, preferDrawerModeOnEditByUser, isDeviceSmallerThanMd] : null,
+    calcDrawerMode,
+    {
+      fallback: calcDrawerMode,
+      revalidateOnFocus: false,
+      revalidateOnReconnect: false,
+    },
+  );
 };
 };
 
 
 export const useDrawerOpened = (isOpened?: boolean): SWRResponse<boolean, Error> => {
 export const useDrawerOpened = (isOpened?: boolean): SWRResponse<boolean, Error> => {
@@ -113,21 +158,6 @@ export const useDrawerOpened = (isOpened?: boolean): SWRResponse<boolean, Error>
   return useStaticSWR('isDrawerOpened', isOpened || null, { fallbackData: initialData });
   return useStaticSWR('isDrawerOpened', isOpened || null, { fallbackData: initialData });
 };
 };
 
 
-
-/** **********************************************************
- *                          SWR Hooks
- *                      for switching UI
- *********************************************************** */
-
-export const useSWRxUserUISettings = (): SWRResponse<IUserUISettings, Error> => {
-  const key = isServer ? null : 'userUISettings';
-
-  return useSWRImmutable(
-    key,
-    () => apiv3Get<IUserUISettings>('/user-ui-settings').then(response => response.data),
-  );
-};
-
 export const useSidebarCollapsed = (): SWRResponse<boolean, Error> => {
 export const useSidebarCollapsed = (): SWRResponse<boolean, Error> => {
   const { data } = useSWRxUserUISettings();
   const { data } = useSWRxUserUISettings();
   const key = data === undefined ? null : 'isSidebarCollapsed';
   const key = data === undefined ? null : 'isSidebarCollapsed';