mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
move filters to interface settings, enable for all feeds
This commit is contained in:
@@ -5,6 +5,8 @@ import useTheme from '../../../hooks/use-theme';
|
||||
import packageJson from '../../../../package.json';
|
||||
import styles from './interface-settings.module.css';
|
||||
import _ from 'lodash';
|
||||
import useInterfaceSettingsStore from '../../../stores/use-interface-settings-store';
|
||||
import useCatalogFiltersStore from '../../../stores/use-catalog-filters-store';
|
||||
|
||||
const commitRef = process.env.REACT_APP_COMMIT_REF;
|
||||
const isElectron = window.isElectron === true;
|
||||
@@ -110,6 +112,8 @@ const InterfaceLanguage = () => {
|
||||
const InterfaceSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
const { hideAvatars, setHideAvatars } = useAvatarVisibilityStore();
|
||||
const { hideGoreBoards, setHideGoreBoards, hideAdultBoards, setHideAdultBoards, hideThreadsWithoutImages, setHideThreadsWithoutImages } = useInterfaceSettingsStore();
|
||||
const { setShowTextOnlyThreads } = useCatalogFiltersStore();
|
||||
|
||||
const handleHideAvatarsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setHideAvatars(e.target.checked);
|
||||
@@ -142,6 +146,29 @@ const InterfaceSettings = () => {
|
||||
<input type='checkbox' checked={hideAvatars} onChange={handleHideAvatarsChange} /> {_.capitalize(t('hide_avatars'))}
|
||||
</label>
|
||||
</div>
|
||||
<div className={styles.setting}>
|
||||
<label>
|
||||
<input type='checkbox' checked={hideGoreBoards} onChange={(e) => setHideGoreBoards(e.target.checked)} /> {_.capitalize(t('hide_gore_boards'))}
|
||||
</label>
|
||||
</div>
|
||||
<div className={styles.setting}>
|
||||
<label>
|
||||
<input type='checkbox' checked={hideAdultBoards} onChange={(e) => setHideAdultBoards(e.target.checked)} /> {_.capitalize(t('hide_adult_boards'))}
|
||||
</label>
|
||||
</div>
|
||||
<div className={styles.setting}>
|
||||
<label>
|
||||
<input
|
||||
type='checkbox'
|
||||
checked={hideThreadsWithoutImages}
|
||||
onChange={(e) => {
|
||||
setHideThreadsWithoutImages(e.target.checked);
|
||||
setShowTextOnlyThreads(!e.target.checked);
|
||||
}}
|
||||
/>
|
||||
{_.capitalize(t('hide_threads_without_images'))}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,17 +2,17 @@ import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useParams, useLocation } from 'react-router-dom';
|
||||
import { useAccountComments, Subplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import useInterfaceSettingsStore from '../stores/use-interface-settings-store';
|
||||
import { getCommentMediaInfo, getHasThumbnail } from '../lib/utils/media-utils';
|
||||
import { isAllView } from '../lib/utils/view-utils';
|
||||
import { useMultisubMetadata } from './use-default-subplebbits';
|
||||
import useCatalogFiltersStore from '../stores/use-catalog-filters-store';
|
||||
import _ from 'lodash';
|
||||
import { getCommentMediaInfo, getHasThumbnail } from '../lib/utils/media-utils';
|
||||
|
||||
const useCatalogFeedRows = (columnCount: number, feed: any, isFeedLoaded: boolean, subplebbit: Subplebbit) => {
|
||||
const { t } = useTranslation();
|
||||
const { address, createdAt, description, rules, shortAddress, suggested, title } = subplebbit || {};
|
||||
const { avatarUrl } = suggested || {};
|
||||
const { showTextOnlyThreads } = useCatalogFiltersStore();
|
||||
const { hideThreadsWithoutImages } = useInterfaceSettingsStore();
|
||||
|
||||
const location = useLocation();
|
||||
const isInAllView = isAllView(location.pathname, useParams());
|
||||
@@ -41,7 +41,7 @@ const useCatalogFeedRows = (columnCount: number, feed: any, isFeedLoaded: boolea
|
||||
!deleted &&
|
||||
!removed &&
|
||||
state === 'succeeded' &&
|
||||
(showTextOnlyThreads || (!showTextOnlyThreads && isMediaShowed)) &&
|
||||
(!hideThreadsWithoutImages || (hideThreadsWithoutImages && isMediaShowed)) &&
|
||||
cid &&
|
||||
cid === postCid &&
|
||||
subplebbitAddress === address &&
|
||||
@@ -63,7 +63,7 @@ const useCatalogFeedRows = (columnCount: number, feed: any, isFeedLoaded: boolea
|
||||
}
|
||||
|
||||
// add subplebbit description and rules as fake posts at the top of the feed
|
||||
if ((description && description.length > 0 && (showTextOnlyThreads || (!showTextOnlyThreads && suggested?.avatarUrl))) || (isInAllView && showTextOnlyThreads)) {
|
||||
if (description && description.length > 0) {
|
||||
_feed.unshift({
|
||||
isDescription: true,
|
||||
subplebbitAddress: address,
|
||||
@@ -77,7 +77,7 @@ const useCatalogFeedRows = (columnCount: number, feed: any, isFeedLoaded: boolea
|
||||
});
|
||||
}
|
||||
|
||||
if (rules && rules.length > 0 && showTextOnlyThreads) {
|
||||
if (rules && rules.length > 0) {
|
||||
_feed.unshift({
|
||||
isRules: true,
|
||||
subplebbitAddress: address,
|
||||
@@ -91,23 +91,7 @@ const useCatalogFeedRows = (columnCount: number, feed: any, isFeedLoaded: boolea
|
||||
}
|
||||
|
||||
return _feed;
|
||||
}, [
|
||||
accountComments,
|
||||
feed,
|
||||
description,
|
||||
rules,
|
||||
address,
|
||||
isFeedLoaded,
|
||||
createdAt,
|
||||
title,
|
||||
shortAddress,
|
||||
avatarUrl,
|
||||
t,
|
||||
isInAllView,
|
||||
multisub,
|
||||
showTextOnlyThreads,
|
||||
suggested?.avatarUrl,
|
||||
]);
|
||||
}, [accountComments, feed, description, rules, address, isFeedLoaded, createdAt, title, shortAddress, avatarUrl, t, isInAllView, multisub, hideThreadsWithoutImages]);
|
||||
|
||||
const rows = useMemo(() => {
|
||||
const rows = [];
|
||||
|
||||
@@ -9,10 +9,6 @@ interface FilterItem {
|
||||
}
|
||||
|
||||
interface CatalogFiltersStore {
|
||||
showAdultBoards: boolean;
|
||||
setShowAdultBoards: (value: boolean) => void;
|
||||
showGoreBoards: boolean;
|
||||
setShowGoreBoards: (value: boolean) => void;
|
||||
showTextOnlyThreads: boolean;
|
||||
setShowTextOnlyThreads: (value: boolean) => void;
|
||||
filterText: string;
|
||||
@@ -35,10 +31,6 @@ const useCatalogFiltersStore = create(
|
||||
set({ showTextOnlyThreads: value, filteredCount: 0 });
|
||||
get().updateFilter();
|
||||
},
|
||||
showAdultBoards: false,
|
||||
setShowAdultBoards: (value: boolean) => set({ showAdultBoards: value }),
|
||||
showGoreBoards: false,
|
||||
setShowGoreBoards: (value: boolean) => set({ showGoreBoards: value }),
|
||||
filterText: '',
|
||||
setFilterText: (value: string) => set({ filterText: value }),
|
||||
filterItems: [],
|
||||
@@ -58,28 +50,28 @@ const useCatalogFiltersStore = create(
|
||||
filter: (comment: Comment) => {
|
||||
const { showTextOnlyThreads, filterItems } = state;
|
||||
|
||||
const shouldShow = (() => {
|
||||
if (!showTextOnlyThreads && !getHasThumbnail(getCommentMediaInfo(comment), comment?.link)) {
|
||||
return false;
|
||||
const hasThumbnail = getHasThumbnail(getCommentMediaInfo(comment), comment?.link);
|
||||
const title = comment?.title?.toLowerCase() || '';
|
||||
const content = comment?.content?.toLowerCase() || '';
|
||||
|
||||
const matchesFilterItems = filterItems
|
||||
.filter((item) => item.enabled)
|
||||
.some((item) => {
|
||||
const text = item.text.toLowerCase();
|
||||
return title.includes(text) || content.includes(text);
|
||||
});
|
||||
|
||||
const shouldShow = showTextOnlyThreads || hasThumbnail;
|
||||
|
||||
if (!shouldShow || matchesFilterItems) {
|
||||
if (matchesFilterItems && !filteredCids.has(comment.cid)) {
|
||||
filteredCids.add(comment.cid);
|
||||
set((state) => ({ filteredCount: state.filteredCount + 1 }));
|
||||
}
|
||||
|
||||
const title = comment?.title?.toLowerCase() || '';
|
||||
const content = comment?.content?.toLowerCase() || '';
|
||||
|
||||
return !filterItems
|
||||
.filter((item) => item.enabled)
|
||||
.some((item) => {
|
||||
const text = item.text.toLowerCase();
|
||||
return title.includes(text) || content.includes(text);
|
||||
});
|
||||
})();
|
||||
|
||||
if (!shouldShow && !filteredCids.has(comment.cid)) {
|
||||
filteredCids.add(comment.cid);
|
||||
set((state) => ({ filteredCount: state.filteredCount + 1 }));
|
||||
return false;
|
||||
}
|
||||
|
||||
return shouldShow;
|
||||
return true;
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
interface InterfaceSettingsStore {
|
||||
hideGoreBoards: boolean;
|
||||
setHideGoreBoards: (value: boolean) => void;
|
||||
hideAdultBoards: boolean;
|
||||
setHideAdultBoards: (value: boolean) => void;
|
||||
hideThreadsWithoutImages: boolean;
|
||||
setHideThreadsWithoutImages: (value: boolean) => void;
|
||||
}
|
||||
|
||||
const useInterfaceSettingsStore = create(
|
||||
persist<InterfaceSettingsStore>(
|
||||
(set) => ({
|
||||
hideGoreBoards: true,
|
||||
setHideGoreBoards: (value: boolean) => set({ hideGoreBoards: value }),
|
||||
hideAdultBoards: true,
|
||||
setHideAdultBoards: (value: boolean) => set({ hideAdultBoards: value }),
|
||||
hideThreadsWithoutImages: true,
|
||||
setHideThreadsWithoutImages: (value: boolean) => set({ hideThreadsWithoutImages: value }),
|
||||
}),
|
||||
{
|
||||
name: 'interface-settings-storage',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
export default useInterfaceSettingsStore;
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
import { useAccount, useAccountComments, useBlock, useFeed, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import { Comment, useAccount, useAccountComments, useBlock, useFeed, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import styles from './board.module.css';
|
||||
@@ -17,13 +17,23 @@ import ReplyModal from '../../components/reply-modal';
|
||||
import SettingsModal from '../../components/settings-modal';
|
||||
import SubplebbitDescription from '../../components/subplebbit-description';
|
||||
import SubplebbitRules from '../../components/subplebbit-rules';
|
||||
import useInterfaceSettingsStore from '../../stores/use-interface-settings-store';
|
||||
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
|
||||
|
||||
const lastVirtuosoStates: { [key: string]: StateSnapshot } = {};
|
||||
|
||||
const threadsWithoutImagesFilter = (comment: Comment) => {
|
||||
if (!getHasThumbnail(getCommentMediaInfo(comment), comment?.link)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const Board = () => {
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
const { subplebbitAddress } = useParams<{ subplebbitAddress: string }>();
|
||||
const { hideThreadsWithoutImages } = useInterfaceSettingsStore();
|
||||
|
||||
const isInAllView = isAllView(location.pathname, useParams());
|
||||
const defaultSubplebbitAddresses = useDefaultSubplebbitAddresses();
|
||||
@@ -51,8 +61,9 @@ const Board = () => {
|
||||
sortType,
|
||||
postsPerPage: isInAllView || isInSubscriptionsView ? 5 : 25,
|
||||
...(isInAllView || isInSubscriptionsView ? { newerThan: timeFilterSeconds } : {}),
|
||||
filter: hideThreadsWithoutImages ? threadsWithoutImagesFilter : undefined,
|
||||
}),
|
||||
[subplebbitAddresses, sortType, timeFilterSeconds, isInAllView, isInSubscriptionsView],
|
||||
[subplebbitAddresses, sortType, timeFilterSeconds, isInAllView, isInSubscriptionsView, hideThreadsWithoutImages],
|
||||
);
|
||||
|
||||
const { feed, hasMore, loadMore, reset } = useFeed(feedOptions);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { isAllView, isCatalogView } from '../../../lib/utils/view-utils';
|
||||
import useCatalogFiltersStore from '../../../stores/use-catalog-filters-store';
|
||||
import styles from './catalog-filters.module.css';
|
||||
|
||||
@@ -100,11 +98,6 @@ const FiltersTable = ({ onSave }: { onSave: () => void }) => {
|
||||
|
||||
const FiltersModal = ({ closeModal }: { closeModal: () => void }) => {
|
||||
const { t } = useTranslation();
|
||||
const { showAdultBoards, setShowAdultBoards, showGoreBoards, setShowGoreBoards, showTextOnlyThreads, setShowTextOnlyThreads } = useCatalogFiltersStore();
|
||||
const location = useLocation();
|
||||
const params = useParams();
|
||||
const isInCatalogView = isCatalogView(location.pathname, params);
|
||||
const isInAllView = isAllView(location.pathname, params);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -114,33 +107,7 @@ const FiltersModal = ({ closeModal }: { closeModal: () => void }) => {
|
||||
<span className={styles.title}>{t('filters')}</span>
|
||||
<span className={styles.closeButton} title='close' onClick={closeModal} />
|
||||
</div>
|
||||
<div className={styles.filters}>
|
||||
{isInCatalogView && (
|
||||
<div>
|
||||
<label className='capitalize'>
|
||||
<input type='checkbox' checked={!showTextOnlyThreads} onChange={(e) => setShowTextOnlyThreads(!e.target.checked)} />
|
||||
{t('hide_threads_without_images')}
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
{isInAllView && (
|
||||
<div className={styles.nsfwLabels}>
|
||||
<div>
|
||||
<label>
|
||||
<input type='checkbox' checked={!showGoreBoards} onChange={(e) => setShowGoreBoards(!e.target.checked)} />
|
||||
hide gore content
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>
|
||||
<input type='checkbox' checked={!showAdultBoards} onChange={(e) => setShowAdultBoards(!e.target.checked)} />
|
||||
hide adult content
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{isInCatalogView && <FiltersTable onSave={closeModal} />}
|
||||
<FiltersTable onSave={closeModal} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -17,6 +17,7 @@ import CatalogRow from '../../components/catalog-row';
|
||||
import LoadingEllipsis from '../../components/loading-ellipsis';
|
||||
import SettingsModal from '../../components/settings-modal';
|
||||
import styles from './catalog.module.css';
|
||||
import useInterfaceSettingsStore from '../../stores/use-interface-settings-store';
|
||||
|
||||
const lastVirtuosoStates: { [key: string]: StateSnapshot } = {};
|
||||
|
||||
@@ -27,7 +28,8 @@ const Catalog = () => {
|
||||
|
||||
const isInAllView = isAllView(location.pathname, useParams());
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
const { filter, showAdultBoards, showGoreBoards } = useCatalogFiltersStore();
|
||||
const { hideAdultBoards, hideGoreBoards } = useInterfaceSettingsStore();
|
||||
const { filter } = useCatalogFiltersStore();
|
||||
|
||||
const account = useAccount();
|
||||
const subscriptions = account?.subscriptions;
|
||||
@@ -40,7 +42,7 @@ const Catalog = () => {
|
||||
const hasGoreTag = tags?.includes('gore');
|
||||
const hasAdultTag = tags?.includes('adult');
|
||||
|
||||
if ((hasGoreTag && !showGoreBoards) || (hasAdultTag && !showAdultBoards)) {
|
||||
if ((hasGoreTag && hideGoreBoards) || (hasAdultTag && hideAdultBoards)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -54,7 +56,7 @@ const Catalog = () => {
|
||||
return subscriptions || [];
|
||||
}
|
||||
return [subplebbitAddress];
|
||||
}, [isInAllView, isInSubscriptionsView, subplebbitAddress, defaultSubplebbits, subscriptions, showAdultBoards, showGoreBoards]);
|
||||
}, [isInAllView, isInSubscriptionsView, subplebbitAddress, defaultSubplebbits, subscriptions, hideAdultBoards, hideGoreBoards]);
|
||||
|
||||
const { imageSize } = useCatalogStyleStore();
|
||||
const columnWidth = imageSize === 'Large' ? 270 : 180;
|
||||
|
||||
Reference in New Issue
Block a user