diff --git a/src/components/board-buttons/board-buttons.tsx b/src/components/board-buttons/board-buttons.tsx
index 4068ac30..3a6c53fc 100644
--- a/src/components/board-buttons/board-buttons.tsx
+++ b/src/components/board-buttons/board-buttons.tsx
@@ -10,6 +10,7 @@ import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
import useCatalogStyleStore from '../../stores/use-catalog-style-store';
import useFeedResetStore from '../../stores/use-feed-reset-store';
import useSortingStore from '../../stores/use-sorting-store';
+import useAllFeedFilterStore from '../../stores/use-all-feed-filter-store';
import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
import useIsMobile from '../../hooks/use-is-mobile';
import useTimeFilter from '../../hooks/use-time-filter';
@@ -247,14 +248,14 @@ export const TimeFilter = ({ isInAllView, isInCatalogView, isInSubscriptionsView
? `/all/catalog/${timeFilterName}`
: `/all/${timeFilterName}`
: isInSubscriptionsView
- ? isInCatalogView
- ? `/subs/catalog/${timeFilterName}`
- : `/subs/${timeFilterName}`
- : isInModView
- ? isInCatalogView
- ? `/mod/catalog/${timeFilterName}`
- : `/mod/${timeFilterName}`
- : null;
+ ? isInCatalogView
+ ? `/subs/catalog/${timeFilterName}`
+ : `/subs/${timeFilterName}`
+ : isInModView
+ ? isInCatalogView
+ ? `/mod/catalog/${timeFilterName}`
+ : `/mod/${timeFilterName}`
+ : null;
link && navigate(link);
};
@@ -282,6 +283,22 @@ export const TimeFilter = ({ isInAllView, isInCatalogView, isInSubscriptionsView
);
};
+const AllFeedFilter = () => {
+ const { t } = useTranslation();
+ const { filter, setFilter } = useAllFeedFilterStore();
+
+ return (
+ <>
+ {t('show')}:
+
+ >
+ );
+};
+
export const MobileBoardButtons = () => {
const { t } = useTranslation();
const params = useParams();
@@ -341,6 +358,14 @@ export const MobileBoardButtons = () => {
)
)}
+ {isInAllView && (
+ <>
+
+
+ >
+ )}
{isInCatalogView && (
<>
@@ -409,11 +434,9 @@ export const DesktopBoardButtons = () => {
{isInPostView || isInPendingPostPage ? (
<>
[
-
- ] [
+ ] [
] [
-
- ] [
+ ] [
]
@@ -462,6 +485,7 @@ export const DesktopBoardButtons = () => {
>
)}
+ {isInAllView && }
{(isInAllView || isInSubscriptionsView || isInModView) && (
)}
diff --git a/src/hooks/use-filtered-default-subplebbit-addresses.ts b/src/hooks/use-filtered-default-subplebbit-addresses.ts
new file mode 100644
index 00000000..54fe5c79
--- /dev/null
+++ b/src/hooks/use-filtered-default-subplebbit-addresses.ts
@@ -0,0 +1,19 @@
+import { useMemo } from 'react';
+import { useDefaultSubplebbits } from './use-default-subplebbits';
+import useAllFeedFilterStore from '../stores/use-all-feed-filter-store';
+
+export const useFilteredDefaultSubplebbitAddresses = () => {
+ const defaultSubplebbits = useDefaultSubplebbits();
+ const { filter } = useAllFeedFilterStore();
+
+ return useMemo(() => {
+ if (filter === 'all') {
+ return defaultSubplebbits.map((subplebbit) => subplebbit.address);
+ }
+ if (filter === 'nsfw') {
+ return defaultSubplebbits.filter((subplebbit) => subplebbit.nsfw === true).map((subplebbit) => subplebbit.address);
+ }
+ // filter === 'sfw'
+ return defaultSubplebbits.filter((subplebbit) => subplebbit.nsfw !== true).map((subplebbit) => subplebbit.address);
+ }, [defaultSubplebbits, filter]);
+};
diff --git a/src/stores/use-all-feed-filter-store.ts b/src/stores/use-all-feed-filter-store.ts
new file mode 100644
index 00000000..6385b38e
--- /dev/null
+++ b/src/stores/use-all-feed-filter-store.ts
@@ -0,0 +1,31 @@
+import { create } from 'zustand';
+
+export type AllFeedFilter = 'all' | 'nsfw' | 'sfw';
+
+interface AllFeedFilterStore {
+ filter: AllFeedFilter;
+ setFilter: (value: AllFeedFilter) => void;
+}
+
+const getStoredFilter = (): AllFeedFilter => {
+ try {
+ const stored = localStorage.getItem('5chan-all-feed-filter') as AllFeedFilter;
+ return stored === 'nsfw' || stored === 'sfw' ? stored : 'all';
+ } catch {
+ return 'all';
+ }
+};
+
+const useAllFeedFilterStore = create((set) => ({
+ filter: getStoredFilter(),
+ setFilter: (value: AllFeedFilter) => {
+ set({ filter: value });
+ try {
+ localStorage.setItem('5chan-all-feed-filter', value);
+ } catch (error) {
+ console.warn('Failed to save allFeedFilter to localStorage:', error);
+ }
+ },
+}));
+
+export default useAllFeedFilterStore;
diff --git a/src/views/board/board.tsx b/src/views/board/board.tsx
index 6c34ac54..dd924127 100644
--- a/src/views/board/board.tsx
+++ b/src/views/board/board.tsx
@@ -7,6 +7,7 @@ import styles from './board.module.css';
import { shouldShowSnow } from '../../lib/snow';
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
import { useDefaultSubplebbitAddresses, useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
+import { useFilteredDefaultSubplebbitAddresses } from '../../hooks/use-filtered-default-subplebbit-addresses';
import { useResolvedSubplebbitAddress, useBoardPath } from '../../hooks/use-resolved-subplebbit-address';
import { useFeedStateString } from '../../hooks/use-state-string';
import useTimeFilter, { timeFilterNameToSeconds } from '../../hooks/use-time-filter';
@@ -60,6 +61,7 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
const boardPath = useBoardPath(subplebbitAddress);
const defaultSubplebbitAddresses = useDefaultSubplebbitAddresses();
+ const filteredDefaultSubplebbitAddresses = useFilteredDefaultSubplebbitAddresses();
const account = useAccount();
const subscriptions = account?.subscriptions;
@@ -69,7 +71,7 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
const subplebbitAddresses = useMemo(() => {
if (isInAllView) {
- return defaultSubplebbitAddresses;
+ return filteredDefaultSubplebbitAddresses;
}
if (isInSubscriptionsView) {
return subscriptions || [];
@@ -78,7 +80,16 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
return accountSubplebbitAddresses;
}
return [subplebbitAddress];
- }, [isInAllView, isInSubscriptionsView, isInModView, subplebbitAddress, defaultSubplebbitAddresses, subscriptions, accountSubplebbitAddresses]);
+ }, [
+ isInAllView,
+ isInSubscriptionsView,
+ isInModView,
+ subplebbitAddress,
+ defaultSubplebbitAddresses,
+ filteredDefaultSubplebbitAddresses,
+ subscriptions,
+ accountSubplebbitAddresses,
+ ]);
const { sortType } = useSortingStore();
const { timeFilterSeconds: timeFilterSecondsFromHook, timeFilterName: timeFilterNameFromHook } = useTimeFilter();
diff --git a/src/views/catalog/catalog.tsx b/src/views/catalog/catalog.tsx
index 42de23d4..a4612ff0 100644
--- a/src/views/catalog/catalog.tsx
+++ b/src/views/catalog/catalog.tsx
@@ -6,6 +6,7 @@ import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
import useCatalogFeedRows from '../../hooks/use-catalog-feed-rows';
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
+import { useFilteredDefaultSubplebbitAddresses } from '../../hooks/use-filtered-default-subplebbit-addresses';
import { useResolvedSubplebbitAddress, useBoardPath } from '../../hooks/use-resolved-subplebbit-address';
import { useFeedStateString } from '../../hooks/use-state-string';
import useTimeFilter, { timeFilterNameToSeconds } from '../../hooks/use-time-filter';
@@ -152,19 +153,18 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp,
const account = useAccount();
const subscriptions = account?.subscriptions;
+ const filteredDefaultSubplebbitAddresses = useFilteredDefaultSubplebbitAddresses();
const subplebbitAddresses = useMemo(() => {
- const filteredDefaultSubplebbits = defaultSubplebbits.map((subplebbit) => subplebbit.address).filter(Boolean); // Filter out any undefined/null values
-
if (isInAllView) {
- return filteredDefaultSubplebbits;
+ return filteredDefaultSubplebbitAddresses;
}
if (isInSubscriptionsView) {
return (subscriptions || []).filter(Boolean); // Filter out any undefined/null values
}
// Only include subplebbitAddress if it's defined
return subplebbitAddress ? [subplebbitAddress] : [];
- }, [isInAllView, isInSubscriptionsView, subplebbitAddress, defaultSubplebbits, subscriptions]);
+ }, [isInAllView, isInSubscriptionsView, subplebbitAddress, filteredDefaultSubplebbitAddresses, subscriptions]);
const { imageSize } = useCatalogStyleStore();
const columnWidth = imageSize === 'Large' ? 270 : 180;