Plugin
HideMessage
Adds a context menu option to hide messages
1
/*2
* FiveCord — a Discord client mod3
* Copyright (c) 2025 FiveCord4
* SPDX-License-Identifier: GPL-3.0-or-later5
*/6
7
import "./styles.css";8
9
import { NavContextMenuPatchCallback } from "@api/ContextMenu";10
import { get, set } from "@api/DataStore";11
import { addAccessory, removeAccessory } from "@api/MessageAccessories";12
import { definePluginSettings } from "@api/Settings";13
import { classNameFactory } from "@api/Styles";14
import { Devs } from "@utils/constants";15
import definePlugin, { OptionType } from "@utils/types";16
import { Menu } from "@webpack/common";17
18
import { EyeIcon } from "./EyeIcon";19
import { HideIcon } from "./HideIcon";20
import { HideMessageAccessory } from "./HideMessageAccessory";21
22
let style: HTMLStyleElement;23
24
const KEY = "HideMessage_hiddenMessages";25
26
let hiddenMessages = new Map<string, {27
id: string;28
channel_id: string;29
}>();30
31
const patchMessageContextMenu: NavContextMenuPatchCallback = (children, { message }) => {32
const { deleted, id, channel_id } = message;33
if (deleted || message.state !== "SENT") return;34
35
const isHidden = hiddenMessages.has(id);36
if (isHidden) {37
return children.push(38
<Menu.MenuItem39
id={cl("reveal")}40
label="Reveal Message"41
icon={EyeIcon}42
action={() => revealMessage(id)}43
/>44
);45
}46
47
children.push(<Menu.MenuItem48
id={cl("hide")}49
label="Hide Message"50
color="danger"51
icon={HideIcon}52
action={() => {53
hiddenMessages.set(id, { id, channel_id });54
if (settings.store.saveHiddenMessages) set(KEY, hiddenMessages);55
56
buildCss();57
}}58
/>);59
};60
61
const buildCss = () => {62
const elements = [...hiddenMessages.values()].map(m => `#chat-messages-${m.channel_id}-${m.id}`).join(",");63
64
style.textContent = settings.store.showNotice ? `65
:is(${elements}):not(.messagelogger-deleted) > div {66
position: relative;67
background: var(--brand-experiment-05a);68
}69
:is(${elements}):not(.messagelogger-deleted) > div:hover {70
background: var(--brand-experiment-10a);71
}72
:is(${elements}):not(.messagelogger-deleted) > div:before {73
background: var(--brand-experiment);74
content: "";75
position: absolute;76
display: block;77
top: 0;78
left: 0;79
bottom: 0;80
pointer-events: none;81
width: 2px;82
}83
:is(${elements}) [id^=039;message-accessories039;] > *:not(.vc-hide-message-accessory),84
:is(${elements}) [id^=039;message-content039;] > * {85
display: none !important;86
}87
:is(${elements}) [id^=039;message-content039;]:empty {88
display: block !important;89
}90
:is(${elements}) [class^=039;contents039;] [id^=039;message-content039;]:after {91
content: "Hidden content";92
}93
` : `94
:is(${elements}) {95
display: none !important;96
}97
`;98
};99
100
export const revealMessage = (id: string) => {101
if (hiddenMessages.has(id)) {102
hiddenMessages.delete(id);103
buildCss();104
105
if (settings.store.saveHiddenMessages) set(KEY, hiddenMessages);106
}107
};108
109
export const cl = classNameFactory("vc-hide-message-");110
111
export const settings = definePluginSettings({112
showNotice: {113
type: OptionType.BOOLEAN,114
description: "Shows a notice when a message is hidden",115
default: true,116
onChange: buildCss117
},118
saveHiddenMessages: {119
type: OptionType.BOOLEAN,120
description: "Persist restarts",121
default: false,122
onChange: async (value: boolean) => {123
if (value) set(KEY, hiddenMessages);124
else (hiddenMessages = await get(KEY) || hiddenMessages);125
}126
},127
});128
129
export default definePlugin({130
name: "HideMessage",131
description: "Adds a context menu option to hide messages",132
authors: [Devs.FiveCord],133
settings,134
135
contextMenus: {136
"message": patchMessageContextMenu137
},138
139
async start() {140
style = document.createElement("style");141
style.id = "VencordHideMessage";142
document.head.appendChild(style);143
144
if (settings.store.saveHiddenMessages) {145
hiddenMessages = await get(KEY) || hiddenMessages;146
buildCss();147
}148
149
addAccessory("vc-hide-message", ({ message }) => {150
if (hiddenMessages.has(message.id) && settings.store.showNotice) return <HideMessageAccessory id={message.id} />;151
return null;152
});153
},154
155
async stop() {156
for (const id of hiddenMessages.keys()) revealMessage(id);157
158
removeAccessory("vc-hide-message");159
160
style.remove();161
hiddenMessages.clear();162
}163
});164