xref: /expo/docs/ui/components/Header/Header.tsx (revision b48ca2c7)
1import { css } from '@emotion/react';
2import { theme, breakpoints, SearchIcon, iconSize, spacing } from '@expo/styleguide';
3import React, { useState } from 'react';
4
5import { Logo } from './Logo';
6import { Search } from './Search';
7import { ThemeSelector } from './ThemeSelector';
8
9import { Button } from '~/ui/components/Button';
10import { BOLD } from '~/ui/components/Text';
11import { MenuIcon } from '~/ui/foundations/icons';
12
13export const Header = () => {
14  const [isMobileSearchVisible, setMobileSearchVisible] = useState(false);
15  const [isMobileMenuVisible, setMobileMenuVisible] = useState(false);
16  return (
17    <>
18      <nav css={containerStyle}>
19        <div css={[columnStyle, leftColumnStyle]}>
20          <Logo />
21        </div>
22        <Search version="latest" css={hideOnMobileStyle} />
23        <div css={[columnStyle, rightColumnStyle, hideOnMobileStyle]}>
24          <ThemeSelector />
25        </div>
26        <div css={[columnStyle, rightColumnStyle, showOnMobileStyle]}>
27          <Button
28            theme="transparent"
29            css={[mobileButtonStyle, isMobileSearchVisible && mobileButtonActiveStyle]}
30            onClick={() => {
31              setMobileMenuVisible(false);
32              setMobileSearchVisible(prevState => !prevState);
33            }}>
34            <SearchIcon size={iconSize.small} color={theme.icon.default} />
35          </Button>
36          <Button
37            theme="transparent"
38            css={[mobileButtonStyle, isMobileMenuVisible && mobileButtonActiveStyle]}
39            onClick={() => {
40              setMobileSearchVisible(false);
41              setMobileMenuVisible(prevState => !prevState);
42            }}>
43            <MenuIcon />
44          </Button>
45        </div>
46      </nav>
47      {isMobileMenuVisible && (
48        <nav css={[containerStyle, showOnMobileStyle]}>
49          <div css={[columnStyle, leftColumnStyle]}>
50            <BOLD>Theme</BOLD>
51          </div>
52          <div css={[columnStyle, rightColumnStyle]}>
53            <ThemeSelector />
54          </div>
55        </nav>
56      )}
57      {isMobileSearchVisible && (
58        <nav css={[containerStyle, showOnMobileStyle]}>
59          <Search mobile version="latest" css={mobileSearchInputStyle} />
60        </nav>
61      )}
62    </>
63  );
64};
65
66const containerStyle = css`
67  display: flex;
68  align-items: center;
69  justify-content: space-between;
70  position: relative;
71  background-color: ${theme.background.default};
72  z-index: 2;
73  margin: 0 auto;
74  padding: 0 ${spacing[4]}px;
75  height: 60px;
76  box-sizing: border-box;
77  border-bottom: 1px solid ${theme.border.default};
78`;
79
80const columnStyle = css`
81  flex-shrink: 0;
82  display: flex;
83  background-color: transparent;
84`;
85
86const leftColumnStyle = css`
87  flex-basis: 256px;
88  width: 256px;
89
90  @media screen and (max-width: ${breakpoints.medium}px) {
91    flex-basis: auto;
92    width: auto;
93  }
94`;
95
96const rightColumnStyle = css`
97  flex-basis: 288px;
98  width: 288px;
99  justify-content: flex-end;
100
101  @media screen and (max-width: ${breakpoints.medium}px) {
102    flex-basis: auto;
103    width: auto;
104  }
105`;
106
107const showOnMobileStyle = css`
108  display: none;
109
110  @media screen and (max-width: ${breakpoints.medium}px) {
111    display: flex;
112  }
113`;
114
115const hideOnMobileStyle = css`
116  @media screen and (max-width: ${breakpoints.medium}px) {
117    display: none;
118  }
119`;
120
121const mobileButtonStyle = css`
122  padding: 0 ${spacing[3]}px;
123  margin-left: ${spacing[2]}px;
124
125  &:hover {
126    background-color: ${theme.background.tertiary};
127    box-shadow: none;
128  }
129`;
130
131const mobileButtonActiveStyle = css`
132  background-color: ${theme.background.secondary};
133`;
134
135const mobileSearchInputStyle = css`
136  margin: 0;
137`;
138