diff --git a/src/plugins/contentWarning/index.tsx b/src/plugins/contentWarning/index.tsx
new file mode 100644
index 000000000..359a00573
--- /dev/null
+++ b/src/plugins/contentWarning/index.tsx
@@ -0,0 +1,151 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2023 Vendicated, camila314, and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import definePlugin, { OptionType } from "@utils/types";
+import { Button, Forms, useState, TextInput } from "@webpack/common";
+import { DataStore } from "@api/index";
+import { definePluginSettings } from "@api/Settings";
+import { DeleteIcon } from "@components/Icons";
+import { Devs } from "@utils/constants";
+import { Flex } from "@components/Flex";
+import { useForceUpdater } from "@utils/react";
+
+const WORDS_KEY = "ContentWarning_words";
+
+let triggerWords = [""];
+
+function safeMatchesRegex(s: string, r: string) {
+ if (r == "") return false;
+ try {
+ return s.match(new RegExp(r.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
+ } catch {
+ return false;
+ }
+}
+
+function TriggerContainer({ child }) {
+ const [visible, setVisible] = useState(false);
+
+ if (visible) {
+ return child;
+ } else {
+ return (
setVisible(true)}>
+
+ {child}
+
+
);
+ }
+}
+
+function FlaggedInput({ index, forceUpdate }) {
+ let [value, setValue] = useState(triggerWords[index]);
+
+ if (value != triggerWords[index]) {
+ setValue(triggerWords[index]);
+ }
+
+ let isLast = index == triggerWords.length - 1;
+
+ const updateValue = (v) => {
+ triggerWords[index] = v;
+ setValue(v);
+
+ if (isLast) {
+ triggerWords.push("");
+ forceUpdate();
+ }
+ };
+
+ const removeSelf = () => {
+ if (triggerWords.length == 1) {
+ return;
+ }
+ triggerWords = triggerWords.slice(0, index).concat(triggerWords.slice(index + 1));
+ forceUpdate();
+ };
+
+ return (
+
+
+
+
+
+ );
+}
+
+function FlaggedWords() {
+ const forceUpdate = useForceUpdater();
+
+ let inputs = triggerWords.map((_, idx) => {
+ return (
+
+ );
+ })
+
+ return (<>
+ Flagged Words
+ {inputs}
+ >);
+}
+
+const settings = definePluginSettings({
+ flagged: {
+ type: OptionType.COMPONENT,
+ component: () => ,
+ }
+});
+
+export default definePlugin({
+ name: "ContentWarning",
+ authors: [Devs.camila314],
+ description: "Allows you to specify certain trigger words that will be blurred by default. Clicking on the blurred content will reveal it.",
+ settings,
+ patches: [
+ {
+ find: ".VOICE_HANGOUT_INVITE?",
+ replacement: {
+ match: /(contentRef:\i}=(\i).+?)\(0,(.+]}\)]}\))/,
+ replace: "$1 $self.modify($2, (0, $3)"
+ }
+ }
+ ],
+
+ beforeSave() {
+ DataStore.set(WORDS_KEY, triggerWords);
+ return true;
+ },
+
+ modify(e, c) {
+ if (triggerWords.some(w => safeMatchesRegex(e.message.content, w))) {
+ return
+ } else {
+ return c;
+ }
+ },
+
+ async start() {
+ triggerWords = await DataStore.get(WORDS_KEY) ?? [""];
+ }
+});
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index 6653e6307..1da18ed38 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -375,6 +375,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
name: "ProffDea",
id: 609329952180928513n
},
+ camila314: {
+ name: "camila314",
+ id: 738592270617542716n
+ },
UlyssesZhan: {
name: "UlyssesZhan",
id: 586808226058862623n