mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 12:51:55 +00:00
svelte: Add search query input to repo pages (#59185)
This PR adds the search query input to the repo page header. I used a similar solution as GitHub, which renders a button that looks a bit like an input and opens a dialog with the real input. The input is prepopulated with a `repo:` filter for the current input. It has a tab/focus trap and closes on escape. Before settling on this solution I tried various other approaches: - Directly render the input in the header and make it expand on focus. That caused strange text selection because mousdown would expand the input and mouseup would happen at a different place in the input, causing text selection. - Using the `<dialog>` element. It has some default styles/behavior that interfered with what I wanted to do. - I wanted to use the newly added `openFocus` option in `createDialog` to disable melt's autofocus behavior, but that didn't work. Happy to iterate on the design of the button, or on the behavior in general. I decided against introducing keyboard shortcuts in this PR, I think that warrants it's own PR.
This commit is contained in:
parent
17cff22ecf
commit
7e2e51a079
@ -63,7 +63,7 @@
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@melt-ui/svelte": "^0.34.3",
|
||||
"@melt-ui/svelte": "^0.66.2",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@remix-run/router": "~1.3.3",
|
||||
"@sourcegraph/branded": "workspace:*",
|
||||
|
||||
@ -150,7 +150,7 @@ export function getQueryURL(
|
||||
queryState.searchMode
|
||||
)
|
||||
|
||||
return 'search?' + searchQueryParameter
|
||||
return '/search?' + searchQueryParameter
|
||||
}
|
||||
|
||||
export function submitSearch(
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
import { computeFit } from '$lib/dom'
|
||||
import { writable } from 'svelte/store'
|
||||
import { getButtonClassName } from '@sourcegraph/wildcard'
|
||||
import RepoSearchInput from './RepoSearchInput.svelte'
|
||||
|
||||
export let data: LayoutData
|
||||
|
||||
@ -100,6 +101,7 @@
|
||||
</MenuLink>
|
||||
{/each}
|
||||
</DropdownMenu>
|
||||
<RepoSearchInput repoName={data.repoName} />
|
||||
</nav>
|
||||
<slot />
|
||||
|
||||
|
||||
@ -0,0 +1,80 @@
|
||||
<script lang="ts">
|
||||
import { createDialog } from '@melt-ui/svelte'
|
||||
import Icon from '$lib/Icon.svelte'
|
||||
import SearchInput from '$lib/search/input/SearchInput.svelte'
|
||||
import { queryStateStore } from '$lib/search/state'
|
||||
import { settings } from '$lib/stores'
|
||||
import { mdiMagnify } from '@mdi/js'
|
||||
import { tick } from 'svelte'
|
||||
|
||||
export let repoName: string
|
||||
|
||||
const {
|
||||
elements: { trigger, overlay, content },
|
||||
states: { open },
|
||||
} = createDialog()
|
||||
|
||||
let searchInput: SearchInput | undefined
|
||||
let queryState = queryStateStore({ query: `repo:${repoName} ` }, $settings)
|
||||
|
||||
$: if ($open) {
|
||||
// @melt-ui automatically focuses the search input but that positions the cursor at the
|
||||
// start of the input. We can move the cursor to the end by calling focus(), but we need
|
||||
// to wait for the next tick to ensure it happens after @melt-ui has updated the DOM.
|
||||
tick().then(() => searchInput?.focus())
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if $open}
|
||||
<div class="wrapper">
|
||||
<div {...$overlay} use:overlay class="overlay" />
|
||||
<div {...$content} use:content>
|
||||
<SearchInput bind:this={searchInput} {queryState} />
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<button {...$trigger} use:trigger>
|
||||
<Icon svgPath={mdiMagnify} inline aria-hidden="true" />
|
||||
Search
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.wrapper {
|
||||
flex: 1;
|
||||
position: absolute;
|
||||
left: 1rem;
|
||||
right: 1rem;
|
||||
// This seems needed to prevent the file headers (which are position: sticky) from overlaying
|
||||
// the search input. Alternatively we could portal the search input with melt, but then
|
||||
// it would be more difficult to position it over the repo header.
|
||||
z-index: 2;
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: transparent;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 1px solid var(--input-border-color);
|
||||
border-radius: 4px;
|
||||
padding: 0 0.25rem;
|
||||
min-height: 32px;
|
||||
width: 10rem;
|
||||
text-align: left;
|
||||
color: var(--text-muted);
|
||||
white-space: nowrap;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--input-focus-border-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1385,8 +1385,8 @@ importers:
|
||||
client/web-sveltekit:
|
||||
dependencies:
|
||||
'@melt-ui/svelte':
|
||||
specifier: ^0.34.3
|
||||
version: 0.34.3(svelte@4.1.1)
|
||||
specifier: ^0.66.2
|
||||
version: 0.66.2(svelte@4.1.1)
|
||||
'@popperjs/core':
|
||||
specifier: ^2.11.8
|
||||
version: 2.11.8
|
||||
@ -5090,6 +5090,12 @@ packages:
|
||||
resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
|
||||
dev: true
|
||||
|
||||
/@internationalized/date@3.5.1:
|
||||
resolution: {integrity: sha512-LUQIfwU9e+Fmutc/DpRTGXSdgYZLBegi4wygCWDSVmUdLTaMHsQyASDiJtREwanwKuQLq0hY76fCJ9J/9I2xOQ==}
|
||||
dependencies:
|
||||
'@swc/helpers': 0.5.3
|
||||
dev: false
|
||||
|
||||
/@isaacs/cliui@8.0.2:
|
||||
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
||||
engines: {node: '>=12'}
|
||||
@ -5371,13 +5377,15 @@ packages:
|
||||
react: 18.2.0
|
||||
dev: true
|
||||
|
||||
/@melt-ui/svelte@0.34.3(svelte@4.1.1):
|
||||
resolution: {integrity: sha512-qJE0+7+8Q8h1UhdqpAWWSJx3vXSjlgAKkfjLC5wn6dtVY70Jkb6Hiu726isZ2yNbPilBmbaLrOzfoMTRurjKXw==}
|
||||
/@melt-ui/svelte@0.66.2(svelte@4.1.1):
|
||||
resolution: {integrity: sha512-ufIhgOYP11A/G3AvW+2Qw74UGudMBJQ2wK+sETpU51VkC63/5D2sctKgXzGl0OUEJBlPHku6LRSry9rIeAVkNw==}
|
||||
peerDependencies:
|
||||
svelte: '>=3 <5'
|
||||
dependencies:
|
||||
'@floating-ui/core': 1.4.1
|
||||
'@floating-ui/dom': 1.5.1
|
||||
'@internationalized/date': 3.5.1
|
||||
dequal: 2.0.3
|
||||
focus-trap: 7.5.2
|
||||
nanoid: 4.0.2
|
||||
svelte: 4.1.1
|
||||
@ -10579,6 +10587,12 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@swc/helpers@0.5.3:
|
||||
resolution: {integrity: sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==}
|
||||
dependencies:
|
||||
tslib: 2.1.0
|
||||
dev: false
|
||||
|
||||
/@szmarczak/http-timer@1.1.2:
|
||||
resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user