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

Merge pull request #24688 from overleaf/td-bs5-editor-beginner-switch-popover

Migrate beginner editor switch popover to BS5

GitOrigin-RevId: c470df46989de7ad6477ee23ff13fc95dd580ea8
Tim Down 1 год назад
Родитель
Сommit
4cee376878

+ 102 - 0
services/web/frontend/js/features/source-editor/components/editor-switch-beginner-popover.tsx

@@ -0,0 +1,102 @@
+import { ReactElement, useCallback, useEffect, useState } from 'react'
+import Close from '@/shared/components/close'
+import { useEditorContext } from '@/shared/context/editor-context'
+import useTutorial from '@/shared/hooks/promotions/use-tutorial'
+import { useUserContext } from '@/shared/context/user-context'
+import useScopeValue from '@/shared/hooks/use-scope-value'
+import { useTranslation } from 'react-i18next'
+import getMeta from '@/utils/meta'
+import OLPopover from '@/features/ui/components/ol/ol-popover'
+import OLOverlay from '@/features/ui/components/ol/ol-overlay'
+
+const CODE_EDITOR_POPOVER_TIMEOUT = 1000
+export const codeEditorModePrompt = 'code-editor-mode-prompt'
+
+export const EditorSwitchBeginnerPopover = ({
+  children,
+  targetRef,
+}: {
+  children: ReactElement
+  targetRef: React.RefObject<HTMLElement>
+}) => {
+  const user = useUserContext()
+  const { inactiveTutorials } = useEditorContext()
+  const { t } = useTranslation()
+  const [codeEditorOpened] = useScopeValue('editor.codeEditorOpened')
+  const { completeTutorial } = useTutorial(codeEditorModePrompt, {
+    location: 'logs',
+    name: codeEditorModePrompt,
+  })
+  const [popoverShown, setPopoverShown] = useState(false)
+
+  const shouldShowCodeEditorPopover = useCallback(() => {
+    if (inactiveTutorials.includes(codeEditorModePrompt)) {
+      return false
+    }
+
+    if (getMeta('ol-usedLatex') !== 'never') {
+      // only show popover to the users that never used LaTeX (submitted in onboarding data collection)
+      return false
+    }
+
+    if (codeEditorOpened) {
+      // dont show popover if code editor was opened at some point
+      return false
+    }
+
+    const msSinceSignedUp =
+      user.signUpDate && Date.now() - new Date(user.signUpDate).getTime()
+
+    if (msSinceSignedUp && msSinceSignedUp < 24 * 60 * 60 * 1000) {
+      // dont show popover if user has signed up is less than 24 hours
+      return false
+    }
+
+    return true
+  }, [codeEditorOpened, inactiveTutorials, user.signUpDate])
+
+  useEffect(() => {
+    if (popoverShown && codeEditorOpened) {
+      setPopoverShown(false)
+    }
+  }, [codeEditorOpened, popoverShown])
+
+  useEffect(() => {
+    const timeout = setTimeout(() => {
+      if (shouldShowCodeEditorPopover()) {
+        setPopoverShown(true)
+      }
+    }, CODE_EDITOR_POPOVER_TIMEOUT)
+
+    return () => clearTimeout(timeout)
+  }, [shouldShowCodeEditorPopover])
+
+  return (
+    <>
+      {children}
+      <OLOverlay
+        placement="bottom"
+        show={popoverShown}
+        rootClose
+        onHide={() => setPopoverShown(false)}
+        target={targetRef.current}
+      >
+        <OLPopover id="editor-switch-popover">
+          <div>
+            <Close
+              variant="dark"
+              onDismiss={() => {
+                setPopoverShown(false)
+                completeTutorial({ event: 'promo-click', action: 'complete' })
+              }}
+            />
+            <div className="tooltip-title">
+              {t('code_editor_tooltip_title')}
+            </div>
+            <div>{t('code_editor_tooltip_message')}</div>
+          </div>
+        </OLPopover>
+      </OLOverlay>
+    </>
+  )
+}

+ 0 - 118
services/web/frontend/js/features/source-editor/components/editor-switch-beginner-tooltip.tsx

