Yuki Takei 4 лет назад
Родитель
Сommit
19a577a4da

+ 64 - 75
packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -13,17 +13,13 @@ import {
 } from '~/stores/context';
 import { useSWRTagsInfo } from '~/stores/page';
 
-import TagLabels from '../Page/TagLabels';
 import SubNavButtons from './SubNavButtons';
 import PageEditorModeManager from './PageEditorModeManager';
 
-import AuthorInfo from './AuthorInfo';
-import DrawerToggler from './DrawerToggler';
-
-import PagePathNav from '../PagePathNav';
-
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
 import { apiPost } from '~/client/util/apiv1-client';
+import { IPageHasId } from '~/interfaces/page';
+import { GrowiSubNavigation } from './GrowiSubNavigation';
 
 const GrowiContextualSubNavigation = (props) => {
   const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
@@ -45,20 +41,15 @@ const GrowiContextualSubNavigation = (props) => {
   const { data: isAbleToShowPageEditorModeManager } = useIsAbleToShowPageEditorModeManager();
   const { data: isAbleToShowPageAuthors } = useIsAbleToShowPageAuthors();
 
-  const { mutate: mutateSWRTagsInfo, data: TagsInfoData } = useSWRTagsInfo(pageId);
+  const { mutate: mutateSWRTagsInfo, data: tagsInfoData } = useSWRTagsInfo(pageId);
 
   const {
     editorContainer, isCompactMode,
   } = props;
 
   const isViewMode = editorMode === EditorMode.View;
-  const isEditorMode = !isViewMode;
   const isPageExist = pageId != null;
 
-  function onPageEditorModeButtonClicked(viewType) {
-    mutateEditorMode(viewType);
-  }
-
   const tagsUpdatedHandler = useCallback(async(newTags: string[]) => {
     // It will not be reflected in the DB until the page is refreshed
     if (editorMode === EditorMode.Editor) {
@@ -81,74 +72,72 @@ const GrowiContextualSubNavigation = (props) => {
   // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [pageId]);
 
-  if (path == null) {
-    return <></>;
-  }
+  const ControlComponents = useCallback(() => {
+    function onPageEditorModeButtonClicked(viewType) {
+      mutateEditorMode(viewType);
+    }
 
-  return (
-    <div className={`grw-subnav container-fluid d-flex align-items-center justify-content-between ${isCompactMode ? 'grw-subnav-compact d-print-none' : ''}`}>
-
-      {/* Left side */}
-      <div className="d-flex grw-subnav-left-side">
-        { isDrawerMode && (
-          <div className={`d-none d-md-flex align-items-center ${isEditorMode ? 'mr-2 pr-2' : 'border-right mr-4 pr-4'}`}>
-            <DrawerToggler />
-          </div>
-        ) }
-
-        <div className="grw-path-nav-container">
-          { isAbleToShowTagLabel && !isCompactMode && (
-            <div className="grw-taglabels-container">
-              <TagLabels tags={TagsInfoData?.tags || []} isGuestUser={isGuestUser ?? false} tagsUpdateInvoked={tagsUpdatedHandler} />
-            </div>
+    return (
+      <>
+        <div className="h-50 d-flex flex-column align-items-end justify-content-center">
+          { isPageExist && path != null && (
+            <SubNavButtons
+              isCompactMode={isCompactMode}
+              pageId={pageId}
+              revisionId={revisionId}
+              path={path}
+              isDeletable={isDeletable}
+              isAbleToDeleteCompletely={isAbleToDeleteCompletely}
+              isViewMode={isViewMode}
+              isAbleToShowPageManagement={isAbleToShowPageManagement}
+            />
           ) }
-          <PagePathNav pageId={pageId} pagePath={path} isSingleLineMode={isEditorMode} isCompactMode={isCompactMode} />
         </div>
-      </div>
-
-      {/* Right side */}
-      <div className="d-flex">
-
-        <div>
-          <div className="h-50 d-flex flex-column align-items-end justify-content-center">
-            { isPageExist && (
-              <SubNavButtons
-                isCompactMode={isCompactMode}
-                pageId={pageId}
-                revisionId={revisionId}
-                path={path}
-                isDeletable={isDeletable}
-                isAbleToDeleteCompletely={isAbleToDeleteCompletely}
-                isViewMode={isViewMode}
-                isAbleToShowPageManagement={isAbleToShowPageManagement}
-              />
-            ) }
-          </div>
-          <div className="h-50 d-flex flex-column align-items-end justify-content-center">
-            {isAbleToShowPageEditorModeManager && (
-              <PageEditorModeManager
-                onPageEditorModeButtonClicked={onPageEditorModeButtonClicked}
-                isBtnDisabled={isGuestUser}
-                editorMode={editorMode}
-                isDeviceSmallerThanMd={isDeviceSmallerThanMd}
-              />
-            )}
-          </div>
+        <div className="h-50 d-flex flex-column align-items-end justify-content-center">
+          {isAbleToShowPageEditorModeManager && (
+            <PageEditorModeManager
+              onPageEditorModeButtonClicked={onPageEditorModeButtonClicked}
+              isBtnDisabled={isGuestUser}
+              editorMode={editorMode}
+              isDeviceSmallerThanMd={isDeviceSmallerThanMd}
+            />
+          )}
         </div>
+      </>
+    );
+  }, [
+    pageId, path, revisionId,
+    editorMode, mutateEditorMode,
+    isAbleToDeleteCompletely, isAbleToShowPageEditorModeManager, isAbleToShowPageManagement,
+    isCompactMode, isDeletable, isDeviceSmallerThanMd, isGuestUser, isPageExist, isViewMode,
+  ]);
 
-        {/* Page Authors */}
-        { (isAbleToShowPageAuthors && !isCompactMode) && (
-          <ul className="authors text-nowrap border-left d-none d-lg-block d-edit-none py-2 pl-4 mb-0 ml-3">
-            <li className="pb-1">
-              <AuthorInfo user={creator} date={createdAt} locate="subnav" />
-            </li>
-            <li className="mt-1 pt-1 border-top">
-              <AuthorInfo user={revisionAuthor} date={updatedAt} mode="update" locate="subnav" />
-            </li>
-          </ul>
-        ) }
-      </div>
-    </div>
+
+  if (path == null) {
+    return <></>;
+  }
+
+  const currentPage: Partial<IPageHasId> = {
+    _id: pageId ?? undefined,
+    path,
+    revision: revisionId ?? undefined,
+    creator: creator ?? undefined,
+    lastUpdateUser: revisionAuthor,
+    createdAt: createdAt ?? undefined,
+    updatedAt: updatedAt ?? undefined,
+  };
+
+
+  return (
+    <GrowiSubNavigation
+      page={currentPage}
+      showDrawerToggler={isDrawerMode}
+      showTagLabel={isAbleToShowTagLabel}
+      showPageAuthors={isAbleToShowPageAuthors}
+      tags={tagsInfoData?.tags || []}
+      tagsUpdatedHandler={tagsUpdatedHandler}
+      controls={ControlComponents}
+    />
   );
 };
 

+ 100 - 0
packages/app/src/components/Navbar/GrowiSubNavigation.tsx

@@ -0,0 +1,100 @@
+import React from 'react';
+
+import { IPageHasId } from '~/interfaces/page';
+
+import {
+  EditorMode, useEditorMode,
+} from '~/stores/ui';
+
+import TagLabels from '../Page/TagLabels';
+
+import AuthorInfo from './AuthorInfo';
+import DrawerToggler from './DrawerToggler';
+
+import PagePathNav from '../PagePathNav';
+import { IUser } from '~/interfaces/user';
+
+
+type Props = {
+  page: Partial<IPageHasId>,
+
+  showDrawerToggler?: boolean,
+  showTagLabel?: boolean,
+  showPageAuthors?: boolean,
+
+  isGuestUser?: boolean,
+  isDrawerMode?: boolean,
+  isCompactMode?: boolean,
+
+  tags?: string[],
+  tagsUpdatedHandler?: (newTags: string[]) => Promise<void>,
+
+  controls?: any,
+}
+
+export const GrowiSubNavigation = (props: Props): JSX.Element => {
+  const { data: editorMode } = useEditorMode();
+
+  const {
+    page,
+    showDrawerToggler, showTagLabel, showPageAuthors,
+    isGuestUser, isDrawerMode, isCompactMode,
+    tags, tagsUpdatedHandler,
+    controls: Controls,
+  } = props;
+
+  const {
+    _id: pageId, path, creator, lastUpdateUser,
+    createdAt, updatedAt,
+  } = page;
+
+  const isViewMode = editorMode === EditorMode.View;
+  const isEditorMode = !isViewMode;
+
+  if (path == null) {
+    return <></>;
+  }
+
+  return (
+    <div className={`grw-subnav container-fluid d-flex align-items-center justify-content-between ${isCompactMode ? 'grw-subnav-compact d-print-none' : ''}`}>
+
+      {/* Left side */}
+      <div className="d-flex grw-subnav-left-side">
+        { showDrawerToggler && isDrawerMode && (
+          <div className={`d-none d-md-flex align-items-center ${isEditorMode ? 'mr-2 pr-2' : 'border-right mr-4 pr-4'}`}>
+            <DrawerToggler />
+          </div>
+        ) }
+
+        <div className="grw-path-nav-container">
+          { showTagLabel && !isCompactMode && (
+            <div className="grw-taglabels-container">
+              <TagLabels tags={tags} isGuestUser={isGuestUser ?? false} tagsUpdateInvoked={tagsUpdatedHandler} />
+            </div>
+          ) }
+          <PagePathNav pageId={pageId} pagePath={path} isSingleLineMode={isEditorMode} isCompactMode={isCompactMode} />
+        </div>
+      </div>
+
+      {/* Right side */}
+      <div className="d-flex">
+
+        <div>
+          <Controls></Controls>
+        </div>
+
+        {/* Page Authors */}
+        { (showPageAuthors && !isCompactMode) && (
+          <ul className="authors text-nowrap border-left d-none d-lg-block d-edit-none py-2 pl-4 mb-0 ml-3">
+            <li className="pb-1">
+              <AuthorInfo user={creator as IUser} date={createdAt} locate="subnav" />
+            </li>
+            <li className="mt-1 pt-1 border-top">
+              <AuthorInfo user={lastUpdateUser as IUser} date={updatedAt} mode="update" locate="subnav" />
+            </li>
+          </ul>
+        ) }
+      </div>
+    </div>
+  );
+};

+ 0 - 5
packages/app/src/components/Page/RenderTagLabels.tsx

@@ -20,11 +20,6 @@ const RenderTagLabels = React.memo((props: RenderTagLabelsProps) => {
     openEditorModal();
   }
 
-  // activate suspense
-  if (tags == null) {
-    throw new Promise(() => {});
-  }
-
   const isTagsEmpty = tags.length === 0;
   const tagElements = tags.map((tag) => {
     return (

+ 14 - 10
packages/app/src/components/Page/TagLabels.tsx

@@ -1,10 +1,10 @@
-import React, { FC, Suspense, useState } from 'react';
+import React, { FC, useState } from 'react';
 
 import RenderTagLabels from './RenderTagLabels';
 import TagEditModal from './TagEditModal';
 
 type Props = {
-  tags: string[],
+  tags?: string[],
   isGuestUser: boolean,
   tagsUpdateInvoked?: (tags: string[]) => Promise<void>,
 }
@@ -27,13 +27,18 @@ const TagLabels:FC<Props> = (props: Props) => {
     <>
       <form className="grw-tag-labels form-inline">
         <i className="tag-icon icon-tag mr-2"></i>
-        <Suspense fallback={<span className="grw-tag-label badge badge-secondary">―</span>}>
-          <RenderTagLabels
-            tags={tags}
-            openEditorModal={openEditorModal}
-            isGuestUser={isGuestUser}
-          />
-        </Suspense>
+        { tags == null
+          ? (
+            <span className="grw-tag-label badge badge-secondary">―</span>
+          )
+          : (
+            <RenderTagLabels
+              tags={tags}
+              openEditorModal={openEditorModal}
+              isGuestUser={isGuestUser}
+            />
+          )
+        }
       </form>
 
       <TagEditModal
@@ -42,7 +47,6 @@ const TagLabels:FC<Props> = (props: Props) => {
         onClose={closeEditorModal}
         onTagsUpdated={tagsUpdateInvoked}
       />
-
     </>
   );
 };