diff --git a/public/scripts/extensions.js b/public/scripts/extensions.js
index b21d7348a..2f7c834d8 100644
--- a/public/scripts/extensions.js
+++ b/public/scripts/extensions.js
@@ -57,6 +57,7 @@ const extension_settings = {
chromadb: {},
translate: {},
objective: {},
+ quickReply: {},
};
let modules = [];
diff --git a/public/scripts/extensions/quick-reply/index.js b/public/scripts/extensions/quick-reply/index.js
new file mode 100644
index 000000000..c37f4b635
--- /dev/null
+++ b/public/scripts/extensions/quick-reply/index.js
@@ -0,0 +1,174 @@
+import { saveSettingsDebounced } from "../../../script.js";
+import { getContext, extension_settings } from "../../extensions.js";
+import { initScrollHeight, resetScrollHeight } from "../../utils.js";
+
+export { MODULE_NAME };
+
+const MODULE_NAME = 'quick-reply';
+const UPDATE_INTERVAL = 1000;
+
+const defaultSettings = {
+ quickReply1Mes: '',
+ quickReply1Label: '',
+ quickReply2Mes: '',
+ quickReply2Label: '',
+ quickReply3Mes: '',
+ quickReply3Label: '',
+ quickReply4Mes: '',
+ quickReply4Label: '',
+ quickReply5Mes: '',
+ quickReply5Label: '',
+ quickReplyEnabled: false,
+}
+
+async function loadSettings() {
+ if (Object.keys(extension_settings.quickReply).length === 0) {
+ Object.assign(extension_settings.quickReply, defaultSettings);
+ }
+
+ $('#quickReplyEnabled').prop('checked', extension_settings.quickReply.quickReplyEnabled);
+
+ $('#quickReply1Mes').val(extension_settings.quickReply.quickReply1Mes).trigger('input');
+ $('#quickReply1Label').val(extension_settings.quickReply.quickReply1Label).trigger('input');
+
+ $('#quickReply2Mes').val(extension_settings.quickReply.quickReply2Mes).trigger('input');
+ $('#quickReply2Label').val(extension_settings.quickReply.quickReply2Label).trigger('input');
+
+ $('#quickReply3Mes').val(extension_settings.quickReply.quickReply3Mes).trigger('input');
+ $('#quickReply3Label').val(extension_settings.quickReply.quickReply3Label).trigger('input');
+
+ $('#quickReply4Mes').val(extension_settings.quickReply.quickReply4Mes).trigger('input');
+ $('#quickReply4Label').val(extension_settings.quickReply.quickReply4Label).trigger('input');
+
+ $('#quickReply5Mes').val(extension_settings.quickReply.quickReply5Mes).trigger('input');
+ $('#quickReply5Label').val(extension_settings.quickReply.quickReply5Label).trigger('input');
+}
+
+function onQuickReplyInput(id) {
+ extension_settings.quickReply[`quickReply${id}Mes`] = $(`#quickReply${id}Mes`).val();
+ $(`#quickReply${id}`).attr('title', ($(`#quickReply${id}Mes`).val()));
+ resetScrollHeight($(`#quickReply${id}Mes`));
+ saveSettingsDebounced();
+}
+
+function onQuickReplyLabelInput(id) {
+ extension_settings.quickReply[`quickReply${id}Label`] = $(`#quickReply${id}Label`).val();
+ $(`#quickReply${id}`).text($(`#quickReply${id}Label`).val());
+ saveSettingsDebounced();
+}
+
+async function onQuickReplyEnabledInput() {
+ let isEnabled = $(this).prop('checked')
+ extension_settings.quickReply.quickReplyEnabled = !!isEnabled;
+ if (isEnabled === true) {
+ $("#quickReplyBar").show();
+ } else { $("#quickReplyBar").hide(); }
+ saveSettingsDebounced();
+}
+
+async function sendQuickReply(id) {
+ var prompt = extension_settings.quickReply[`${id}Mes`];
+ $("#send_textarea").val(prompt);
+ $("#send_but").trigger('click');
+}
+
+function addQuickReplyBar(numButtons) {
+ var numButtons = 5;
+ const quickReplyBarStartHtml = `
+
+
+ `;
+ let quickReplyButtonHtml = '';
+ for (let i = 0; i < numButtons; i++) {
+ let quickReplyMes = extension_settings.quickReply[`quickReply${i + 1}Mes`];
+ let quickReplyLabel = extension_settings.quickReply[`quickReply${i + 1}Label`];
+ console.log(quickReplyMes);
+ quickReplyButtonHtml += `
${quickReplyLabel}
`;
+ }
+ const quickReplyEndHtml = `
`
+ const quickReplyBarFullHtml = [quickReplyBarStartHtml, quickReplyButtonHtml, quickReplyEndHtml].join('');
+
+ $('#send_form').prepend(quickReplyBarFullHtml);
+
+ $('.quickReplyButton').on('click', function () {
+ console.log('got quick reply click');
+ let quickReplyButtonID = $(this).attr('id');
+ sendQuickReply(quickReplyButtonID);
+ });
+}
+
+
+async function moduleWorker() {
+ if (extension_settings.quickReply.quickReplyEnabled === true) {
+ $('#quickReplyBar').toggle(getContext().onlineStatus !== 'no_connection');
+ }
+}
+
+jQuery(async () => {
+
+ moduleWorker();
+ setInterval(moduleWorker, UPDATE_INTERVAL);
+ const settingsHtml = `
+
+
`;
+
+ $('#extensions_settings').append(settingsHtml);
+
+ $('#quickReply1Mes').on('input', function () { onQuickReplyInput(1); });
+ $('#quickReply2Mes').on('input', function () { onQuickReplyInput(2); });
+ $('#quickReply3Mes').on('input', function () { onQuickReplyInput(3); });
+ $('#quickReply4Mes').on('input', function () { onQuickReplyInput(4); });
+ $('#quickReply5Mes').on('input', function () { onQuickReplyInput(5); });
+
+ $('#quickReply1Label').on('input', function () { onQuickReplyLabelInput(1); });
+ $('#quickReply2Label').on('input', function () { onQuickReplyLabelInput(2); });
+ $('#quickReply3Label').on('input', function () { onQuickReplyLabelInput(3); });
+ $('#quickReply4Label').on('input', function () { onQuickReplyLabelInput(4); });
+ $('#quickReply5Label').on('input', function () { onQuickReplyLabelInput(5); });
+
+ $('#quickReplyEnabled').on('input', onQuickReplyEnabledInput);
+
+ $('.quickReplySettings .inline-drawer-toggle').on('click', function () {
+ initScrollHeight($("#quickReply1Mes"));
+ initScrollHeight($("#quickReply2Mes"));
+ initScrollHeight($("#quickReply3Mes"));
+ initScrollHeight($("#quickReply4Mes"));
+ initScrollHeight($("#quickReply5Mes"));
+ })
+
+ await loadSettings();
+ addQuickReplyBar();
+});
+
diff --git a/public/scripts/extensions/quick-reply/manifest.json b/public/scripts/extensions/quick-reply/manifest.json
new file mode 100644
index 000000000..e104a5761
--- /dev/null
+++ b/public/scripts/extensions/quick-reply/manifest.json
@@ -0,0 +1,11 @@
+{
+ "display_name": "Quick Replies",
+ "loading_order": 12,
+ "requires": [],
+ "optional": [],
+ "js": "index.js",
+ "css": "style.css",
+ "author": "RossAscends#1779",
+ "version": "1.0.0",
+ "homePage": "https://github.com/SillyTavern/SillyTavern"
+}
\ No newline at end of file
diff --git a/public/scripts/extensions/quick-reply/style.css b/public/scripts/extensions/quick-reply/style.css
new file mode 100644
index 000000000..7df2c3d8f
--- /dev/null
+++ b/public/scripts/extensions/quick-reply/style.css
@@ -0,0 +1,47 @@
+#quickReplyBar {
+ outline: none;
+ padding: 5px 0;
+ border-bottom: 1px solid var(--black30a);
+ margin: 0;
+ transition: 0.3s;
+ opacity: 0.7;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ display: none;
+}
+
+#quickReplies {
+ margin: 0;
+ padding: 0;
+ display: flex;
+ justify-content: center;
+ flex-wrap: nowrap;
+ gap: 5px;
+ width: 100%;
+}
+
+#quickReplies div {
+ color: var(--SmartThemeBodyColor);
+ background-color: var(--black50a);
+ border: 1px solid var(--white30a);
+ border-radius: 10px;
+ padding: 3px 5px;
+ width: min-content;
+ cursor: pointer;
+ transition: 0.3s;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+}
+
+#quickReplies div:hover {
+ opacity: 1;
+ filter: brightness(1.2);
+ cursor: pointer;
+
+
+
+}
\ No newline at end of file
diff --git a/public/style.css b/public/style.css
index 0160a1784..347df934b 100644
--- a/public/style.css
+++ b/public/style.css
@@ -412,6 +412,7 @@ code {
#send_form {
display: flex;
+ flex-wrap: wrap;
align-items: center;
width: 100%;
margin: 0 auto 0 auto;
@@ -4477,4 +4478,4 @@ body.waifuMode #avatar_zoom_popup {
overflow-y: auto;
overflow-x: hidden;
}
-}
+}
\ No newline at end of file