Skip to content

Commit 193f0e8

Browse files
authored
move search bar near version picker (#55404)
1 parent a46625e commit 193f0e8

File tree

7 files changed

+104
-41
lines changed

7 files changed

+104
-41
lines changed

src/fixtures/tests/playwright-rendering.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ test('open new search, and perform a general search', async ({ page }) => {
7979
window.overrideControlGroup('ai_search_experiment', 'treatment')
8080
})
8181

82-
await page.getByTestId('search').click()
82+
await page.locator('[data-testid="search"]:visible').click()
8383

8484
await page.getByTestId('overlay-search-input').fill('serve playwright')
8585
// Wait for the results to load
@@ -112,7 +112,7 @@ test('open new search, and select a general search article', async ({ page }) =>
112112
window.overrideControlGroup('ai_search_experiment', 'treatment')
113113
})
114114

115-
await page.getByTestId('search').click()
115+
await page.locator('[data-testid="search"]:visible').click()
116116

117117
await page.getByTestId('overlay-search-input').fill('serve playwright')
118118
// Let new suggestions load
@@ -138,7 +138,7 @@ test('open new search, and get auto-complete results', async ({ page }) => {
138138
window.overrideControlGroup('ai_search_experiment', 'treatment')
139139
})
140140

141-
await page.getByTestId('search').click()
141+
await page.locator('[data-testid="search"]:visible').click()
142142

143143
let listGroup = page.getByTestId('ai-autocomplete-suggestions')
144144

src/frame/components/page-header/Header.module.scss

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,13 @@
4141
display: none;
4242
}
4343
}
44+
45+
.displayOverLarge {
46+
display: none;
47+
visibility: none;
48+
49+
@include breakpoint(lg) {
50+
display: flex !important;
51+
visibility: visible !important;
52+
}
53+
}

src/frame/components/page-header/Header.tsx

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@ import { Breadcrumbs } from 'src/frame/components/page-header/Breadcrumbs'
1414
import { VersionPicker } from 'src/versions/components/VersionPicker'
1515
import { SidebarNav } from 'src/frame/components/sidebar/SidebarNav'
1616
import { AllProductsLink } from 'src/frame/components/sidebar/AllProductsLink'
17-
18-
import styles from './Header.module.scss'
17+
import { SearchBarButton } from '@/search/components/input/SearchBarButton'
1918
import { OldHeaderSearchAndWidgets } from './OldHeaderSearchAndWidgets'
2019
import { HeaderSearchAndWidgets } from './HeaderSearchAndWidgets'
2120
import { useInnerWindowWidth } from './hooks/useInnerWindowWidth'
2221
import { EXPERIMENTS } from '@/events/components/experiments/experiments'
2322
import { useShouldShowExperiment } from '@/events/components/experiments/useShouldShowExperiment'
2423
import { useQueryParam } from '@/frame/components/hooks/useQueryParam'
24+
import { useMultiQueryParams } from '@/search/components/hooks/useMultiQueryParams'
25+
import { SearchOverlayContainer } from '@/search/components/input/SearchOverlayContainer'
26+
27+
import styles from './Header.module.scss'
2528

