editor-switch.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import { 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. const params = new URLSearchParams(window.location.search)
  6. function Badge() {
  7. const content = (
  8. <>
  9. Overleaf has upgraded the source editor. You can still use the old editor
  10. by selecting "Source (legacy)".
  11. <br />
  12. <br />
  13. Click to learn more and give feedback
  14. </>
  15. )
  16. return (
  17. <Tooltip
  18. id="editor-switch"
  19. description={content}
  20. overlayProps={{
  21. placement: 'bottom',
  22. delayHide: 100,
  23. }}
  24. tooltipProps={{ className: 'tooltip-wide' }}
  25. >
  26. <a
  27. href="https://forms.gle/GmSs6odZRKRp3VX98"
  28. target="_blank"
  29. rel="noopener noreferrer"
  30. className="badge info-badge"
  31. >
  32. <span className="sr-only">{content}</span>
  33. </a>
  34. </Tooltip>
  35. )
  36. }
  37. function EditorSwitch() {
  38. const [newSourceEditor, setNewSourceEditor] = useScopeValue(
  39. 'editor.newSourceEditor'
  40. )
  41. const [richText, setRichText] = useScopeValue('editor.showRichText')
  42. const [visual, setVisual] = useScopeValue('editor.showVisual')
  43. const richTextOrVisual = richText || visual
  44. const handleChange = useCallback(
  45. event => {
  46. const editorType = event.target.value
  47. switch (editorType) {
  48. case 'ace':
  49. setRichText(false)
  50. setVisual(false)
  51. setNewSourceEditor(false)
  52. break
  53. case 'cm6':
  54. setRichText(false)
  55. setVisual(false)
  56. setNewSourceEditor(true)
  57. break
  58. case 'rich-text':
  59. if (params.has('cm_visual')) {
  60. setRichText(false)
  61. setVisual(true)
  62. setNewSourceEditor(true)
  63. } else {
  64. setRichText(true)
  65. setVisual(false)
  66. }
  67. break
  68. }
  69. sendMB('editor-switch-change', { editorType })
  70. },
  71. [setRichText, setVisual, setNewSourceEditor]
  72. )
  73. return (
  74. <div className="editor-toggle-switch">
  75. <Badge />
  76. <fieldset className="toggle-switch">
  77. <legend className="sr-only">Editor mode.</legend>
  78. <input
  79. type="radio"
  80. name="editor"
  81. value="cm6"
  82. id="editor-switch-cm6"
  83. className="toggle-switch-input"
  84. checked={!richTextOrVisual && !!newSourceEditor}
  85. onChange={handleChange}
  86. />
  87. <label htmlFor="editor-switch-cm6" className="toggle-switch-label">
  88. <span>Source</span>
  89. </label>
  90. <input
  91. type="radio"
  92. name="editor"
  93. value="ace"
  94. id="editor-switch-ace"
  95. className="toggle-switch-input"
  96. checked={!richTextOrVisual && !newSourceEditor}
  97. onChange={handleChange}
  98. />
  99. <label htmlFor="editor-switch-ace" className="toggle-switch-label">
  100. <span>Source (legacy)</span>
  101. </label>
  102. <input
  103. type="radio"
  104. name="editor"
  105. value="rich-text"
  106. id="editor-switch-rich-text"
  107. className="toggle-switch-input"
  108. checked={!!richTextOrVisual}
  109. onChange={handleChange}
  110. />
  111. <label
  112. htmlFor="editor-switch-rich-text"
  113. className="toggle-switch-label"
  114. >
  115. <span>Rich Text</span>
  116. </label>
  117. </fieldset>
  118. </div>
  119. )
  120. }
  121. export default memo(EditorSwitch)