file-tree-toolbar.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import { useTranslation } from 'react-i18next'
  2. import * as eventTracking from '../../../infrastructure/event-tracking'
  3. import Icon from '../../../shared/components/icon'
  4. import { useFileTreeActionable } from '../contexts/file-tree-actionable'
  5. import { useFileTreeData } from '@/shared/context/file-tree-data-context'
  6. import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
  7. import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
  8. import MaterialIcon from '@/shared/components/material-icon'
  9. import OLButtonToolbar from '@/features/ui/components/ol/ol-button-toolbar'
  10. import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
  11. import React, { ElementType } from 'react'
  12. const fileTreeToolbarComponents = importOverleafModules(
  13. 'fileTreeToolbarComponents'
  14. ) as { import: { default: ElementType }; path: string }[]
  15. function FileTreeToolbar() {
  16. const { fileTreeReadOnly } = useFileTreeData()
  17. const { t } = useTranslation()
  18. if (fileTreeReadOnly) return null
  19. return (
  20. <OLButtonToolbar
  21. className="toolbar toolbar-filetree"
  22. aria-label={t('project_files')}
  23. >
  24. <FileTreeToolbarLeft />
  25. <FileTreeToolbarRight />
  26. </OLButtonToolbar>
  27. )
  28. }
  29. function FileTreeToolbarLeft() {
  30. const { t } = useTranslation()
  31. const {
  32. canCreate,
  33. startCreatingFolder,
  34. startCreatingDocOrFile,
  35. startUploadingDocOrFile,
  36. } = useFileTreeActionable()
  37. const createWithAnalytics = () => {
  38. eventTracking.sendMB('new-file-click', { location: 'toolbar' })
  39. startCreatingDocOrFile()
  40. }
  41. const uploadWithAnalytics = () => {
  42. eventTracking.sendMB('upload-click', { location: 'toolbar' })
  43. startUploadingDocOrFile()
  44. }
  45. if (!canCreate) return null
  46. return (
  47. <div className="toolbar-left">
  48. <OLTooltip
  49. id="new-file"
  50. description={t('new_file')}
  51. overlayProps={{ placement: 'bottom' }}
  52. >
  53. <button className="btn" onClick={createWithAnalytics}>
  54. <BootstrapVersionSwitcher
  55. bs5={
  56. <MaterialIcon
  57. type="description"
  58. accessibilityLabel={t('new_file')}
  59. />
  60. }
  61. bs3={<Icon type="file" fw accessibilityLabel={t('new_file')} />}
  62. />
  63. </button>
  64. </OLTooltip>
  65. <OLTooltip
  66. id="new-folder"
  67. description={t('new_folder')}
  68. overlayProps={{ placement: 'bottom' }}
  69. >
  70. <button className="btn" onClick={startCreatingFolder} tabIndex={-1}>
  71. <BootstrapVersionSwitcher
  72. bs5={
  73. <MaterialIcon
  74. type="folder"
  75. accessibilityLabel={t('new_folder')}
  76. />
  77. }
  78. bs3={<Icon type="folder" fw accessibilityLabel={t('new_folder')} />}
  79. />
  80. </button>
  81. </OLTooltip>
  82. <OLTooltip
  83. id="upload"
  84. description={t('upload')}
  85. overlayProps={{ placement: 'bottom' }}
  86. >
  87. <button className="btn" onClick={uploadWithAnalytics} tabIndex={-1}>
  88. <BootstrapVersionSwitcher
  89. bs5={
  90. <MaterialIcon type="upload" accessibilityLabel={t('upload')} />
  91. }
  92. bs3={<Icon type="upload" fw accessibilityLabel={t('upload')} />}
  93. />
  94. </button>
  95. </OLTooltip>
  96. </div>
  97. )
  98. }
  99. function FileTreeToolbarRight() {
  100. const { t } = useTranslation()
  101. const { canRename, canDelete, startRenaming, startDeleting } =
  102. useFileTreeActionable()
  103. return (
  104. <div className="toolbar-right">
  105. {fileTreeToolbarComponents.map(
  106. ({ import: { default: Component }, path }) => (
  107. <Component key={path} />
  108. )
  109. )}
  110. {canRename ? (
  111. <OLTooltip
  112. id="rename"
  113. description={t('rename')}
  114. overlayProps={{ placement: 'bottom' }}
  115. >
  116. <button className="btn" onClick={startRenaming} tabIndex={-1}>
  117. <BootstrapVersionSwitcher
  118. bs3={<Icon type="pencil" fw accessibilityLabel={t('rename')} />}
  119. bs5={
  120. <MaterialIcon type="edit" accessibilityLabel={t('rename')} />
  121. }
  122. />
  123. </button>
  124. </OLTooltip>
  125. ) : null}
  126. {canDelete ? (
  127. <OLTooltip
  128. id="delete"
  129. description={t('delete')}
  130. overlayProps={{ placement: 'bottom' }}
  131. >
  132. <button className="btn" onClick={startDeleting} tabIndex={-1}>
  133. <BootstrapVersionSwitcher
  134. bs3={<Icon type="trash-o" fw accessibilityLabel={t('delete')} />}
  135. bs5={
  136. <MaterialIcon type="delete" accessibilityLabel={t('delete')} />
  137. }
  138. />
  139. </button>
  140. </OLTooltip>
  141. ) : null}
  142. </div>
  143. )
  144. }
  145. export default FileTreeToolbar