Yuki Takei 2 лет назад
Родитель
Сommit
7b487178ba

+ 51 - 55
apps/app/src/components/CustomNavigation/CustomNavButton.tsx

@@ -1,73 +1,69 @@
-import React, {
-  useRef, useMemo, useCallback,
-} from 'react';
+import { memo, type ReactNode } from 'react';
 
-import {
-  Nav, NavItem, NavLink,
-} from 'reactstrap';
-
-import type { ICustomNavTabMappings } from '~/interfaces/ui';
+import { useTranslation } from 'next-i18next';
 
 import styles from './CustomNavButton.module.scss';
 
-type CustomNavTabProps = {
-  activeTab: string,
-  navTabMapping: ICustomNavTabMappings,
-  onNavSelected?: (selectedTabKey: string) => void,
-};
+const moduleClass = styles['grw-custom-nav-tab'] ?? '';
 
-export const CustomNavTab = (props: CustomNavTabProps): JSX.Element => {
 
+type SwitchingButtonProps = {
+  active?: boolean,
+  children?: ReactNode,
+  onClick?: () => void,
+}
+const SwitchingButton = memo((props: SwitchingButtonProps) => {
   const {
-    activeTab, navTabMapping, onNavSelected,
+    active, children, onClick,
   } = props;
 
-  const navContainerRef = useRef<HTMLDivElement>(null);
+  const classNames = ['btn py-1 px-2 d-flex align-items-center justify-content-center'];
+  if (active) {
+    classNames.push('active');
+  }
 
-  const navTabRefs: { [key: string]: HTMLAnchorElement } = useMemo(() => {
-    const obj = {};
-    Object.keys(navTabMapping).forEach((key) => {
-      obj[key] = React.createRef();
-    });
-    return obj;
-  }, [navTabMapping]);
+  return (
+    <button
+      type="button"
+      className={classNames.join(' ')}
+      onClick={onClick}
+    >
+      {children}
+    </button>
+  );
+});
 
-  const navLinkClickHandler = useCallback((key) => {
-    if (onNavSelected != null) {
-      onNavSelected(key);
-    }
-  }, [onNavSelected]);
 
-  function registerNavLink(key: string, anchorElem: HTMLAnchorElement | null) {
-    if (anchorElem != null) {
-      navTabRefs[key] = anchorElem;
-    }
-  }
+type CustomNavTabProps = {
+  showPreview: boolean,
+  onNavSelected?: (showPreview: boolean) => void,
+};
 
-  return (
-    <div className={`grw-custom-nav-tab ${styles['grw-custom-nav-tab']}`}>
-      <div ref={navContainerRef} className="d-flex justify-content-between">
-        <Nav className="nav-title rounded">
-          {Object.entries(navTabMapping).map(([key, value]) => {
+export const CustomNavTab = (props: CustomNavTabProps): JSX.Element => {
 
-            const isActive = activeTab === key;
-            const _isLinkEnabled = value.isLinkEnabled ?? true;
-            const isLinkEnabled = typeof _isLinkEnabled === 'boolean' ? _isLinkEnabled : _isLinkEnabled(value);
-            const { Icon, i18n, roundClass } = value;
+  const { t } = useTranslation();
 
-            return (
-              <NavItem
-                key={key}
-                className={`${isActive ? 'active' : 'passive'} rounded-1 ${roundClass}`}
-              >
-                <NavLink type="button" key={key} innerRef={elm => registerNavLink(key, elm)} disabled={!isLinkEnabled} onClick={() => navLinkClickHandler(key)}>
-                  { Icon != null && <span className="me-1"><Icon /></span> } <small>{i18n}</small>
-                </NavLink>
-              </NavItem>
-            );
-          })}
-        </Nav>
-      </div>
+  const {
+    showPreview, onNavSelected,
+  } = props;
+
+  return (
+    <div
+      className={`btn-group ${moduleClass}`}
+      role="group"
+    >
+      <SwitchingButton
+        active={!showPreview}
+        onClick={() => onNavSelected?.(false)}
+      >
+        <span className="material-symbols-outlined me-1">edit_square</span>{t('Write')}
+      </SwitchingButton>
+      <SwitchingButton
+        active={showPreview}
+        onClick={() => onNavSelected?.(true)}
+      >
+        <span className="material-symbols-outlined me-0">play_arrow</span>{t('Preview')}
+      </SwitchingButton>
     </div>
   );
 

+ 7 - 20
apps/app/src/components/PageComment/CommentEditor.tsx

@@ -42,19 +42,6 @@ const logger = loggerFactory('growi:components:CommentEditor');
 
 const SlackNotification = dynamic(() => import('../SlackNotification').then(mod => mod.SlackNotification), { ssr: false });
 
-const navTabMapping = {
-  comment_editor: {
-    Icon: () => <span className="material-symbols-outlined">edit_square</span>,
-    roundClass: 'rounded-end-0',
-    i18n: 'Write',
-  },
-  comment_preview: {
-    Icon: () => <span className="material-symbols-outlined">play_arrow</span>,
-    roundClass: 'rounded-start-0',
-    i18n: 'Preview',
-  },
-};
-
 export type CommentEditorProps = {
   pageId: string,
   isForNewComment?: boolean,
@@ -94,7 +81,7 @@ export const CommentEditor = (props: CommentEditorProps): JSX.Element => {
 
   const [isReadyToUse, setIsReadyToUse] = useState(!isForNewComment);
   const [comment, setComment] = useState(commentBody ?? '');
-  const [activeTab, setActiveTab] = useState('comment_editor');
+  const [showPreview, setShowPreview] = useState(false);
   const [error, setError] = useState();
   const [slackChannels, setSlackChannels] = useState<string>('');
   const [incremented, setIncremented] = useState(false);
@@ -117,8 +104,8 @@ export const CommentEditor = (props: CommentEditorProps): JSX.Element => {
     };
   }, [onRouterChangeComplete, router.events]);
 
-  const handleSelect = useCallback((activeTab: string) => {
-    setActiveTab(activeTab);
+  const handleSelect = useCallback((showPreview: boolean) => {
+    setShowPreview(showPreview);
   }, []);
 
   // DO NOT dependent on slackChannelsData directly: https://github.com/weseek/growi/pull/7332
@@ -144,7 +131,7 @@ export const CommentEditor = (props: CommentEditorProps): JSX.Element => {
     const editingCommentsNum = comment !== '' ? await decrementEditingCommentsNum() : undefined;
 
     setComment('');
-    setActiveTab('comment_editor');
+    setShowPreview(false);
     setError(undefined);
     initializeSlackEnabled();
     // reset value
@@ -276,7 +263,7 @@ export const CommentEditor = (props: CommentEditorProps): JSX.Element => {
         </NotAvailableForGuest>
       </div>
     );
-  }, []);
+  }, [currentUser]);
 
   // const onChangeHandler = useCallback((newValue: string, isClean: boolean) => {
   //   setComment(newValue);
@@ -337,9 +324,9 @@ export const CommentEditor = (props: CommentEditorProps): JSX.Element => {
               <UserPicture user={currentUser} noLink noTooltip />
               <p className="ms-2 mb-0">Add a comment</p>
             </div>
-            <CustomNavTab activeTab={activeTab} navTabMapping={navTabMapping} onNavSelected={handleSelect} />
+            <CustomNavTab showPreview={showPreview} onNavSelected={handleSelect} />
           </div>
-          <TabContent activeTab={activeTab}>
+          <TabContent activeTab={showPreview ? 'comment_preview' : 'comment_editor'}>
             <TabPane tabId="comment_editor">
               <CodeMirrorEditorComment
                 acceptedUploadFileType={acceptedUploadFileType}