webapp/src/components/Views/Search.tsx

116 lines
3.2 KiB
TypeScript
Raw Normal View History

2023-12-19 13:06:54 +00:00
import type { SearchResult, Shout } from '../../graphql/schema/core.gen'
2023-02-17 09:21:02 +00:00
import { Show, For, createSignal } from 'solid-js'
import '../../styles/Search.scss'
import { useLocalize } from '../../context/localize'
import { useRouter } from '../../stores/router'
2022-11-18 02:23:04 +00:00
import { loadShouts, useArticlesStore } from '../../stores/zine/articles'
2022-11-17 23:20:40 +00:00
import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll'
import { ArticleCard } from '../Feed/ArticleCard'
2022-09-22 09:37:49 +00:00
type SearchPageSearchParams = {
by: '' | 'relevance' | 'rating'
}
2022-09-09 11:53:35 +00:00
type Props = {
2022-09-22 09:37:49 +00:00
query: string
2023-12-19 13:06:54 +00:00
results: SearchResult[]
2022-09-09 11:53:35 +00:00
}
2022-11-17 23:20:40 +00:00
const LOAD_MORE_PAGE_SIZE = 50
2022-09-22 09:37:49 +00:00
export const SearchView = (props: Props) => {
2023-02-17 09:21:02 +00:00
const { t } = useLocalize()
2023-12-19 13:06:54 +00:00
const { articleEntities, sortedArticles } = useArticlesStore()
2022-11-17 23:20:40 +00:00
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
const [query, setQuery] = createSignal(props.query)
const [offset, setOffset] = createSignal(0)
2022-09-09 11:53:35 +00:00
2023-04-03 13:11:02 +00:00
const { searchParams } = useRouter<SearchPageSearchParams>()
2022-11-17 23:20:40 +00:00
let searchEl: HTMLInputElement
const handleQueryChange = () => {
2022-11-17 23:20:40 +00:00
setQuery(searchEl.value)
2022-09-13 09:59:04 +00:00
}
2022-11-17 23:20:40 +00:00
const loadMore = async () => {
saveScrollPosition()
const { hasMore } = await loadShouts({
filters: {},
2022-11-17 23:20:40 +00:00
offset: offset(),
limit: LOAD_MORE_PAGE_SIZE,
2022-11-17 23:20:40 +00:00
})
setIsLoadMoreButtonVisible(hasMore)
setOffset(offset() + LOAD_MORE_PAGE_SIZE)
restoreScrollPosition()
2022-09-13 09:59:04 +00:00
}
2022-09-09 11:53:35 +00:00
return (
<div class="search-page wide-container">
<form action="/search" class="search-form row">
2023-03-10 17:42:48 +00:00
<div class="col-sm-18">
2022-11-17 23:20:40 +00:00
<input
type="search"
name="q"
ref={searchEl}
onInput={handleQueryChange}
placeholder={t('Enter text') + '...'}
/>
2022-09-09 11:53:35 +00:00
</div>
2023-03-10 17:42:48 +00:00
<div class="col-sm-6">
2022-11-17 23:20:40 +00:00
<button class="button" type="submit" onClick={loadMore}>
2022-09-13 09:59:04 +00:00
{t('Search')}
</button>
2022-09-09 11:53:35 +00:00
</div>
</form>
<ul class="view-switcher">
2022-09-22 09:37:49 +00:00
<li
classList={{
'view-switcher__item--selected': searchParams().by === 'relevance',
2022-09-22 09:37:49 +00:00
}}
>
2023-04-03 13:11:02 +00:00
<a href="?by=relevance">{t('By relevance')}</a>
2022-09-09 11:53:35 +00:00
</li>
2022-09-22 09:37:49 +00:00
<li
classList={{
'view-switcher__item--selected': searchParams().by === 'rating',
2022-09-22 09:37:49 +00:00
}}
>
2023-04-03 13:11:02 +00:00
<a href="?by=rating">{t('Top rated')}</a>
2022-09-09 11:53:35 +00:00
</li>
</ul>
2022-09-28 20:16:44 +00:00
<Show when={sortedArticles().length > 0}>
2022-09-09 11:53:35 +00:00
<h3>{t('Publications')}</h3>
<div class="floor">
<div class="row">
2022-09-28 20:16:44 +00:00
<For each={sortedArticles()}>
2022-09-09 11:53:35 +00:00
{(article) => (
2023-03-10 17:42:48 +00:00
<div class="col-md-6">
<ArticleCard article={article} desktopCoverSize="L" />
2022-09-09 11:53:35 +00:00
</div>
)}
</For>
2023-03-10 17:42:48 +00:00
<div class="col-md-6">
2022-09-09 11:53:35 +00:00
<a href="#" class="search__show-more">
<span class="search__show-more-inner">{t('Load more')}</span>
</a>
</div>
</div>
</div>
2022-11-17 23:20:40 +00:00
<Show when={isLoadMoreButtonVisible()}>
<p class="load-more-container">
<button class="button" onClick={loadMore}>
{t('Load more')}
</button>
</p>
</Show>
2022-09-09 11:53:35 +00:00
</Show>
</div>
)
}