editor-switch.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { ChangeEvent, FC, memo, useCallback } from 'react'
  2. import useScopeValue from '@/shared/hooks/use-scope-value'
  3. import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
  4. import useTutorial from '@/shared/hooks/promotions/use-tutorial'
  5. import { sendMB } from '../../../infrastructure/event-tracking'
  6. import { isValidTeXFile } from '../../../main/is-valid-tex-file'
  7. import { useTranslation } from 'react-i18next'
  8. import {
  9. EditorSwitchBeginnerTooltip,
  10. codeEditorModePrompt,
  11. } from './editor-switch-beginner-tooltip'
  12. import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
  13. function EditorSwitch() {
  14. const { t } = useTranslation()
  15. const [visual, setVisual] = useScopeValue('editor.showVisual')
  16. const [codeEditorOpened] = useScopeValue('editor.codeEditorOpened')
  17. const { openDocName } = useEditorManagerContext()
  18. const richTextAvailable = openDocName ? isValidTeXFile(openDocName) : false
  19. const { completeTutorial } = useTutorial(codeEditorModePrompt, {
  20. location: 'logs',
  21. name: codeEditorModePrompt,
  22. })
  23. const handleChange = useCallback(
  24. event => {
  25. const editorType = event.target.value
  26. switch (editorType) {
  27. case 'cm6':
  28. setVisual(false)
  29. if (!codeEditorOpened) {
  30. completeTutorial({ event: 'promo-click', action: 'complete' })
  31. }
  32. break
  33. case 'rich-text':
  34. setVisual(true)
  35. break
  36. }
  37. sendMB('editor-switch-change', { editorType })
  38. },
  39. [codeEditorOpened, completeTutorial, setVisual]
  40. )
  41. return (
  42. <div
  43. className="editor-toggle-switch"
  44. aria-label={t('toolbar_code_visual_editor_switch')}
  45. >
  46. <fieldset className="toggle-switch">
  47. <legend className="sr-only">Editor mode.</legend>
  48. <input
  49. type="radio"
  50. name="editor"
  51. value="cm6"
  52. id="editor-switch-cm6"
  53. className="toggle-switch-input"
  54. checked={!richTextAvailable || !visual}
  55. onChange={handleChange}
  56. />
  57. <EditorSwitchBeginnerTooltip>
  58. <label htmlFor="editor-switch-cm6" className="toggle-switch-label">
  59. <span>{t('code_editor')}</span>
  60. </label>
  61. </EditorSwitchBeginnerTooltip>
  62. <RichTextToggle
  63. checked={richTextAvailable && visual}
  64. disabled={!richTextAvailable}
  65. handleChange={handleChange}
  66. />
  67. </fieldset>
  68. </div>
  69. )
  70. }
  71. const RichTextToggle: FC<{
  72. checked: boolean
  73. disabled: boolean
  74. handleChange: (event: ChangeEvent<HTMLInputElement>) => void
  75. }> = ({ checked, disabled, handleChange }) => {
  76. const { t } = useTranslation()
  77. const toggle = (
  78. <span>
  79. <input
  80. type="radio"
  81. name="editor"
  82. value="rich-text"
  83. id="editor-switch-rich-text"
  84. className="toggle-switch-input"
  85. checked={checked}
  86. onChange={handleChange}
  87. disabled={disabled}
  88. />
  89. <label htmlFor="editor-switch-rich-text" className="toggle-switch-label">
  90. <span>{t('visual_editor')}</span>
  91. </label>
  92. </span>
  93. )
  94. if (disabled) {
  95. return (
  96. <OLTooltip
  97. description={t('visual_editor_is_only_available_for_tex_files')}
  98. id="rich-text-toggle-tooltip"
  99. overlayProps={{ placement: 'bottom' }}
  100. tooltipProps={{ className: 'tooltip-wide' }}
  101. >
  102. {toggle}
  103. </OLTooltip>
  104. )
  105. }
  106. return toggle
  107. }
  108. export default memo(EditorSwitch)