This commit is contained in:
parent
24978f4e62
commit
81d6f41050
@ -34,14 +34,14 @@ const Timeline = (props: TimelineProps) => {
|
||||
}, [props]);
|
||||
const feed: TimelineFeed = useTimelineFeed(props.subject, feedOptions);
|
||||
|
||||
const { muted, isMuted } = useModeration();
|
||||
const { muted, isEventMuted } = useModeration();
|
||||
const filterPosts = useCallback(
|
||||
(nts: readonly TaggedNostrEvent[]) => {
|
||||
const a = [...nts.filter(a => a.kind !== EventKind.LiveEvent)];
|
||||
props.noSort || a.sort((a, b) => b.created_at - a.created_at);
|
||||
return a
|
||||
?.filter(a => (props.postsOnly ? !a.tags.some(b => b[0] === "e") : true))
|
||||
.filter(a => props.ignoreModeration || !isMuted(a.pubkey));
|
||||
.filter(a => props.ignoreModeration || !isEventMuted(a));
|
||||
},
|
||||
[props.postsOnly, muted, props.ignoreModeration],
|
||||
);
|
||||
|
@ -39,7 +39,7 @@ const TimelineFollows = (props: TimelineFollowsProps) => {
|
||||
);
|
||||
const system = useContext(SnortContext);
|
||||
const login = useLogin();
|
||||
const { muted, isMuted } = useModeration();
|
||||
const { muted, isEventMuted } = useModeration();
|
||||
|
||||
const sortedFeed = useMemo(() => orderDescending(feed), [feed]);
|
||||
|
||||
@ -49,11 +49,11 @@ const TimelineFollows = (props: TimelineFollowsProps) => {
|
||||
);
|
||||
|
||||
const filterPosts = useCallback(
|
||||
function <T extends NostrEvent>(nts: Array<T>) {
|
||||
(nts: Array<TaggedNostrEvent>) => {
|
||||
const a = nts.filter(a => a.kind !== EventKind.LiveEvent);
|
||||
return a
|
||||
?.filter(postsOnly)
|
||||
.filter(a => !isMuted(a.pubkey) && login.follows.item.includes(a.pubkey) && (props.noteFilter?.(a) ?? true));
|
||||
.filter(a => !isEventMuted(a) && login.follows.item.includes(a.pubkey) && (props.noteFilter?.(a) ?? true));
|
||||
},
|
||||
[postsOnly, muted, login.follows.timestamp],
|
||||
);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { HexKey, TaggedNostrEvent } from "@snort/system";
|
||||
import { HexKey, NostrEvent, TaggedNostrEvent } from "@snort/system";
|
||||
import useEventPublisher from "Hooks/useEventPublisher";
|
||||
import useLogin from "Hooks/useLogin";
|
||||
import { setBlocked, setMuted } from "Login";
|
||||
@ -60,7 +60,7 @@ export default function useModeration() {
|
||||
return appData.item.mutedWords.includes(word.toLowerCase());
|
||||
}
|
||||
|
||||
function isEventMuted(ev: TaggedNostrEvent) {
|
||||
function isEventMuted(ev: TaggedNostrEvent | NostrEvent) {
|
||||
return isMuted(ev.pubkey) || appData.item.mutedWords.some(w => ev.content.toLowerCase().includes(w));
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { ReactNode, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { unixNowMs } from "@snort/shared";
|
||||
|
||||
import AsyncButton from "Element/AsyncButton";
|
||||
import classNames from "classnames";
|
||||
import { appendDedupe } from "SnortUtils";
|
||||
import useEventPublisher from "Hooks/useEventPublisher";
|
||||
import { setMuted } from "Login";
|
||||
import { ToggleSwitch } from "Icons/Toggle";
|
||||
import { updateAppData } from "Login";
|
||||
import useLogin from "Hooks/useLogin";
|
||||
|
||||
export const FixedModeration = {
|
||||
hateSpeech: {
|
||||
/*hateSpeech: {
|
||||
title: <FormattedMessage defaultMessage="Hate Speech" />,
|
||||
words: [],
|
||||
canEdit: false,
|
||||
@ -19,7 +19,7 @@ export const FixedModeration = {
|
||||
title: <FormattedMessage defaultMessage="Derogatory" />,
|
||||
words: [],
|
||||
canEdit: false,
|
||||
},
|
||||
},*/
|
||||
nsfw: {
|
||||
title: <FormattedMessage defaultMessage="NSFW" />,
|
||||
words: [
|
||||
@ -43,6 +43,7 @@ export const FixedModeration = {
|
||||
"explicit language",
|
||||
"adult-only",
|
||||
"mature language",
|
||||
"sex"
|
||||
],
|
||||
canEdit: false,
|
||||
},
|
||||
@ -72,18 +73,50 @@ export const FixedModeration = {
|
||||
"crypto wallet",
|
||||
"satoshi nakamoto",
|
||||
],
|
||||
canEdit: true,
|
||||
canEdit: false,
|
||||
},
|
||||
politics: {
|
||||
title: <FormattedMessage defaultMessage="Politics" />,
|
||||
words: [],
|
||||
canEdit: true,
|
||||
words: [
|
||||
"politics",
|
||||
"election",
|
||||
"democrat",
|
||||
"republican",
|
||||
"senate",
|
||||
"congress",
|
||||
"parliament",
|
||||
"president",
|
||||
"prime minister",
|
||||
"policy",
|
||||
"legislation",
|
||||
"vote",
|
||||
"campaign",
|
||||
"government",
|
||||
"political party",
|
||||
"lobbying",
|
||||
"referendum",
|
||||
"bill",
|
||||
"conservative",
|
||||
"liberal",
|
||||
"left-wing",
|
||||
"right-wing",
|
||||
"socialist",
|
||||
"capitalist",
|
||||
"diplomacy",
|
||||
"sanction",
|
||||
"geopolitics",
|
||||
"activism",
|
||||
"protest",
|
||||
"rally"
|
||||
],
|
||||
canEdit: false,
|
||||
},
|
||||
};
|
||||
|
||||
export function Moderation() {
|
||||
const { publisher, system } = useEventPublisher();
|
||||
const id = useLogin(s => s.id);
|
||||
const [topics, setTopics] = useState<Array<string>>(Object.keys(FixedModeration));
|
||||
const [extraTerms, setExtraTerms] = useState("");
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
@ -135,7 +168,7 @@ export function Moderation() {
|
||||
<small className="font-medium">
|
||||
<FormattedMessage defaultMessage="Use commas to separate words e.g. word1, word2, word3" />
|
||||
</small>
|
||||
<textarea></textarea>
|
||||
<textarea onChange={e => setExtraTerms(e.target.value)} value={extraTerms}></textarea>
|
||||
</div>
|
||||
<AsyncButton
|
||||
className="primary"
|
||||
@ -143,9 +176,18 @@ export function Moderation() {
|
||||
const words = Object.entries(FixedModeration)
|
||||
.filter(([k]) => topics.includes(k))
|
||||
.map(([, v]) => v.words)
|
||||
.flat();
|
||||
.flat()
|
||||
.concat(extraTerms.split(",").map(a => a.trim()));
|
||||
if (words.length > 0) {
|
||||
// no
|
||||
updateAppData(id, ad => {
|
||||
return {
|
||||
item: {
|
||||
...ad,
|
||||
mutedWords: appendDedupe(ad.mutedWords, words)
|
||||
},
|
||||
timestamp: unixNowMs()
|
||||
}
|
||||
})
|
||||
}
|
||||
navigate("/");
|
||||
}}>
|
||||
|
@ -10,35 +10,248 @@ import { NostrHashtagLink } from "@snort/system";
|
||||
export const FixedTopics = {
|
||||
life: {
|
||||
text: <FormattedMessage defaultMessage="Life" />,
|
||||
tags: ["life"],
|
||||
tags: [
|
||||
"life",
|
||||
"lifestyle",
|
||||
"dailyinspiration",
|
||||
"motivation",
|
||||
"lifelessons",
|
||||
"personaldevelopment",
|
||||
"happiness",
|
||||
"wellbeing",
|
||||
"mindfulness",
|
||||
"selfcare",
|
||||
"positivity",
|
||||
"growth",
|
||||
"inspiration",
|
||||
"lifegoals",
|
||||
"mindset",
|
||||
"joy",
|
||||
"balance",
|
||||
"fulfillment",
|
||||
"purpose",
|
||||
"living",
|
||||
"lifetips",
|
||||
"lifehacks",
|
||||
"wellness",
|
||||
"lifejourney",
|
||||
"enjoylife",
|
||||
"simplepleasures",
|
||||
"gratitude",
|
||||
"lifeadvice",
|
||||
"lifecoaching",
|
||||
"lifelove"
|
||||
],
|
||||
},
|
||||
science: {
|
||||
text: <FormattedMessage defaultMessage="Science" />,
|
||||
tags: ["science"],
|
||||
tags: [
|
||||
"science",
|
||||
"research",
|
||||
"innovation",
|
||||
"technology",
|
||||
"biology",
|
||||
"physics",
|
||||
"chemistry",
|
||||
"astronomy",
|
||||
"environment",
|
||||
"ecology",
|
||||
"geology",
|
||||
"neuroscience",
|
||||
"genetics",
|
||||
"data",
|
||||
"experiment",
|
||||
"theory",
|
||||
"discovery",
|
||||
"engineering",
|
||||
"mathematics",
|
||||
"robotics",
|
||||
"artificialintelligence",
|
||||
"climate",
|
||||
"space",
|
||||
"quantum",
|
||||
"microbiology",
|
||||
"biotechnology",
|
||||
"nanotechnology",
|
||||
"pharmacology",
|
||||
"astrophysics",
|
||||
"scientificmethod"
|
||||
],
|
||||
},
|
||||
nature: {
|
||||
text: <FormattedMessage defaultMessage="Nature" />,
|
||||
tags: ["nature"],
|
||||
tags: [
|
||||
"nature",
|
||||
"wildlife",
|
||||
"forest",
|
||||
"mountains",
|
||||
"rivers",
|
||||
"oceans",
|
||||
"flora",
|
||||
"fauna",
|
||||
"ecosystem",
|
||||
"biodiversity",
|
||||
"conservation",
|
||||
"habitat",
|
||||
"landscape",
|
||||
"outdoors",
|
||||
"environment",
|
||||
"geography",
|
||||
"earth",
|
||||
"climate",
|
||||
"naturalbeauty",
|
||||
"wilderness",
|
||||
"green",
|
||||
"sustainability",
|
||||
"wildlifeconservation",
|
||||
"nationalpark",
|
||||
"gardening",
|
||||
"hiking",
|
||||
"birdwatching",
|
||||
"ecotourism",
|
||||
"photography",
|
||||
"naturelovers"
|
||||
],
|
||||
},
|
||||
business: {
|
||||
text: <FormattedMessage defaultMessage="Business" />,
|
||||
tags: ["business"],
|
||||
tags: [
|
||||
"business",
|
||||
"entrepreneurship",
|
||||
"marketing",
|
||||
"finance",
|
||||
"innovation",
|
||||
"management",
|
||||
"startup",
|
||||
"leadership",
|
||||
"economics",
|
||||
"strategy",
|
||||
"branding",
|
||||
"sales",
|
||||
"technology",
|
||||
"investment",
|
||||
"networking",
|
||||
"growth",
|
||||
"corporate",
|
||||
"customer",
|
||||
"market",
|
||||
"productivity",
|
||||
"advertising",
|
||||
"ecommerce",
|
||||
"analytics",
|
||||
"humanresources",
|
||||
"globalbusiness",
|
||||
"digitalmarketing",
|
||||
"socialmedia",
|
||||
"sustainability",
|
||||
"entrepreneur",
|
||||
"businessdevelopment"
|
||||
],
|
||||
},
|
||||
game: {
|
||||
text: <FormattedMessage defaultMessage="Game" />,
|
||||
tags: ["game", "gaming"],
|
||||
tags: [
|
||||
"gaming",
|
||||
"videogames",
|
||||
"esports",
|
||||
"multiplayer",
|
||||
"onlinegaming",
|
||||
"gameplay",
|
||||
"streaming",
|
||||
"gamer",
|
||||
"console",
|
||||
"pcgaming",
|
||||
"mobilegaming",
|
||||
"gamedevelopment",
|
||||
"virtualreality",
|
||||
"roleplaying",
|
||||
"strategygames",
|
||||
"actiongames",
|
||||
"simulation",
|
||||
"indiegames",
|
||||
"adventuregames",
|
||||
"puzzle",
|
||||
"fantasy",
|
||||
"scifi",
|
||||
"horror",
|
||||
"sports",
|
||||
"racing",
|
||||
"fighting",
|
||||
"platformer",
|
||||
"mmorpg",
|
||||
"retrogaming",
|
||||
"arcade"
|
||||
],
|
||||
},
|
||||
sport: {
|
||||
text: <FormattedMessage defaultMessage="Sport" />,
|
||||
tags: ["sport"],
|
||||
tags: [
|
||||
"sports",
|
||||
"athletics",
|
||||
"soccer",
|
||||
"basketball",
|
||||
"baseball",
|
||||
"football",
|
||||
"tennis",
|
||||
"golf",
|
||||
"swimming",
|
||||
"running",
|
||||
"cycling",
|
||||
"volleyball",
|
||||
"hockey",
|
||||
"skiing",
|
||||
"boxing",
|
||||
"martialarts",
|
||||
"gymnastics",
|
||||
"cricket",
|
||||
"rugby",
|
||||
"tabletennis",
|
||||
"badminton",
|
||||
"fishing",
|
||||
"archery",
|
||||
"bowling",
|
||||
"surfing",
|
||||
"skateboarding",
|
||||
"motorsports",
|
||||
"equestrian",
|
||||
"fitness",
|
||||
"yoga"
|
||||
],
|
||||
},
|
||||
photography: {
|
||||
text: <FormattedMessage defaultMessage="Photography" />,
|
||||
tags: ["photography"],
|
||||
},
|
||||
bitcoin: {
|
||||
text: <FormattedMessage defaultMessage="Bitcoin" />,
|
||||
tags: ["bitcoin"],
|
||||
tags: [
|
||||
"photography",
|
||||
"landscape",
|
||||
"portrait",
|
||||
"naturephotography",
|
||||
"streetphotography",
|
||||
"blackandwhite",
|
||||
"travelphotography",
|
||||
"macro",
|
||||
"wildlifephotography",
|
||||
"urbanphotography",
|
||||
"nightphotography",
|
||||
"fashionphotography",
|
||||
"fineartphotography",
|
||||
"documentary",
|
||||
"sportsphotography",
|
||||
"foodphotography",
|
||||
"architecturalphotography",
|
||||
"candid",
|
||||
"aerialphotography",
|
||||
"underwaterphotography",
|
||||
"filmphotography",
|
||||
"digitalphotography",
|
||||
"photographytips",
|
||||
"photoediting",
|
||||
"photographygear",
|
||||
"lighting",
|
||||
"composition",
|
||||
"exposure",
|
||||
"photographyworkshop",
|
||||
"photographyart"
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user