diff --git a/public/index.html b/public/index.html index 0317a9b16..992f6b2c9 100644 --- a/public/index.html +++ b/public/index.html @@ -56,7 +56,6 @@
-
diff --git a/public/script.js b/public/script.js index 7efe1d231..bb4a13020 100644 --- a/public/script.js +++ b/public/script.js @@ -3283,27 +3283,9 @@ function read_bg_load(input) { processData: false, success: function (html) { setBackground(html); - if (bg1_toggle == true) { - // this is a repeat of the background setting function for when user uploads a new BG image - bg1_toggle = false; // should make the Bg setting a modular function to be called in both cases - var number_bg = 2; - var target_opacity = 1.0; - } else { - bg1_toggle = true; - var number_bg = 1; - var target_opacity = 0.0; - } - $("#bg2").transition({ - opacity: target_opacity, - duration: 1300, //animation_rm_duration, - easing: "linear", - complete: function () { - $("#options").css("display", "none"); - }, - }); - $("#bg" + number_bg).css( + $("#bg1").css( "background-image", - "url(" + e.target.result + ")" + `url(${e.target.result})` ); $("#form_bg_download").after( `
@@ -3890,40 +3872,35 @@ $(document).ready(function () { $("#form_upload_avatar").trigger("reset"); }); - $(document).on("click", ".bg_example", function () { + $(document).on("click", ".bg_example", async function () { //when user clicks on a BG thumbnail... - var this_bgfile = $(this).attr("bgfile"); // this_bgfile = whatever they clicked + const this_bgfile = $(this).attr("bgfile"); // this_bgfile = whatever they clicked + + const customBg = window.getComputedStyle(document.getElementById('bg_custom')).backgroundImage; + + // custom background is set. Do not override the layer below + if (customBg !== 'none') { + return; + } // if clicked on upload button if (!this_bgfile) { return; } - if (bg1_toggle == true) { - //if bg1 is toggled true (initially set as true in first JS vars) - bg1_toggle = false; // then toggle it false - var number_bg = 2; // sets a variable for bg2 - var target_opacity = 1.0; // target opacity is 100% - } else { - //if bg1 is FALSE - bg1_toggle = true; // make it true - var number_bg = 1; // set variable to bg1.. - var target_opacity = 0.0; // set target opacity to 0 - } - $("#bg2").stop(); // first, stop whatever BG transition was happening before - $("#bg2").transition({ - // start a new BG transition routine - opacity: target_opacity, // set opacity to previously set variable - duration: 1300, //animation_rm_duration, - easing: "linear", - complete: function () { - }, + const backgroundUrl = `backgrounds/${this_bgfile}`; + + // fetching to browser memory to reduce flicker + fetch(backgroundUrl).then(() => { + $("#bg1").css( + "background-image", + `url("${backgroundUrl}")` + ); + setBackground(this_bgfile); + }).catch(() => { + console.log('Background could not be set: ' + backgroundUrl); }); - $("#bg" + number_bg).css( - "background-image", - 'url("backgrounds/' + this_bgfile + '")' - ); - setBackground(this_bgfile); + }); $(document).on("click", ".bg_example_cross", function (e) { e.stopPropagation(); diff --git a/public/scripts/extensions.js b/public/scripts/extensions.js index 0596e843c..df4b7022f 100644 --- a/public/scripts/extensions.js +++ b/public/scripts/extensions.js @@ -9,7 +9,7 @@ export { extension_settings, }; -const extensionNames = ['caption', 'dice', 'expressions', 'floating-prompt', 'memory']; +const extensionNames = ['caption', 'dice', 'expressions', 'floating-prompt', 'memory', 'backgrounds']; const manifests = await getManifests(extensionNames); const defaultUrl = "http://localhost:5100"; diff --git a/public/scripts/extensions/backgrounds/index.js b/public/scripts/extensions/backgrounds/index.js new file mode 100644 index 000000000..4ae8d389a --- /dev/null +++ b/public/scripts/extensions/backgrounds/index.js @@ -0,0 +1,140 @@ +import { getContext } from "../../extensions.js"; +export { MODULE_NAME }; + +const MODULE_NAME = 'backgrounds'; +const METADATA_KEY = 'custom_background'; +const UPDATE_INTERVAL = 1000; + +async function moduleWorker() { + if (hasCustomBackground()) { + $('#unlock_background').show(); + $('#lock_background').hide(); + setCustomBackground(); + } + else { + $('#unlock_background').hide(); + $('#lock_background').show(); + unsetCustomBackground(); + } +} + +function onLockBackgroundClick() { + const bgImage = window.getComputedStyle(document.getElementById('bg1')).backgroundImage; + + // Extract the URL from the CSS string + const urlRegex = /url\((['"])?(.*?)\1\)/; + const matches = bgImage.match(urlRegex); + const url = matches[2]; + + // Remove the protocol and host, leaving the relative URL + const relativeUrl = new URL(url).pathname; + const relativeBgImage = `url("${relativeUrl}")` + + saveBackgroundMetadata(relativeBgImage); + setCustomBackground(); + $('#unlock_background').show(); + $('#lock_background').hide(); +} + +function onUnlockBackgroundClick() { + removeBackgroundMetadata(); + unsetCustomBackground(); + $('#unlock_background').hide(); + $('#lock_background').show(); +} + +function hasCustomBackground() { + const context = getContext(); + return !!context.chatMetadata[METADATA_KEY]; +} + +function saveBackgroundMetadata(file) { + const context = getContext(); + context.chatMetadata[METADATA_KEY] = file; + context.saveChat(); +} + +function removeBackgroundMetadata() { + const context = getContext(); + delete context.chatMetadata[METADATA_KEY]; + context.saveChat(); +} + +function setCustomBackground() { + const context = getContext(); + const file = context.chatMetadata[METADATA_KEY]; + + // bg already set + if (document.getElementById("bg_custom").style.backgroundImage == file) { + return; + } + + $("#bg_custom").css("background-image", file); + $("#custom_bg_preview").css("background-image", file); +} + +function animateBgSet(selector, value) { + $(selector).animate({ + opacity: 0 + }, 500, + function () { + $(this).css('background-image', value).animate({ + opacity: 1 + }, 500); + }); +} + +function unsetCustomBackground() { + animateBgSet("#bg_custom", 'none'); + $("#custom_bg_preview").css("background-image", 'none'); +} + +function onSelectBackgroundClick() { + const bgfile = $(this).attr("bgfile"); + + if (hasCustomBackground()) { + saveBackgroundMetadata(`url("backgrounds/${bgfile}")`); + setCustomBackground(); + } +} + +$(document).ready(function () { + function addSettings() { + const html = ` +
+
+
+ Character Backgrounds +
+
+
+
+ + + + Press "Lock" to assign a currently selected background to a character or group chat.
+ Any background image selected while lock is engaged will be saved automatically. +
+
+
Preview
+
+
+
+
+
+ `; + $('#extensions_settings').append(html); + $('#lock_background').on('click', onLockBackgroundClick); + $('#unlock_background').on('click', onUnlockBackgroundClick); + $(document).on("click", ".bg_example", onSelectBackgroundClick); + } + + addSettings(); + setInterval(moduleWorker, UPDATE_INTERVAL); +}); \ No newline at end of file diff --git a/public/scripts/extensions/backgrounds/manifest.json b/public/scripts/extensions/backgrounds/manifest.json new file mode 100644 index 000000000..a95e547eb --- /dev/null +++ b/public/scripts/extensions/backgrounds/manifest.json @@ -0,0 +1,8 @@ +{ + "display_name": "Character Backgrounds", + "loading_order": 7, + "requires": [], + "optional": [], + "js": "index.js", + "css": "style.css" +} \ No newline at end of file diff --git a/public/scripts/extensions/backgrounds/style.css b/public/scripts/extensions/backgrounds/style.css new file mode 100644 index 000000000..6a4bde1af --- /dev/null +++ b/public/scripts/extensions/backgrounds/style.css @@ -0,0 +1,45 @@ +#custom_bg_preview { + width: 160px; + height: 90px; + background-color: var(--grey30a); + background-repeat: no-repeat; + background-attachment: fixed; + background-size: cover; + border-radius: 20px; + border: 1px solid var(--black50a); + box-shadow: 0 0 7px var(--black50a); + margin: 5px; +} + +#custom_bg_preview::before { + content: 'No Background'; + color: white; + position: relative; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; +} + +#custom_bg_preview:not([style*="background-image: none"])::before { + display: none; +} + +.background_controls .menu_button { + display: flex; + flex-direction: row; + align-items: center; + column-gap: 10px; +} + +.background_controls { + display: flex; + flex-direction: row; + align-items: center; + column-gap: 10px; +} + +.background_controls small { + flex-grow: 1; +} \ No newline at end of file diff --git a/public/style.css b/public/style.css index 4eb0630f6..4769b24fa 100644 --- a/public/style.css +++ b/public/style.css @@ -157,26 +157,23 @@ code { line-height: var(--mainFontSize); } -#bg1 { - background: url(backgrounds/tavern1.jpg); +#bg1, #bg_custom { background-repeat: no-repeat; background-attachment: fixed; background-size: cover; position: absolute; width: 100%; height: 100%; + transition: background-image 0.5s ease-in-out; +} + +#bg1 { + background-image: url(backgrounds/tavern1.jpg); z-index: 0; } -#bg2 { - background: url(backgrounds/tavern1.jpg); - background-repeat: no-repeat; - background-attachment: fixed; - background-size: cover; - opacity: 0.0; - position: absolute; - width: 100%; - height: 100%; +#bg_custom { + background-image: none; z-index: 1; } @@ -3260,7 +3257,7 @@ toolcool-color-picker { } #bg1, - #bg2 { + #bg_custom { position: fixed; } @@ -3420,7 +3417,7 @@ body.no-blur #send_form.no-connection { } body.no-blur #bg1, -body.no-blur #bg2 { +body.no-blur #bg_custom { filter: unset; }