mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Add character backgrounds plugin #82
This commit is contained in:
@ -56,7 +56,6 @@
|
|||||||
|
|
||||||
<div id="bg_custom"></div>
|
<div id="bg_custom"></div>
|
||||||
<div id="bg1"></div>
|
<div id="bg1"></div>
|
||||||
<div id="bg2"></div>
|
|
||||||
|
|
||||||
<!-- top bar central settings buttons -->
|
<!-- top bar central settings buttons -->
|
||||||
<div id="top-bar">
|
<div id="top-bar">
|
||||||
|
@ -3283,27 +3283,9 @@ function read_bg_load(input) {
|
|||||||
processData: false,
|
processData: false,
|
||||||
success: function (html) {
|
success: function (html) {
|
||||||
setBackground(html);
|
setBackground(html);
|
||||||
if (bg1_toggle == true) {
|
$("#bg1").css(
|
||||||
// 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(
|
|
||||||
"background-image",
|
"background-image",
|
||||||
"url(" + e.target.result + ")"
|
`url(${e.target.result})`
|
||||||
);
|
);
|
||||||
$("#form_bg_download").after(
|
$("#form_bg_download").after(
|
||||||
`<div class="bg_example" bgfile="${html}" style="background-image: url('${getThumbnailUrl('bg', html)}');">
|
`<div class="bg_example" bgfile="${html}" style="background-image: url('${getThumbnailUrl('bg', html)}');">
|
||||||
@ -3890,40 +3872,35 @@ $(document).ready(function () {
|
|||||||
$("#form_upload_avatar").trigger("reset");
|
$("#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...
|
//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 clicked on upload button
|
||||||
if (!this_bgfile) {
|
if (!this_bgfile) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bg1_toggle == true) {
|
const backgroundUrl = `backgrounds/${this_bgfile}`;
|
||||||
//if bg1 is toggled true (initially set as true in first JS vars)
|
|
||||||
bg1_toggle = false; // then toggle it false
|
// fetching to browser memory to reduce flicker
|
||||||
var number_bg = 2; // sets a variable for bg2
|
fetch(backgroundUrl).then(() => {
|
||||||
var target_opacity = 1.0; // target opacity is 100%
|
$("#bg1").css(
|
||||||
} 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 () {
|
|
||||||
},
|
|
||||||
});
|
|
||||||
$("#bg" + number_bg).css(
|
|
||||||
"background-image",
|
"background-image",
|
||||||
'url("backgrounds/' + this_bgfile + '")'
|
`url("${backgroundUrl}")`
|
||||||
);
|
);
|
||||||
setBackground(this_bgfile);
|
setBackground(this_bgfile);
|
||||||
|
}).catch(() => {
|
||||||
|
console.log('Background could not be set: ' + backgroundUrl);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
$(document).on("click", ".bg_example_cross", function (e) {
|
$(document).on("click", ".bg_example_cross", function (e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
@ -9,7 +9,7 @@ export {
|
|||||||
extension_settings,
|
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 manifests = await getManifests(extensionNames);
|
||||||
const defaultUrl = "http://localhost:5100";
|
const defaultUrl = "http://localhost:5100";
|
||||||
|
|
||||||
|
140
public/scripts/extensions/backgrounds/index.js
Normal file
140
public/scripts/extensions/backgrounds/index.js
Normal file
@ -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 = `
|
||||||
|
<div class="background_settings">
|
||||||
|
<div class="inline-drawer">
|
||||||
|
<div class="inline-drawer-toggle inline-drawer-header">
|
||||||
|
<b>Character Backgrounds</b>
|
||||||
|
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
|
||||||
|
</div>
|
||||||
|
<div class="inline-drawer-content">
|
||||||
|
<div class="background_controls">
|
||||||
|
<div id="lock_background" class="menu_button">
|
||||||
|
<i class="fa-solid fa-lock"></i>
|
||||||
|
Lock
|
||||||
|
</div>
|
||||||
|
<div id="unlock_background" class="menu_button">
|
||||||
|
<i class="fa-solid fa-unlock"></i>
|
||||||
|
Unlock
|
||||||
|
</div>
|
||||||
|
<small>
|
||||||
|
Press "Lock" to assign a currently selected background to a character or group chat.<br>
|
||||||
|
Any background image selected while lock is engaged will be saved automatically.
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<div>Preview</div>
|
||||||
|
<div id="custom_bg_preview">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
$('#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);
|
||||||
|
});
|
8
public/scripts/extensions/backgrounds/manifest.json
Normal file
8
public/scripts/extensions/backgrounds/manifest.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"display_name": "Character Backgrounds",
|
||||||
|
"loading_order": 7,
|
||||||
|
"requires": [],
|
||||||
|
"optional": [],
|
||||||
|
"js": "index.js",
|
||||||
|
"css": "style.css"
|
||||||
|
}
|
45
public/scripts/extensions/backgrounds/style.css
Normal file
45
public/scripts/extensions/backgrounds/style.css
Normal file
@ -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;
|
||||||
|
}
|
@ -157,26 +157,23 @@ code {
|
|||||||
line-height: var(--mainFontSize);
|
line-height: var(--mainFontSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
#bg1 {
|
#bg1, #bg_custom {
|
||||||
background: url(backgrounds/tavern1.jpg);
|
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-attachment: fixed;
|
background-attachment: fixed;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
transition: background-image 0.5s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bg1 {
|
||||||
|
background-image: url(backgrounds/tavern1.jpg);
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#bg2 {
|
#bg_custom {
|
||||||
background: url(backgrounds/tavern1.jpg);
|
background-image: none;
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-attachment: fixed;
|
|
||||||
background-size: cover;
|
|
||||||
opacity: 0.0;
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3260,7 +3257,7 @@ toolcool-color-picker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#bg1,
|
#bg1,
|
||||||
#bg2 {
|
#bg_custom {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3420,7 +3417,7 @@ body.no-blur #send_form.no-connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body.no-blur #bg1,
|
body.no-blur #bg1,
|
||||||
body.no-blur #bg2 {
|
body.no-blur #bg_custom {
|
||||||
filter: unset;
|
filter: unset;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user