Option to blur message links from NSFW channels

This commit is contained in:
Suffocate 2024-12-24 10:54:30 +00:00
parent 9ccc74bde3
commit 32ad04f752

View file

@ -22,6 +22,7 @@ import { definePluginSettings } from "@api/Settings";
import { getUserSettingLazy } from "@api/UserSettings"; import { getUserSettingLazy } from "@api/UserSettings";
import ErrorBoundary from "@components/ErrorBoundary"; import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants.js"; import { Devs } from "@utils/constants.js";
import { getIntlMessage } from "@utils/discord";
import { classes } from "@utils/misc"; import { classes } from "@utils/misc";
import { Queue } from "@utils/Queue"; import { Queue } from "@utils/Queue";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
@ -31,6 +32,7 @@ import {
ChannelStore, ChannelStore,
Constants, Constants,
GuildStore, GuildStore,
Icons,
IconUtils, IconUtils,
MessageStore, MessageStore,
Parser, Parser,
@ -38,7 +40,8 @@ import {
PermissionStore, PermissionStore,
RestAPI, RestAPI,
Text, Text,
UserStore UserStore,
useState
} from "@webpack/common"; } from "@webpack/common";
import { Channel, Message } from "discord-types/general"; import { Channel, Message } from "discord-types/general";
@ -53,6 +56,8 @@ const ChannelMessage = findComponentByCodeLazy("childrenExecutedCommand:", ".hid
const SearchResultClasses = findByPropsLazy("message", "searchResult"); const SearchResultClasses = findByPropsLazy("message", "searchResult");
const EmbedClasses = findByPropsLazy("embedAuthorIcon", "embedAuthor", "embedAuthor"); const EmbedClasses = findByPropsLazy("embedAuthorIcon", "embedAuthor", "embedAuthor");
const SpoilerClasses = findByPropsLazy("explicitContentWarning", "explicitContentWarningText", "spoilerContent");
const MosaicClasses = findByPropsLazy("obscured", "hiddenMosaicItem", "hiddenExplicit");
const MessageDisplayCompact = getUserSettingLazy("textAndImages", "messageDisplayCompact")!; const MessageDisplayCompact = getUserSettingLazy("textAndImages", "messageDisplayCompact")!;
@ -97,6 +102,11 @@ const settings = definePluginSettings({
} }
] ]
}, },
blurNsfw: {
description: "Blur embeds from age restricted channels",
type: OptionType.BOOLEAN,
default: true
},
listMode: { listMode: {
description: "Whether to use ID list as blacklist or whitelist", description: "Whether to use ID list as blacklist or whitelist",
type: OptionType.SELECT, type: OptionType.SELECT,
@ -283,6 +293,55 @@ function getChannelLabelAndIconUrl(channel: Channel) {
return ["Server", IconUtils.getGuildIconURL(GuildStore.getGuild(channel.guild_id))]; return ["Server", IconUtils.getGuildIconURL(GuildStore.getGuild(channel.guild_id))];
} }
function Spoiler(props: { children: JSX.Element }) : JSX.Element {
const [visible, setVisible] = useState(false);
const {
explicitContentWarning,
explicitContentWarningText,
spoilerContent,
spoilerContainer,
hidden,
spoilerInnerContainer,
obscureButtonContainer,
obscureHoverButton
} = SpoilerClasses;
const { obscured, hiddenMosaicItem, hiddenExplicit } = MosaicClasses;
return (
<div
aria-label={!visible && getIntlMessage("EXPLICIT_CONTENT_WARNING_TOOLTIP")}
aria-expanded={visible}
className={classes(spoilerContainer, !visible && classes(hidden, spoilerContent))}
role={visible ? "presentation" : "button"}
tabIndex={visible ? -1 : 0}
>
{!visible &&
<div className={explicitContentWarning}>
<Icons.ImageWarningIcon size="lg" color="white"/>
<Text variant="text-sm/normal" color="always-white"
className={classes(explicitContentWarningText)}>
{getIntlMessage("EXPLICIT_CONTENT_WARNING")}
</Text>
</div>
}
<div
aria-hidden={!visible}
className={classes(spoilerInnerContainer, !visible && classes(obscured, hiddenMosaicItem, hiddenExplicit))}
>
{props.children}
</div>
<div className={obscureButtonContainer}>
<Icons.Clickable onClick={() => setVisible(!visible)}
aria-label={getIntlMessage("EXPLICIT_CONTENT_BUTTON_TOOLTIP")}
className={obscureHoverButton}>
{visible ? <Icons.EyeIcon size="md" color="currentColor"/> :
<Icons.EyeSlashIcon size="md" color="currentColor"/>}
</Icons.Clickable>
</div>
</div>
);
}
function ChannelMessageEmbedAccessory({ message, channel }: MessageEmbedProps): JSX.Element | null { function ChannelMessageEmbedAccessory({ message, channel }: MessageEmbedProps): JSX.Element | null {
const compact = MessageDisplayCompact.useSetting(); const compact = MessageDisplayCompact.useSetting();
@ -314,6 +373,7 @@ function ChannelMessageEmbedAccessory({ message, channel }: MessageEmbedProps):
/> />
</div> </div>
)} )}
{...(settings.store.blurNsfw && channel.isNSFW() && { obscureReason: "explicit_content" })}
/> />
); );
} }
@ -326,7 +386,7 @@ function AutomodEmbedAccessory(props: MessageEmbedProps): JSX.Element | null {
const [channelLabel, iconUrl] = getChannelLabelAndIconUrl(channel); const [channelLabel, iconUrl] = getChannelLabelAndIconUrl(channel);
return <AutoModEmbed const embed = <AutoModEmbed
channel={channel} channel={channel}
childrenAccessories={ childrenAccessories={
<Text color="text-muted" variant="text-xs/medium" tag="span" className={`${EmbedClasses.embedAuthor} ${EmbedClasses.embedMargin}`}> <Text color="text-muted" variant="text-xs/medium" tag="span" className={`${EmbedClasses.embedAuthor} ${EmbedClasses.embedMargin}`}>
@ -361,6 +421,12 @@ function AutomodEmbedAccessory(props: MessageEmbedProps): JSX.Element | null {
message={message} message={message}
_messageEmbed="automod" _messageEmbed="automod"
/>; />;
if (settings.store.blurNsfw && channel.isNSFW()) {
return <Spoiler>{embed}</Spoiler>;
}
return embed;
} }
export default definePlugin({ export default definePlugin({