mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
feat(catalog): add search
This commit is contained in:
@@ -246,7 +246,7 @@ export const MobileBoardButtons = () => {
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||
|
||||
const { filteredCount } = useCatalogFiltersStore();
|
||||
const { filteredCount, searchText } = useCatalogFiltersStore();
|
||||
|
||||
return (
|
||||
<div className={`${styles.mobileBoardButtons} ${!isInCatalogView ? styles.addMargin : ''}`}>
|
||||
@@ -269,11 +269,19 @@ export const MobileBoardButtons = () => {
|
||||
)}
|
||||
{!(isInAllView || isInSubscriptionsView) && <SubscribeButton address={subplebbitAddress} />}
|
||||
<RefreshButton />
|
||||
{isInCatalogView && filteredCount > 0 && (
|
||||
{isInCatalogView && searchText ? (
|
||||
<span className={styles.filteredThreadsCount}>
|
||||
{' '}
|
||||
— {t('filtered_threads')}: <strong>{filteredCount}</strong>
|
||||
— {t('search_results_for')}: <strong>{searchText}</strong>
|
||||
</span>
|
||||
) : (
|
||||
isInCatalogView &&
|
||||
filteredCount > 0 && (
|
||||
<span className={styles.filteredThreadsCount}>
|
||||
{' '}
|
||||
— {t('filtered_threads')}: <strong>{filteredCount}</strong>
|
||||
</span>
|
||||
)
|
||||
)}
|
||||
{isInCatalogView && (
|
||||
<>
|
||||
@@ -331,7 +339,7 @@ export const DesktopBoardButtons = () => {
|
||||
const isInPostView = isPostPageView(location.pathname, params);
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
||||
|
||||
const { filteredCount } = useCatalogFiltersStore();
|
||||
const { filteredCount, searchText } = useCatalogFiltersStore();
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -364,11 +372,19 @@ export const DesktopBoardButtons = () => {
|
||||
</>
|
||||
)}
|
||||
[<RefreshButton />]
|
||||
{isInCatalogView && filteredCount > 0 && (
|
||||
{isInCatalogView && searchText ? (
|
||||
<span className={styles.filteredThreadsCount}>
|
||||
{' '}
|
||||
— {t('filtered_threads')}: <strong>{filteredCount}</strong>
|
||||
— {t('search_results_for')}: <strong>{searchText}</strong>
|
||||
</span>
|
||||
) : (
|
||||
isInCatalogView &&
|
||||
filteredCount > 0 && (
|
||||
<span className={styles.filteredThreadsCount}>
|
||||
{' '}
|
||||
— {t('filtered_threads')}: <strong>{filteredCount}</strong>
|
||||
</span>
|
||||
)
|
||||
)}
|
||||
<span className={styles.rightSideButtons}>
|
||||
{isInCatalogView && (
|
||||
|
||||
@@ -1,11 +1,43 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import styles from './catalog-search.module.css';
|
||||
import useIsMobile from '../../hooks/use-is-mobile';
|
||||
import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
|
||||
import _ from 'lodash';
|
||||
|
||||
const CatalogSearch = () => {
|
||||
const { t } = useTranslation();
|
||||
const [openSearch, setOpenSearch] = useState(false);
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const { setSearchFilter, clearSearchFilter } = useCatalogFiltersStore();
|
||||
|
||||
// Create a debounced version of setSearchFilter
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const debouncedSetSearchFilter = useCallback(
|
||||
_.debounce((text: string) => {
|
||||
if (text.trim()) {
|
||||
setSearchFilter(text);
|
||||
} else {
|
||||
clearSearchFilter();
|
||||
}
|
||||
}, 300),
|
||||
[setSearchFilter, clearSearchFilter],
|
||||
);
|
||||
|
||||
const handleToggleSearch = useCallback(() => {
|
||||
setOpenSearch((prev) => !prev);
|
||||
|
||||
if (openSearch) {
|
||||
setInputValue('');
|
||||
clearSearchFilter();
|
||||
}
|
||||
}, [openSearch, clearSearchFilter]);
|
||||
|
||||
const handleCloseSearch = useCallback(() => {
|
||||
setOpenSearch(false);
|
||||
setInputValue('');
|
||||
clearSearchFilter();
|
||||
}, [clearSearchFilter]);
|
||||
|
||||
useEffect(() => {
|
||||
if (openSearch) {
|
||||
@@ -14,26 +46,42 @@ const CatalogSearch = () => {
|
||||
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape') {
|
||||
setOpenSearch(false);
|
||||
handleCloseSearch();
|
||||
}
|
||||
};
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}
|
||||
}, [openSearch]);
|
||||
}, [openSearch, handleCloseSearch]);
|
||||
|
||||
useEffect(() => {
|
||||
debouncedSetSearchFilter(inputValue);
|
||||
|
||||
return () => {
|
||||
debouncedSetSearchFilter.cancel();
|
||||
};
|
||||
}, [inputValue, debouncedSetSearchFilter]);
|
||||
|
||||
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setInputValue(e.target.value);
|
||||
};
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
return (
|
||||
<>
|
||||
{!isMobile && '['}
|
||||
<span className={`${styles.filtersButton} button`} onClick={() => setOpenSearch(!openSearch)}>
|
||||
<span className={`${styles.filtersButton} button`} onClick={handleToggleSearch}>
|
||||
{t('search')}
|
||||
</span>
|
||||
{!isMobile && ']'}
|
||||
{openSearch && (
|
||||
<div className={styles.searchContainer}>
|
||||
<input type='text' />
|
||||
<span className={styles.closeSearch} onClick={() => setOpenSearch(false)}>
|
||||
<input type='text' value={inputValue} onChange={handleSearchChange} />
|
||||
<span className={styles.closeSearch} onClick={handleCloseSearch}>
|
||||
✖
|
||||
</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user