editor-switch-legacy.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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. function Badge() {
  9. const content = (
  10. <>
  11. Overleaf has upgraded the source editor.
  12. <br />
  13. You can still use the old editor by selecting "Source (legacy)".
  14. <br />
  15. <br />
  16. Click to learn more and give feedback
  17. </>
  18. )
  19. return (
  20. <Tooltip
  21. id="editor-switch"
  22. description={content}
  23. overlayProps={{
  24. placement: 'bottom',
  25. delayHide: 100,
  26. }}
  27. tooltipProps={{ className: 'tooltip-wide' }}
  28. >
  29. <a
  30. href="https://forms.gle/GmSs6odZRKRp3VX98"
  31. target="_blank"
  32. rel="noopener noreferrer"
  33. className="info-badge"
  34. >
  35. <span className="sr-only">{content}</span>
  36. </a>
  37. </Tooltip>
  38. )
  39. }
  40. const showLegacySourceEditor: boolean = getMeta('ol-showLegacySourceEditor')
  41. function EditorSwitch() {
  42. const { t } = useTranslation()
  43. const [newSourceEditor, setNewSourceEditor] = useScopeValue(
  44. 'editor.newSourceEditor'
  45. )
  46. const [visual, setVisual] = useScopeValue('editor.showVisual')
  47. const [docName] = useScopeValue('editor.open_doc_name')
  48. const richTextAvailable = isValidTeXFile(docName)
  49. // TODO: rename this after legacy & toolbar split tests are complete
  50. const richTextOrVisual = richTextAvailable && visual
  51. const handleChange = useCallback(
  52. event => {
  53. const editorType = event.target.value
  54. switch (editorType) {
  55. case 'ace':
  56. setVisual(false)
  57. setNewSourceEditor(false)
  58. break
  59. case 'cm6':
  60. setVisual(false)
  61. setNewSourceEditor(true)
  62. break
  63. case 'rich-text':
  64. setVisual(true)
  65. setNewSourceEditor(true)
  66. break
  67. }
  68. sendMB('editor-switch-change', { editorType })
  69. },
  70. [setVisual, setNewSourceEditor]
  71. )
  72. return (
  73. <div className="editor-toggle-switch">
  74. {showLegacySourceEditor ? <Badge /> : null}
  75. <fieldset className="toggle-switch">
  76. <legend className="sr-only">Editor mode.</legend>
  77. <input
  78. type="radio"
  79. name="editor"
  80. value="cm6"
  81. id="editor-switch-cm6"
  82. className="toggle-switch-input"
  83. checked={!richTextOrVisual && !!newSourceEditor}
  84. onChange={handleChange}
  85. />
  86. <label htmlFor="editor-switch-cm6" className="toggle-switch-label">
  87. <span>{t('code_editor')}</span>
  88. </label>
  89. {showLegacySourceEditor ? (
  90. <>
  91. <input
  92. type="radio"
  93. name="editor"
  94. value="ace"
  95. id="editor-switch-ace"
  96. className="toggle-switch-input"
  97. checked={!richTextOrVisual && !newSourceEditor}
  98. onChange={handleChange}
  99. />
  100. <label htmlFor="editor-switch-ace" className="toggle-switch-label">
  101. <span>Source (legacy)</span>
  102. </label>
  103. </>
  104. ) : null}
  105. <RichTextToggle
  106. checked={!!richTextOrVisual}
  107. disabled={!richTextAvailable}
  108. handleChange={handleChange}
  109. />
  110. </fieldset>
  111. </div>
  112. )
  113. }
  114. const RichTextToggle: FC<{
  115. checked: boolean
  116. disabled: boolean
  117. handleChange: (event: ChangeEvent<HTMLInputElement>) => void
  118. }> = ({ checked, disabled, handleChange }) => {
  119. const { t } = useTranslation()
  120. const toggle = (
  121. <span>
  122. <input
  123. type="radio"
  124. name="editor"
  125. value="rich-text"
  126. id="editor-switch-rich-text"
  127. className="toggle-switch-input"
  128. checked={checked}
  129. onChange={handleChange}
  130. disabled={disabled}
  131. />
  132. <label htmlFor="editor-switch-rich-text" className="toggle-switch-label">
  133. <span>{t('visual_editor')}</span>
  134. </label>
  135. </span>
  136. )
  137. if (disabled) {
  138. return (
  139. <Tooltip
  140. description={t('visual_editor_is_only_available_for_tex_files')}
  141. id="rich-text-toggle-tooltip"
  142. overlayProps={{ placement: 'bottom' }}
  143. tooltipProps={{ className: 'tooltip-wide' }}
  144. >
  145. {toggle}
  146. </Tooltip>
  147. )
  148. }
  149. return toggle
  150. }
  151. export default memo(EditorSwitch)