Răsfoiți Sursa

refactor DisplaySwitcher

Yuki Takei 3 ani în urmă
părinte
comite
a315dee17a

+ 37 - 0
packages/app/src/components/Common/LazyRenderer.tsx

@@ -0,0 +1,37 @@
+import React, { useEffect, useState } from 'react';
+
+type Props = {
+  shouldRender: boolean | (() => boolean),
+  children: JSX.Element,
+}
+
+export const LazyRenderer = (props: Props): JSX.Element => {
+  const { shouldRender: _shouldRender, children } = props;
+
+  const [isActivated, setActivated] = useState(false);
+
+  const shouldRender = typeof _shouldRender === 'function'
+    ? _shouldRender()
+    : _shouldRender;
+
+  useEffect(() => {
+    if (isActivated) {
+      return;
+    }
+    setActivated(shouldRender);
+  }, [isActivated, shouldRender]);
+
+  const additionalClassName = shouldRender ? '' : 'd-none';
+
+  if (!isActivated) {
+    return <></>;
+  }
+
+  return (
+    <>
+      { React.cloneElement(children, {
+        className: `${children.props.className ?? ''} ${additionalClassName}`,
+      }) }
+    </>
+  );
+};

+ 13 - 36
packages/app/src/components/Page/DisplaySwitcher.tsx

@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import React from 'react';
 
 import { type IPagePopulatedToShowRevision, pagePathUtils } from '@growi/core';
 import dynamic from 'next/dynamic';
@@ -10,7 +10,7 @@ import { usePageUpdatedEffect } from '~/client/services/event-listeners/page-upd
 import { useIsEditable } from '~/stores/context';
 import { EditorMode, useEditorMode } from '~/stores/ui';
 
-import CustomTabContent from '../CustomNavigation/CustomTabContent';
+import { LazyRenderer } from '../Common/LazyRenderer';
 import { MainPane } from '../Layout/MainPane';
 import { Page } from '../Page';
 import { PageAlerts } from '../PageAlert/PageAlerts';
