UI performance fixes (#3207)

* Optimize visibility checks for burger and wand menus

* Optimize message actions visibility toggle

* Run drawer toggle in animation frame

* Replace jQuery slideToggle with a 3rd-party lib

* Refactor export button functionality to manage popup state with a boolean flag

* Do not close the pinned drawer on unpin

* Revert "Do not close the pinned drawer on unpin"

This reverts commit e3b34e9a58.

* Refactor slideToggle options

* ease-in-out

* Don't skip frame on drawer toggle
This commit is contained in:
Cohee
2024-12-20 22:20:46 +02:00
committed by GitHub
parent 4232f6c5f4
commit 94de9411b6
7 changed files with 150 additions and 96 deletions

7
package-lock.json generated
View File

@ -63,6 +63,7 @@
"showdown": "^2.1.0", "showdown": "^2.1.0",
"sillytavern-transformers": "2.14.6", "sillytavern-transformers": "2.14.6",
"simple-git": "^3.19.1", "simple-git": "^3.19.1",
"slidetoggle": "^4.0.0",
"tiktoken": "^1.0.16", "tiktoken": "^1.0.16",
"vectra": "^0.2.2", "vectra": "^0.2.2",
"wavefile": "^11.0.0", "wavefile": "^11.0.0",
@ -6531,6 +6532,12 @@
"integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==", "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/slidetoggle": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/slidetoggle/-/slidetoggle-4.0.0.tgz",
"integrity": "sha512-6qvrOS1dnDFEr41UEEFFRQE8nswaAFIYZAHer6dVlznRIjHyCISjNJoxIn5U5QlAbZfBBxTELQk4jS7miHto1A==",
"license": "MIT"
},
"node_modules/smart-buffer": { "node_modules/smart-buffer": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",

View File

@ -53,6 +53,7 @@
"showdown": "^2.1.0", "showdown": "^2.1.0",
"sillytavern-transformers": "2.14.6", "sillytavern-transformers": "2.14.6",
"simple-git": "^3.19.1", "simple-git": "^3.19.1",
"slidetoggle": "^4.0.0",
"tiktoken": "^1.0.16", "tiktoken": "^1.0.16",
"vectra": "^0.2.2", "vectra": "^0.2.2",
"wavefile": "^11.0.0", "wavefile": "^11.0.0",

View File

@ -19,6 +19,7 @@ import seedrandom from 'seedrandom';
import * as Popper from '@popperjs/core'; import * as Popper from '@popperjs/core';
import droll from 'droll'; import droll from 'droll';
import morphdom from 'morphdom'; import morphdom from 'morphdom';
import { toggle as slideToggle } from 'slidetoggle';
/** /**
* Expose the libraries to the 'window' object. * Expose the libraries to the 'window' object.
@ -94,6 +95,7 @@ export default {
Popper, Popper,
droll, droll,
morphdom, morphdom,
slideToggle,
}; };
export { export {
@ -115,4 +117,5 @@ export {
Popper, Popper,
droll, droll,
morphdom, morphdom,
slideToggle,
}; };

View File

@ -10,6 +10,7 @@ import {
SVGInject, SVGInject,
Popper, Popper,
initLibraryShims, initLibraryShims,
slideToggle,
default as libs, default as libs,
} from './lib.js'; } from './lib.js';
@ -549,6 +550,7 @@ let optionsPopper = Popper.createPopper(document.getElementById('options_button'
let exportPopper = Popper.createPopper(document.getElementById('export_button'), document.getElementById('export_format_popup'), { let exportPopper = Popper.createPopper(document.getElementById('export_button'), document.getElementById('export_format_popup'), {
placement: 'left', placement: 'left',
}); });
let isExportPopupOpen = false;
// Saved here for performance reasons // Saved here for performance reasons
const messageTemplate = $('#message_template .mes'); const messageTemplate = $('#message_template .mes');
@ -895,6 +897,13 @@ export function getRequestHeaders() {
}; };
} }
export function getSlideToggleOptions() {
return {
miliseconds: animation_duration * 1.5,
transitionFunction: animation_duration > 0 ? 'ease-in-out' : 'step-start',
};
}
$.ajaxPrefilter((options, originalOptions, xhr) => { $.ajaxPrefilter((options, originalOptions, xhr) => {
xhr.setRequestHeader('X-CSRF-Token', token); xhr.setRequestHeader('X-CSRF-Token', token);
}); });
@ -9209,40 +9218,48 @@ function doDrawerOpenClick() {
* @returns {void} * @returns {void}
*/ */
function doNavbarIconClick() { function doNavbarIconClick() {
var icon = $(this).find('.drawer-icon'); const icon = $(this).find('.drawer-icon');
var drawer = $(this).parent().find('.drawer-content'); const drawer = $(this).parent().find('.drawer-content');
if (drawer.hasClass('resizing')) { return; } if (drawer.hasClass('resizing')) { return; }
var drawerWasOpenAlready = $(this).parent().find('.drawer-content').hasClass('openDrawer'); const drawerWasOpenAlready = $(this).parent().find('.drawer-content').hasClass('openDrawer');
let targetDrawerID = $(this).parent().find('.drawer-content').attr('id'); const targetDrawerID = $(this).parent().find('.drawer-content').attr('id');
const pinnedDrawerClicked = drawer.hasClass('pinnedOpen'); const pinnedDrawerClicked = drawer.hasClass('pinnedOpen');
if (!drawerWasOpenAlready) { //to open the drawer if (!drawerWasOpenAlready) { //to open the drawer
$('.openDrawer').not('.pinnedOpen').addClass('resizing').slideToggle(200, 'swing', async function () { $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => {
await delay(50); $(this).closest('.drawer-content').removeClass('resizing'); slideToggle(el, {
...getSlideToggleOptions(),
onAnimationEnd: function (el) {
el.closest('.drawer-content').classList.remove('resizing');
},
});
}); });
$('.openIcon').toggleClass('closedIcon openIcon'); $('.openIcon').not('.drawerPinnedOpen').toggleClass('closedIcon openIcon');
$('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer'); $('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer');
icon.toggleClass('openIcon closedIcon'); icon.toggleClass('openIcon closedIcon');
drawer.toggleClass('openDrawer closedDrawer'); drawer.toggleClass('openDrawer closedDrawer');
//console.log(targetDrawerID); //console.log(targetDrawerID);
if (targetDrawerID === 'right-nav-panel') { if (targetDrawerID === 'right-nav-panel') {
$(this).closest('.drawer').find('.drawer-content').addClass('resizing').slideToggle({ $(this).closest('.drawer').find('.drawer-content').addClass('resizing').each((_, el) => {
duration: 200, slideToggle(el, {
easing: 'swing', ...getSlideToggleOptions(),
start: function () { elementDisplayStyle: 'flex',
jQuery(this).css('display', 'flex'); //flex needed to make charlist scroll onAnimationEnd: function (el) {
}, el.closest('.drawer-content').classList.remove('resizing');
complete: async function () { favsToHotswap();
favsToHotswap(); $('#rm_print_characters_block').trigger('scroll');
await delay(50); },
$(this).closest('.drawer-content').removeClass('resizing'); });
$('#rm_print_characters_block').trigger('scroll');
},
}); });
} else { } else {
$(this).closest('.drawer').find('.drawer-content').addClass('resizing').slideToggle(200, 'swing', async function () { $(this).closest('.drawer').find('.drawer-content').addClass('resizing').each((_, el) => {
await delay(50); $(this).closest('.drawer-content').removeClass('resizing'); slideToggle(el, {
...getSlideToggleOptions(),
onAnimationEnd: function (el) {
el.closest('.drawer-content').classList.remove('resizing');
},
});
}); });
} }
@ -9258,13 +9275,23 @@ function doNavbarIconClick() {
icon.toggleClass('closedIcon openIcon'); icon.toggleClass('closedIcon openIcon');
if (pinnedDrawerClicked) { if (pinnedDrawerClicked) {
$(drawer).addClass('resizing').slideToggle(200, 'swing', async function () { $(drawer).addClass('resizing').each((_, el) => {
await delay(50); $(this).removeClass('resizing'); slideToggle(el, {
...getSlideToggleOptions(),
onAnimationEnd: function (el) {
el.classList.remove('resizing');
},
});
}); });
} }
else { else {
$('.openDrawer').not('.pinnedOpen').addClass('resizing').slideToggle(200, 'swing', async function () { $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => {
await delay(50); $(this).closest('.drawer-content').removeClass('resizing'); slideToggle(el, {
...getSlideToggleOptions(),
onAnimationEnd: function (el) {
el.closest('.drawer-content').classList.remove('resizing');
},
});
}); });
} }
@ -10086,20 +10113,21 @@ jQuery(async function () {
await getStatusNovel(); await getStatusNovel();
}); });
var button = $('#options_button'); const button = $('#options_button');
var menu = $('#options'); const menu = $('#options');
let isOptionsMenuVisible = false;
function showMenu() { function showMenu() {
showBookmarksButtons(); showBookmarksButtons();
// menu.stop()
menu.fadeIn(animation_duration); menu.fadeIn(animation_duration);
optionsPopper.update(); optionsPopper.update();
isOptionsMenuVisible = true;
} }
function hideMenu() { function hideMenu() {
// menu.stop();
menu.fadeOut(animation_duration); menu.fadeOut(animation_duration);
optionsPopper.update(); optionsPopper.update();
isOptionsMenuVisible = false;
} }
function isMouseOverButtonOrMenu() { function isMouseOverButtonOrMenu() {
@ -10107,26 +10135,15 @@ jQuery(async function () {
} }
button.on('click', function () { button.on('click', function () {
if (menu.is(':visible')) { if (isOptionsMenuVisible) {
hideMenu(); hideMenu();
} else { } else {
showMenu(); showMenu();
} }
}); });
button.on('blur', function () {
//delay to prevent menu hiding when mouse leaves button into menu
setTimeout(() => {
if (!isMouseOverButtonOrMenu()) { hideMenu(); }
}, 100);
});
menu.on('blur', function () {
//delay to prevent menu hide when mouseleaves menu into button
setTimeout(() => {
if (!isMouseOverButtonOrMenu()) { hideMenu(); }
}, 100);
});
$(document).on('click', function () { $(document).on('click', function () {
if (!isMouseOverButtonOrMenu() && menu.is(':visible')) { hideMenu(); } if (!isOptionsMenuVisible) return;
if (!isMouseOverButtonOrMenu()) { hideMenu(); }
}); });
/* $('#set_chat_scenario').on('click', setScenarioOverride); */ /* $('#set_chat_scenario').on('click', setScenarioOverride); */
@ -10522,22 +10539,28 @@ jQuery(async function () {
}); });
$(document).on('click', '.extraMesButtonsHint', function (e) { $(document).on('click', '.extraMesButtonsHint', function (e) {
const elmnt = e.target; const $hint = $(e.target);
$(elmnt).transition({ const $buttons = $hint.siblings('.extraMesButtons');
$hint.transition({
opacity: 0, opacity: 0,
duration: animation_duration, duration: animation_duration,
easing: 'ease-in-out', easing: animation_easing,
complete: function () {
$hint.hide();
$buttons
.addClass('visible')
.css({
opacity: 0,
display: 'flex',
})
.transition({
opacity: 1,
duration: animation_duration,
easing: animation_easing,
});
},
}); });
setTimeout(function () {
$(elmnt).hide();
$(elmnt).siblings('.extraMesButtons').css('opcacity', '0');
$(elmnt).siblings('.extraMesButtons').css('display', 'flex');
$(elmnt).siblings('.extraMesButtons').transition({
opacity: 1,
duration: animation_duration,
easing: 'ease-in-out',
});
}, animation_duration);
}); });
$(document).on('click', function (e) { $(document).on('click', function (e) {
@ -10548,23 +10571,36 @@ jQuery(async function () {
// Check if the click was outside the relevant elements // Check if the click was outside the relevant elements
if (!$(e.target).closest('.extraMesButtons, .extraMesButtonsHint').length) { if (!$(e.target).closest('.extraMesButtons, .extraMesButtonsHint').length) {
const $visibleButtons = $('.extraMesButtons.visible');
if (!$visibleButtons.length) {
return;
}
const $hiddenHints = $('.extraMesButtonsHint:hidden');
// Transition out the .extraMesButtons first // Transition out the .extraMesButtons first
$('.extraMesButtons:visible').transition({ $visibleButtons.transition({
opacity: 0, opacity: 0,
duration: animation_duration, duration: animation_duration,
easing: 'ease-in-out', easing: animation_easing,
complete: function () { complete: function () {
$(this).hide(); // Hide the .extraMesButtons after the transition // Hide the .extraMesButtons after the transition
$(this)
.hide()
.removeClass('visible');
// Transition the .extraMesButtonsHint back in // Transition the .extraMesButtonsHint back in
$('.extraMesButtonsHint:not(:visible)').show().transition({ $hiddenHints
opacity: .3, .show()
duration: animation_duration, .transition({
easing: 'ease-in-out', opacity: 0.3,
complete: function () { duration: animation_duration,
$(this).css('opacity', ''); easing: animation_easing,
}, complete: function () {
}); $(this).css('opacity', '');
},
});
}, },
}); });
} }
@ -10748,8 +10784,9 @@ jQuery(async function () {
} }
}); });
$('#export_button').on('click', function (e) { $('#export_button').on('click', function () {
$('#export_format_popup').toggle(); isExportPopupOpen = !isExportPopupOpen;
$('#export_format_popup').toggle(isExportPopupOpen);
exportPopper.update(); exportPopper.update();
}); });
@ -10760,6 +10797,10 @@ jQuery(async function () {
return; return;
} }
$('#export_format_popup').hide();
isExportPopupOpen = false;
exportPopper.update();
// Save before exporting // Save before exporting
await createOrEditCharacter(); await createOrEditCharacter();
const body = { format, avatar_url: characters[this_chid].avatar }; const body = { format, avatar_url: characters[this_chid].avatar };
@ -10781,9 +10822,6 @@ jQuery(async function () {
URL.revokeObjectURL(a.href); URL.revokeObjectURL(a.href);
document.body.removeChild(a); document.body.removeChild(a);
} }
$('#export_format_popup').hide();
}); });
//**************************CHAT IMPORT EXPORT*************************// //**************************CHAT IMPORT EXPORT*************************//
$('#chat_import_button').click(function () { $('#chat_import_button').click(function () {
@ -10855,15 +10893,18 @@ jQuery(async function () {
}); });
$(document).on('click', '.drawer-opener', doDrawerOpenClick); $(document).on('click', '.drawer-opener', doDrawerOpenClick);
$('.drawer-toggle').on('click', doNavbarIconClick); $('.drawer-toggle').on('click', doNavbarIconClick);
$('html').on('touchstart mousedown', function (e) { $('html').on('touchstart mousedown', function (e) {
var clickTarget = $(e.target); var clickTarget = $(e.target);
if ($('#export_format_popup').is(':visible') if (isExportPopupOpen
&& clickTarget.closest('#export_button').length == 0 && clickTarget.closest('#export_button').length == 0
&& clickTarget.closest('#export_format_popup').length == 0) { && clickTarget.closest('#export_format_popup').length == 0) {
$('#export_format_popup').hide(); $('#export_format_popup').hide();
isExportPopupOpen = false;
exportPopper.update();
} }
const forbiddenTargets = [ const forbiddenTargets = [
@ -10888,12 +10929,16 @@ jQuery(async function () {
if ($('.openDrawer').length !== 0) { if ($('.openDrawer').length !== 0) {
if (targetParentHasOpenDrawer === 0) { if (targetParentHasOpenDrawer === 0) {
//console.log($('.openDrawer').not('.pinnedOpen').length); //console.log($('.openDrawer').not('.pinnedOpen').length);
$('.openDrawer').not('.pinnedOpen').addClass('resizing').slideToggle(200, 'swing', function () { $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => {
$(this).closest('.drawer-content').removeClass('resizing'); slideToggle(el, {
...getSlideToggleOptions(),
onAnimationEnd: (el) => {
el.closest('.drawer-content').classList.remove('resizing');
},
});
}); });
$('.openIcon').not('.drawerPinnedOpen').toggleClass('closedIcon openIcon'); $('.openIcon').not('.drawerPinnedOpen').toggleClass('closedIcon openIcon');
$('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer'); $('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer');
} }
} }
} }
@ -11059,14 +11104,6 @@ jQuery(async function () {
case 'renameCharButton': case 'renameCharButton':
renameCharacter(); renameCharacter();
break; break;
/*case 'dupe_button':
DupeChar();
break;
case 'export_button':
$('#export_format_popup').toggle();
exportPopper.update();
break;
*/
case 'import_character_info': case 'import_character_info':
await importEmbeddedWorldInfo(); await importEmbeddedWorldInfo();
saveCharacterDebounced(); saveCharacterDebounced();

View File

@ -1,4 +1,4 @@
import { DOMPurify, Bowser } from '../lib.js'; import { DOMPurify, Bowser, slideToggle } from '../lib.js';
import { import {
characters, characters,
@ -19,6 +19,7 @@ import {
menu_type, menu_type,
substituteParams, substituteParams,
sendTextareaMessage, sendTextareaMessage,
getSlideToggleOptions,
} from '../script.js'; } from '../script.js';
import { import {
@ -748,8 +749,8 @@ export function initRossMods() {
$(RightNavDrawerIcon).removeClass('drawerPinnedOpen'); $(RightNavDrawerIcon).removeClass('drawerPinnedOpen');
if ($(RightNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) { if ($(RightNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) {
$(RightNavPanel).slideToggle(200, 'swing'); slideToggle(RightNavPanel, getSlideToggleOptions());
$(RightNavDrawerIcon).toggleClass('openIcon closedIcon'); $(RightNavDrawerIcon).toggleClass('closedIcon openIcon');
$(RightNavPanel).toggleClass('openDrawer closedDrawer'); $(RightNavPanel).toggleClass('openDrawer closedDrawer');
} }
} }
@ -766,8 +767,8 @@ export function initRossMods() {
$(LeftNavDrawerIcon).removeClass('drawerPinnedOpen'); $(LeftNavDrawerIcon).removeClass('drawerPinnedOpen');
if ($(LeftNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) { if ($(LeftNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) {
$(LeftNavPanel).slideToggle(200, 'swing'); slideToggle(LeftNavPanel, getSlideToggleOptions());
$(LeftNavDrawerIcon).toggleClass('openIcon closedIcon'); $(LeftNavDrawerIcon).toggleClass('closedIcon openIcon');
$(LeftNavPanel).toggleClass('openDrawer closedDrawer'); $(LeftNavPanel).toggleClass('openDrawer closedDrawer');
} }
} }
@ -786,8 +787,8 @@ export function initRossMods() {
if ($(WorldInfo).hasClass('openDrawer') && $('.openDrawer').length > 1) { if ($(WorldInfo).hasClass('openDrawer') && $('.openDrawer').length > 1) {
console.debug('closing WI after lock removal'); console.debug('closing WI after lock removal');
$(WorldInfo).slideToggle(200, 'swing'); slideToggle(WorldInfo, getSlideToggleOptions());
$(WIDrawerIcon).toggleClass('openIcon closedIcon'); $(WIDrawerIcon).toggleClass('closedIcon openIcon');
$(WorldInfo).toggleClass('openDrawer closedDrawer'); $(WorldInfo).toggleClass('openDrawer closedDrawer');
} }
} }

View File

@ -417,26 +417,30 @@ async function addExtensionsButtonAndMenu() {
const button = $('#extensionsMenuButton'); const button = $('#extensionsMenuButton');
const dropdown = $('#extensionsMenu'); const dropdown = $('#extensionsMenu');
//dropdown.hide(); let isDropdownVisible = false;
let popper = Popper.createPopper(button.get(0), dropdown.get(0), { let popper = Popper.createPopper(button.get(0), dropdown.get(0), {
placement: 'top-start', placement: 'top-start',
}); });
$(button).on('click', function () { $(button).on('click', function () {
if (dropdown.is(':visible')) { if (isDropdownVisible) {
dropdown.fadeOut(animation_duration); dropdown.fadeOut(animation_duration);
isDropdownVisible = false;
} else { } else {
dropdown.fadeIn(animation_duration); dropdown.fadeIn(animation_duration);
isDropdownVisible = true;
} }
popper.update(); popper.update();
}); });
$('html').on('click', function (e) { $('html').on('click', function (e) {
if (!isDropdownVisible) return;
const clickTarget = $(e.target); const clickTarget = $(e.target);
const noCloseTargets = ['#sd_gen', '#extensionsMenuButton', '#roll_dice']; const noCloseTargets = ['#sd_gen', '#extensionsMenuButton', '#roll_dice'];
if (dropdown.is(':visible') && !noCloseTargets.some(id => clickTarget.closest(id).length > 0)) { if (!noCloseTargets.some(id => clickTarget.closest(id).length > 0)) {
$(dropdown).fadeOut(animation_duration); dropdown.fadeOut(animation_duration);
isDropdownVisible = false;
} }
}); });
} }

View File

@ -2874,6 +2874,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
.mes_block .ch_name { .mes_block .ch_name {
max-width: 100%; max-width: 100%;
min-height: 22px;
} }
/*applies to both groups and solos chars in the char list*/ /*applies to both groups and solos chars in the char list*/
@ -4043,7 +4044,7 @@ input[type="range"]::-webkit-slider-thumb {
.mes_button, .mes_button,
.extraMesButtons>div { .extraMesButtons>div {
cursor: pointer; cursor: pointer;
transition: 0.3s ease-in-out; transition: opacity 0.2s ease-in-out;
filter: drop-shadow(0px 0px 2px black); filter: drop-shadow(0px 0px 2px black);
opacity: 0.3; opacity: 0.3;
padding: 1px 3px; padding: 1px 3px;