1import { css } from '@emotion/react'; 2import { breakpoints, theme } from '@expo/styleguide'; 3import React, { PropsWithChildren, ReactNode } from 'react'; 4 5import { LayoutScroll } from './LayoutScroll'; 6 7type LayoutProps = PropsWithChildren<{ 8 /** The content within the top bar that spans the columns */ 9 header: ReactNode; 10 /** The content within the left column */ 11 navigation?: ReactNode; 12 /** The content within the right column */ 13 sidebar?: ReactNode; 14}>; 15 16export function Layout({ header, navigation, sidebar, children }: LayoutProps) { 17 return ( 18 <div css={layoutStyle}> 19 <div css={headerStyle}>{header}</div> 20 <div css={navigationStyle}>{navigation}</div> 21 <div css={contentStyle}> 22 <LayoutScroll> 23 <div css={innerContentStyle}>{children}</div> 24 </LayoutScroll> 25 </div> 26 <div css={sidebarStyle}>{sidebar}</div> 27 </div> 28 ); 29} 30 31const layoutStyle = css({ 32 display: 'grid', 33 height: '100vh', 34 gridTemplateRows: '60px calc(100vh - 60px)', 35 gridTemplateColumns: 'min-content auto min-content', 36 gridTemplateAreas: ` 37 "header header header" 38 "navigation content sidebar" 39 `, 40 backgroundColor: theme.background.default, 41 '[data-expo-theme="dark"] &': { 42 backgroundColor: theme.background.screen, 43 }, 44}); 45 46const headerStyle = css({ gridArea: 'header' }); 47 48const navigationStyle = css({ 49 gridArea: 'navigation', 50 [`@media screen and (max-width: 768px)`]: { 51 display: 'none', 52 }, 53}); 54 55const contentStyle = css({ gridArea: 'content' }); 56const innerContentStyle = css({ 57 margin: '0 auto', 58 maxWidth: breakpoints.large, 59 height: '100%', 60 overflowY: 'visible', 61}); 62 63const sidebarStyle = css({ 64 gridArea: 'sidebar', 65 [`@media screen and (max-width: ${breakpoints.medium}px)`]: { 66 display: 'none', 67 }, 68}); 69