Browse Source

refactor hooks to detect changing device size

Yuki Takei 2 years ago
parent
commit
24f7085779

+ 3 - 3
apps/app/src/components/Navbar/GrowiNavbarBottom.tsx

@@ -3,7 +3,7 @@ import React from 'react';
 import { useIsSearchPage } from '~/stores/context';
 import { usePageCreateModal } from '~/stores/modal';
 import { useCurrentPagePath } from '~/stores/page';
-import { useIsDeviceSmallerThanMd, useDrawerOpened } from '~/stores/ui';
+import { useIsDeviceLargerThanMd, useDrawerOpened } from '~/stores/ui';
 
 import { GlobalSearch } from './GlobalSearch';
 
@@ -13,7 +13,7 @@ import styles from './GrowiNavbarBottom.module.scss';
 export const GrowiNavbarBottom = (): JSX.Element => {
 
   const { data: isDrawerOpened, mutate: mutateDrawerOpened } = useDrawerOpened();
-  const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
+  const { data: isDeviceLargerThanMd } = useIsDeviceLargerThanMd();
   const { open: openCreateModal } = usePageCreateModal();
   const { data: currentPagePath } = useCurrentPagePath();
   const { data: isSearchPage } = useIsSearchPage();
@@ -26,7 +26,7 @@ export const GrowiNavbarBottom = (): JSX.Element => {
   return (
     <div className="d-md-none d-edit-none fixed-bottom">
 
-      { isDeviceSmallerThanMd && !isSearchPage && (
+      { !isDeviceLargerThanMd && !isSearchPage && (
         <div id="grw-global-search-collapse" className="grw-global-search collapse bg-dark">
           <div className="p-3">
             <GlobalSearch dropup />

+ 11 - 10
apps/app/src/components/Navbar/PageEditorModeManager.module.scss

@@ -7,11 +7,12 @@
     --bs-btn-font-size: 13px;
     --bs-btn-border-width: 2px;
 
-    width: 70px;
-    height: 30px;
-    @include bs.media-breakpoint-down(md) {
-      width: 90px;
-      height: 38px;
+    width: 90px;
+    height: 38px;
+
+    @include bs.media-breakpoint-up(md) {
+      width: 70px;
+      height: 30px;
     }
 
     @include mixins.border-vertical('before', 70%, 1, true);
@@ -19,11 +20,11 @@
 }
 
 .grw-page-editor-mode-manager-skeleton :global {
-  width: 179px;
-  height: 30px;
-  @include bs.media-breakpoint-down(md) {
-    width: 90px;
-    height: 38px;
+  width: 90px;
+  height: 38px;
+  @include bs.media-breakpoint-up(md) {
+    width: 179px;
+    height: 30px;
   }
 }
 

+ 4 - 4
apps/app/src/components/Navbar/PageEditorModeManager.tsx

@@ -2,7 +2,7 @@ import React, { type ReactNode, useCallback, useState } from 'react';
 
 import { useTranslation } from 'next-i18next';
 
-import { EditorMode, useIsDeviceSmallerThanMd } from '~/stores/ui';
+import { EditorMode, useIsDeviceLargerThanMd } from '~/stores/ui';
 
 import { useOnPageEditorModeButtonClicked } from './hooks';
 
@@ -61,7 +61,7 @@ export const PageEditorModeManager = (props: Props): JSX.Element => {
   const { t } = useTranslation();
   const [isCreating, setIsCreating] = useState(false);
 
-  const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
+  const { data: isDeviceLargerThanMd } = useIsDeviceLargerThanMd();
 
   const onPageEditorModeButtonClicked = useOnPageEditorModeButtonClicked(setIsCreating, path, grant, grantUserGroupId);
   const _isBtnDisabled = isCreating || isBtnDisabled;
@@ -82,7 +82,7 @@ export const PageEditorModeManager = (props: Props): JSX.Element => {
         aria-label="page-editor-mode-manager"
         id="grw-page-editor-mode-manager"
       >
-        {(!isDeviceSmallerThanMd || editorMode !== EditorMode.View) && (
+        {(isDeviceLargerThanMd || editorMode !== EditorMode.View) && (
           <PageEditorModeButton
             currentEditorMode={editorMode}
             editorMode={EditorMode.View}
@@ -92,7 +92,7 @@ export const PageEditorModeManager = (props: Props): JSX.Element => {
             <span className="material-symbols-outlined fs-4">play_arrow</span>{t('View')}
           </PageEditorModeButton>
         )}
-        {(!isDeviceSmallerThanMd || editorMode === EditorMode.View) && (
+        {(isDeviceLargerThanMd || editorMode === EditorMode.View) && (
           <PageEditorModeButton
             currentEditorMode={editorMode}
             editorMode={EditorMode.Editor}

+ 7 - 18
apps/app/src/components/PageEditor/EditorNavbarBottom.tsx

@@ -9,7 +9,7 @@ import { useIsSlackConfigured } from '~/stores/context';
 import { useSWRxSlackChannels, useIsSlackEnabled } from '~/stores/editor';
 import { useCurrentPagePath } from '~/stores/page';
 import {
-  useDrawerOpened, useEditorMode, useIsDeviceSmallerThanMd,
+  useDrawerOpened, useEditorMode, useIsDeviceLargerThanLg, useIsDeviceLargerThanMd,
 } from '~/stores/ui';
 
 
@@ -31,8 +31,8 @@ const EditorNavbarBottom = (): JSX.Element => {
 
   const { data: editorMode } = useEditorMode();
   const { data: isSlackConfigured } = useIsSlackConfigured();
-  const { mutate: mutateDrawerOpened } = useDrawerOpened();
-  const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
+  const { data: isDeviceLargerThanMd } = useIsDeviceLargerThanMd();
+  const { data: isDeviceLargerThanLg } = useIsDeviceLargerThanLg();
   const { data: currentPagePath } = useCurrentPagePath();
   const { data: slackChannelsData } = useSWRxSlackChannels(currentPagePath);
 
@@ -58,16 +58,6 @@ const EditorNavbarBottom = (): JSX.Element => {
   }, []);
 
 
-  const renderDrawerButton = () => (
-    <button
-      type="button"
-      className="btn btn-outline-secondary border-0"
-      onClick={() => mutateDrawerOpened(true)}
-    >
-      <i className="icon-menu"></i>
-    </button>
-  );
-
   const renderExpandButton = () => (
     <div className="d-md-none ms-2">
       <button
@@ -80,13 +70,13 @@ const EditorNavbarBottom = (): JSX.Element => {
     </div>
   );
 
-  const isCollapsedOptionsSelectorEnabled = isDeviceSmallerThanMd;
+  const isCollapsedOptionsSelectorEnabled = !isDeviceLargerThanLg;
 
   return (
     <div className={`${isCollapsedOptionsSelectorEnabled ? 'fixed-bottom' : ''} `}>
       {/* Collapsed SlackNotification */}
       {isSlackConfigured && (
-        <Collapse isOpen={isSlackExpanded && isDeviceSmallerThanMd === true}>
+        <Collapse isOpen={isSlackExpanded && !isDeviceLargerThanLg}>
           <nav className={`navbar navbar-expand-lg border-top ${moduleClass}`}>
             {isSlackEnabled != null
             && (
@@ -105,13 +95,12 @@ const EditorNavbarBottom = (): JSX.Element => {
       }
       <div className={`flex-expand-horiz align-items-center border-top px-2 px-md-3 ${moduleClass}`}>
         <form>
-          { isDeviceSmallerThanMd && renderDrawerButton() }
-          { !isDeviceSmallerThanMd && <OptionsSelector /> }
+          { isDeviceLargerThanMd && <OptionsSelector /> }
         </form>
         <form className="flex-nowrap ms-auto">
           {/* Responsive Design for the SlackNotification */}
           {/* Button or the normal Slack banner */}
-          {isSlackConfigured && (isDeviceSmallerThanMd ? (
+          {isSlackConfigured && (!isDeviceLargerThanMd ? (
             <Button
               className="grw-btn-slack border me-2"
               onClick={() => (setSlackExpanded(!isSlackExpanded))}

+ 6 - 6
apps/app/src/components/PageList/PageListItemL.tsx

@@ -28,7 +28,7 @@ import { useSWRMUTxCurrentUserBookmarks } from '~/stores/bookmark';
 import {
   usePageRenameModal, usePageDuplicateModal, usePageDeleteModal, usePutBackPageModal,
 } from '~/stores/modal';
-import { useIsDeviceSmallerThanLg } from '~/stores/ui';
+import { useIsDeviceLargerThanLg } from '~/stores/ui';
 
 import { useSWRMUTxPageInfo, useSWRxPageInfo } from '../../stores/page';
 import { ForceHideMenuItems, PageItemControl } from '../Common/Dropdown/PageItemControl';
@@ -82,7 +82,7 @@ const PageListItemLSubstance: ForwardRefRenderFunction<ISelectable, Props> = (pr
     },
   }));
 
-  const { data: isDeviceSmallerThanLg } = useIsDeviceSmallerThanLg();
+  const { data: isDeviceLargerThanLg } = useIsDeviceLargerThanLg();
   const { open: openDuplicateModal } = usePageDuplicateModal();
   const { open: openRenameModal } = usePageRenameModal();
   const { open: openDeleteModal } = usePageDeleteModal();
@@ -116,14 +116,14 @@ const PageListItemLSubstance: ForwardRefRenderFunction<ISelectable, Props> = (pr
   // click event handler
   const clickHandler = useCallback(() => {
     // do nothing if mobile
-    if (isDeviceSmallerThanLg) {
+    if (!isDeviceLargerThanLg) {
       return;
     }
 
     if (onClickItem != null) {
       onClickItem(pageData._id);
     }
-  }, [isDeviceSmallerThanLg, onClickItem, pageData._id]);
+  }, [isDeviceLargerThanLg, onClickItem, pageData._id]);
 
   const bookmarkMenuItemClickHandler = async(_pageId: string, _newValue: boolean): Promise<void> => {
     const bookmarkOperation = _newValue ? bookmark : unbookmark;
@@ -173,9 +173,9 @@ const PageListItemLSubstance: ForwardRefRenderFunction<ISelectable, Props> = (pr
     openPutBackPageModal({ pageId, path }, { onPutBacked: putBackedHandler });
   }, [onPagePutBacked, openPutBackPageModal, pageData]);
 
-  const styleListGroupItem = (!isDeviceSmallerThanLg && onClickItem != null) ? 'list-group-item-action' : '';
+  const styleListGroupItem = (isDeviceLargerThanLg && onClickItem != null) ? 'list-group-item-action' : '';
   // background color of list item changes when class "active" exists under 'list-group-item'
-  const styleActive = !isDeviceSmallerThanLg && isSelected ? 'active' : '';
+  const styleActive = isDeviceLargerThanLg && isSelected ? 'active' : '';
 
   const shouldDangerouslySetInnerHTMLForPaths = elasticSearchResult != null && elasticSearchResult.highlightedPath != null;
 

+ 1 - 5
apps/app/src/components/Sidebar/AppTitle/AppTitle.module.scss

@@ -29,7 +29,7 @@
 .on-subnavigation {
   top: 0;
 
-  @include bs.media-breakpoint-up(sm) {
+  @include bs.media-breakpoint-up(md) {
     left: var.$grw-sidebar-nav-width;
   }
 }
@@ -44,10 +44,6 @@
   $gap: 8px;
   width: calc(100vw - #{$grw-page-controls-width + $grw-page-editor-mode-manager-width + $grw-contextual-subnavigation-padding-right + $gap * 2});
 
-  @include bs.media-breakpoint-up(sm) {
-    width: calc(100vw - #{var.$grw-sidebar-nav-width + $grw-page-controls-width + $grw-page-editor-mode-manager-width + $grw-contextual-subnavigation-padding-right + $gap * 2});
-  }
-
   @include bs.media-breakpoint-up(md) {
     $grw-page-editor-mode-manager-width: 140px;
     $gap: 24px;

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

@@ -191,7 +191,7 @@ export const Sidebar = (): JSX.Element => {
   return (
     <>
       { sidebarMode != null && isDrawerMode() && (
-        <DrawerToggler className="position-fixed d-none d-sm-block">
+        <DrawerToggler className="position-fixed d-none d-md-block">
           <span className="material-symbols-outlined">reorder</span>
         </DrawerToggler>
       ) }

+ 44 - 16
apps/app/src/stores/ui.tsx

@@ -166,8 +166,8 @@ export const useEditorMode = (): SWRResponseWithUtils<EditorModeUtils, EditorMod
   });
 };
 
-export const useIsDeviceSmallerThanMd = (): SWRResponse<boolean, Error> => {
-  const key: Key = isClient() ? 'isDeviceSmallerThanMd' : null;
+export const useIsDeviceLargerThanMd = (): SWRResponse<boolean, Error> => {
+  const key: Key = isClient() ? 'isDeviceLargerThanMd' : null;
 
   const { cache, mutate } = useSWRConfig();
 
@@ -176,13 +176,13 @@ export const useIsDeviceSmallerThanMd = (): SWRResponse<boolean, Error> => {
       const mdOrAvobeHandler = function(this: MediaQueryList): void {
         // sm -> md: matches will be true
         // md -> sm: matches will be false
-        mutate(key, !this.matches);
+        mutate(key, this.matches);
       };
       const mql = addBreakpointListener(Breakpoint.MD, mdOrAvobeHandler);
 
       // initialize
       if (cache.get(key)?.data == null) {
-        cache.set(key, { ...cache.get(key), data: !mql.matches });
+        cache.set(key, { ...cache.get(key), data: mql.matches });
       }
 
       return () => {
@@ -191,11 +191,11 @@ export const useIsDeviceSmallerThanMd = (): SWRResponse<boolean, Error> => {
     }
   }, [cache, key, mutate]);
 
-  return useStaticSWR(key);
+  return useSWRStatic(key);
 };
 
-export const useIsDeviceSmallerThanLg = (): SWRResponse<boolean, Error> => {
-  const key: Key = isClient() ? 'isDeviceSmallerThanLg' : null;
+export const useIsDeviceLargerThanLg = (): SWRResponse<boolean, Error> => {
+  const key: Key = isClient() ? 'isDeviceLargerThanLg' : null;
 
   const { cache, mutate } = useSWRConfig();
 
@@ -204,13 +204,13 @@ export const useIsDeviceSmallerThanLg = (): SWRResponse<boolean, Error> => {
       const lgOrAvobeHandler = function(this: MediaQueryList): void {
         // md -> lg: matches will be true
         // lg -> md: matches will be false
-        mutate(key, !this.matches);
+        mutate(key, this.matches);
       };
       const mql = addBreakpointListener(Breakpoint.LG, lgOrAvobeHandler);
 
       // initialize
       if (cache.get(key)?.data == null) {
-        cache.set(key, { ...cache.get(key), data: !mql.matches });
+        cache.set(key, { ...cache.get(key), data: mql.matches });
       }
 
       return () => {
@@ -219,7 +219,35 @@ export const useIsDeviceSmallerThanLg = (): SWRResponse<boolean, Error> => {
     }
   }, [cache, key, mutate]);
 
-  return useStaticSWR(key);
+  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);
 };
 
 
@@ -250,28 +278,28 @@ type DetectSidebarModeUtils = {
 }
 
 export const useSidebarMode = (): SWRResponseWithUtils<DetectSidebarModeUtils, SidebarMode> => {
-  const { data: isDeviceSmallerThanLg } = useIsDeviceSmallerThanLg();
+  const { data: isDeviceLargerThanXl } = useIsDeviceLargerThanXl();
   const { data: editorMode } = useEditorMode();
   const { data: isCollapsedModeUnderDockMode } = usePreferCollapsedMode();
 
-  const condition = isDeviceSmallerThanLg != null && editorMode != null && isCollapsedModeUnderDockMode != null;
+  const condition = isDeviceLargerThanXl != null && editorMode != null && isCollapsedModeUnderDockMode != null;
 
   const isEditorMode = editorMode === EditorMode.Editor;
 
   const fetcher = useCallback((
-      [, isDeviceSmallerThanLg, isEditorMode, isCollapsedModeUnderDockMode]: [Key, boolean|undefined, boolean|undefined, boolean|undefined],
+      [, isDeviceLargerThanXl, isEditorMode, isCollapsedModeUnderDockMode]: [Key, boolean|undefined, boolean|undefined, boolean|undefined],
   ) => {
-    if (isDeviceSmallerThanLg) {
+    if (!isDeviceLargerThanXl) {
       return SidebarMode.DRAWER;
     }
     return isEditorMode || isCollapsedModeUnderDockMode ? SidebarMode.COLLAPSED : SidebarMode.DOCK;
   }, []);
 
   const swrResponse = useSWRImmutable(
-    condition ? ['sidebarMode', isDeviceSmallerThanLg, isEditorMode, isCollapsedModeUnderDockMode] : null,
+    condition ? ['sidebarMode', isDeviceLargerThanXl, isEditorMode, isCollapsedModeUnderDockMode] : null,
     // calcDrawerMode,
     fetcher,
-    { fallbackData: fetcher(['sidebarMode', isDeviceSmallerThanLg, isEditorMode, isCollapsedModeUnderDockMode]) },
+    { fallbackData: fetcher(['sidebarMode', isDeviceLargerThanXl, isEditorMode, isCollapsedModeUnderDockMode]) },
   );
 
   const _isDrawerMode = useCallback(() => swrResponse.data === SidebarMode.DRAWER, [swrResponse.data]);