new plugin AddAttachments: add new files to existing messages (#3202)

This commit is contained in:
Lumap 2026-09-06 02:08:09 +02:00 • committed by GitHub
parent 843657c5cc
commit 6fef6b5179
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 183 additions and 0 deletions

View file

@ -640,6 +640,20 @@ export function RightArrow(props: IconProps) {
);
}
export function UploadIcon(props: IconProps) {
return (
<Icon
{...props}
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M12 23a11 11 0 1 0 0-22 11 11 0 0 0 0 22Zm0-17a1 1 0 0 1 1 1v4h4a1 1 0 1 1 0 2h-4v4a1 1 0 1 1-2 0v-4H7a1 1 0 1 1 0-2h4V7a1 1 0 0 1 1-1Z"
/>
</Icon>
);
}
export function TopRightArrow(props: IconProps) {
return (
<Icon

View file

@ -0,0 +1,7 @@
# AddAttachments
Allows you to add new attachments while editing messages.
Start editing a message and then you can either press the "Add Attachment" button or paste files from your clipboard!
![](https://github.com/user-attachments/assets/3a3a5cda-ab36-4dee-bd28-2d2a08f8f996)

View file

@ -0,0 +1,162 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2025 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { ChatBarButton } from "@api/ChatButtons";
import { UploadIcon } from "@components/Icons";
import { Devs } from "@utils/constants";
import { pluralise } from "@utils/misc";
import definePlugin from "@utils/types";
import { Message } from "@vencord/discord-types";
import { MessageFlags, MessageType } from "@vencord/discord-types/enums";
import { findByPropsLazy } from "@webpack";
import { AuthenticationStore, ChannelStore, EditMessageStore, MessageStore, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast, Toasts } from "@webpack/common";
const { uniqueId } = findByPropsLazy("uniqueId");
function chooseAttachments(channelId: string, messageId: string, existingAttachmentCount: number) {
const input = document.createElement("input");
input.type = "file";
input.accept = "*/*";
input.multiple = true;
input.click();
input.addEventListener("change", async () => {
try {
if (!input.files) return;
await addAttachments(channelId, messageId, existingAttachmentCount, input.files);
} finally {
input.remove();
}
});
}
async function addAttachments(channelId: string, messageId: string, existingAttachmentCount: number, files: FileList) {
if (!files) return;
if (files.length + existingAttachmentCount > 10) {
const remaining = 10 - existingAttachmentCount;
if (remaining <= 0) {
showToast("You cannot add more attachments to this message.", Toasts.Type.FAILURE);
return;
}
showToast(`You can only add ${pluralise(remaining, "more attachment")} to this message.`, Toasts.Type.FAILURE);
return;
}
showToast("Uploading, this can take a while...", Toasts.Type.CLOCK);
const { body: { attachments } } = await RestAPI.post({
url: `/channels/${channelId}/attachments`,
body: {
files: Array.from(files, file => ({
filename: file.name,
file_size: file.size,
id: uniqueId(),
is_clip: false
}))
}
}) as { body: { attachments: { id: string, upload_url: string, upload_filename: string; }[]; }; };
const newAttachments = await Promise.all(
attachments.map((file, i) =>
fetch(file.upload_url, {
method: "PUT",
body: files[i]
}).then(() => ({
id: file.id,
uploaded_filename: file.upload_filename,
filename: files[i].name
}))
)
);
const msg = MessageStore.getMessage(channelId, messageId);
await RestAPI.patch({
url: `/channels/${channelId}/messages/${messageId}`,
body: {
attachments: [
...msg.attachments,
...newAttachments
]
}
});
showToast(`${files.length === 1 ? "Attachment" : "Attachments"} added successfully!`, Toasts.Type.SUCCESS);
}
function canAddAttachments(msg: Message) {
return (
[MessageType.DEFAULT, MessageType.REPLY].includes(msg.type) &&
!msg.hasFlag(MessageFlags.IS_VOICE_MESSAGE) &&
AuthenticationStore.getId() === msg.author.id &&
msg.attachments.length < 10
);
}
function handlePaste(e: ClipboardEvent) {
if (!e.clipboardData?.files.length) return;
const msg = EditMessageStore.getEditingMessage(SelectedChannelStore.getChannelId());
if (!msg) return;
e.preventDefault();
e.stopImmediatePropagation();
addAttachments(msg.channel_id, msg.id, msg.attachments.length, e.clipboardData.files);
}
export default definePlugin({
name: "AddAttachments",
description: "Allows you to add new attachments while editing messages",
authors: [Devs.Lumap],
start() {
document.addEventListener("paste", handlePaste, { capture: true });
},
stop() {
document.removeEventListener("paste", handlePaste, { capture: true });
},
messagePopoverButton: {
icon: UploadIcon,
render(msg) {
if (!canAddAttachments(msg)) return null;
const channel = ChannelStore.getChannel(msg.channel_id);
if (!channel.isPrivate() && !PermissionStore.can(PermissionsBits.SEND_MESSAGES, channel)) return null;
return {
label: "Add Attachments",
icon: UploadIcon,
message: msg,
channel: ChannelStore.getChannel(msg.channel_id),
onClick: () => chooseAttachments(msg.channel_id, msg.id, msg.attachments.length)
};
},
},
chatBarButton: {
icon: UploadIcon,
render({ channel, type }) {
if (type.analyticsName !== "edit") return null;
const msg = EditMessageStore.getEditingMessage(channel.id);
if (!msg || !canAddAttachments(msg)) return null;
return (
<ChatBarButton
tooltip="Add Attachments"
onClick={() => chooseAttachments(msg.channel_id, msg.id, msg.attachments.length)}
>
<UploadIcon height={18} width={18} />
</ChatBarButton>
);
}
}
});