1import { css } from '@emotion/react'; 2import { theme, Button } from '@expo/styleguide'; 3import { breakpoints, spacing } from '@expo/styleguide-base'; 4import { GithubIcon, Menu01Icon } from '@expo/styleguide-icons'; 5import type { ReactNode } from 'react'; 6 7import { Logo } from './Logo'; 8import { ThemeSelector } from './ThemeSelector'; 9 10import { SidebarFooter, SidebarHead } from '~/ui/components/Sidebar'; 11import { DEMI } from '~/ui/components/Text'; 12 13type HeaderProps = { 14 sidebar: ReactNode; 15 sidebarActiveGroup: string; 16 isMobileMenuVisible: boolean; 17 setMobileMenuVisible: (isMobileMenuVisible: boolean) => void; 18}; 19 20export const Header = ({ 21 sidebar, 22 sidebarActiveGroup, 23 isMobileMenuVisible, 24 setMobileMenuVisible, 25}: HeaderProps) => { 26 const isArchive = sidebarActiveGroup === 'archive'; 27 return ( 28 <> 29 <nav css={[containerStyle, isMobileMenuVisible]}> 30 <div css={[columnStyle, leftColumnStyle]}> 31 <Logo subgroup={isArchive ? 'Archive' : undefined} /> 32 </div> 33 <div css={[columnStyle, rightColumnStyle]}> 34 <Button 35 openInNewTab 36 theme="quaternary" 37 className="px-2 text-secondary" 38 href="https://blog.expo.dev"> 39 Blog 40 </Button> 41 <Button 42 openInNewTab 43 theme="quaternary" 44 href="https://github.com/expo/expo" 45 aria-label="GitHub" 46 className="px-2"> 47 <GithubIcon className="icon-lg" /> 48 </Button> 49 <div css={hideOnMobileStyle}> 50 <ThemeSelector /> 51 </div> 52 <div css={showOnMobileStyle}> 53 <Button 54 theme="quaternary" 55 css={[mobileButtonStyle, isMobileMenuVisible && mobileButtonActiveStyle]} 56 onClick={() => { 57 setMobileMenuVisible(!isMobileMenuVisible); 58 }}> 59 <Menu01Icon className="icon-sm" /> 60 </Button> 61 </div> 62 </div> 63 </nav> 64 {isMobileMenuVisible && ( 65 <nav css={[containerStyle, showOnMobileStyle]}> 66 <div css={[columnStyle, leftColumnStyle]}> 67 <DEMI>Theme</DEMI> 68 </div> 69 <div css={[columnStyle, rightColumnStyle]}> 70 <ThemeSelector /> 71 </div> 72 </nav> 73 )} 74 {isMobileMenuVisible && ( 75 <div css={mobileSidebarStyle}> 76 <SidebarHead sidebarActiveGroup={sidebarActiveGroup} /> 77 {sidebar} 78 <SidebarFooter /> 79 </div> 80 )} 81 </> 82 ); 83}; 84 85const containerStyle = css` 86 display: flex; 87 align-items: center; 88 justify-content: flex-end; 89 position: relative; 90 background-color: ${theme.background.default}; 91 z-index: 2; 92 margin: 0 auto; 93 padding: 0 ${spacing[4]}px; 94 height: 60px; 95 box-sizing: border-box; 96 border-bottom: 1px solid ${theme.border.default}; 97 gap: ${spacing[2.5]}px; 98`; 99 100const columnStyle = css` 101 flex-shrink: 0; 102 display: flex; 103 gap: ${spacing[8]}px; 104 align-items: center; 105 background-color: transparent; 106 107 @media screen and (max-width: ${(breakpoints.medium + breakpoints.large) / 2}px) { 108 gap: ${spacing[4]}px; 109 } 110`; 111 112const leftColumnStyle = css` 113 flex-grow: 1; 114 align-items: center; 115 116 @media screen and (max-width: ${(breakpoints.medium + breakpoints.large) / 2}px) { 117 flex-basis: auto; 118 width: auto; 119 } 120`; 121 122const rightColumnStyle = css` 123 justify-content: flex-end; 124 gap: ${spacing[4]}px; 125 126 @media screen and (max-width: ${(breakpoints.medium + breakpoints.large) / 2}px) { 127 flex-basis: auto; 128 width: auto; 129 } 130`; 131 132const showOnMobileStyle = css` 133 display: none; 134 135 @media screen and (max-width: ${(breakpoints.medium + breakpoints.large) / 2}px) { 136 display: flex; 137 } 138`; 139 140const hideOnMobileStyle = css` 141 @media screen and (max-width: ${(breakpoints.medium + breakpoints.large) / 2}px) { 142 display: none; 143 } 144`; 145 146const mobileButtonStyle = css` 147 padding: 0 ${spacing[3]}px; 148 149 &:hover { 150 background-color: ${theme.background.element}; 151 box-shadow: none; 152 } 153`; 154 155const mobileButtonActiveStyle = css` 156 background-color: ${theme.background.subtle}; 157`; 158 159const mobileSidebarStyle = css` 160 background-color: ${theme.background.subtle}; 161 height: calc(100vh - (60px * 2)); 162 overflow-y: auto; 163 overflow-x: hidden; 164`; 165