2629
export const Header = () => {
2730
const router = useRouter()
@@ -34,6 +37,7 @@ export const Header = () => {
3437
'search-overlay-open',
3538
true,
3639
)
40+
const { params, updateParams } = useMultiQueryParams()
3741
const [scroll, setScroll] = useState(false)
3842
const [isSidebarOpen, setIsSidebarOpen] = useState(false)
3943
const openSidebar = useCallback(() => setIsSidebarOpen(true), [isSidebarOpen])
@@ -45,8 +49,20 @@ export const Header = () => {
4549
const isEarlyAccessPage = currentProduct && currentProduct.id === 'early-access'
4650
const { width } = useInnerWindowWidth()
4751
const returnFocusRef = useRef(null)
52+
const searchButtonRef = useRef<HTMLButtonElement>(null)
4853

4954
const showNewSearch = useShouldShowExperiment(EXPERIMENTS.ai_search_experiment)
55+
let SearchButton: JSX.Element | null = (
56+
<SearchBarButton
57+
isSearchOpen={isSearchOpen}
58+
setIsSearchOpen={setIsSearchOpen}
59+
params={params}
60+
searchButtonRef={searchButtonRef}
61+
/>
62+
)
63+
if (!showNewSearch) {
64+
SearchButton = null
65+
}
5066

5167
useEffect(() => {
5268
function onScroll() {
@@ -166,14 +182,16 @@ export const Header = () => {
166182
<MarkGithubIcon size={32} />
167183
<span className="h4 text-semibold ml-2 mr-3">{t('github_docs')}</span>
168184
</Link>
169-
<div className="hide-sm border-left pl-3">
185+
<div className="hide-sm border-left pl-3 d-flex flex-items-center">
170186
<VersionPicker />
187+
{/* In larger viewports, we want to show the search bar next to the version picker */}
188+
<div className={styles.displayOverLarge}>{SearchButton}</div>
171189
</div>
172190
</div>
173191
{showNewSearch ? (
174192
<HeaderSearchAndWidgets
175193
isSearchOpen={isSearchOpen}
176-
setIsSearchOpen={setIsSearchOpen}
194+
SearchButton={SearchButton}
177195
width={width}
178196
/>
179197
) : (
@@ -246,6 +264,15 @@ export const Header = () => {
246264
</div>
247265
</div>
248266
)}
267+
{showNewSearch && (
268+
<SearchOverlayContainer
269+
isSearchOpen={isSearchOpen}
270+
setIsSearchOpen={setIsSearchOpen}
271+
params={params}
272+
updateParams={updateParams}
273+
searchButtonRef={searchButtonRef}
274+
/>
275+
)}
249276
</header>
250277
</div>
251278
)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@import "@primer/css/support/variables/layout.scss";
2+
@import "@primer/css/support/mixins/layout.scss";
3+
4+
.displayUnderLarge {
5+
display: flex;
6+
visibility: visible;
7+
8+
@include breakpoint(lg) {
9+
display: none !important;
10+
visibility: hidden !important;
11+
}
12+
}

src/frame/components/page-header/HeaderSearchAndWidgets.tsx

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,26 @@ import { VersionPicker } from '@/versions/components/VersionPicker'
1010
import { DEFAULT_VERSION, useVersion } from '@/versions/components/useVersion'
1111
import { useHasAccount } from '../hooks/useHasAccount'
1212

13-
import { SearchBarButton } from '@/search/components/input/SearchBarButton'
14-
import { useBreakpoint } from '@/search/components/hooks/useBreakpoint'
13+
import styles from './HeaderSearchAndWidgets.module.scss'
1514

1615
type Props = {
1716
isSearchOpen: boolean
18-
setIsSearchOpen: (value: boolean) => void
1917
width: number | null
18+
SearchButton: JSX.Element | null
2019
}
2120

22-
export function HeaderSearchAndWidgets({ isSearchOpen, setIsSearchOpen, width }: Props) {
21+
export function HeaderSearchAndWidgets({ width, isSearchOpen, SearchButton }: Props) {
2322
const { currentVersion } = useVersion()
2423
const { t } = useTranslation(['header'])
25-
const isLarge = useBreakpoint('large')
2624
const { hasAccount } = useHasAccount()
2725
const signupCTAVisible =
2826
hasAccount === false && // don't show if `null`
2927
(currentVersion === DEFAULT_VERSION || currentVersion === 'enterprise-cloud@latest')
3028

3129
const showDomainNameEdit = currentVersion.startsWith('enterprise-server@')
3230

33-
const SearchButton = (
34-
<SearchBarButton isSearchOpen={isSearchOpen} setIsSearchOpen={setIsSearchOpen} />
35-
)
36-
3731
return (
3832
<>
39-
{/* At larger & up widths we show the search as an input. This doesn't need to be grouped with the widgets */}
40-
{isLarge ? SearchButton : null}
4133
<div className={cx('d-flex flex-items-center', isSearchOpen && 'd-none')}>
4234
<div className={cx('d-none d-lg-flex flex-items-center', signupCTAVisible && 'mr-3')}>
4335
<LanguagePicker />
@@ -57,7 +49,7 @@ export function HeaderSearchAndWidgets({ isSearchOpen, setIsSearchOpen, width }:
5749
)}
5850

5951
{/* Below large widths we show the search as a button which needs to be grouped with the widgets */}
60-
{!isLarge ? SearchButton : null}
52+
<div className={styles.displayUnderLarge}>{SearchButton}</div>
6153

6254
{/* The ... navigation menu at medium and smaller widths */}
6355
<div>

src/search/components/input/SearchBarButton.tsx

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,23 @@
1-
import { useRef } from 'react'
21
import cx from 'classnames'
32
import { IconButton } from '@primer/react'
43
import { CopilotIcon, SearchIcon } from '@primer/octicons-react'
54

65
import { useTranslation } from 'src/languages/components/useTranslation'
7-
import { SearchOverlay } from './SearchOverlay'
86

97
import styles from './SearchBarButton.module.scss'
10-
import { useMultiQueryParams } from '../hooks/useMultiQueryParams'
8+
import { QueryParams } from '../hooks/useMultiQueryParams'
119

1210
type Props = {
1311
isSearchOpen: boolean
1412
setIsSearchOpen: (value: boolean) => void
13+
params: QueryParams
14+
searchButtonRef: React.RefObject<HTMLButtonElement>
1515
}
1616

17-
export function SearchBarButton({ isSearchOpen, setIsSearchOpen }: Props) {
17+
export function SearchBarButton({ isSearchOpen, setIsSearchOpen, params, searchButtonRef }: Props) {
1818
const { t } = useTranslation('search')
1919

20-
const { params, updateParams } = useMultiQueryParams()
2120
const urlSearchInputQuery = params['search-overlay-input']
22-
const debug = params.debug === 'true'
23-
24-
const buttonRef = useRef(null)
2521

2622
// Handle click events
2723
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
@@ -60,7 +56,7 @@ export function SearchBarButton({ isSearchOpen, setIsSearchOpen }: Props) {
6056
{/* On mobile only the IconButton is shown */}
6157
<IconButton
6258
data-testid="mobile-search-button"
63-
ref={buttonRef}
59+
ref={searchButtonRef}
6460
className={styles.searchIconButton}
6561
onClick={handleClick}
6662
tabIndex={0}
@@ -75,7 +71,7 @@ export function SearchBarButton({ isSearchOpen, setIsSearchOpen }: Props) {
7571
className={styles.searchInputButton}
7672
onKeyDown={handleKeyDown}
7773
onClick={handleClick}
78-
ref={buttonRef}
74+
ref={searchButtonRef}
7975
>
8076
{/* Styled to look like an input */}
8177
<div
@@ -101,18 +97,7 @@ export function SearchBarButton({ isSearchOpen, setIsSearchOpen }: Props) {
10197
</span>
10298
</button>
10399
</>
104-
) : (
105-
<SearchOverlay
106-
searchOverlayOpen={isSearchOpen}
107-
parentRef={buttonRef}
108-
debug={debug}
109-
params={params}
110-
updateParams={updateParams}
111-
onClose={() => {
112-
setIsSearchOpen(false)
113-
}}
114-
/>
115-
)}
100+
) : null}
116101
</>
117102
)
118103
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { SearchOverlay } from './SearchOverlay'
2+
import { QueryParams } from '../hooks/useMultiQueryParams'
3+
4+
type Props = {
5+
isSearchOpen: boolean
6+
setIsSearchOpen: (value: boolean) => void
7+
params: QueryParams
8+
updateParams: (updates: Partial<QueryParams>) => void
9+
searchButtonRef: React.RefObject<HTMLButtonElement>
10+
}
11+
12+
export function SearchOverlayContainer({
13+
isSearchOpen,
14+
setIsSearchOpen,
15+
params,
16+
updateParams,
17+
searchButtonRef,
18+
}: Props) {
19+
const debug = params.debug === 'true'
20+
21+
if (isSearchOpen) {
22+
return (
23+
<SearchOverlay
24+
searchOverlayOpen={isSearchOpen}
25+
parentRef={searchButtonRef}
26+
debug={debug}
27+
params={params}
28+
updateParams={updateParams}
29+
onClose={() => {
30+
setIsSearchOpen(false)
31+
}}
32+
/>
33+
)
34+
}
35+
36+
return null
37+
}

0 commit comments

Comments
 (0)