layout-context.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { createContext, useContext, useCallback, useMemo } from 'react'
  2. import PropTypes from 'prop-types'
  3. import useScopeValue from '../hooks/use-scope-value'
  4. import { useIdeContext } from './ide-context'
  5. import localStorage from '../../infrastructure/local-storage'
  6. export const LayoutContext = createContext()
  7. LayoutContext.Provider.propTypes = {
  8. value: PropTypes.shape({
  9. view: PropTypes.string,
  10. setView: PropTypes.func.isRequired,
  11. chatIsOpen: PropTypes.bool,
  12. setChatIsOpen: PropTypes.func.isRequired,
  13. reviewPanelOpen: PropTypes.bool,
  14. setReviewPanelOpen: PropTypes.func.isRequired,
  15. leftMenuShown: PropTypes.bool,
  16. setLeftMenuShown: PropTypes.func.isRequired,
  17. pdfLayout: PropTypes.oneOf(['sideBySide', 'flat']).isRequired,
  18. }).isRequired,
  19. }
  20. export function LayoutProvider({ children }) {
  21. const { $scope } = useIdeContext()
  22. // what to show in the "flat" view (editor or pdf)
  23. const [view, _setView] = useScopeValue('ui.view')
  24. const setView = useCallback(
  25. value => {
  26. _setView(oldValue => {
  27. // ensure that the "history:toggle" event is broadcast when switching in or out of history view
  28. if (value === 'history' || oldValue === 'history') {
  29. $scope.toggleHistory()
  30. }
  31. return value
  32. })
  33. },
  34. [$scope, _setView]
  35. )
  36. // whether the chat pane is open
  37. const [chatIsOpen, setChatIsOpen] = useScopeValue('ui.chatOpen')
  38. // whether the review pane is open
  39. const [reviewPanelOpen, setReviewPanelOpen] = useScopeValue(
  40. 'ui.reviewPanelOpen'
  41. )
  42. // whether the menu pane is open
  43. const [leftMenuShown, setLeftMenuShown] = useScopeValue('ui.leftMenuShown')
  44. // whether to display the editor and preview side-by-side or full-width ("flat")
  45. const [pdfLayout, setPdfLayout] = useScopeValue('ui.pdfLayout')
  46. // switch to either side-by-side or flat (full-width) layout
  47. const switchLayout = useCallback(() => {
  48. setPdfLayout(layout => {
  49. const newLayout = layout === 'sideBySide' ? 'flat' : 'sideBySide'
  50. setView(newLayout === 'sideBySide' ? 'editor' : 'pdf')
  51. setPdfLayout(newLayout)
  52. localStorage.setItem('pdf.layout', newLayout)
  53. })
  54. }, [setPdfLayout, setView])
  55. const changeLayout = useCallback(
  56. (newLayout, newView) => {
  57. setPdfLayout(newLayout)
  58. setView(newLayout === 'sideBySide' ? 'editor' : newView)
  59. localStorage.setItem('pdf.layout', newLayout)
  60. },
  61. [setPdfLayout, setView]
  62. )
  63. const value = useMemo(
  64. () => ({
  65. changeLayout,
  66. chatIsOpen,
  67. leftMenuShown,
  68. pdfLayout,
  69. reviewPanelOpen,
  70. setChatIsOpen,
  71. setLeftMenuShown,
  72. setPdfLayout,
  73. setReviewPanelOpen,
  74. setView,
  75. switchLayout,
  76. view,
  77. }),
  78. [
  79. changeLayout,
  80. chatIsOpen,
  81. leftMenuShown,
  82. pdfLayout,
  83. reviewPanelOpen,
  84. setChatIsOpen,
  85. setLeftMenuShown,
  86. setPdfLayout,
  87. setReviewPanelOpen,
  88. setView,
  89. switchLayout,
  90. view,
  91. ]
  92. )
  93. return (
  94. <LayoutContext.Provider value={value}>{children}</LayoutContext.Provider>
  95. )
  96. }
  97. LayoutProvider.propTypes = {
  98. children: PropTypes.any,
  99. }
  100. export function useLayoutContext(propTypes) {
  101. const data = useContext(LayoutContext)
  102. PropTypes.checkPropTypes(propTypes, data, 'data', 'LayoutContext.Provider')
  103. return data
  104. }