feat: update topic lists
Some checks are pending
continuous-integration/drone/push Build is running

This commit is contained in:
Kieran 2023-11-13 22:55:51 +00:00
parent 24978f4e62
commit 81d6f41050
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
5 changed files with 287 additions and 32 deletions

View File

@ -34,14 +34,14 @@ const Timeline = (props: TimelineProps) => {
}, [props]); }, [props]);
const feed: TimelineFeed = useTimelineFeed(props.subject, feedOptions); const feed: TimelineFeed = useTimelineFeed(props.subject, feedOptions);
const { muted, isMuted } = useModeration(); const { muted, isEventMuted } = useModeration();
const filterPosts = useCallback( const filterPosts = useCallback(
(nts: readonly TaggedNostrEvent[]) => { (nts: readonly TaggedNostrEvent[]) => {
const a = [...nts.filter(a => a.kind !== EventKind.LiveEvent)]; const a = [...nts.filter(a => a.kind !== EventKind.LiveEvent)];
props.noSort || a.sort((a, b) => b.created_at - a.created_at); props.noSort || a.sort((a, b) => b.created_at - a.created_at);
return a return a
?.filter(a => (props.postsOnly ? !a.tags.some(b => b[0] === "e") : true)) ?.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], [props.postsOnly, muted, props.ignoreModeration],
); );

View File

@ -39,7 +39,7 @@ const TimelineFollows = (props: TimelineFollowsProps) => {
); );
const system = useContext(SnortContext); const system = useContext(SnortContext);
const login = useLogin(); const login = useLogin();
const { muted, isMuted } = useModeration(); const { muted, isEventMuted } = useModeration();
const sortedFeed = useMemo(() => orderDescending(feed), [feed]); const sortedFeed = useMemo(() => orderDescending(feed), [feed]);
@ -49,11 +49,11 @@ const TimelineFollows = (props: TimelineFollowsProps) => {
); );
const filterPosts = useCallback( const filterPosts = useCallback(
function <T extends NostrEvent>(nts: Array<T>) { (nts: Array<TaggedNostrEvent>) => {
const a = nts.filter(a => a.kind !== EventKind.LiveEvent); const a = nts.filter(a => a.kind !== EventKind.LiveEvent);
return a return a
?.filter(postsOnly) ?.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], [postsOnly, muted, login.follows.timestamp],
); );

View File

@ -1,4 +1,4 @@
import { HexKey, TaggedNostrEvent } from "@snort/system"; import { HexKey, NostrEvent, TaggedNostrEvent } from "@snort/system";
import useEventPublisher from "Hooks/useEventPublisher"; import useEventPublisher from "Hooks/useEventPublisher";
import useLogin from "Hooks/useLogin"; import useLogin from "Hooks/useLogin";
import { setBlocked, setMuted } from "Login"; import { setBlocked, setMuted } from "Login";
@ -60,7 +60,7 @@ export default function useModeration() {
return appData.item.mutedWords.includes(word.toLowerCase()); 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)); return isMuted(ev.pubkey) || appData.item.mutedWords.some(w => ev.content.toLowerCase().includes(w));
} }

View File

@ -1,16 +1,16 @@
/* eslint-disable @typescript-eslint/no-unused-vars */ import { useState } from "react";
import { ReactNode, useState } from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { unixNowMs } from "@snort/shared";
import AsyncButton from "Element/AsyncButton"; import AsyncButton from "Element/AsyncButton";
import classNames from "classnames";
import { appendDedupe } from "SnortUtils"; import { appendDedupe } from "SnortUtils";
import useEventPublisher from "Hooks/useEventPublisher";
import { setMuted } from "Login";
import { ToggleSwitch } from "Icons/Toggle"; import { ToggleSwitch } from "Icons/Toggle";
import { updateAppData } from "Login";
import useLogin from "Hooks/useLogin";
export const FixedModeration = { export const FixedModeration = {
hateSpeech: { /*hateSpeech: {
title: <FormattedMessage defaultMessage="Hate Speech" />, title: <FormattedMessage defaultMessage="Hate Speech" />,
words: [], words: [],
canEdit: false, canEdit: false,
@ -19,7 +19,7 @@ export const FixedModeration = {
title: <FormattedMessage defaultMessage="Derogatory" />, title: <FormattedMessage defaultMessage="Derogatory" />,
words: [], words: [],
canEdit: false, canEdit: false,
}, },*/
nsfw: { nsfw: {
title: <FormattedMessage defaultMessage="NSFW" />, title: <FormattedMessage defaultMessage="NSFW" />,
words: [ words: [
@ -43,6 +43,7 @@ export const FixedModeration = {
"explicit language", "explicit language",
"adult-only", "adult-only",
"mature language", "mature language",
"sex"
], ],
canEdit: false, canEdit: false,
}, },
@ -72,18 +73,50 @@ export const FixedModeration = {
"crypto wallet", "crypto wallet",
"satoshi nakamoto", "satoshi nakamoto",
], ],
canEdit: true, canEdit: false,
}, },
politics: { politics: {
title: <FormattedMessage defaultMessage="Politics" />, title: <FormattedMessage defaultMessage="Politics" />,
words: [], words: [
canEdit: true, "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() { export function Moderation() {
const { publisher, system } = useEventPublisher(); const id = useLogin(s => s.id);
const [topics, setTopics] = useState<Array<string>>(Object.keys(FixedModeration)); const [topics, setTopics] = useState<Array<string>>(Object.keys(FixedModeration));
const [extraTerms, setExtraTerms] = useState("");
const navigate = useNavigate(); const navigate = useNavigate();
return ( return (
@ -135,7 +168,7 @@ export function Moderation() {
<small className="font-medium"> <small className="font-medium">
<FormattedMessage defaultMessage="Use commas to separate words e.g. word1, word2, word3" /> <FormattedMessage defaultMessage="Use commas to separate words e.g. word1, word2, word3" />
</small> </small>
<textarea></textarea> <textarea onChange={e => setExtraTerms(e.target.value)} value={extraTerms}></textarea>
</div> </div>
<AsyncButton <AsyncButton
className="primary" className="primary"
@ -143,9 +176,18 @@ export function Moderation() {
const words = Object.entries(FixedModeration) const words = Object.entries(FixedModeration)
.filter(([k]) => topics.includes(k)) .filter(([k]) => topics.includes(k))
.map(([, v]) => v.words) .map(([, v]) => v.words)
.flat(); .flat()
.concat(extraTerms.split(",").map(a => a.trim()));
if (words.length > 0) { if (words.length > 0) {
// no updateAppData(id, ad => {
return {
item: {
...ad,
mutedWords: appendDedupe(ad.mutedWords, words)
},
timestamp: unixNowMs()
}
})
} }
navigate("/"); navigate("/");
}}> }}>

View File

@ -10,35 +10,248 @@ import { NostrHashtagLink } from "@snort/system";
export const FixedTopics = { export const FixedTopics = {
life: { life: {
text: <FormattedMessage defaultMessage="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: { science: {
text: <FormattedMessage defaultMessage="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: { nature: {
text: <FormattedMessage defaultMessage="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: { business: {
text: <FormattedMessage defaultMessage="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: { game: {
text: <FormattedMessage defaultMessage="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: { sport: {
text: <FormattedMessage defaultMessage="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: { photography: {
text: <FormattedMessage defaultMessage="Photography" />, text: <FormattedMessage defaultMessage="Photography" />,
tags: ["photography"], tags: [
}, "photography",
bitcoin: { "landscape",
text: <FormattedMessage defaultMessage="Bitcoin" />, "portrait",
tags: ["bitcoin"], "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"
],
}, },
}; };