editor-switch.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import { ChangeEvent, FC, memo, useCallback } from 'react'
  2. import useScopeValue from '../../../shared/hooks/use-scope-value'
  3. import Tooltip from '../../../shared/components/tooltip'
  4. import { sendMB } from '../../../infrastructure/event-tracking'
  5. import getMeta from '../../../utils/meta'
  6. import isValidTeXFile from '../../../main/is-valid-tex-file'
  7. import { useTranslation } from 'react-i18next'
  8. import SplitTestBadge from '../../../shared/components/split-test-badge'
  9. function EditorSwitch() {
  10. const { t } = useTranslation()
  11. const [newSourceEditor, setNewSourceEditor] = useScopeValue(
  12. 'editor.newSourceEditor'
  13. )
  14. const [richText, setRichText] = useScopeValue('editor.showRichText')
  15. const [visual, setVisual] = useScopeValue('editor.showVisual')
  16. const [docName] = useScopeValue('editor.open_doc_name')
  17. const richTextAvailable = isValidTeXFile(docName)
  18. const richTextOrVisual = richText || (richTextAvailable && visual)
  19. const handleChange = useCallback(
  20. event => {
  21. const editorType = event.target.value
  22. switch (editorType) {
  23. case 'ace':
  24. setRichText(false)
  25. setVisual(false)
  26. setNewSourceEditor(false)
  27. break
  28. case 'cm6':
  29. setRichText(false)
  30. setVisual(false)
  31. setNewSourceEditor(true)
  32. break
  33. case 'rich-text':
  34. if (getMeta('ol-richTextVariant') === 'cm6') {
  35. setRichText(false)
  36. setVisual(true)
  37. setNewSourceEditor(true)
  38. } else {
  39. setRichText(true)
  40. setVisual(false)
  41. }
  42. break
  43. }
  44. sendMB('editor-switch-change', { editorType })
  45. },
  46. [setRichText, setVisual, setNewSourceEditor]
  47. )
  48. return (
  49. <div className="editor-toggle-switch">
  50. <fieldset className="toggle-switch">
  51. <legend className="sr-only">Editor mode.</legend>
  52. <input
  53. type="radio"
  54. name="editor"
  55. value="cm6"
  56. id="editor-switch-cm6"
  57. className="toggle-switch-input"
  58. checked={!richTextOrVisual && !!newSourceEditor}
  59. onChange={handleChange}
  60. />
  61. <label htmlFor="editor-switch-cm6" className="toggle-switch-label">
  62. <span>{t('code_editor')}</span>
  63. </label>
  64. <RichTextToggle
  65. checked={!!richTextOrVisual}
  66. disabled={!richTextAvailable}
  67. handleChange={handleChange}
  68. />
  69. </fieldset>
  70. {!!richTextOrVisual && (
  71. <SplitTestBadge splitTestName="rich-text" displayOnVariants={['cm6']} />
  72. )}
  73. </div>
  74. )
  75. }
  76. const RichTextToggle: FC<{
  77. checked: boolean
  78. disabled: boolean
  79. handleChange: (event: ChangeEvent<HTMLInputElement>) => void
  80. }> = ({ checked, disabled, handleChange }) => {
  81. const { t } = useTranslation()
  82. const toggle = (
  83. <span>
  84. <input
  85. type="radio"
  86. name="editor"
  87. value="rich-text"
  88. id="editor-switch-rich-text"
  89. className="toggle-switch-input"
  90. checked={checked}
  91. onChange={handleChange}
  92. disabled={disabled}
  93. />
  94. <label htmlFor="editor-switch-rich-text" className="toggle-switch-label">
  95. <span>{t('visual_editor')}</span>
  96. </label>
  97. </span>
  98. )
  99. if (disabled) {
  100. return (
  101. <Tooltip
  102. description={t('the_visual_editor_is_only_available_for_tex_files')}
  103. id="rich-text-toggle-tooltip"
  104. overlayProps={{ placement: 'bottom' }}
  105. tooltipProps={{ className: 'tooltip-wide' }}
  106. >
  107. {toggle}
  108. </Tooltip>
  109. )
  110. }
  111. return toggle
  112. }
  113. export default memo(EditorSwitch)