@@ -105,44 +105,21 @@ export const DisplaySwitcher = (props: Props): JSX.Element => {
 
   const isViewMode = editorMode === EditorMode.View;
 
-  const view = useMemo(() => <View {...props} />, [props]);
-  const editor = useMemo(() => {
-    return isEditable
-      ? (
-        <div data-testid="page-editor" id="page-editor">
+  return (
+    <>
+      { isViewMode && <View {...props} /> }
+
+      <LazyRenderer shouldRender={isEditable === true && editorMode === EditorMode.Editor}>
+        <div data-testid="page-editor" id="page-editor" className="editor-root">
           <PageEditor />
         </div>
-      )
-      : <></>;
-  }, [isEditable]);
-  const hackmd = useMemo(() => {
-    return isEditable
-      ? (
-        <div id="page-editor-with-hackmd">
+      </LazyRenderer>
+
+      <LazyRenderer shouldRender={isEditable === true && editorMode === EditorMode.HackMD}>
+        <div id="page-editor-with-hackmd" className="editor-root">
           <PageEditorByHackmd />
         </div>
-      )
-      : <></>;
-  }, [isEditable]);
-
-  const navTabMapping = useMemo(() => {
-    return {
-      [EditorMode.View]: {
-        Content: () => view,
-      },
-      [EditorMode.Editor]: {
-        Content: () => editor,
-      },
-      [EditorMode.HackMD]: {
-        Content: () => hackmd,
-      },
-    };
-  }, [editor, hackmd, view]);
-
-
-  return (
-    <>
-      <CustomTabContent activeTab={editorMode} navTabMapping={navTabMapping} />
+      </LazyRenderer>
 
       { isEditable && !isViewMode && <EditorNavbarBottom /> }
     </>

+ 2 - 18
packages/app/src/pages/[[...path]].page.tsx

@@ -20,15 +20,8 @@ import { useRouter } from 'next/router';
 import superjson from 'superjson';
 
 import { useCurrentGrowiLayoutFluidClassName } from '~/client/services/layout';
-import { MainPane } from '~/components/Layout/MainPane';
-import { PageAlerts } from '~/components/PageAlert/PageAlerts';
-// import { useTranslation } from '~/i18n';
 import { DrawioViewerScript } from '~/components/Script/DrawioViewerScript';
-import { UsersHomePageFooterProps } from '~/components/UsersHomePageFooter';
 import type { CrowiRequest } from '~/interfaces/crowi-request';
-// import { renderScriptTagByName, renderHighlightJsStyleTag } from '~/service/cdn-resources-loader';
-// import { useRendererSettings } from '~/stores/renderer';
-// import { EditorMode, useEditorMode, useIsMobile } from '~/stores/ui';
 import type { EditorConfig } from '~/interfaces/editor-settings';
 import { IPageGrantData } from '~/interfaces/page';
 import type { RendererConfig } from '~/interfaces/services/renderer';
@@ -49,17 +42,10 @@ import {
 import { useSetupGlobalSocket, useSetupGlobalSocketForPage } from '~/stores/websocket';
 import loggerFactory from '~/utils/logger';
 
-// import { isUserPage, isTrashPage, isSharedPage } from '~/utils/path-utils';
-
-// import GrowiSubNavigation from '../client/js/components/Navbar/GrowiSubNavigation';
-// import GrowiSubNavigationSwitcher from '../client/js/components/Navbar/GrowiSubNavigationSwitcher';
 import { DescendantsPageListModal } from '../components/DescendantsPageListModal';
 import { BasicLayoutWithEditorMode } from '../components/Layout/BasicLayout';
 import GrowiContextualSubNavigationSubstance from '../components/Navbar/GrowiContextualSubNavigation';
 import { DisplaySwitcher } from '../components/Page/DisplaySwitcher';
-// import { serializeUserSecurely } from '../server/models/serializers/user-serializer';
-// import PageStatusAlert from '../client/js/components/PageStatusAlert';
-import type { PageSideContentsProps } from '../components/PageSideContents';
 import {
   useCurrentUser,
   useIsLatestRevision,
@@ -95,7 +81,7 @@ const PageStatusAlert = dynamic(() => import('../components/PageStatusAlert').th
 const logger = loggerFactory('growi:pages:all');
 
 const {
-  isPermalink: _isPermalink, isUsersHomePage, isTrashPage: _isTrashPage, isCreatablePage, isTopPage,
+  isPermalink: _isPermalink, isTrashPage: _isTrashPage, isCreatablePage,
 } = pagePathUtils;
 const { removeHeadingSlash } = pathUtils;
 
@@ -302,11 +288,8 @@ const Page: NextPageWithLayout<Props> = (props: Props) => {
     }
   }, [props.currentPathname, router]);
 
-  const isTopPagePath = isTopPage(pageWithMeta?.data.path ?? '');
-
   const title = generateCustomTitleForPage(props, pagePath ?? '');
 
-
   return (
     <>
       <Head>
@@ -318,6 +301,7 @@ const Page: NextPageWithLayout<Props> = (props: Props) => {
             <GrowiContextualSubNavigation isLinkSharingDisabled={props.disableLinkSharing} />
           </div>
         </header>
+
         <div className="d-edit-none">
           <GrowiSubNavigationSwitcher />
         </div>

+ 28 - 50
packages/app/src/styles/_mixins.scss

@@ -24,63 +24,41 @@
     + 25px //   add .btn-open-dropzone height
     + 30px; //  add .navbar-editor height
 
-  .main {
+  .editor-root {
     width: 100%;
-    height: calc(100vh - #{$editor-margin-top});
+    height: calc(100vh - #{$header-plus-footer});
+    min-height: calc(100vh - #{$header-plus-footer}); // for IE11
     margin-top: 0px !important;
 
-    .grw-container-convertible {
-      max-width: unset;
-      padding: 0;
-      margin: 0;
-    }
+    // left(editor)
+    .page-editor-editor-container {
+      height: calc(100vh - #{$header-plus-footer});
+      min-height: calc(100vh - #{$header-plus-footer}); // for IE11
 
-    &,
-    .content-main,
-    .tab-content {
-      display: flex;
-      flex: 1;
-      flex-direction: column;
-
-      .tab-pane {
-        height: calc(100vh - #{$header-plus-footer});
-        min-height: calc(100vh - #{$header-plus-footer}); // for IE11
+      .react-codemirror2,
+      .CodeMirror,
+      .CodeMirror-scroll,
+      .textarea-editor {
+        height: calc(100vh - #{$editor-margin});
       }
+    }
 
-      #page-editor {
-        // right(preview)
-        &,
-        & > .row,
-        .page-editor-preview-container,
-        .page-editor-preview-body {
-          height: calc(100vh - #{$header-plus-footer});
-          min-height: calc(100vh - #{$header-plus-footer}); // for IE11
-        }
-
-        // left(editor)
-        .page-editor-editor-container {
-          height: calc(100vh - #{$header-plus-footer});
-          min-height: calc(100vh - #{$header-plus-footer}); // for IE11
-
-          .react-codemirror2,
-          .CodeMirror,
-          .CodeMirror-scroll,
-          .textarea-editor {
-            height: calc(100vh - #{$editor-margin});
-          }
-        }
-      }
+    // right(preview)
+    .page-editor-preview-container,
+    .page-editor-preview-body {
+      height: calc(100vh - #{$header-plus-footer});
+      min-height: calc(100vh - #{$header-plus-footer}); // for IE11
+    }
+  }
 
-      #page-editor-with-hackmd {
-        &,
-        .hackmd-preinit,
-        .hackmd-error,
-        #iframe-hackmd-container > iframe {
-          width: 100%;
-          height: calc(100vh - #{$header-plus-footer});
-          min-height: calc(100vh - #{$header-plus-footer}); // for IE11
-        }
-      }
+  .editor-root#page-editor-with-hackmd {
+    &,
+    .hackmd-preinit,
+    .hackmd-error,
+    #iframe-hackmd-container > iframe {
+      width: 100%;
+      height: calc(100vh - #{$header-plus-footer});
+      min-height: calc(100vh - #{$header-plus-footer}); // for IE11
     }
   }
 }