index.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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 FluidGrid from 'sentry/views/replays/detail/layout/fluidGrid';
  9. import FluidHeight from 'sentry/views/replays/detail/layout/fluidHeight';
  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. <FluidGrid>
  51. <FocusTabs />
  52. <FocusArea />
  53. </FluidGrid>
  54. </ErrorBoundary>
  55. );
  56. const sidebarArea = (
  57. <ErrorBoundary mini>
  58. <FluidGrid>
  59. <SideTabs />
  60. <SidebarArea />
  61. </FluidGrid>
  62. </ErrorBoundary>
  63. );
  64. if (layout === LayoutKey.no_video) {
  65. return (
  66. <BodyContent>
  67. {timeline}
  68. <MeasureSize>
  69. {({width}) => (
  70. <SplitPanel
  71. key={layout}
  72. availableSize={width}
  73. left={{
  74. content: focusArea,
  75. default: (width - DIVIDER_SIZE) * 0.9,
  76. min: 0,
  77. max: width - DIVIDER_SIZE,
  78. }}
  79. right={sidebarArea}
  80. />
  81. )}
  82. </MeasureSize>
  83. </BodyContent>
  84. );
  85. }
  86. if (layout === LayoutKey.sidebar_left) {
  87. return (
  88. <BodyContent>
  89. {timeline}
  90. <MeasureSize>
  91. {({height, width}) => (
  92. <SplitPanel
  93. key={layout}
  94. availableSize={width}
  95. left={{
  96. content: (
  97. <SplitPanel
  98. key={layout}
  99. availableSize={height}
  100. top={{
  101. content: video,
  102. default: (height - DIVIDER_SIZE) * 0.65,
  103. min: MIN_CONTENT_HEIGHT,
  104. max: height - DIVIDER_SIZE - MIN_SIDEBAR_HEIGHT,
  105. }}
  106. bottom={sidebarArea}
  107. />
  108. ),
  109. default: (width - DIVIDER_SIZE) * 0.5,
  110. min: MIN_SIDEBAR_WIDTH,
  111. max: width - DIVIDER_SIZE - MIN_CONTENT_WIDTH,
  112. }}
  113. right={focusArea}
  114. />
  115. )}
  116. </MeasureSize>
  117. </BodyContent>
  118. );
  119. }
  120. // layout === 'topbar'
  121. return (
  122. <BodyContent>
  123. {timeline}
  124. <MeasureSize>
  125. {({height, width}) => (
  126. <SplitPanel
  127. key={layout}
  128. availableSize={height}
  129. top={{
  130. content: (
  131. <SplitPanel
  132. availableSize={width}
  133. left={{
  134. content: video,
  135. default: (width - DIVIDER_SIZE) * 0.5,
  136. min: MIN_VIDEO_WIDTH,
  137. max: width - DIVIDER_SIZE - MIN_SIDEBAR_WIDTH,
  138. }}
  139. right={sidebarArea}
  140. />
  141. ),
  142. default: (height - DIVIDER_SIZE) * 0.5,
  143. min: MIN_VIDEO_HEIGHT,
  144. max: height - DIVIDER_SIZE - MIN_CONTENT_HEIGHT,
  145. }}
  146. bottom={focusArea}
  147. />
  148. )}
  149. </MeasureSize>
  150. </BodyContent>
  151. );
  152. }
  153. const BodyContent = styled('main')`
  154. background: ${p => p.theme.background};
  155. width: 100%;
  156. height: 100%;
  157. display: grid;
  158. gap: ${space(2)};
  159. grid-template-rows: auto 1fr;
  160. overflow: hidden;
  161. padding: ${space(2)};
  162. `;
  163. const VideoSection = styled(FluidHeight)`
  164. background: ${p => p.theme.background};
  165. gap: ${space(1)};
  166. :fullscreen {
  167. padding: ${space(1)};
  168. }
  169. `;
  170. export default ReplayLayout;