mirror of
https://github.com/plebbit/seedit.git
synced 2026-02-08 13:00:57 -05:00
feat(settings): add nsfw filters and filtering community by nsfw tag
This commit is contained in:
@@ -177,6 +177,7 @@
|
||||
unicode-bidi: isolate;
|
||||
font-size: small;
|
||||
margin-bottom: 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.alwaysShowNsfwNotice p {
|
||||
|
||||
@@ -5,6 +5,7 @@ import Embed from '../embed';
|
||||
import { CommentMediaInfo } from '../../../lib/utils/media-utils';
|
||||
import Markdown from '../../markdown';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import useFilterSettingsStore from '../../../stores/use-filter-settings-store';
|
||||
|
||||
interface ExpandoProps {
|
||||
authorEditReason?: string;
|
||||
@@ -36,8 +37,8 @@ const Expando = ({
|
||||
toggleExpanded,
|
||||
}: ExpandoProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [hideContent, setHideContent] = useState(true);
|
||||
const { blurNsfwThumbnails, setBlurNsfwThumbnails } = useFilterSettingsStore();
|
||||
const [hideContent, setHideContent] = useState(blurNsfwThumbnails);
|
||||
const [alwaysShowNsfw, setAlwaysShowNsfw] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -46,6 +47,12 @@ const Expando = ({
|
||||
}
|
||||
}, [expanded]);
|
||||
|
||||
const handleAlwaysShowNsfw = () => {
|
||||
setBlurNsfwThumbnails(false);
|
||||
setHideContent(false);
|
||||
setAlwaysShowNsfw(true);
|
||||
};
|
||||
|
||||
let mediaComponent = null;
|
||||
|
||||
if (commentMediaInfo?.type === 'image' || commentMediaInfo?.type === 'gif') {
|
||||
@@ -64,13 +71,13 @@ const Expando = ({
|
||||
<div className={expanded ? styles.expando : styles.expandoHidden}>
|
||||
{link && !removed && commentMediaInfo?.type !== 'webpage' && (
|
||||
<div className={styles.mediaPreview} onClick={() => setHideContent(false)}>
|
||||
{(nsfw || spoiler) && hideContent && link && commentMediaInfo?.type !== 'webpage' && !(deleted || removed) && (
|
||||
{((nsfw && blurNsfwThumbnails) || spoiler) && hideContent && link && commentMediaInfo?.type !== 'webpage' && !(deleted || removed) && (
|
||||
<>
|
||||
<div className={styles.blurContent} />
|
||||
<span className={styles.unblurButton}>{nsfw && spoiler ? 'CLICK TO SEE NSFW SPOILER' : spoiler ? t('view_spoiler') : nsfw ? 'CLICK TO SEE NSFW' : ''}</span>
|
||||
<span className={styles.unblurButton}>{nsfw && spoiler ? t('see_nsfw_spoiler') : spoiler ? t('view_spoiler') : nsfw ? t('see_nsfw') : ''}</span>
|
||||
{nsfw && (
|
||||
<span className={styles.alwaysShowNsfwButton} onClick={() => setAlwaysShowNsfw(!alwaysShowNsfw)}>
|
||||
Always show NSFW media?
|
||||
<span className={styles.alwaysShowNsfwButton} onClick={handleAlwaysShowNsfw}>
|
||||
{t('always_show_nsfw')}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
@@ -89,9 +96,11 @@ const Expando = ({
|
||||
</div>
|
||||
)}
|
||||
{alwaysShowNsfw && (
|
||||
<div className={styles.alwaysShowNsfwNotice}>
|
||||
<p>Ok, we changed your preferences to always show NSFW media.</p>
|
||||
<button onClick={() => setAlwaysShowNsfw(false)}>Undo</button>
|
||||
<div className={styles.alwaysShowNsfwContainer}>
|
||||
<div className={styles.alwaysShowNsfwNotice}>
|
||||
<p>{t('always_show_nsfw_notice')}</p>
|
||||
<button onClick={() => setAlwaysShowNsfw(false)}>{t('undo')}</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{content && showContent && (
|
||||
|
||||
@@ -96,7 +96,6 @@ const Post = ({ index, post = {} }: PostProps) => {
|
||||
link,
|
||||
linkHeight,
|
||||
linkWidth,
|
||||
nsfw,
|
||||
pinned,
|
||||
reason,
|
||||
removed,
|
||||
@@ -108,6 +107,7 @@ const Post = ({ index, post = {} }: PostProps) => {
|
||||
title,
|
||||
upvoteCount,
|
||||
} = post || {};
|
||||
const nsfw = true;
|
||||
const { displayName, shortAddress } = author || {};
|
||||
const { shortAuthorAddress, authorAddressChanged } = useAuthorAddress({ comment: post });
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import styles from './thumbnail.module.css';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { CommentMediaInfo } from '../../../lib/utils/media-utils';
|
||||
import useFetchGifFirstFrame from '../../../hooks/use-fetch-gif-first-frame';
|
||||
import useFilterSettingsStore from '../../../stores/use-filter-settings-store';
|
||||
|
||||
interface ThumbnailProps {
|
||||
cid?: string;
|
||||
@@ -84,7 +85,9 @@ const Thumbnail = ({
|
||||
mediaComponent = <span className={`${styles.iconThumbnail} ${styles.spoilerIcon}`} />;
|
||||
}
|
||||
|
||||
if (isNsfw) {
|
||||
const { blurNsfwThumbnails } = useFilterSettingsStore();
|
||||
|
||||
if (isNsfw && blurNsfwThumbnails) {
|
||||
mediaComponent = <span className={`${styles.iconThumbnail} ${styles.nsfwIcon}`} />;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useEffect, useMemo, useState } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useAccount } from '@plebbit/plebbit-react-hooks';
|
||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||
import useFilterSettingsStore from '../stores/use-filter-settings-store';
|
||||
|
||||
interface Subplebbit {
|
||||
title?: string;
|
||||
@@ -28,10 +29,9 @@ export const categorizeSubplebbits = (subplebbits: Subplebbit[]) => {
|
||||
return { plebbitSubs, interestsSubs, randomSubs, internationalSubs, projectsSubs };
|
||||
};
|
||||
|
||||
const nsfwTags = ['gore', 'adult', 'anti'];
|
||||
|
||||
export const useDefaultSubplebbits = () => {
|
||||
const [subplebbits, setSubplebbits] = useState<Subplebbit[]>([]);
|
||||
const { hideAdultCommunities, hideGoreCommunities, hideAntiCommunities } = useFilterSettingsStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (cache) {
|
||||
@@ -39,13 +39,16 @@ export const useDefaultSubplebbits = () => {
|
||||
}
|
||||
(async () => {
|
||||
try {
|
||||
const multisub = await fetch(
|
||||
'https://raw.githubusercontent.com/plebbit/temporary-default-subplebbits/master/multisub.json',
|
||||
// { cache: 'no-cache' }
|
||||
).then((res) => res.json());
|
||||
const multisub = await fetch('https://raw.githubusercontent.com/plebbit/temporary-default-subplebbits/master/multisub.json').then((res) => res.json());
|
||||
|
||||
const filteredSubplebbits = multisub.subplebbits.filter((subplebbit: Subplebbit) => {
|
||||
return !subplebbit.tags?.some((tag) => nsfwTags.includes(tag));
|
||||
const tags = subplebbit.tags || [];
|
||||
|
||||
if (hideAdultCommunities && tags.includes('adult')) return false;
|
||||
if (hideGoreCommunities && tags.includes('gore')) return false;
|
||||
if (hideAntiCommunities && tags.includes('anti')) return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
cache = filteredSubplebbits;
|
||||
@@ -54,7 +57,7 @@ export const useDefaultSubplebbits = () => {
|
||||
console.warn(e);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
}, [hideAdultCommunities, hideGoreCommunities, hideAntiCommunities]);
|
||||
|
||||
return cache || subplebbits;
|
||||
};
|
||||
|
||||
33
src/stores/use-filter-settings-store.ts
Normal file
33
src/stores/use-filter-settings-store.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
interface FilterSettingsState {
|
||||
blurNsfwThumbnails: boolean;
|
||||
hideAdultCommunities: boolean;
|
||||
hideGoreCommunities: boolean;
|
||||
hideAntiCommunities: boolean;
|
||||
setBlurNsfwThumbnails: (blur: boolean) => void;
|
||||
setHideAdultCommunities: (hide: boolean) => void;
|
||||
setHideGoreCommunities: (hide: boolean) => void;
|
||||
setHideAntiCommunities: (hide: boolean) => void;
|
||||
}
|
||||
|
||||
const useFilterSettingsStore = create<FilterSettingsState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
blurNsfwThumbnails: true,
|
||||
hideAdultCommunities: true,
|
||||
hideGoreCommunities: true,
|
||||
hideAntiCommunities: true,
|
||||
setBlurNsfwThumbnails: (blur) => set({ blurNsfwThumbnails: blur }),
|
||||
setHideAdultCommunities: (hide) => set({ hideAdultCommunities: hide }),
|
||||
setHideGoreCommunities: (hide) => set({ hideGoreCommunities: hide }),
|
||||
setHideAntiCommunities: (hide) => set({ hideAntiCommunities: hide }),
|
||||
}),
|
||||
{
|
||||
name: 'filter-settings',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
export default useFilterSettingsStore;
|
||||
@@ -104,3 +104,17 @@
|
||||
.highlightedSetting {
|
||||
background-color: var(--yellow-highlight);
|
||||
}
|
||||
|
||||
.filterSettingTitle {
|
||||
font-style: italic;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.filters input[type='checkbox'] {
|
||||
margin: 2px 0.5em 0 0;
|
||||
}
|
||||
|
||||
.filters label {
|
||||
margin-top: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,14 @@ import { useLocation } from 'react-router-dom';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { setAccount, useAccount } from '@plebbit/plebbit-react-hooks';
|
||||
import { isSettingsPlebbitOptionsView } from '../../lib/utils/view-utils';
|
||||
import styles from './settings.module.css';
|
||||
import useFilterSettingsStore from '../../stores/use-filter-settings-store';
|
||||
import useTheme from '../../hooks/use-theme';
|
||||
import AccountSettings from './account-settings';
|
||||
import AddressSettings from './address-settings';
|
||||
import AvatarSettings from './avatar-settings';
|
||||
import PlebbitOptions from './plebbit-options';
|
||||
import WalletSettings from './wallet-settings';
|
||||
import useTheme from '../../hooks/use-theme';
|
||||
import styles from './settings.module.css';
|
||||
import packageJson from '../../../package.json';
|
||||
import _ from 'lodash';
|
||||
|
||||
@@ -111,6 +112,39 @@ const ThemeSettings = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const FiltersSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
blurNsfwThumbnails,
|
||||
hideAdultCommunities,
|
||||
hideGoreCommunities,
|
||||
hideAntiCommunities,
|
||||
setBlurNsfwThumbnails,
|
||||
setHideAdultCommunities,
|
||||
setHideGoreCommunities,
|
||||
setHideAntiCommunities,
|
||||
} = useFilterSettingsStore();
|
||||
|
||||
return (
|
||||
<div className={styles.filters}>
|
||||
<div className={styles.filterSettingTitle}>{t('nsfw_content')}</div>
|
||||
<input type='checkbox' id='blurNsfwThumbnails' checked={blurNsfwThumbnails} onChange={(e) => setBlurNsfwThumbnails(e.target.checked)} />
|
||||
<label htmlFor='blurNsfwThumbnails'>{t('blur_media')}</label>
|
||||
<br />
|
||||
<br />
|
||||
<div className={styles.filterSettingTitle}>{t('nsfw_communities')}</div>
|
||||
<input type='checkbox' id='hideAdultCommunities' checked={hideAdultCommunities} onChange={(e) => setHideAdultCommunities(e.target.checked)} />
|
||||
<label htmlFor='hideAdultCommunities'>{t('hide_adult')}</label>
|
||||
<br />
|
||||
<input type='checkbox' id='hideGoreCommunities' checked={hideGoreCommunities} onChange={(e) => setHideGoreCommunities(e.target.checked)} />
|
||||
<label htmlFor='hideGoreCommunities'>{t('hide_gore')}</label>
|
||||
<br />
|
||||
<input type='checkbox' id='hideAntiCommunities' checked={hideAntiCommunities} onChange={(e) => setHideAntiCommunities(e.target.checked)} />
|
||||
<label htmlFor='hideAntiCommunities'>{t('hide_anti')}</label>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const DisplayNameSetting = () => {
|
||||
const { t } = useTranslation();
|
||||
const account = useAccount();
|
||||
@@ -192,6 +226,12 @@ const GeneralSettings = () => {
|
||||
<ThemeSettings />
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.category}>
|
||||
<span className={styles.categoryTitle}>{t('filters')}</span>
|
||||
<span className={styles.categorySettings}>
|
||||
<FiltersSettings />
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.category}>
|
||||
<span className={styles.categoryTitle}>{t('avatar')}</span>
|
||||
<span className={styles.categorySettings}>
|
||||
|
||||
Reference in New Issue
Block a user