diff --git a/package.json b/package.json
index ac4859593..cfd4bd010 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "vencord",
"private": "true",
- "version": "1.9.4",
+ "version": "1.9.5",
"description": "The cutest Discord client mod",
"homepage": "https://github.com/Vendicated/Vencord#readme",
"bugs": {
diff --git a/src/plugins/messageLogger/HistoryModal.tsx b/src/plugins/messageLogger/HistoryModal.tsx
new file mode 100644
index 000000000..a7715203d
--- /dev/null
+++ b/src/plugins/messageLogger/HistoryModal.tsx
@@ -0,0 +1,91 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2024 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { classNameFactory } from "@api/Styles";
+import ErrorBoundary from "@components/ErrorBoundary";
+import { Margins } from "@utils/margins";
+import { classes } from "@utils/misc";
+import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
+import { findByPropsLazy } from "@webpack";
+import { TabBar, Text, Timestamp, TooltipContainer, useState } from "@webpack/common";
+
+import { parseEditContent } from ".";
+
+const CodeContainerClasses = findByPropsLazy("markup", "codeContainer");
+const MiscClasses = findByPropsLazy("messageContent", "markupRtl");
+
+const cl = classNameFactory("vc-ml-modal-");
+
+export function openHistoryModal(message: any) {
+ openModal(props =>
+
+
+
+ );
+}
+
+export function HistoryModal({ modalProps, message }: { modalProps: ModalProps; message: any; }) {
+ const [currentTab, setCurrentTab] = useState(message.editHistory.length);
+ const timestamps = [message.firstEditTimestamp, ...message.editHistory.map(m => m.timestamp)];
+ const contents = [...message.editHistory.map(m => m.content), message.content];
+
+ return (
+
+
+ Message Edit History
+
+
+
+
+
+ {message.firstEditTimestamp.getTime() !== message.timestamp.getTime() && (
+
+
+
+
+
+ )}
+
+ {timestamps.map((timestamp, index) => (
+
+
+
+ ))}
+
+
+
+ {parseEditContent(contents[currentTab], message)}
+
+
+
+ );
+}
diff --git a/src/plugins/messageLogger/index.tsx b/src/plugins/messageLogger/index.tsx
index f88af01a0..9181306ad 100644
--- a/src/plugins/messageLogger/index.tsx
+++ b/src/plugins/messageLogger/index.tsx
@@ -24,21 +24,26 @@ import { Settings } from "@api/Settings";
import { disableStyle, enableStyle } from "@api/Styles";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
+import { proxyLazy } from "@utils/lazy";
import { Logger } from "@utils/Logger";
+import { classes } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types";
-import { findByPropsLazy } from "@webpack";
+import { findByCodeLazy, findByPropsLazy } from "@webpack";
import { ChannelStore, FluxDispatcher, i18n, Menu, MessageStore, Parser, SelectedChannelStore, Timestamp, UserStore, useStateFromStores } from "@webpack/common";
import { Message } from "discord-types/general";
import overlayStyle from "./deleteStyleOverlay.css?managed";
import textStyle from "./deleteStyleText.css?managed";
+import { openHistoryModal } from "./HistoryModal";
interface MLMessage extends Message {
deleted?: boolean;
editHistory?: { timestamp: Date; content: string; }[];
+ firstEditTimestamp?: Date;
}
const styles = findByPropsLazy("edited", "communicationDisabled", "isSystemMessage");
+const getMessage = findByCodeLazy('replace(/^\\n+|\\n+$/g,"")');
function addDeleteStyle() {
if (Settings.plugins.MessageLogger.deleteStyle === "text") {
@@ -125,10 +130,22 @@ const patchChannelContextMenu: NavContextMenuPatchCallback = (children, { channe
);
};
+export function parseEditContent(content: string, message: Message) {
+ return Parser.parse(content, true, {
+ channelId: message.channel_id,
+ messageId: message.id,
+ allowLinks: true,
+ allowHeading: true,
+ allowList: true,
+ allowEmojiLinks: true,
+ viewingChannelId: SelectedChannelStore.getChannelId(),
+ });
+}
+
export default definePlugin({
name: "MessageLogger",
description: "Temporarily logs deleted and edited messages.",
- authors: [Devs.rushii, Devs.Ven, Devs.AutumnVN, Devs.Nickyux],
+ authors: [Devs.rushii, Devs.Ven, Devs.AutumnVN, Devs.Nickyux, Devs.Kyuuhachi],
dependencies: ["MessageUpdaterAPI"],
contextMenus: {
@@ -150,19 +167,11 @@ export default definePlugin({
(oldMsg, newMsg) => oldMsg?.editHistory === newMsg?.editHistory
);
- return (
+ return Settings.plugins.MessageLogger.inlineEdits && (
<>
{message.editHistory?.map(edit => (
- {Parser.parse(edit.content, true, {
- channelId,
- messageId,
- allowLinks: true,
- allowHeading: true,
- allowList: true,
- allowEmojiLinks: true,
- viewingChannelId: SelectedChannelStore.getChannelId(),
- })}
+ {parseEditContent(edit.content, message)}
openHistoryModal(message)}
+ aria-role="button"
+ >
+ {children}
+
+ );
+ },
+
+ Messages: proxyLazy(() => ({
+ DELETED_MESSAGE_COUNT: getMessage("{count, plural, =0 {No deleted messages} one {{count} deleted message} other {{count} deleted messages}}")
+ })),
+
patches: [
{
// MessageStore
@@ -332,7 +368,8 @@ export default definePlugin({
match: /this\.customRenderedContent=(\i)\.customRenderedContent,/,
replace: "this.customRenderedContent = $1.customRenderedContent," +
"this.deleted = $1.deleted || false," +
- "this.editHistory = $1.editHistory || [],"
+ "this.editHistory = $1.editHistory || []," +
+ "this.firstEditTimestamp = $1.firstEditTimestamp || this.editedTimestamp || this.timestamp,"
}
]
},
@@ -345,7 +382,7 @@ export default definePlugin({
// Pass through editHistory & deleted & original attachments to the "edited message" transformer
match: /(?<=null!=\i\.edited_timestamp\)return )\i\(\i,\{reactions:(\i)\.reactions.{0,50}\}\)/,
replace:
- "Object.assign($&,{ deleted:$1.deleted, editHistory:$1.editHistory })"
+ "Object.assign($&,{ deleted:$1.deleted, editHistory:$1.editHistory, firstEditTimestamp:$1.firstEditTimestamp })"
},
{
@@ -364,7 +401,8 @@ export default definePlugin({
" return $2;" +
"})())," +
"deleted: arguments[1]?.deleted," +
- "editHistory: arguments[1]?.editHistory"
+ "editHistory: arguments[1]?.editHistory," +
+ "firstEditTimestamp: new Date(arguments[1]?.firstEditTimestamp ?? $2.editedTimestamp ?? $2.timestamp)"
},
{
// Preserve deleted attribute on attachments
@@ -412,6 +450,11 @@ export default definePlugin({
// Render editHistory in the deepest div for message content
match: /(\)\("div",\{id:.+?children:\[)/,
replace: "$1 (!!arguments[0].message.editHistory?.length && $self.renderEdits(arguments[0])),"
+ },
+ {
+ // Make edit marker clickable
+ match: /"span",\{(?=className:\i\.edited,)/,
+ replace: "$self.EditMarker,{message:arguments[0].message,"
}
]
},
@@ -441,6 +484,30 @@ export default definePlugin({
replace: "children:arguments[0].message.deleted?[]:$1"
}
]
+ },
+ {
+ // Message grouping
+ find: "NON_COLLAPSIBLE.has(",
+ replacement: {
+ match: /if\((\i)\.blocked\)return \i\.\i\.MESSAGE_GROUP_BLOCKED;/,
+ replace: '$&else if($1.deleted) return"MESSAGE_GROUP_DELETED";',
+ },
+ predicate: () => Settings.plugins.MessageLogger.collapseDeleted
+ },
+ {
+ // Message group rendering
+ find: "Messages.NEW_MESSAGES_ESTIMATED_WITH_DATE",
+ replacement: [
+ {
+ match: /(\i).type===\i\.\i\.MESSAGE_GROUP_BLOCKED\|\|/,
+ replace: '$&$1.type==="MESSAGE_GROUP_DELETED"||',
+ },
+ {
+ match: /(\i).type===\i\.\i\.MESSAGE_GROUP_BLOCKED\?.*?:/,
+ replace: '$&$1.type==="MESSAGE_GROUP_DELETED"?$self.Messages.DELETED_MESSAGE_COUNT:',
+ },
+ ],
+ predicate: () => Settings.plugins.MessageLogger.collapseDeleted
}
]
});
diff --git a/src/plugins/messageLogger/messageLogger.css b/src/plugins/messageLogger/messageLogger.css
index a112b1961..2759129d9 100644
--- a/src/plugins/messageLogger/messageLogger.css
+++ b/src/plugins/messageLogger/messageLogger.css
@@ -38,3 +38,17 @@
.theme-light .messagelogger-edited {
opacity: 0.5;
}
+
+.messagelogger-edit-marker {
+ cursor: pointer;
+}
+
+.vc-ml-modal-timestamp {
+ cursor: unset;
+ height: unset;
+}
+
+.vc-ml-modal-tab-bar {
+ flex-wrap: wrap;
+ gap: 16px;
+}
diff --git a/src/plugins/viewRaw/index.tsx b/src/plugins/viewRaw/index.tsx
index 68b33eed0..56c285ecd 100644
--- a/src/plugins/viewRaw/index.tsx
+++ b/src/plugins/viewRaw/index.tsx
@@ -55,6 +55,7 @@ function cleanMessage(msg: Message) {
const cloneAny = clone as any;
delete cloneAny.editHistory;
delete cloneAny.deleted;
+ delete cloneAny.firstEditTimestamp;
cloneAny.attachments?.forEach(a => delete a.deleted);
return clone;