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

Merge pull request #6282 from weseek/feat/show-sidebar-drawer-mode

feat: Show sidebar drawer mode
Yohei Shiina 3 лет назад
Родитель
Сommit
4b42949b7c

+ 10 - 10
packages/app/src/components/Sidebar.module.scss

@@ -240,18 +240,18 @@
   }
   }
 }
 }
 
 
-// '&' could not be set after :global
-// workaround from https://github.com/css-modules/css-modules/issues/295#issuecomment-404873976
-.grw-sidebar :global {
-  .grw-sidebar-drawer {
-    @include drawer();
-  }
-  .grw-sidebar-dock {
-    @include bs.media-breakpoint-down(sm) {
+.grw-sidebar {
+  &:global {
+    &.grw-sidebar-drawer {
       @include drawer();
       @include drawer();
     }
     }
-    @include bs.media-breakpoint-up(md) {
-      @include dock();
+    &.grw-sidebar-dock {
+      @include bs.media-breakpoint-down(sm) {
+        @include drawer();
+      }
+      @include bs.media-breakpoint-up(md) {
+        @include dock();
+      }
     }
     }
   }
   }
 }
 }

+ 50 - 48
packages/app/src/components/Sidebar.tsx

@@ -88,8 +88,7 @@ const SidebarContentsWrapper = () => {
 
 
 const Sidebar = (): JSX.Element => {
 const Sidebar = (): JSX.Element => {
 
 
-  // const { data: isDrawerMode } = useDrawerMode(); Todo Universalize
-  const isDrawerMode = false; // dummy
+  const { data: isDrawerMode } = useDrawerMode();
   const { data: isDrawerOpened, mutate: mutateDrawerOpened } = useDrawerOpened();
   const { data: isDrawerOpened, mutate: mutateDrawerOpened } = useDrawerOpened();
   const { data: currentProductNavWidth, mutate: mutateProductNavWidth } = useCurrentProductNavWidth();
   const { data: currentProductNavWidth, mutate: mutateProductNavWidth } = useCurrentProductNavWidth();
   const { data: isCollapsed, mutate: mutateSidebarCollapsed } = useSidebarCollapsed();
   const { data: isCollapsed, mutate: mutateSidebarCollapsed } = useSidebarCollapsed();
@@ -287,58 +286,61 @@ const Sidebar = (): JSX.Element => {
 
 
   const showContents = isDrawerMode || isHover || !isCollapsed;
   const showContents = isDrawerMode || isHover || !isCollapsed;
 
 
+
+  // css styles
+  const grwSidebarClass = `grw-sidebar ${styles['grw-sidebar']}`;
+  const sidebarModeClass = `${isDrawerMode ? 'grw-sidebar-drawer' : 'grw-sidebar-dock'}`;
+  const isOpenClass = `${isDrawerOpened ? 'open' : ''}`;
   return (
   return (
     <>
     <>
-      <div className={`grw-sidebar ${styles['grw-sidebar']}`}>
-        <div className={`d-print-none ${isDrawerMode ? 'grw-sidebar-drawer' : 'grw-sidebar-dock'} ${isDrawerOpened ? 'open' : ''}`}>
-          <div className="data-layout-container">
-            <div
-              className='navigation transition-enabled'
-              onMouseEnter={hoverOnHandler}
-              onMouseLeave={hoverOutHandler}
-            >
-              <div className="grw-navigation-wrap">
-                <div className="grw-global-navigation">
-                  <GlobalNavigation></GlobalNavigation>
-                </div>
-                <div
-                  ref={resizableContainer}
-                  className="grw-contextual-navigation"
-                  onMouseEnter={hoverOnResizableContainerHandler}
-                  onMouseLeave={hoverOutResizableContainerHandler}
-                  style={{ width: isCollapsed ? sidebarMinimizeWidth : currentProductNavWidth }}
-                >
-                  <div className="grw-contextual-navigation-child">
-                    <div role="group" data-testid="grw-contextual-navigation-sub" className={`grw-contextual-navigation-sub ${showContents ? '' : 'd-none'}`}>
-                      <SidebarContentsWrapper></SidebarContentsWrapper>
-                    </div>
+      <div className={`${grwSidebarClass} ${sidebarModeClass} ${isOpenClass} d-print-none`}>
+        <div className="data-layout-container">
+          <div
+            className='navigation transition-enabled'
+            onMouseEnter={hoverOnHandler}
+            onMouseLeave={hoverOutHandler}
+          >
+            <div className="grw-navigation-wrap">
+              <div className="grw-global-navigation">
+                <GlobalNavigation></GlobalNavigation>
+              </div>
+              <div
+                ref={resizableContainer}
+                className="grw-contextual-navigation"
+                onMouseEnter={hoverOnResizableContainerHandler}
+                onMouseLeave={hoverOutResizableContainerHandler}
+                style={{ width: isCollapsed ? sidebarMinimizeWidth : currentProductNavWidth }}
+              >
+                <div className="grw-contextual-navigation-child">
+                  <div role="group" data-testid="grw-contextual-navigation-sub" className={`grw-contextual-navigation-sub ${showContents ? '' : 'd-none'}`}>
+                    <SidebarContentsWrapper></SidebarContentsWrapper>
                   </div>
                   </div>
                 </div>
                 </div>
               </div>
               </div>
-              <div className="grw-navigation-draggable">
-                { isResizableByDrag && (
-                  <div
-                    className="grw-navigation-draggable-hitarea"
-                    onMouseDown={dragableAreaMouseDownHandler}
-                  >
-                    <div className="grw-navigation-draggable-hitarea-child"></div>
-                  </div>
-                ) }
-                <button
-                  data-testid="grw-navigation-resize-button"
-                  className={`grw-navigation-resize-button ${!isDrawerMode ? 'resizable' : ''} ${isCollapsed ? 'collapsed' : ''} `}
-                  type="button"
-                  aria-expanded="true"
-                  aria-label="Toggle navigation"
-                  disabled={isDrawerMode}
-                  onClick={toggleNavigationBtnClickHandler}
+            </div>
+            <div className="grw-navigation-draggable">
+              { isResizableByDrag && (
+                <div
+                  className="grw-navigation-draggable-hitarea"
+                  onMouseDown={dragableAreaMouseDownHandler}
                 >
                 >
-                  <span className="hexagon-container" role="presentation">
-                    <NavigationResizeHexagon />
-                  </span>
-                  <span className="hitarea" role="presentation"></span>
-                </button>
-              </div>
+                  <div className="grw-navigation-draggable-hitarea-child"></div>
+                </div>
+              ) }
+              <button
+                data-testid="grw-navigation-resize-button"
+                className={`grw-navigation-resize-button ${!isDrawerMode ? 'resizable' : ''} ${isCollapsed ? 'collapsed' : ''} `}
+                type="button"
+                aria-expanded="true"
+                aria-label="Toggle navigation"
+                disabled={isDrawerMode}
+                onClick={toggleNavigationBtnClickHandler}
+              >
+                <span className="hexagon-container" role="presentation">
+                  <NavigationResizeHexagon />
+                </span>
+                <span className="hitarea" role="presentation"></span>
+              </button>
             </div>
             </div>
           </div>
           </div>
         </div>
         </div>

+ 3 - 5
packages/app/src/pages/[[...path]].page.tsx

@@ -255,10 +255,9 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
         <div id="grw-fav-sticky-trigger" className="sticky-top"></div>
         <div id="grw-fav-sticky-trigger" className="sticky-top"></div>
 
 
         <div id="main" className={`main ${isUsersHomePage(props.currentPathname) && 'user-page'}`}>
         <div id="main" className={`main ${isUsersHomePage(props.currentPathname) && 'user-page'}`}>
-
-          <div className="row">
-            <div className="col">
-              <div id="content-main" className="content-main grw-container-convertible">
+          <div id="content-main" className="content-main grw-container-convertible">
+            <div className="row">
+              <div className="col">
                 { props.isIdenticalPathPage && <IdenticalPathPage /> }
                 { props.isIdenticalPathPage && <IdenticalPathPage /> }
 
 
                 { !props.isIdenticalPathPage && (
                 { !props.isIdenticalPathPage && (
@@ -283,7 +282,6 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
               </div>
               </div>
             </div> */}
             </div> */}
           </div>
           </div>
-
         </div>
         </div>
         <footer>
         <footer>
           {/* <PageComments /> */}
           {/* <PageComments /> */}

+ 2 - 1
packages/app/src/server/crowi/express-init.js

@@ -122,7 +122,8 @@ module.exports = function(crowi, app) {
   });
   });
 
 
   // csurf should be initialized after express-session
   // csurf should be initialized after express-session
-  app.use(csrf({ cookie: false }));
+  // default methods + PUT. See: https://expressjs.com/en/resources/middleware/csurf.html#ignoremethods
+  app.use(csrf({ ignoreMethods: ['GET', 'HEAD', 'OPTIONS', 'PUT'], cookie: false }));
 
 
   // passport
   // passport
   debug('initialize Passport');
   debug('initialize Passport');

+ 15 - 8
packages/app/src/stores/ui.tsx

@@ -3,6 +3,7 @@ import { RefObject } from 'react';
 import {
 import {
   isClient, isServer, pagePathUtils, Nullable,
   isClient, isServer, pagePathUtils, Nullable,
 } from '@growi/core';
 } from '@growi/core';
+import { withUtils, SWRResponseWithUtils } from '@growi/core/src/utils/with-utils';
 import { Breakpoint, addBreakpointListener } from '@growi/ui';
 import { Breakpoint, addBreakpointListener } from '@growi/ui';
 import SimpleBar from 'simplebar-react';
 import SimpleBar from 'simplebar-react';
 import {
 import {
@@ -222,15 +223,13 @@ type PreferDrawerModeByUserUtils = {
   update: (preferDrawerMode: boolean) => void
   update: (preferDrawerMode: boolean) => void
 }
 }
 
 
-export const usePreferDrawerModeByUser = (initialData?: boolean): SWRResponse<boolean, Error> & PreferDrawerModeByUserUtils => {
+export const usePreferDrawerModeByUser = (initialData?: boolean): SWRResponseWithUtils<SWRResponse, PreferDrawerModeByUserUtils> => {
   const { data: isGuestUser } = useIsGuestUser();
   const { data: isGuestUser } = useIsGuestUser();
   const { scheduleToPut } = useUserUISettings();
   const { scheduleToPut } = useUserUISettings();
 
 
   const swrResponse: SWRResponse<boolean, Error> = useStaticSWR('preferDrawerModeByUser', initialData, { use: isGuestUser ? [localStorageMiddleware] : [] });
   const swrResponse: SWRResponse<boolean, Error> = useStaticSWR('preferDrawerModeByUser', initialData, { use: isGuestUser ? [localStorageMiddleware] : [] });
 
 
-  return {
-    ...swrResponse,
-    data: swrResponse.data,
+  const utils: PreferDrawerModeByUserUtils = {
     update: (preferDrawerMode: boolean) => {
     update: (preferDrawerMode: boolean) => {
       swrResponse.mutate(preferDrawerMode);
       swrResponse.mutate(preferDrawerMode);
 
 
@@ -239,6 +238,9 @@ export const usePreferDrawerModeByUser = (initialData?: boolean): SWRResponse<bo
       }
       }
     },
     },
   };
   };
+
+  return withUtils(swrResponse, utils);
+
 };
 };
 
 
 export const usePreferDrawerModeOnEditByUser = (initialData?: boolean): SWRResponse<boolean, Error> => {
 export const usePreferDrawerModeOnEditByUser = (initialData?: boolean): SWRResponse<boolean, Error> => {
@@ -258,9 +260,9 @@ export const useCurrentProductNavWidth = (initialData?: number): SWRResponse<num
 };
 };
 
 
 export const useDrawerMode = (): SWRResponse<boolean, Error> => {
 export const useDrawerMode = (): SWRResponse<boolean, Error> => {
-  const { data: editorMode } = useEditorMode();
   const { data: preferDrawerModeByUser } = usePreferDrawerModeByUser();
   const { data: preferDrawerModeByUser } = usePreferDrawerModeByUser();
   const { data: preferDrawerModeOnEditByUser } = usePreferDrawerModeOnEditByUser();
   const { data: preferDrawerModeOnEditByUser } = usePreferDrawerModeOnEditByUser();
+  const { data: editorMode } = useEditorMode();
   const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
   const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
 
 
   const condition = editorMode != null || preferDrawerModeByUser != null || preferDrawerModeOnEditByUser != null || isDeviceSmallerThanMd != null;
   const condition = editorMode != null || preferDrawerModeByUser != null || preferDrawerModeOnEditByUser != null || isDeviceSmallerThanMd != null;
@@ -275,12 +277,17 @@ export const useDrawerMode = (): SWRResponse<boolean, Error> => {
     return isDeviceSmallerThanMd || preferDrawerMode;
     return isDeviceSmallerThanMd || preferDrawerMode;
   };
   };
 
 
+  const isViewModeWithPreferDrawerMode = editorMode === EditorMode.View && preferDrawerModeByUser;
+  const isEditModeWithPreferDrawerMode = editorMode === EditorMode.Editor && preferDrawerModeOnEditByUser;
+  const useFallbackData = isViewModeWithPreferDrawerMode || isEditModeWithPreferDrawerMode;
+  const fallbackOption = useFallbackData
+    ? { fallbackData: true }
+    : { fallback: calcDrawerMode };
+
   return useSWRImmutable(
   return useSWRImmutable(
     condition ? ['isDrawerMode', editorMode, preferDrawerModeByUser, preferDrawerModeOnEditByUser, isDeviceSmallerThanMd] : null,
     condition ? ['isDrawerMode', editorMode, preferDrawerModeByUser, preferDrawerModeOnEditByUser, isDeviceSmallerThanMd] : null,
     calcDrawerMode,
     calcDrawerMode,
-    {
-      fallback: calcDrawerMode,
-    },
+    fallbackOption,
   );
   );
 };
 };
 
 

+ 7 - 0
packages/core/src/utils/with-utils.ts

@@ -0,0 +1,7 @@
+import { SWRResponse } from 'swr';
+
+export type SWRResponseWithUtils<R extends SWRResponse, U> = R & U;
+
+export const withUtils = <R extends SWRResponse, U>(response: R, utils: U): SWRResponseWithUtils<R, U> => {
+  return Object.assign(response, utils);
+};