editor-switch.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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 isValidTeXFile from '../../../main/is-valid-tex-file'
  6. import { useTranslation } from 'react-i18next'
  7. import { PromotionOverlay } from './table-generator/promotion/popover'
  8. import { FeedbackBadge } from '@/shared/components/feedback-badge'
  9. function EditorSwitch() {
  10. const { t } = useTranslation()
  11. const [newSourceEditor, setNewSourceEditor] = useScopeValue(
  12. 'editor.newSourceEditor'
  13. )
  14. const [visual, setVisual] = useScopeValue('editor.showVisual')
  15. const [docName] = useScopeValue('editor.open_doc_name')
  16. const richTextAvailable = isValidTeXFile(docName)
  17. // TODO: rename this after legacy & toolbar split tests are complete
  18. const richTextOrVisual = richTextAvailable && visual
  19. const handleChange = useCallback(
  20. event => {
  21. const editorType = event.target.value
  22. switch (editorType) {
  23. case 'ace':
  24. setVisual(false)
  25. setNewSourceEditor(false)
  26. break
  27. case 'cm6':
  28. setVisual(false)
  29. setNewSourceEditor(true)
  30. break
  31. case 'rich-text':
  32. setVisual(true)
  33. setNewSourceEditor(true)
  34. break
  35. }
  36. sendMB('editor-switch-change', { editorType })
  37. },
  38. [setVisual, setNewSourceEditor]
  39. )
  40. return (
  41. <div className="editor-toggle-switch">
  42. <fieldset className="toggle-switch">
  43. <legend className="sr-only">Editor mode.</legend>
  44. <input
  45. type="radio"
  46. name="editor"
  47. value="cm6"
  48. id="editor-switch-cm6"
  49. className="toggle-switch-input"
  50. checked={!richTextOrVisual && !!newSourceEditor}
  51. onChange={handleChange}
  52. />
  53. <label htmlFor="editor-switch-cm6" className="toggle-switch-label">
  54. <span>{t('code_editor')}</span>
  55. </label>
  56. <RichTextToggle
  57. checked={!!richTextOrVisual}
  58. disabled={!richTextAvailable}
  59. handleChange={handleChange}
  60. />
  61. </fieldset>
  62. {!!richTextOrVisual && (
  63. <FeedbackBadge
  64. id="visual-editor-feedback"
  65. url="https://forms.gle/AUqHmKNiEH3DRniPA"
  66. text={<VisualEditorFeedbackContent />}
  67. />
  68. )}
  69. </div>
  70. )
  71. }
  72. const VisualEditorFeedbackContent = () => (
  73. <>
  74. We have a new Visual Editor!
  75. <br />
  76. Click to give feedback
  77. </>
  78. )
  79. const RichTextToggle: FC<{
  80. checked: boolean
  81. disabled: boolean
  82. handleChange: (event: ChangeEvent<HTMLInputElement>) => void
  83. }> = ({ checked, disabled, handleChange }) => {
  84. const { t } = useTranslation()
  85. const toggle = (
  86. <span>
  87. <input
  88. type="radio"
  89. name="editor"
  90. value="rich-text"
  91. id="editor-switch-rich-text"
  92. className="toggle-switch-input"
  93. checked={checked}
  94. onChange={handleChange}
  95. disabled={disabled}
  96. />
  97. <label htmlFor="editor-switch-rich-text" className="toggle-switch-label">
  98. <span>{t('visual_editor')}</span>
  99. </label>
  100. </span>
  101. )
  102. if (disabled) {
  103. return (
  104. <Tooltip
  105. description={t('visual_editor_is_only_available_for_tex_files')}
  106. id="rich-text-toggle-tooltip"
  107. overlayProps={{ placement: 'bottom' }}
  108. tooltipProps={{ className: 'tooltip-wide' }}
  109. >
  110. {toggle}
  111. </Tooltip>
  112. )
  113. }
  114. return <PromotionOverlay>{toggle}</PromotionOverlay>
  115. }
  116. export default memo(EditorSwitch)