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