pdf-viewer-controls-toolbar.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. import { memo, useCallback, useState } from 'react'
  2. import { createPortal } from 'react-dom'
  3. import PdfPageNumberControl from './pdf-page-number-control'
  4. import PdfZoomButtons from './pdf-zoom-buttons'
  5. import PdfZoomDropdown from './pdf-zoom-dropdown'
  6. import { useResizeObserver } from '@/shared/hooks/use-resize-observer'
  7. import PdfViewerControlsMenuButton from './pdf-viewer-controls-menu-button'
  8. import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
  9. import { useCommandProvider } from '@/features/ide-react/hooks/use-command-provider'
  10. import { useTranslation } from 'react-i18next'
  11. import { useLayoutContext } from '@/shared/context/layout-context'
  12. import { PdfHybridThemeButton } from './pdf-hybrid-theme-button'
  13. type PdfViewerControlsToolbarProps = {
  14. requestPresentationMode: () => void
  15. setZoom: (zoom: string) => void
  16. rawScale: number
  17. setPage: (page: number) => void
  18. page: number
  19. totalPages: number
  20. pdfContainer?: HTMLDivElement
  21. }
  22. function PdfViewerControlsToolbar({
  23. requestPresentationMode,
  24. setZoom,
  25. rawScale,
  26. setPage,
  27. page,
  28. totalPages,
  29. pdfContainer,
  30. }: PdfViewerControlsToolbarProps) {
  31. const { t } = useTranslation()
  32. const { showLogs } = useCompileContext()
  33. const toolbarControlsElement = document.querySelector('#toolbar-pdf-controls')
  34. const [availableWidth, setAvailableWidth] = useState<number>(1000)
  35. const handleResize = useCallback(
  36. (element: Element) => {
  37. setAvailableWidth((element as HTMLElement).offsetWidth)
  38. },
  39. [setAvailableWidth]
  40. )
  41. const { elementRef: pdfControlsRef } = useResizeObserver(handleResize)
  42. const { view: ideView, pdfLayout } = useLayoutContext()
  43. const editorOnly = ideView !== 'pdf' && pdfLayout === 'flat'
  44. useCommandProvider(() => {
  45. if (editorOnly) {
  46. return
  47. }
  48. return [
  49. {
  50. id: 'view-pdf-presentation-mode',
  51. label: t('presentation_mode'),
  52. handler: requestPresentationMode,
  53. },
  54. {
  55. id: 'view-pdf-zoom-in',
  56. label: t('zoom_in'),
  57. handler: () => setZoom('zoom-in'),
  58. },
  59. {
  60. id: 'view-pdf-zoom-out',
  61. label: t('zoom_out'),
  62. handler: () => setZoom('zoom-out'),
  63. },
  64. {
  65. id: 'view-pdf-fit-width',
  66. label: t('fit_to_width'),
  67. handler: () => setZoom('page-width'),
  68. },
  69. {
  70. id: 'view-pdf-fit-height',
  71. label: t('fit_to_height'),
  72. handler: () => setZoom('page-height'),
  73. },
  74. ]
  75. }, [t, requestPresentationMode, setZoom, editorOnly])
  76. if (!toolbarControlsElement) {
  77. return null
  78. }
  79. if (showLogs) {
  80. return null
  81. }
  82. const InnerControlsComponent =
  83. availableWidth >= 320
  84. ? PdfViewerControlsToolbarFull
  85. : PdfViewerControlsToolbarSmall
  86. return createPortal(
  87. <div className="pdfjs-viewer-controls" ref={pdfControlsRef}>
  88. <InnerControlsComponent
  89. requestPresentationMode={requestPresentationMode}
  90. setZoom={setZoom}
  91. rawScale={rawScale}
  92. setPage={setPage}
  93. page={page}
  94. totalPages={totalPages}
  95. pdfContainer={pdfContainer}
  96. />
  97. </div>,
  98. toolbarControlsElement
  99. )
  100. }
  101. type InnerControlsProps = {
  102. requestPresentationMode: () => void
  103. setZoom: (zoom: string) => void
  104. rawScale: number
  105. setPage: (page: number) => void
  106. page: number
  107. totalPages: number
  108. // eslint-disable-next-line react/no-unused-prop-types
  109. pdfContainer?: HTMLDivElement
  110. }
  111. function PdfViewerControlsToolbarFull({
  112. requestPresentationMode,
  113. setZoom,
  114. rawScale,
  115. setPage,
  116. page,
  117. totalPages,
  118. }: InnerControlsProps) {
  119. return (
  120. <>
  121. <PdfHybridThemeButton />
  122. <PdfPageNumberControl
  123. setPage={setPage}
  124. page={page}
  125. totalPages={totalPages}
  126. />
  127. <div className="pdfjs-zoom-controls">
  128. <PdfZoomButtons setZoom={setZoom} />
  129. <PdfZoomDropdown
  130. requestPresentationMode={requestPresentationMode}
  131. rawScale={rawScale}
  132. setZoom={setZoom}
  133. />
  134. </div>
  135. </>
  136. )
  137. }
  138. function PdfViewerControlsToolbarSmall({
  139. requestPresentationMode,
  140. setZoom,
  141. rawScale,
  142. setPage,
  143. page,
  144. totalPages,
  145. pdfContainer,
  146. }: InnerControlsProps) {
  147. return (
  148. <div className="pdfjs-viewer-controls-small">
  149. <PdfHybridThemeButton />
  150. <PdfZoomDropdown
  151. requestPresentationMode={requestPresentationMode}
  152. rawScale={rawScale}
  153. setZoom={setZoom}
  154. />
  155. <PdfViewerControlsMenuButton
  156. setZoom={setZoom}
  157. setPage={setPage}
  158. page={page}
  159. totalPages={totalPages}
  160. pdfContainer={pdfContainer}
  161. />
  162. </div>
  163. )
  164. }
  165. export default memo(PdfViewerControlsToolbar)