diff --git a/src/equicordplugins/chatButtonsPlus/index.tsx b/src/equicordplugins/chatButtonsPlus/index.tsx
new file mode 100644
index 000000000..3634d67d1
--- /dev/null
+++ b/src/equicordplugins/chatButtonsPlus/index.tsx
@@ -0,0 +1,284 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2024 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import "./styles.css";
+
+import { ChatBarButton } from "@api/ChatButtons";
+import { DataStore } from "@api/index";
+import { definePluginSettings, Settings } from "@api/Settings";
+import { EquicordDevs } from "@utils/constants";
+import { getCurrentChannel, sendMessage } from "@utils/discord";
+import { useForceUpdater } from "@utils/react";
+import definePlugin, { OptionType } from "@utils/types";
+import { Button, Forms, React, Switch, TextInput } from "@webpack/common";
+
+type ButtonEntry = {
+ id: string;
+ label: string;
+ message: string;
+ svg: string;
+ enabled: boolean;
+};
+
+let buttonEntries: ButtonEntry[] = [];
+const BUTTON_ENTRIES_KEY = "ChatButtonsPlus_buttonEntries";
+
+function generateId(): string {
+ return Date.now().toString(36) + Math.random().toString(36).substr(2);
+}
+
+async function handleButtonClick(context: string) {
+ const currentChannel = getCurrentChannel();
+
+ if (!currentChannel) return;
+
+ sendMessage(currentChannel.id, { content: context });
+}
+
+async function addButtonEntry(forceUpdate: () => void) {
+ try {
+ buttonEntries.push({
+ id: generateId(),
+ label: "New Button",
+ message: "Hello!",
+ svg: '',
+ enabled: true
+ });
+ await DataStore.set(BUTTON_ENTRIES_KEY, buttonEntries);
+ forceUpdate();
+ } catch (error) {
+ console.error("ChatButtonsPlus: Failed to add button entry:", error);
+ }
+}
+
+async function removeButtonEntry(id: string, forceUpdate: () => void) {
+ try {
+ const index = buttonEntries.findIndex(entry => entry.id === id);
+ if (index !== -1) {
+ buttonEntries.splice(index, 1);
+ await DataStore.set(BUTTON_ENTRIES_KEY, buttonEntries);
+ forceUpdate();
+ }
+ } catch (error) {
+ console.error("ChatButtonsPlus: Failed to remove button entry:", error);
+ }
+}
+
+function ButtonEntries() {
+ const update = useForceUpdater();
+
+ async function setLabel(id: string, value: string) {
+ try {
+ const index = buttonEntries.findIndex(entry => entry.id === id);
+ if (index !== -1) {
+ buttonEntries[index].label = value.trim() || "Button";
+ await DataStore.set(BUTTON_ENTRIES_KEY, buttonEntries);
+ update();
+ }
+ } catch (error) {
+ console.error("ChatButtonsPlus: Failed to update label:", error);
+ }
+ }
+
+ async function setMessage(id: string, value: string) {
+ try {
+ const index = buttonEntries.findIndex(entry => entry.id === id);
+ if (index !== -1) {
+ buttonEntries[index].message = value.trim() || "Hello!";
+ await DataStore.set(BUTTON_ENTRIES_KEY, buttonEntries);
+ update();
+ }
+ } catch (error) {
+ console.error("ChatButtonsPlus: Failed to update message:", error);
+ }
+ }
+
+ async function setSvg(id: string, value: string) {
+ try {
+ const index = buttonEntries.findIndex(entry => entry.id === id);
+ if (index !== -1 && isValidSvg(value.trim())) {
+ buttonEntries[index].svg = value.trim();
+ await DataStore.set(BUTTON_ENTRIES_KEY, buttonEntries);
+ update();
+ }
+ } catch (error) {
+ console.error("ChatButtonsPlus: Failed to update SVG:", error);
+ }
+ }
+
+ async function setEnabled(id: string, value: boolean) {
+ try {
+ const index = buttonEntries.findIndex(entry => entry.id === id);
+ if (index !== -1) {
+ buttonEntries[index].enabled = value;
+ await DataStore.set(BUTTON_ENTRIES_KEY, buttonEntries);
+ update();
+ }
+ } catch (error) {
+ console.error("ChatButtonsPlus: Failed to update enabled state:", error);
+ }
+ }
+
+ function isValidSvg(svg: string): boolean {
+ if (!svg) return true;
+
+ const dangerousPatterns = [
+ /