diff --git a/public/index.html b/public/index.html index 11662d5a6..9456f7a25 100644 --- a/public/index.html +++ b/public/index.html @@ -2394,6 +2394,7 @@ ${characterName}
+
@@ -2409,6 +2410,13 @@
+
+
+
+
+
+ +
diff --git a/public/script.js b/public/script.js index faf1d247e..063d5cc98 100644 --- a/public/script.js +++ b/public/script.js @@ -1030,13 +1030,14 @@ function getMessageFromTemplate({ mesId, characterName, isUser, avatarImg, bias, return mes; } -function appendImageToMessage(mes, messageElement) { +export function appendImageToMessage(mes, messageElement) { if (mes.extra?.image) { - const image = document.createElement("img"); - image.src = mes.extra?.image; - image.title = mes.extra?.title || mes.title; - image.classList.add("img_extra"); - mes.extra?.inline_image?messageElement.find(".mes_text").append(image):messageElement.find(".mes_text").prepend(image); + const image = messageElement.find('.mes_img'); + const isInline = !!mes.extra?.inline_image; + image.attr('src', mes.extra?.image); + image.attr('title', mes.extra?.title || mes.title); + messageElement.find(".mes_img_container").addClass("img_extra"); + image.toggleClass("img_inline", isInline); } } @@ -4479,6 +4480,40 @@ export function cancelTtsPlay() { } } +async function deleteMessageImage() { + const value = await callPopup("

Delete image from message?
This action can't be undone.

", 'confirm'); + + if (!value) { + return; + } + + const mesBlock = $(this).closest('.mes'); + const mesId = mesBlock.attr('mesid'); + const message = chat[mesId]; + delete message.extra.image; + delete message.extra.inline_image; + mesBlock.find('.mes_img_container').removeClass('img_extra'); + mesBlock.find('.mes_img').attr('src', ''); + saveChatConditional(); +} + +function enlargeMessageImage() { + const mesBlock = $(this).closest('.mes'); + const mesId = mesBlock.attr('mesid'); + const message = chat[mesId]; + const imgSrc = message?.extra?.image; + + if (!imgSrc) { + return; + } + + const img = document.createElement('img'); + img.classList.add('img_enlarged'); + img.src = imgSrc; + $('#dialogue_popup').addClass('wide_dialogue_popup'); + callPopup(img.outerHTML, 'text'); +} + window["SillyTavern"].getContext = function () { return { chat: chat, @@ -6433,6 +6468,9 @@ $(document).ready(function () { $('.code-copied').css({ 'display': 'none' }); }); + $(document).on('click', '.mes_img_enlarge', enlargeMessageImage); + $(document).on('click', '.mes_img_delete', deleteMessageImage); + $(window).on('beforeunload', () => { cancelTtsPlay(); if (streamingProcessor) { diff --git a/public/scripts/extensions/stable-diffusion/index.js b/public/scripts/extensions/stable-diffusion/index.js index a4f24194c..e22b6b49c 100644 --- a/public/scripts/extensions/stable-diffusion/index.js +++ b/public/scripts/extensions/stable-diffusion/index.js @@ -7,7 +7,8 @@ import { callPopup, getRequestHeaders, event_types, - eventSource + eventSource, + appendImageToMessage } from "../../../script.js"; import { getApiUrl, getContext, extension_settings, defaultRequestArgs, modules } from "../../extensions.js"; import { stringFormat, initScrollHeight, resetScrollHeight } from "../../utils.js"; @@ -477,9 +478,6 @@ async function sendMessage(prompt, image) { } function addSDGenButtons() { - const messageButtonHtml = ` -
- `; const buttonHtml = `
@@ -501,7 +499,6 @@ function addSDGenButtons() { `; - $('.mes_buttons').prepend(messageButtonHtml); $('#send_but_sheld').prepend(buttonHtml); $('#send_but_sheld').prepend(waitButtonHtml); $(document.body).append(dropdownHtml); @@ -519,6 +516,8 @@ function addSDGenButtons() { placement: 'top-start', }); + $(document).on('click', '.sd_message_gen', sdMessageButton); + $(document).on('click touchend', function (e) { const target = $(e.target); if (target.is(dropdown)) return; @@ -538,11 +537,11 @@ async function moduleWorker() { if (context.onlineStatus === 'no_connection'){ $('#sd_gen').hide(200); - $('.sd_message_gen').hide(200); + $('.sd_message_gen').hide(); } else{ $('#sd_gen').show(200); - $('.sd_message_gen').show(200); + $('.sd_message_gen').show(); } } @@ -551,31 +550,32 @@ addSDGenButtons(); setInterval(moduleWorker, UPDATE_INTERVAL); function sdMessageButton (e) { - const character = $(e.currentTarget).parents('div.mes_block').children('div.ch_name').children('span.name_text').text(), - message = $(e.currentTarget).parents('div.mes_block').children('div.mes_text').text(); + const $mes = $(e.currentTarget).closest('.mes'); + const character = $mes.find('.name_text').text(), + message = $mes.find('.mes_text').text(); console.log("doing /sd raw last"); - generatePicture('sd', 'raw_last', `${character} said: ${message}`, appendImageToMessage); + generatePicture('sd', 'raw_last', `${character} said: ${message}`, saveGeneratedImage); - function appendImageToMessage(prompt, image){ - const sd_image = document.createElement("img"), - context = getContext(), - message_id = $(e.target).parents('div.mes').attr('mesid'); - sd_image.src = image; - sd_image.title = prompt; - sd_image.classList.add("img_extra"); - $(e.target).parents('div.mes_block').children('div.mes_text').append(sd_image); + function saveGeneratedImage(prompt, image){ + const context = getContext(); + const message_id = $mes.attr('mesid'); + const message = context.chat[message_id]; - context.chat[message_id].extra.inline_image = true; - context.chat[message_id].extra.image = image; - context.chat[message_id].extra.title = prompt; + // Some message sources may not create the extra object + if (typeof message.extra !== 'object') { + message.extra = {}; + } + + message.extra.inline_image = true; + message.extra.image = image; + message.extra.title = prompt; + appendImageToMessage(message, $mes); context.saveChat(); } }; -window.sdMessageButton = sdMessageButton; - $("#sd_dropdown [id]").on("click", function () { var id = $(this).attr("id"); if (id == "sd_you") { @@ -672,4 +672,5 @@ jQuery(async () => { }); await loadSettings(); + $('body').addClass('sd'); }); diff --git a/public/style.css b/public/style.css index b6480a705..6f953e9ec 100644 --- a/public/style.css +++ b/public/style.css @@ -204,12 +204,14 @@ table.responsiveTable { text-align: center; } +.sd_message_gen, .mes_narrate, body.tts .mes[is_user="true"] .mes_narrate, body.tts .mes[is_system="true"] .mes_narrate { display: none; } +body.sd .sd_message_gen, body.tts .mes_narrate { display: inline-block; } @@ -2187,6 +2189,7 @@ input[type="range"]::-webkit-slider-thumb { .mes_prompt, .mes_narrate, +.sd_message_gen, .mes_copy, .mes_edit { cursor: pointer; @@ -2199,11 +2202,13 @@ input[type="range"]::-webkit-slider-thumb { .mes_edit:hover, .mes_copy:hover, +.sd_message_gen:hover, .mes_narrate:hover, .mes_stop:hover { opacity: 1; } +.last_mes .sd_message_gen, .last_mes .mes_copy, .last_mes .mes_narrate, .last_mes .mes_prompt { @@ -3307,16 +3312,59 @@ a { } /* Message images */ -.mes img.img_extra { +.mes .mes_img_container { max-width: 100%; max-height: 60svh; /*to fit inside single window height of mobile landscape*/ - border-radius: 10px; - display: block; + display: none; + position: relative; + width: fit-content; + transition: all 0.1s; } -.mes img.img_extra~* { +.mes_img { + border-radius: 10px; + width: 100%; +} + +.mes_img_controls { + position: absolute; + top: 0.5em; + left: 0; + width: 100%; display: none; + flex-direction: row; + justify-content: space-between; + padding: 0.75em; +} + +.mes_img_controls .right_menu_button { + padding: 0; + filter: brightness(80%); +} + +.mes_img_controls .right_menu_button:hover { + filter: brightness(150%); +} + +/* +.mes_img_container:hover .mes_img { + opacity: 0.9; +} +*/ + +.mes_img_container:hover .mes_img_controls { + display: flex; +} + +.mes .mes_img_container.img_extra { + display: flex; +} + +.img_enlarged { + width: 100%; + padding: 10px 0; + border-radius: 2px; } /* Extensions */