reasource-based-search-results-load

This commit is contained in:
Untone 2024-01-28 10:06:31 +03:00
parent 5c827ca287
commit b866af2ff7
5 changed files with 34 additions and 13 deletions

View File

@ -2,6 +2,7 @@ import type { Author, Shout, Topic } from '../../../graphql/schema/core.gen'
import { getPagePath, openPage } from '@nanostores/router' import { getPagePath, openPage } from '@nanostores/router'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { createMemo, createSignal, For, Show } from 'solid-js'
import { useLocalize } from '../../../context/localize' import { useLocalize } from '../../../context/localize'
import { useSession } from '../../../context/session' import { useSession } from '../../../context/session'

View File

@ -4,8 +4,6 @@ import { getPagePath, redirectPage } from '@nanostores/router'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { Show, createSignal, createEffect, onMount, onCleanup, For } from 'solid-js' import { Show, createSignal, createEffect, onMount, onCleanup, For } from 'solid-js'
import { apiClient } from '../../../utils/apiClient'
import { useLocalize } from '../../../context/localize' import { useLocalize } from '../../../context/localize'
import { useSession } from '../../../context/session' import { useSession } from '../../../context/session'
import { apiClient } from '../../../graphql/client/core' import { apiClient } from '../../../graphql/client/core'
@ -22,7 +20,6 @@ import { HeaderAuth } from '../HeaderAuth'
import { Modal } from '../Modal' import { Modal } from '../Modal'
import { SearchModal } from '../SearchModal/SearchModal' import { SearchModal } from '../SearchModal/SearchModal'
import { Snackbar } from '../Snackbar' import { Snackbar } from '../Snackbar'
import { SearchModal } from '../SearchModal/SearchModal'
import { Link } from './Link' import { Link } from './Link'

View File

@ -128,7 +128,7 @@ export const HeaderAuth = (props: Props) => {
<Show when={!isSaveButtonVisible()}> <Show when={!isSaveButtonVisible()}>
<div class={styles.userControlItem}> <div class={styles.userControlItem}>
<a href="?modal=search"> <a href="?m=search">
<Icon name="search" class={styles.icon} /> <Icon name="search" class={styles.icon} />
<Icon name="search" class={clsx(styles.icon, styles.iconHover)} /> <Icon name="search" class={clsx(styles.icon, styles.iconHover)} />
</a> </a>

View File

@ -1,6 +1,6 @@
import type { Shout } from '../../../graphql/schema/core.gen' import type { Shout } from '../../../graphql/schema/core.gen'
import { createResource, createSignal, For, Show } from 'solid-js' import { createEffect, createResource, createSignal, For, onCleanup, Show } from 'solid-js'
import { debounce } from 'throttle-debounce' import { debounce } from 'throttle-debounce'
import { useLocalize } from '../../../context/localize' import { useLocalize } from '../../../context/localize'
@ -55,6 +55,7 @@ export const SearchModal = () => {
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
const [inputValue, setInputValue] = createSignal('') const [inputValue, setInputValue] = createSignal('')
const [isLoading, setIsLoading] = createSignal(false) const [isLoading, setIsLoading] = createSignal(false)
const [offset, setOffset] = createSignal<number>(0)
const [searchResultsList, { refetch: loadSearchResults, mutate: setSearchResultsList }] = createResource< const [searchResultsList, { refetch: loadSearchResults, mutate: setSearchResultsList }] = createResource<
Shout[] Shout[]
>( >(
@ -63,8 +64,10 @@ export const SearchModal = () => {
const { hasMore, newShouts } = await loadShoutsSearch({ const { hasMore, newShouts } = await loadShoutsSearch({
limit: FEED_PAGE_SIZE, limit: FEED_PAGE_SIZE,
text: inputValue(), text: inputValue(),
offset: searchResultsList().length, offset: offset(),
}) })
setIsLoading(false)
setOffset(newShouts.length)
setIsLoadMoreButtonVisible(hasMore) setIsLoadMoreButtonVisible(hasMore)
return newShouts return newShouts
}, },
@ -76,13 +79,33 @@ export const SearchModal = () => {
let searchEl: HTMLInputElement let searchEl: HTMLInputElement
const debouncedLoadMore = debounce(500, loadSearchResults) const debouncedLoadMore = debounce(500, loadSearchResults)
const handleQueryInput = () => {
const inp = searchEl.value const handleQueryInput = async () => {
setInputValue(inp) setInputValue(searchEl.value)
if (inp?.length > 2) debouncedLoadMore() if (searchEl.value?.length > 2) {
else setSearchResultsList([]) await debouncedLoadMore()
} else {
setIsLoading(false)
setSearchResultsList([])
}
} }
const enterQuery = async (ev: KeyboardEvent) => {
setIsLoading(true)
if (ev.key === 'Enter' && inputValue().length > 2) {
await debouncedLoadMore()
} else {
setIsLoading(false)
setSearchResultsList([])
}
}
// Cleanup the debounce timer when the component unmounts
onCleanup(() => {
debouncedLoadMore.cancel()
console.log('cleanup search')
})
return ( return (
<div class={styles.searchContainer}> <div class={styles.searchContainer}>
<input <input
@ -90,13 +113,13 @@ export const SearchModal = () => {
placeholder={t('Site search')} placeholder={t('Site search')}
class={styles.searchInput} class={styles.searchInput}
onInput={handleQueryInput} onInput={handleQueryInput}
onChange={debouncedLoadMore} onKeyDown={enterQuery}
ref={searchEl} ref={searchEl}
/> />
<Button <Button
class={styles.searchButton} class={styles.searchButton}
onClick={loadSearchResults} onClick={debouncedLoadMore}
value={isLoading() ? <div class={styles.searchLoader} /> : <Icon name="search" />} value={isLoading() ? <div class={styles.searchLoader} /> : <Icon name="search" />}
/> />

View File