index.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import styled from '@emotion/styled';
  2. import ErrorBoundary from 'sentry/components/errorBoundary';
  3. import ReplayTimeline from 'sentry/components/replays/breadcrumbs/replayTimeline';
  4. import ReplayView from 'sentry/components/replays/replayView';
  5. import {space} from 'sentry/styles/space';
  6. import useFullscreen from 'sentry/utils/replays/hooks/useFullscreen';
  7. import {LayoutKey} from 'sentry/utils/replays/hooks/useReplayLayout';
  8. import FluidHeight from 'sentry/views/replays/detail/layout/fluidHeight';
  9. import FluidPanel from 'sentry/views/replays/detail/layout/fluidPanel';
  10. import FocusArea from 'sentry/views/replays/detail/layout/focusArea';
  11. import FocusTabs from 'sentry/views/replays/detail/layout/focusTabs';
  12. import MeasureSize from 'sentry/views/replays/detail/layout/measureSize';
  13. import SidebarArea from 'sentry/views/replays/detail/layout/sidebarArea';
  14. import SideTabs from 'sentry/views/replays/detail/layout/sideTabs';
  15. import SplitPanel from 'sentry/views/replays/detail/layout/splitPanel';
  16. const MIN_VIDEO_WIDTH = 325;
  17. const MIN_CONTENT_WIDTH = 340;
  18. const MIN_SIDEBAR_WIDTH = 325;
  19. const MIN_VIDEO_HEIGHT = 200;
  20. const MIN_CONTENT_HEIGHT = 180;
  21. const MIN_SIDEBAR_HEIGHT = 120;
  22. const DIVIDER_SIZE = 16;
  23. type Props = {
  24. layout?: LayoutKey;
  25. };
  26. function ReplayLayout({layout = LayoutKey.TOPBAR}: Props) {
  27. const {ref: fullscreenRef, toggle: toggleFullscreen} = useFullscreen();
  28. const timeline = (
  29. <ErrorBoundary mini>
  30. <ReplayTimeline />
  31. </ErrorBoundary>
  32. );
  33. const video = (
  34. <VideoSection ref={fullscreenRef}>
  35. <ErrorBoundary mini>
  36. <ReplayView toggleFullscreen={toggleFullscreen} />
  37. </ErrorBoundary>
  38. </VideoSection>
  39. );
  40. if (layout === LayoutKey.VIDEO_ONLY) {
  41. return (
  42. <BodyContent>
  43. {timeline}
  44. {video}
  45. </BodyContent>
  46. );
  47. }
  48. const focusArea = (
  49. <ErrorBoundary mini>
  50. <FluidPanel title={<SmallMarginFocusTabs />}>
  51. <FocusArea />
  52. </FluidPanel>
  53. </ErrorBoundary>
  54. );
  55. const sidebarArea = (
  56. <ErrorBoundary mini>
  57. <FluidPanel title={<SmallMarginSideTabs />}>
  58. <SidebarArea />
  59. </FluidPanel>
  60. </ErrorBoundary>
  61. );
  62. if (layout === LayoutKey.NO_VIDEO) {
  63. return (
  64. <BodyContent>
  65. {timeline}
  66. <MeasureSize>
  67. {({width}) => (
  68. <SplitPanel
  69. key={layout}
  70. availableSize={width}
  71. left={{
  72. content: focusArea,
  73. default: (width - DIVIDER_SIZE) * 0.9,
  74. min: 0,
  75. max: width - DIVIDER_SIZE,
  76. }}
  77. right={sidebarArea}
  78. />
  79. )}
  80. </MeasureSize>
  81. </BodyContent>
  82. );
  83. }
  84. if (layout === LayoutKey.SIDEBAR_LEFT) {
  85. return (
  86. <BodyContent>
  87. {timeline}
  88. <MeasureSize>
  89. {({height, width}) => (
  90. <SplitPanel
  91. key={layout}
  92. availableSize={width}
  93. left={{
  94. content: (
  95. <SplitPanel
  96. key={layout}
  97. availableSize={height}
  98. top={{
  99. content: video,
  100. default: (height - DIVIDER_SIZE) * 0.65,
  101. min: MIN_CONTENT_HEIGHT,
  102. max: height - DIVIDER_SIZE - MIN_SIDEBAR_HEIGHT,
  103. }}
  104. bottom={sidebarArea}
  105. />
  106. ),
  107. default: (width - DIVIDER_SIZE) * 0.5,
  108. min: MIN_SIDEBAR_WIDTH,
  109. max: width - DIVIDER_SIZE - MIN_CONTENT_WIDTH,
  110. }}
  111. right={focusArea}
  112. />
  113. )}
  114. </MeasureSize>
  115. </BodyContent>
  116. );
  117. }
  118. // layout === 'topbar'
  119. return (
  120. <BodyContent>
  121. {timeline}
  122. <MeasureSize>
  123. {({height, width}) => (
  124. <SplitPanel
  125. key={layout}
  126. availableSize={height}
  127. top={{
  128. content: (
  129. <SplitPanel
  130. availableSize={width}
  131. left={{
  132. content: video,
  133. default: (width - DIVIDER_SIZE) * 0.5,
  134. min: MIN_VIDEO_WIDTH,
  135. max: width - DIVIDER_SIZE - MIN_SIDEBAR_WIDTH,
  136. }}
  137. right={sidebarArea}
  138. />
  139. ),
  140. default: (height - DIVIDER_SIZE) * 0.5,
  141. min: MIN_VIDEO_HEIGHT,
  142. max: height - DIVIDER_SIZE - MIN_CONTENT_HEIGHT,
  143. }}
  144. bottom={focusArea}
  145. />
  146. )}
  147. </MeasureSize>
  148. </BodyContent>
  149. );
  150. }
  151. const BodyContent = styled('main')`
  152. background: ${p => p.theme.background};
  153. width: 100%;
  154. height: 100%;
  155. display: grid;
  156. grid-template-rows: auto 1fr;
  157. overflow: hidden;
  158. padding: ${space(2)};
  159. `;
  160. const SmallMarginFocusTabs = styled(FocusTabs)`
  161. margin-bottom: ${space(1)};
  162. `;
  163. const SmallMarginSideTabs = styled(SideTabs)`
  164. margin-bottom: ${space(1)};
  165. `;
  166. const VideoSection = styled(FluidHeight)`
  167. background: ${p => p.theme.background};
  168. gap: ${space(1)};
  169. :fullscreen {
  170. padding: ${space(1)};
  171. }
  172. `;
  173. export default ReplayLayout;