Преглед изворни кода

add tooltips to editor toolbar

ryosei-f пре 1 месец
родитељ
комит
1c29804419

+ 10 - 1
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/AttachmentsDropup.tsx

@@ -1,10 +1,11 @@
-import { type JSX, useState } from 'react';
+import { type JSX, useRef, useState } from 'react';
 import { AcceptedUploadFileType } from '@growi/core';
 import {
   Dropdown,
   DropdownItem,
   DropdownMenu,
   DropdownToggle,
+  UncontrolledTooltip,
 } from 'reactstrap';
 
 import type { GlobalCodeMirrorEditorKey } from '../../../../consts';
@@ -26,6 +27,8 @@ export const AttachmentsDropup = (props: Props): JSX.Element => {
 
   const [isOpen, setOpen] = useState(false);
 
+  const buttonRef = useRef<HTMLButtonElement>(null);
+
   return (
     <>
       <Dropdown
@@ -35,6 +38,7 @@ export const AttachmentsDropup = (props: Props): JSX.Element => {
         className="lh-1"
       >
         <DropdownToggle
+          innerRef={buttonRef}
           className={`${btnAttachmentToggleClass} btn-toolbar-button rounded-circle`}
           color="unset"
         >
@@ -74,6 +78,11 @@ export const AttachmentsDropup = (props: Props): JSX.Element => {
           <LinkEditButton editorKey={editorKey} />
         </DropdownMenu>
       </Dropdown>
+      {!isOpen && (
+        <UncontrolledTooltip placement="top" target={buttonRef}>
+          Attachments
+        </UncontrolledTooltip>
+      )}
     </>
   );
 };

+ 19 - 9
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/DiagramButton.tsx

@@ -1,4 +1,5 @@
-import { type JSX, useCallback } from 'react';
+import { type JSX, useCallback, useRef } from 'react';
+import { UncontrolledTooltip } from 'reactstrap';
 
 import { useDrawioModalForEditorActions } from '../../../../states/modal/drawio-for-editor';
 
@@ -9,17 +10,26 @@ type Props = {
 export const DiagramButton = (props: Props): JSX.Element => {
   const { editorKey } = props;
   const { open: openDrawioModal } = useDrawioModalForEditorActions();
+  const buttonRef = useRef<HTMLButtonElement>(null);
+
   const onClickDiagramButton = useCallback(() => {
     openDrawioModal(editorKey);
   }, [editorKey, openDrawioModal]);
+
   return (
-    <button
-      type="button"
-      className="btn btn-toolbar-button"
-      onClick={onClickDiagramButton}
-    >
-      {/* TODO: chack and fix font-size. see: https://redmine.weseek.co.jp/issues/143015 */}
-      <span className="growi-custom-icons fs-6">drawer_io</span>
-    </button>
+    <>
+      <button
+        ref={buttonRef}
+        type="button"
+        className="btn btn-toolbar-button"
+        onClick={onClickDiagramButton}
+      >
+        {/* TODO: chack and fix font-size. see: https://redmine.weseek.co.jp/issues/143015 */}
+        <span className="growi-custom-icons fs-6">drawer_io</span>
+      </button>
+      <UncontrolledTooltip placement="top" target={buttonRef}>
+        Diagram
+      </UncontrolledTooltip>
+    </>
   );
 };

+ 13 - 2
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/EmojiButton.tsx

@@ -4,9 +4,10 @@ import {
   type JSX,
   useCallback,
   useEffect,
+  useRef,
   useState,
 } from 'react';
-import { Modal } from 'reactstrap';
+import { Modal, UncontrolledTooltip } from 'reactstrap';
 
 import { useResolvedTheme } from '../../../../states/ui/resolved-theme';
 import { useCodeMirrorEditorIsolated } from '../../../stores/codemirror-editor';
@@ -24,6 +25,8 @@ type Props = {
 export const EmojiButton = (props: Props): JSX.Element => {
   const { editorKey } = props;
 
+  const buttonRef = useRef<HTMLButtonElement>(null);
+
   const [isOpen, setIsOpen] = useState(false);
   const [Picker, setPicker] = useState<ComponentType<PickerProps> | null>(null);
   const [emojiData, setEmojiData] = useState<unknown>(null);
@@ -89,9 +92,17 @@ export const EmojiButton = (props: Props): JSX.Element => {
 
   return (
     <>
-      <button type="button" className="btn btn-toolbar-button" onClick={toggle}>
+      <button
+        ref={buttonRef}
+        type="button"
+        className="btn btn-toolbar-button"
+        onClick={toggle}
+      >
         <span className="material-symbols-outlined fs-5">emoji_emotions</span>
       </button>
+      <UncontrolledTooltip placement="top" target={buttonRef}>
+        Emoji
+      </UncontrolledTooltip>
       {isOpen && Picker != null && emojiData != null && (
         <div className="mb-2 d-none d-md-block">
           <Modal

+ 18 - 8
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/TableButton.tsx

@@ -1,4 +1,5 @@
-import { type JSX, useCallback } from 'react';
+import { type JSX, useCallback, useRef } from 'react';
+import { UncontrolledTooltip } from 'reactstrap';
 
 import { useHandsontableModalForEditorActions } from '../../../../states/modal/handsontable';
 import { useCodeMirrorEditorIsolated } from '../../../stores/codemirror-editor';
@@ -9,6 +10,9 @@ type Props = {
 
 export const TableButton = (props: Props): JSX.Element => {
   const { editorKey } = props;
+
+  const buttonRef = useRef<HTMLButtonElement>(null);
+
   const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(editorKey);
   const { open: openTableModal } = useHandsontableModalForEditorActions();
   const editor = codeMirrorEditor?.view;
@@ -17,12 +21,18 @@ export const TableButton = (props: Props): JSX.Element => {
   }, [editor, openTableModal]);
 
   return (
-    <button
-      type="button"
-      className="btn btn-toolbar-button"
-      onClick={onClickTableButton}
-    >
-      <span className="material-symbols-outlined fs-5">table</span>
-    </button>
+    <>
+      <button
+        ref={buttonRef}
+        type="button"
+        className="btn btn-toolbar-button"
+        onClick={onClickTableButton}
+      >
+        <span className="material-symbols-outlined fs-5">table</span>
+      </button>
+      <UncontrolledTooltip placement="top" target={buttonRef}>
+        Table
+      </UncontrolledTooltip>
+    </>
   );
 };

+ 19 - 9
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/TemplateButton.tsx

@@ -1,4 +1,5 @@
-import { type JSX, useCallback } from 'react';
+import { type JSX, useCallback, useRef } from 'react';
+import { UncontrolledTooltip } from 'reactstrap';
 
 import { useTemplateModalActions } from '../../../../states/modal/template';
 import { useCodeMirrorEditorIsolated } from '../../../stores/codemirror-editor';
@@ -9,6 +10,9 @@ type Props = {
 
 export const TemplateButton = (props: Props): JSX.Element => {
   const { editorKey } = props;
+
+  const buttonRef = useRef<HTMLButtonElement>(null);
+
   const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(editorKey);
   const { open: openTemplateModal } = useTemplateModalActions();
 
@@ -23,13 +27,19 @@ export const TemplateButton = (props: Props): JSX.Element => {
   }, [codeMirrorEditor?.view, openTemplateModal]);
 
   return (
-    <button
-      type="button"
-      className="btn btn-toolbar-button"
-      onClick={onClickTempleteButton}
-      data-testid="open-template-button"
-    >
-      <span className="material-symbols-outlined fs-5">file_copy</span>
-    </button>
+    <>
+      <button
+        ref={buttonRef}
+        type="button"
+        className="btn btn-toolbar-button"
+        onClick={onClickTempleteButton}
+        data-testid="open-template-button"
+      >
+        <span className="material-symbols-outlined fs-5">file_copy</span>
+      </button>
+      <UncontrolledTooltip placement="top" target={buttonRef}>
+        Template
+      </UncontrolledTooltip>
+    </>
   );
 };

+ 62 - 9
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/TextFormatTools.tsx

@@ -1,5 +1,5 @@
-import { type JSX, useCallback, useState } from 'react';
-import { Collapse } from 'reactstrap';
+import { type JSX, useCallback, useRef, useState } from 'react';
+import { Collapse, UncontrolledTooltip } from 'reactstrap';
 
 import type { GlobalCodeMirrorEditorKey } from '../../../../consts';
 import { useCodeMirrorEditorIsolated } from '../../../stores/codemirror-editor';
@@ -16,16 +16,23 @@ type TogglarProps = {
 const TextFormatToolsToggler = (props: TogglarProps): JSX.Element => {
   const { isOpen, onClick } = props;
 
+  const buttonRef = useRef<HTMLButtonElement>(null);
   const activeClass = isOpen ? 'active' : '';
 
   return (
-    <button
-      type="button"
-      className={`btn btn-toolbar-button ${btnTextFormatToolsTogglerClass} ${activeClass}`}
-      onClick={onClick}
-    >
-      <span className="material-symbols-outlined fs-3">match_case</span>
-    </button>
+    <>
+      <button
+        ref={buttonRef}
+        type="button"
+        className={`btn btn-toolbar-button ${btnTextFormatToolsTogglerClass} ${activeClass}`}
+        onClick={onClick}
+      >
+        <span className="material-symbols-outlined fs-3">match_case</span>
+      </button>
+      <UncontrolledTooltip placement="top" target={buttonRef}>
+        Text Formatting
+      </UncontrolledTooltip>
+    </>
   );
 };
 
@@ -39,6 +46,16 @@ export const TextFormatTools = (props: TextFormatToolsType): JSX.Element => {
   const [isOpen, setOpen] = useState(false);
   const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(editorKey);
 
+  const boldRef = useRef<HTMLButtonElement>(null);
+  const italicRef = useRef<HTMLButtonElement>(null);
+  const strikethroughRef = useRef<HTMLButtonElement>(null);
+  const headingRef = useRef<HTMLButtonElement>(null);
+  const codeRef = useRef<HTMLButtonElement>(null);
+  const bulletListRef = useRef<HTMLButtonElement>(null);
+  const numberedListRef = useRef<HTMLButtonElement>(null);
+  const quoteRef = useRef<HTMLButtonElement>(null);
+  const checklistRef = useRef<HTMLButtonElement>(null);
+
   const toggle = useCallback(() => {
     setOpen((bool) => !bool);
   }, []);
@@ -66,13 +83,18 @@ export const TextFormatTools = (props: TextFormatToolsType): JSX.Element => {
       >
         <div className="d-flex px-1 gap-1" style={{ width: '220px' }}>
           <button
+            ref={boldRef}
             type="button"
             className="btn btn-toolbar-button"
             onClick={() => onClickInsertMarkdownElements('**', '**')}
           >
             <span className="material-symbols-outlined fs-5">format_bold</span>
           </button>
+          <UncontrolledTooltip placement="top" target={boldRef}>
+            Bold
+          </UncontrolledTooltip>
           <button
+            ref={italicRef}
             type="button"
             className="btn btn-toolbar-button"
             onClick={() => onClickInsertMarkdownElements('*', '*')}
@@ -81,7 +103,11 @@ export const TextFormatTools = (props: TextFormatToolsType): JSX.Element => {
               format_italic
             </span>
           </button>
+          <UncontrolledTooltip placement="top" target={italicRef}>
+            Italic
+          </UncontrolledTooltip>
           <button
+            ref={strikethroughRef}
             type="button"
             className="btn btn-toolbar-button"
             onClick={() => onClickInsertMarkdownElements('~', '~')}
@@ -90,7 +116,11 @@ export const TextFormatTools = (props: TextFormatToolsType): JSX.Element => {
               format_strikethrough
             </span>
           </button>
+          <UncontrolledTooltip placement="top" target={strikethroughRef}>
+            Strikethrough
+          </UncontrolledTooltip>
           <button
+            ref={headingRef}
             type="button"
             className="btn btn-toolbar-button"
             onClick={() => onClickInsertPrefix('#', true)}
@@ -98,14 +128,22 @@ export const TextFormatTools = (props: TextFormatToolsType): JSX.Element => {
             {/* TODO: chack and fix font-size. see: https://redmine.weseek.co.jp/issues/143015 */}
             <span className="growi-custom-icons">header</span>
           </button>
+          <UncontrolledTooltip placement="top" target={headingRef}>
+            Heading
+          </UncontrolledTooltip>
           <button
+            ref={codeRef}
             type="button"
             className="btn btn-toolbar-button"
             onClick={() => onClickInsertMarkdownElements('`', '`')}
           >
             <span className="material-symbols-outlined fs-5">code</span>
           </button>
+          <UncontrolledTooltip placement="top" target={codeRef}>
+            Code
+          </UncontrolledTooltip>
           <button
+            ref={bulletListRef}
             type="button"
             className="btn btn-toolbar-button"
             onClick={() => onClickInsertPrefix('-')}
@@ -114,7 +152,11 @@ export const TextFormatTools = (props: TextFormatToolsType): JSX.Element => {
               format_list_bulleted
             </span>
           </button>
+          <UncontrolledTooltip placement="top" target={bulletListRef}>
+            Bullet List
+          </UncontrolledTooltip>
           <button
+            ref={numberedListRef}
             type="button"
             className="btn btn-toolbar-button"
             onClick={() => onClickInsertPrefix('1.')}
@@ -123,7 +165,11 @@ export const TextFormatTools = (props: TextFormatToolsType): JSX.Element => {
               format_list_numbered
             </span>
           </button>
+          <UncontrolledTooltip placement="top" target={numberedListRef}>
+            Numbered List
+          </UncontrolledTooltip>
           <button
+            ref={quoteRef}
             type="button"
             className="btn btn-toolbar-button"
             onClick={() => onClickInsertPrefix('>')}
@@ -131,13 +177,20 @@ export const TextFormatTools = (props: TextFormatToolsType): JSX.Element => {
             {/* TODO: chack and fix font-size. see: https://redmine.weseek.co.jp/issues/143015 */}
             <span className="growi-custom-icons">format_quote</span>
           </button>
+          <UncontrolledTooltip placement="top" target={quoteRef}>
+            Quote
+          </UncontrolledTooltip>
           <button
+            ref={checklistRef}
             type="button"
             className="btn btn-toolbar-button"
             onClick={() => onClickInsertPrefix('- [ ]')}
           >
             <span className="material-symbols-outlined fs-5">checklist</span>
           </button>
+          <UncontrolledTooltip placement="top" target={checklistRef}>
+            Checklist
+          </UncontrolledTooltip>
         </div>
       </Collapse>
     </div>