pdf-compile-button.jsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import { useTranslation } from 'react-i18next'
  2. import { memo } from 'react'
  3. import classNames from 'classnames'
  4. import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
  5. import { useStopOnFirstError } from '../../../shared/hooks/use-stop-on-first-error'
  6. import SplitMenu from '../../../shared/components/split-menu'
  7. import Icon from '../../../shared/components/icon'
  8. import * as eventTracking from '../../../infrastructure/event-tracking'
  9. const modifierKey = /Mac/i.test(navigator.platform) ? 'Cmd' : 'Ctrl'
  10. function sendEventAndSet(value, setter, settingName) {
  11. eventTracking.sendMB('recompile-setting-changed', {
  12. setting: settingName,
  13. settingVal: value,
  14. })
  15. setter(value)
  16. }
  17. function PdfCompileButton() {
  18. const {
  19. animateCompileDropdownArrow,
  20. autoCompile,
  21. compiling,
  22. draft,
  23. hasChanges,
  24. setAnimateCompileDropdownArrow,
  25. setAutoCompile,
  26. setDraft,
  27. setStopOnValidationError,
  28. stopOnFirstError,
  29. stopOnValidationError,
  30. startCompile,
  31. stopCompile,
  32. recompileFromScratch,
  33. } = useCompileContext()
  34. const { enableStopOnFirstError, disableStopOnFirstError } =
  35. useStopOnFirstError({ eventSource: 'dropdown' })
  36. const { t } = useTranslation()
  37. const fromScratchWithEvent = () => {
  38. eventTracking.sendMB('recompile-setting-changed', {
  39. setting: 'from-scratch',
  40. })
  41. recompileFromScratch()
  42. }
  43. const compileButtonLabel = compiling ? `${t('compiling')}…` : t('recompile')
  44. const tooltipElement = (
  45. <>
  46. {t('recompile_pdf')}{' '}
  47. <span className="keyboard-shortcut">({modifierKey} + Enter)</span>
  48. </>
  49. )
  50. const dropdownToggleClassName = classNames({
  51. 'detach-compile-button-animate': animateCompileDropdownArrow,
  52. 'btn-striped-animated': hasChanges,
  53. })
  54. const buttonClassName = classNames({
  55. 'btn-striped-animated': hasChanges,
  56. 'no-left-radius': true,
  57. })
  58. return (
  59. <SplitMenu
  60. bsStyle="primary"
  61. bsSize="xs"
  62. disabled={compiling}
  63. button={{
  64. tooltip: {
  65. description: tooltipElement,
  66. id: 'compile',
  67. tooltipProps: { className: 'keyboard-tooltip' },
  68. overlayProps: { delayShow: 500 },
  69. },
  70. icon: { type: 'refresh', spin: compiling },
  71. onClick: () => startCompile(),
  72. text: compileButtonLabel,
  73. className: buttonClassName,
  74. }}
  75. dropdownToggle={{
  76. 'aria-label': t('toggle_compile_options_menu'),
  77. handleAnimationEnd: () => setAnimateCompileDropdownArrow(false),
  78. className: dropdownToggleClassName,
  79. }}
  80. dropdown={{
  81. id: 'pdf-recompile-dropdown',
  82. }}
  83. >
  84. <SplitMenu.Item header>{t('auto_compile')}</SplitMenu.Item>
  85. <SplitMenu.Item
  86. onSelect={() => sendEventAndSet(true, setAutoCompile, 'auto-compile')}
  87. >
  88. <Icon type={autoCompile ? 'check' : ''} fw />
  89. {t('on')}
  90. </SplitMenu.Item>
  91. <SplitMenu.Item
  92. onSelect={() => sendEventAndSet(false, setAutoCompile, 'auto-compile')}
  93. >
  94. <Icon type={!autoCompile ? 'check' : ''} fw />
  95. {t('off')}
  96. </SplitMenu.Item>
  97. <SplitMenu.Item header>{t('compile_mode')}</SplitMenu.Item>
  98. <SplitMenu.Item
  99. onSelect={() => sendEventAndSet(false, setDraft, 'compile-mode')}
  100. >
  101. <Icon type={!draft ? 'check' : ''} fw />
  102. {t('normal')}
  103. </SplitMenu.Item>
  104. <SplitMenu.Item
  105. onSelect={() => sendEventAndSet(true, setDraft, 'compile-mode')}
  106. >
  107. <Icon type={draft ? 'check' : ''} fw />
  108. {t('fast')} <span className="subdued">[draft]</span>
  109. </SplitMenu.Item>
  110. <SplitMenu.Item header>Syntax Checks</SplitMenu.Item>
  111. <SplitMenu.Item
  112. onSelect={() =>
  113. sendEventAndSet(true, setStopOnValidationError, 'syntax-check')
  114. }
  115. >
  116. <Icon type={stopOnValidationError ? 'check' : ''} fw />
  117. {t('stop_on_validation_error')}
  118. </SplitMenu.Item>
  119. <SplitMenu.Item
  120. onSelect={() =>
  121. sendEventAndSet(false, setStopOnValidationError, 'syntax-check')
  122. }
  123. >
  124. <Icon type={!stopOnValidationError ? 'check' : ''} fw />
  125. {t('ignore_validation_errors')}
  126. </SplitMenu.Item>
  127. <SplitMenu.Item header>{t('compile_error_handling')}</SplitMenu.Item>
  128. <SplitMenu.Item onSelect={enableStopOnFirstError}>
  129. <Icon type={stopOnFirstError ? 'check' : ''} fw />
  130. {t('stop_on_first_error')}
  131. </SplitMenu.Item>
  132. <SplitMenu.Item onSelect={disableStopOnFirstError}>
  133. <Icon type={!stopOnFirstError ? 'check' : ''} fw />
  134. {t('try_to_compile_despite_errors')}
  135. </SplitMenu.Item>
  136. <SplitMenu.Item divider />
  137. <SplitMenu.Item
  138. onSelect={() => stopCompile()}
  139. disabled={!compiling}
  140. aria-disabled={!compiling}
  141. >
  142. {t('stop_compile')}
  143. </SplitMenu.Item>
  144. <SplitMenu.Item
  145. onSelect={fromScratchWithEvent}
  146. disabled={compiling}
  147. aria-disabled={compiling}
  148. >
  149. {t('recompile_from_scratch')}
  150. </SplitMenu.Item>
  151. </SplitMenu>
  152. )
  153. }
  154. export default memo(PdfCompileButton)