feat: improve search input user experience

This commit is contained in:
codytseng
2025-09-11 09:43:53 +08:00
parent 6571468150
commit 1a58e54ed0

View File

@@ -13,6 +13,7 @@ import { nip19 } from 'nostr-tools'
import { import {
forwardRef, forwardRef,
HTMLAttributes, HTMLAttributes,
useCallback,
useEffect, useEffect,
useImperativeHandle, useImperativeHandle,
useMemo, useMemo,
@@ -36,6 +37,7 @@ const SearchBar = forwardRef<
const [debouncedInput, setDebouncedInput] = useState(input) const [debouncedInput, setDebouncedInput] = useState(input)
const { profiles, isFetching: isFetchingProfiles } = useSearchProfiles(debouncedInput, 5) const { profiles, isFetching: isFetchingProfiles } = useSearchProfiles(debouncedInput, 5)
const [searching, setSearching] = useState(false) const [searching, setSearching] = useState(false)
const [displayList, setDisplayList] = useState(false)
const searchInputRef = useRef<HTMLInputElement>(null) const searchInputRef = useRef<HTMLInputElement>(null)
const normalizedUrl = useMemo(() => { const normalizedUrl = useMemo(() => {
if (['w', 'ws', 'ws:', 'ws:/', 'wss', 'wss:', 'wss:/'].includes(input)) { if (['w', 'ws', 'ws:', 'ws:/', 'wss', 'wss:', 'wss:/'].includes(input)) {
@@ -166,18 +168,33 @@ const SearchBar = forwardRef<
}, [input, debouncedInput, profiles]) }, [input, debouncedInput, profiles])
useEffect(() => { useEffect(() => {
if (searching) { if (list) {
modalManager.register(id, () => { modalManager.register(id, () => {
blur() setDisplayList(false)
}) })
} else { } else {
modalManager.unregister(id) modalManager.unregister(id)
} }
}, [searching]) }, [list])
useEffect(() => {
setDisplayList(searching && !!input)
}, [searching, input])
const handleKeyDown = useCallback(
(e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
e.stopPropagation()
onSearch({ type: 'notes', search: input.trim() })
blur()
}
},
[input, onSearch]
)
return ( return (
<div className="relative flex gap-1 items-center h-full w-full"> <div className="relative flex gap-1 items-center h-full w-full">
{searching && ( {displayList && list && (
<> <>
<div <div
className={cn( className={cn(
@@ -188,13 +205,7 @@ const SearchBar = forwardRef<
)} )}
onMouseDown={(e) => e.preventDefault()} onMouseDown={(e) => e.preventDefault()}
> >
{list ? ( <div className="h-fit">{list}</div>
<div className="h-fit">{list}</div>
) : (
<div className="p-4 text-muted-foreground text-center h-20">
{t('Type searching for people, keywords, or relays')}
</div>
)}
</div> </div>
<div className="fixed inset-0 w-full h-full" onClick={() => blur()} /> <div className="fixed inset-0 w-full h-full" onClick={() => blur()} />
</> </>
@@ -205,8 +216,10 @@ const SearchBar = forwardRef<
'bg-surface-background shadow-inner h-full border-none', 'bg-surface-background shadow-inner h-full border-none',
searching ? 'z-50' : '' searching ? 'z-50' : ''
)} )}
placeholder={t('Type searching for people, keywords, or relays')}
value={input} value={input}
onChange={(e) => setInput(e.target.value)} onChange={(e) => setInput(e.target.value)}
onKeyDown={handleKeyDown}
onFocus={() => setSearching(true)} onFocus={() => setSearching(true)}
onBlur={() => setSearching(false)} onBlur={() => setSearching(false)}
/> />