add search loader & refactor results rendering
This commit is contained in:
parent
cf7aec3e1c
commit
f520de9d52
|
@ -363,6 +363,7 @@
|
||||||
"Video": "Video",
|
"Video": "Video",
|
||||||
"Video format not supported": "Video format not supported",
|
"Video format not supported": "Video format not supported",
|
||||||
"Views": "Views",
|
"Views": "Views",
|
||||||
|
"We couldn't find anything for your request": "We couldn’t find anything for your request",
|
||||||
"We can't find you, check email or": "We can't find you, check email or",
|
"We can't find you, check email or": "We can't find you, check email or",
|
||||||
"We know you, please try to login": "This email address is already registered, please try to login",
|
"We know you, please try to login": "This email address is already registered, please try to login",
|
||||||
"We've sent you a message with a link to enter our website.": "We've sent you an email with a link to your email. Follow the link in the email to enter our website.",
|
"We've sent you a message with a link to enter our website.": "We've sent you an email with a link to your email. Follow the link in the email to enter our website.",
|
||||||
|
|
|
@ -381,6 +381,7 @@
|
||||||
"Video": "Видео",
|
"Video": "Видео",
|
||||||
"Video format not supported": "Тип видео не поддерживается",
|
"Video format not supported": "Тип видео не поддерживается",
|
||||||
"Views": "Просмотры",
|
"Views": "Просмотры",
|
||||||
|
"We couldn't find anything for your request": "Мы не смогли ничего найти по вашему запросу",
|
||||||
"We can't find you, check email or": "Не можем вас найти, проверьте адрес электронной почты или",
|
"We can't find you, check email or": "Не можем вас найти, проверьте адрес электронной почты или",
|
||||||
"We know you, please try to login": "Такой адрес почты уже зарегистрирован, попробуйте залогиниться",
|
"We know you, please try to login": "Такой адрес почты уже зарегистрирован, попробуйте залогиниться",
|
||||||
"We've sent you a message with a link to enter our website.": "Мы выслали вам письмо с ссылкой на почту. Перейдите по ссылке в письме, чтобы войти на сайт.",
|
"We've sent you a message with a link to enter our website.": "Мы выслали вам письмо с ссылкой на почту. Перейдите по ссылке в письме, чтобы войти на сайт.",
|
||||||
|
|
|
@ -109,3 +109,24 @@
|
||||||
.filterResultsControl {
|
.filterResultsControl {
|
||||||
@include searchFilterControl;
|
@include searchFilterControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.searchLoader {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
|
||||||
|
border: 5px solid #fff;
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
animation: rotation 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotation {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,22 +5,16 @@ import { ArticleCard } from '../../Feed/ArticleCard'
|
||||||
import { Button } from '../../_shared/Button'
|
import { Button } from '../../_shared/Button'
|
||||||
import { Icon } from '../../_shared/Icon'
|
import { Icon } from '../../_shared/Icon'
|
||||||
|
|
||||||
// import { PRERENDERED_ARTICLES_COUNT } from '../../Views/Home'
|
|
||||||
|
|
||||||
// import { restoreScrollPosition, saveScrollPosition } from '../../../utils/scroll'
|
|
||||||
|
|
||||||
import type { Shout } from '../../../graphql/types.gen'
|
import type { Shout } from '../../../graphql/types.gen'
|
||||||
|
|
||||||
|
import { searchUrl } from '../../../utils/config'
|
||||||
|
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { useLocalize } from '../../../context/localize'
|
||||||
|
|
||||||
import styles from './SearchModal.module.scss'
|
import styles from './SearchModal.module.scss'
|
||||||
|
|
||||||
// @@TODO implement search
|
// @@TODO handle founded shouts rendering (cors)
|
||||||
// @@TODO implement throttling
|
|
||||||
|
|
||||||
// @@TODO implement load more (await ...({ filters: { .. }, limit: .., offset: .. }))
|
// @@TODO implement load more (await ...({ filters: { .. }, limit: .., offset: .. }))
|
||||||
// @@TODO implement modal hiding on article click
|
|
||||||
// @@TODO search url as const
|
|
||||||
// @@TODO refactor switcher, filters, topics
|
|
||||||
|
|
||||||
const getSearchCoincidences = ({ str, intersection }) =>
|
const getSearchCoincidences = ({ str, intersection }) =>
|
||||||
`<span>${str.replace(
|
`<span>${str.replace(
|
||||||
|
@ -33,15 +27,17 @@ export const SearchModal = () => {
|
||||||
|
|
||||||
const searchInputRef: { current: HTMLInputElement } = { current: null }
|
const searchInputRef: { current: HTMLInputElement } = { current: null }
|
||||||
|
|
||||||
const [isSearching, setIsSearching] = createSignal(false)
|
const [searchResultsList, setSearchResultsList] = createSignal<[] | null>([])
|
||||||
const [searchResultsList, setSearchResultsList] = createSignal([])
|
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
||||||
// const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
const [isLoading, setIsLoading] = createSignal(false)
|
||||||
|
|
||||||
const handleSearch = async () => {
|
const handleSearch = async () => {
|
||||||
const searchValue = searchInputRef.current?.value || ''
|
const searchValue = searchInputRef.current?.value || ''
|
||||||
|
|
||||||
if (Boolean(searchValue)) {
|
if (Boolean(searchValue)) {
|
||||||
await fetch(`https://search.discours.io/search?q=${searchValue}`, {
|
setIsLoading(true)
|
||||||
|
|
||||||
|
await fetch(`${searchUrl}=${searchValue}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
accept: 'application/json',
|
accept: 'application/json',
|
||||||
|
@ -50,10 +46,8 @@ export const SearchModal = () => {
|
||||||
})
|
})
|
||||||
.then((data) => data.json())
|
.then((data) => data.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
console.log(data)
|
// if (data.what) {
|
||||||
|
// const preparedSearchResultsList = data.what.map((article) => ({
|
||||||
// if (data.length) {
|
|
||||||
// const preparedSearchResultsList = [].map((article) => ({
|
|
||||||
// ...article,
|
// ...article,
|
||||||
// title: getSearchCoincidences({
|
// title: getSearchCoincidences({
|
||||||
// str: article.title,
|
// str: article.title,
|
||||||
|
@ -62,19 +56,27 @@ export const SearchModal = () => {
|
||||||
// subtitle: getSearchCoincidences({
|
// subtitle: getSearchCoincidences({
|
||||||
// str: article.subtitle,
|
// str: article.subtitle,
|
||||||
// intersection: searchInputRef.current?.value || ''
|
// intersection: searchInputRef.current?.value || ''
|
||||||
// })
|
// }),
|
||||||
// }))
|
// }))
|
||||||
|
//
|
||||||
// setSearchResultsList(preparedSearchResultsList)
|
// setSearchResultsList(preparedSearchResultsList)
|
||||||
|
//
|
||||||
|
// @@TODO handle setIsLoadMoreButtonVisible()
|
||||||
// } else {
|
// } else {
|
||||||
// // @@TODO handle no search results notice
|
// setSearchResultsList(null)
|
||||||
// }
|
// }
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log('search request failed', error)
|
console.log('search request failed', error)
|
||||||
})
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsLoading(false)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loadMore = () => {}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class={styles.searchContainer}>
|
<div class={styles.searchContainer}>
|
||||||
<input
|
<input
|
||||||
|
@ -83,11 +85,13 @@ export const SearchModal = () => {
|
||||||
ref={(el) => (searchInputRef.current = el)}
|
ref={(el) => (searchInputRef.current = el)}
|
||||||
class={styles.searchInput}
|
class={styles.searchInput}
|
||||||
onInput={handleSearch}
|
onInput={handleSearch}
|
||||||
onFocusIn={() => setIsSearching(true)}
|
|
||||||
onFocusOut={() => setIsSearching(false)}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button class={styles.searchButton} onClick={handleSearch} value={<Icon name="search" />} />
|
<Button
|
||||||
|
class={styles.searchButton}
|
||||||
|
onClick={handleSearch}
|
||||||
|
value={isLoading() ? <div class={styles.searchLoader} /> : <Icon name="search" />}
|
||||||
|
/>
|
||||||
|
|
||||||
<p
|
<p
|
||||||
class={styles.searchDescription}
|
class={styles.searchDescription}
|
||||||
|
@ -96,18 +100,56 @@ export const SearchModal = () => {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* @@TODO handle switcher */}
|
{/* <Show when={!isLoading()}> */}
|
||||||
{/* <ul class={clsx('view-switcher', styles.filterSwitcher)}>
|
<Show when={false}>
|
||||||
<li class="view-switcher__item view-switcher__item--selected">
|
<Show when={searchResultsList().length}>
|
||||||
<button type="button">Все</button>
|
{/* <For each={searchResultsList()}> */}
|
||||||
</li>
|
<For
|
||||||
<li class="view-switcher__item">
|
each={[
|
||||||
<button type="button">Публикации</button>
|
{
|
||||||
</li>
|
body: 'body',
|
||||||
<li class="view-switcher__item">
|
cover: 'production/image/bbad6b10-9b44-11ee-bdef-5758f9198f7d.png',
|
||||||
<button type="button">Темы</button>
|
createdAt: '12',
|
||||||
</li>
|
id: 12,
|
||||||
</ul> */}
|
slug: '/about',
|
||||||
|
authors: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'author',
|
||||||
|
slug: '/'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
title: 'asas',
|
||||||
|
subtitle: 'asas',
|
||||||
|
topics: []
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{(article: Shout) => (
|
||||||
|
<ArticleCard
|
||||||
|
article={article}
|
||||||
|
settings={{
|
||||||
|
isFloorImportant: true,
|
||||||
|
isSingle: true,
|
||||||
|
nodate: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
|
||||||
|
<Show when={isLoadMoreButtonVisible()}>
|
||||||
|
<p class="load-more-container">
|
||||||
|
<button class="button" onClick={loadMore}>
|
||||||
|
{t('Load more')}
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</Show>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<Show when={!searchResultsList()}>
|
||||||
|
<p class={styles.searchDescription} innerHTML={t("We couldn't find anything for your request")} />
|
||||||
|
</Show>
|
||||||
|
</Show>
|
||||||
|
|
||||||
{/* @@TODO handle filter */}
|
{/* @@TODO handle filter */}
|
||||||
{/* <Show when={FILTERS.length}>
|
{/* <Show when={FILTERS.length}>
|
||||||
|
@ -119,71 +161,29 @@ export const SearchModal = () => {
|
||||||
class={styles.filterResultsControl}
|
class={styles.filterResultsControl}
|
||||||
onClick={() => setActiveFilter(filter)}
|
onClick={() => setActiveFilter(filter)}
|
||||||
>
|
>
|
||||||
Период времени
|
{filter.name}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
</div>
|
</div>
|
||||||
</Show> */}
|
</Show> */}
|
||||||
|
|
||||||
{/* <Show when={searchResultsList().length}> */}
|
|
||||||
<Show when={true}>
|
|
||||||
{/* <For each={searchResultsList()}> */}
|
|
||||||
<For
|
|
||||||
each={[
|
|
||||||
{
|
|
||||||
body: 'body',
|
|
||||||
cover: 'production/image/bbad6b10-9b44-11ee-bdef-5758f9198f7d.png',
|
|
||||||
createdAt: '12',
|
|
||||||
id: 12,
|
|
||||||
slug: '/',
|
|
||||||
authors: [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: 'author',
|
|
||||||
slug: '/'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
title: '',
|
|
||||||
subtitle: '',
|
|
||||||
topics: []
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{(article: Shout) => (
|
|
||||||
<ArticleCard
|
|
||||||
article={article}
|
|
||||||
settings={{
|
|
||||||
isFloorImportant: true,
|
|
||||||
isSingle: true,
|
|
||||||
nodate: true
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
|
|
||||||
{/* @@TODO handle load more */}
|
|
||||||
{/* <Show when={isLoadMoreButtonVisible()}>
|
|
||||||
<p class="load-more-container">
|
|
||||||
<button class="button" onClick={loadMore}>
|
|
||||||
{t('Load more')}
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</Show> */}
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
{/* @@TODO handle topics */}
|
{/* @@TODO handle topics */}
|
||||||
{/* <div class="container-xl">
|
{/* <Show when={TOPICS.length}>
|
||||||
<div class="row">
|
<div class="container-xl">
|
||||||
<div class={clsx('col-md-18 offset-md-2', styles.topicsList)}>
|
<div class="row">
|
||||||
{topics.map((topic) => (
|
<div class={clsx('col-md-18 offset-md-2', styles.topicsList)}>
|
||||||
<button type="button" class={styles.topTopic}>
|
<For each={TOPICS}>
|
||||||
{topic.name}
|
{(topic) => (
|
||||||
</button>
|
<button type="button" class={styles.topTopic} onClick={() => setActiveTopic(topic)}>
|
||||||
))}
|
{topic.name}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div> */}
|
</Show> */}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,3 +7,6 @@ const defaultThumborUrl = 'https://images.discours.io'
|
||||||
export const thumborUrl = import.meta.env.PUBLIC_THUMBOR_URL || defaultThumborUrl
|
export const thumborUrl = import.meta.env.PUBLIC_THUMBOR_URL || defaultThumborUrl
|
||||||
|
|
||||||
export const SENTRY_DSN = import.meta.env.PUBLIC_SENTRY_DSN || ''
|
export const SENTRY_DSN = import.meta.env.PUBLIC_SENTRY_DSN || ''
|
||||||
|
|
||||||
|
const defaultSearchUrl = 'https://search.discours.io/search?q'
|
||||||
|
export const searchUrl = import.meta.env.PUBLIC_SEARCH_URL || defaultSearchUrl
|
||||||
|
|
Loading…
Reference in New Issue
Block a user