@@ -1,118 +0,0 @@
-import { ReactElement, useCallback, useEffect, useRef, useState } from 'react'
-import Tooltip from '../../../shared/components/tooltip'
-import Close from '@/shared/components/close'
-import { useEditorContext } from '@/shared/context/editor-context'
-import useTutorial from '@/shared/hooks/promotions/use-tutorial'
-import { useUserContext } from '@/shared/context/user-context'
-import useScopeValue from '@/shared/hooks/use-scope-value'
-import { useTranslation } from 'react-i18next'
-import getMeta from '@/utils/meta'
-
-const CODE_EDITOR_TOOLTIP_TIMEOUT = 1000
-export const codeEditorModePrompt = 'code-editor-mode-prompt'
-
-export const EditorSwitchBeginnerTooltip = ({
-  children,
-}: {
-  children: ReactElement
-}) => {
-  const toolbarRef = useRef<any>(null)
-  const user = useUserContext()
-  const { inactiveTutorials } = useEditorContext()
-  const { t } = useTranslation()
-  const [codeEditorOpened] = useScopeValue('editor.codeEditorOpened')
-  const { completeTutorial } = useTutorial(codeEditorModePrompt, {
-    location: 'logs',
-    name: codeEditorModePrompt,
-  })
-  const [tooltipShown, setTooltipShown] = useState(false)
-
-  const shouldShowCodeEditorTooltip = useCallback(() => {
-    if (inactiveTutorials.includes(codeEditorModePrompt)) {
-      return false
-    }
-
-    if (getMeta('ol-usedLatex') !== 'never') {
-      // only show tooltip to the users that never used LaTeX (submitted in onboarding data collection)
-      return false
-    }
-
-    if (codeEditorOpened) {
-      // dont show tooltip if code editor was opened at some point
-      return false
-    }
-
-    const msSinceSignedUp =
-      user.signUpDate && Date.now() - new Date(user.signUpDate).getTime()
-
-    if (msSinceSignedUp && msSinceSignedUp < 24 * 60 * 60 * 1000) {
-      // dont show tooltip if user has signed up is less than 24 hours
-      return false
-    }
-
-    return true
-  }, [codeEditorOpened, inactiveTutorials, user.signUpDate])
-
-  const showCodeEditorTooltip = useCallback(() => {
-    if (toolbarRef.current && 'show' in toolbarRef.current) {
-      toolbarRef.current.show()
-      setTooltipShown(true)
-    }
-  }, [])
-
-  const hideCodeEditorTooltip = useCallback(() => {
-    if (toolbarRef.current && 'hide' in toolbarRef.current) {
-      toolbarRef.current.hide()
-      setTooltipShown(false)
-    }
-  }, [])
-
-  useEffect(() => {
-    if (tooltipShown && codeEditorOpened) {
-      hideCodeEditorTooltip()
-    }
-  }, [codeEditorOpened, hideCodeEditorTooltip, tooltipShown])
-
-  useEffect(() => {
-    const timeout = setTimeout(() => {
-      if (shouldShowCodeEditorTooltip()) {
-        showCodeEditorTooltip()
-      }
-    }, CODE_EDITOR_TOOLTIP_TIMEOUT)
-
-    return () => clearTimeout(timeout)
-  }, [showCodeEditorTooltip, shouldShowCodeEditorTooltip])
-
-  return (
-    <Tooltip
-      id="editor-switch-tooltip"
-      description={
-        <div>
-          <Close
-            variant="dark"
-            onDismiss={() => {
-              hideCodeEditorTooltip()
-              completeTutorial({ event: 'promo-click', action: 'complete' })
-            }}
-          />
-          <div className="tooltip-title">{t('code_editor_tooltip_title')}</div>
-          <div>{t('code_editor_tooltip_message')}</div>
-        </div>
-      }
-      tooltipProps={{
-        className: 'editor-switch-tooltip',
-      }}
-      overlayProps={{
-        ref: toolbarRef,
-        placement: 'bottom',
-        shouldUpdatePosition: true,
-        // @ts-ignore
-        // trigger: null is used to prevent the tooltip from showing on hover
-        // but it is not allowed in the type definition
-        trigger: null,
-      }}
-    >
-      {children}
-    </Tooltip>
-  )
-}

+ 12 - 6
services/web/frontend/js/features/source-editor/components/editor-switch.tsx

@@ -1,4 +1,4 @@
-import { ChangeEvent, FC, memo, useCallback } from 'react'
+import { ChangeEvent, FC, memo, useCallback, useRef } from 'react'
 import useScopeValue from '@/shared/hooks/use-scope-value'
 import useScopeValue from '@/shared/hooks/use-scope-value'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import useTutorial from '@/shared/hooks/promotions/use-tutorial'
 import useTutorial from '@/shared/hooks/promotions/use-tutorial'
@@ -6,9 +6,9 @@ import { sendMB } from '../../../infrastructure/event-tracking'
 import { isValidTeXFile } from '../../../main/is-valid-tex-file'
 import { isValidTeXFile } from '../../../main/is-valid-tex-file'
 import { useTranslation } from 'react-i18next'
 import { useTranslation } from 'react-i18next'
 import {
 import {
-  EditorSwitchBeginnerTooltip,
+  EditorSwitchBeginnerPopover,
   codeEditorModePrompt,
   codeEditorModePrompt,
-} from './editor-switch-beginner-tooltip'
+} from './editor-switch-beginner-popover'
 import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
 import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
 
 
 function EditorSwitch() {
 function EditorSwitch() {
@@ -17,6 +17,8 @@ function EditorSwitch() {
   const [codeEditorOpened] = useScopeValue('editor.codeEditorOpened')
   const [codeEditorOpened] = useScopeValue('editor.codeEditorOpened')
   const { openDocName } = useEditorManagerContext()
   const { openDocName } = useEditorManagerContext()
 
 
+  const codeEditorRef = useRef<HTMLLabelElement>(null)
+
   const richTextAvailable = openDocName ? isValidTeXFile(openDocName) : false
   const richTextAvailable = openDocName ? isValidTeXFile(openDocName) : false
   const { completeTutorial } = useTutorial(codeEditorModePrompt, {
   const { completeTutorial } = useTutorial(codeEditorModePrompt, {
     location: 'logs',
     location: 'logs',
@@ -62,11 +64,15 @@ function EditorSwitch() {
           checked={!richTextAvailable || !visual}
           checked={!richTextAvailable || !visual}
           onChange={handleChange}
           onChange={handleChange}
         />
         />
-        <EditorSwitchBeginnerTooltip>
-          <label htmlFor="editor-switch-cm6" className="toggle-switch-label">
+        <EditorSwitchBeginnerPopover targetRef={codeEditorRef}>
+          <label
+            ref={codeEditorRef}
+            htmlFor="editor-switch-cm6"
+            className="toggle-switch-label"
+          >
             <span>{t('code_editor')}</span>
             <span>{t('code_editor')}</span>
           </label>
           </label>
-        </EditorSwitchBeginnerTooltip>
+        </EditorSwitchBeginnerPopover>
 
 
         <RichTextToggle
         <RichTextToggle
           checked={richTextAvailable && visual}
           checked={richTextAvailable && visual}