1import { css } from '@emotion/react'; 2import { theme, Button } from '@expo/styleguide'; 3import { breakpoints, spacing } from '@expo/styleguide-base'; 4import { GithubIcon, Menu01Icon, Star01Icon } 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 css={hideOnMobileStyle} 45 className="px-2 text-secondary" 46 leftSlot={<Star01Icon className="icon-sm" />} 47 href="https://github.com/expo/expo"> 48 Star Us on GitHub 49 </Button> 50 <Button 51 openInNewTab 52 theme="quaternary" 53 href="https://github.com/expo/expo" 54 css={showOnMobileStyle} 55 aria-label="GitHub" 56 className="px-2"> 57 <GithubIcon className="icon-lg" /> 58 </Button> 59 <div css={hideOnMobileStyle}> 60 <ThemeSelector /> 61 </div> 62 <div css={showOnMobileStyle}> 63 <Button 64 theme="quaternary" 65 css={[mobileButtonStyle, isMobileMenuVisible && mobileButtonActiveStyle]} 66 onClick={() => { 67 setMobileMenuVisible(!isMobileMenuVisible); 68 }}> 69 <Menu01Icon className="icon-sm" /> 70 </Button> 71 </div> 72 </div> 73 </nav> 74 {isMobileMenuVisible && ( 75 <nav css={[containerStyle, showOnMobileStyle]}> 76 <div css={[columnStyle, leftColumnStyle]}> 77 <DEMI>Theme</DEMI> 78 </div> 79 <div css={[columnStyle, rightColumnStyle]}> 80 <ThemeSelector /> 81 </div> 82 </nav> 83 )} 84 {isMobileMenuVisible && ( 85 <div css={mobileSidebarStyle}> 86 <SidebarHead sidebarActiveGroup={sidebarActiveGroup} /> 87 {sidebar} 88 <SidebarFooter /> 89 </div> 90 )} 91 </> 92 ); 93}; 94 95const containerStyle = css` 96 display: flex; 97 align-items: center; 98 justify-content: flex-end; 99 position: relative; 100 background-color: ${theme.background.default}; 101 z-index: 2; 102 margin: 0 auto; 103 padding: 0 ${spacing[4]}px; 104 height: 60px; 105 box-sizing: border-box; 106 border-bottom: 1px solid ${theme.border.default}; 107 gap: ${spacing[2.5]}px; 108`; 109 110const columnStyle = css` 111 flex-shrink: 0; 112 display: flex; 113 gap: ${spacing[8]}px; 114 align-items: center; 115 background-color: transparent; 116 117 @media screen and (max-width: ${(breakpoints.medium + breakpoints.large) / 2}px) { 118 gap: ${spacing[4]}px; 119 } 120`; 121 122const leftColumnStyle = css` 123 flex-grow: 1; 124 align-items: center; 125 126 @media screen and (max-width: ${(breakpoints.medium + breakpoints.large) / 2}px) { 127 flex-basis: auto; 128 width: auto; 129 } 130`; 131 132const rightColumnStyle = css` 133 justify-content: flex-end; 134 gap: ${spacing[4]}px; 135 136 @media screen and (max-width: ${(breakpoints.medium + breakpoints.large) / 2}px) { 137 flex-basis: auto; 138 width: auto; 139 } 140`; 141 142const showOnMobileStyle = css` 143 display: none; 144 145 @media screen and (max-width: ${(breakpoints.medium + breakpoints.large) / 2}px) { 146 display: flex; 147 } 148`; 149 150const hideOnMobileStyle = css` 151 @media screen and (max-width: ${(breakpoints.medium + breakpoints.large) / 2}px) { 152 display: none; 153 } 154`; 155 156const mobileButtonStyle = css` 157 padding: 0 ${spacing[3]}px; 158 159 &:hover { 160 background-color: ${theme.background.element}; 161 box-shadow: none; 162 } 163`; 164 165const mobileButtonActiveStyle = css` 166 background-color: ${theme.background.subtle}; 167`; 168 169const mobileSidebarStyle = css` 170 background-color: ${theme.background.subtle}; 171 height: calc(100vh - (60px * 2)); 172 overflow-y: auto; 173 overflow-x: hidden; 174`; 175