diff --git a/package-lock.json b/package-lock.json index 2419fe002..fa23bf5a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,6 +63,7 @@ "showdown": "^2.1.0", "sillytavern-transformers": "2.14.6", "simple-git": "^3.19.1", + "slidetoggle": "^4.0.0", "tiktoken": "^1.0.16", "vectra": "^0.2.2", "wavefile": "^11.0.0", @@ -6531,6 +6532,12 @@ "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==", "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": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", diff --git a/package.json b/package.json index 777d99076..26d979a7f 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "showdown": "^2.1.0", "sillytavern-transformers": "2.14.6", "simple-git": "^3.19.1", + "slidetoggle": "^4.0.0", "tiktoken": "^1.0.16", "vectra": "^0.2.2", "wavefile": "^11.0.0", diff --git a/public/lib.js b/public/lib.js index 2870d018d..4c6f318af 100644 --- a/public/lib.js +++ b/public/lib.js @@ -19,6 +19,7 @@ import seedrandom from 'seedrandom'; import * as Popper from '@popperjs/core'; import droll from 'droll'; import morphdom from 'morphdom'; +import { toggle as slideToggle } from 'slidetoggle'; /** * Expose the libraries to the 'window' object. @@ -94,6 +95,7 @@ export default { Popper, droll, morphdom, + slideToggle, }; export { @@ -115,4 +117,5 @@ export { Popper, droll, morphdom, + slideToggle, }; diff --git a/public/script.js b/public/script.js index 312418487..04eb8bc09 100644 --- a/public/script.js +++ b/public/script.js @@ -10,6 +10,7 @@ import { SVGInject, Popper, initLibraryShims, + slideToggle, default as libs, } 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'), { placement: 'left', }); +let isExportPopupOpen = false; // Saved here for performance reasons 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) => { xhr.setRequestHeader('X-CSRF-Token', token); }); @@ -9209,40 +9218,48 @@ function doDrawerOpenClick() { * @returns {void} */ function doNavbarIconClick() { - var icon = $(this).find('.drawer-icon'); - var drawer = $(this).parent().find('.drawer-content'); + const icon = $(this).find('.drawer-icon'); + const drawer = $(this).parent().find('.drawer-content'); if (drawer.hasClass('resizing')) { return; } - var drawerWasOpenAlready = $(this).parent().find('.drawer-content').hasClass('openDrawer'); - let targetDrawerID = $(this).parent().find('.drawer-content').attr('id'); + const drawerWasOpenAlready = $(this).parent().find('.drawer-content').hasClass('openDrawer'); + const targetDrawerID = $(this).parent().find('.drawer-content').attr('id'); const pinnedDrawerClicked = drawer.hasClass('pinnedOpen'); if (!drawerWasOpenAlready) { //to open the drawer - $('.openDrawer').not('.pinnedOpen').addClass('resizing').slideToggle(200, 'swing', async function () { - await delay(50); $(this).closest('.drawer-content').removeClass('resizing'); + $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => { + 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'); icon.toggleClass('openIcon closedIcon'); drawer.toggleClass('openDrawer closedDrawer'); //console.log(targetDrawerID); if (targetDrawerID === 'right-nav-panel') { - $(this).closest('.drawer').find('.drawer-content').addClass('resizing').slideToggle({ - duration: 200, - easing: 'swing', - start: function () { - jQuery(this).css('display', 'flex'); //flex needed to make charlist scroll - }, - complete: async function () { - favsToHotswap(); - await delay(50); - $(this).closest('.drawer-content').removeClass('resizing'); - $('#rm_print_characters_block').trigger('scroll'); - }, + $(this).closest('.drawer').find('.drawer-content').addClass('resizing').each((_, el) => { + slideToggle(el, { + ...getSlideToggleOptions(), + elementDisplayStyle: 'flex', + onAnimationEnd: function (el) { + el.closest('.drawer-content').classList.remove('resizing'); + favsToHotswap(); + $('#rm_print_characters_block').trigger('scroll'); + }, + }); }); } else { - $(this).closest('.drawer').find('.drawer-content').addClass('resizing').slideToggle(200, 'swing', async function () { - await delay(50); $(this).closest('.drawer-content').removeClass('resizing'); + $(this).closest('.drawer').find('.drawer-content').addClass('resizing').each((_, el) => { + slideToggle(el, { + ...getSlideToggleOptions(), + onAnimationEnd: function (el) { + el.closest('.drawer-content').classList.remove('resizing'); + }, + }); }); } @@ -9258,13 +9275,23 @@ function doNavbarIconClick() { icon.toggleClass('closedIcon openIcon'); if (pinnedDrawerClicked) { - $(drawer).addClass('resizing').slideToggle(200, 'swing', async function () { - await delay(50); $(this).removeClass('resizing'); + $(drawer).addClass('resizing').each((_, el) => { + slideToggle(el, { + ...getSlideToggleOptions(), + onAnimationEnd: function (el) { + el.classList.remove('resizing'); + }, + }); }); } else { - $('.openDrawer').not('.pinnedOpen').addClass('resizing').slideToggle(200, 'swing', async function () { - await delay(50); $(this).closest('.drawer-content').removeClass('resizing'); + $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => { + slideToggle(el, { + ...getSlideToggleOptions(), + onAnimationEnd: function (el) { + el.closest('.drawer-content').classList.remove('resizing'); + }, + }); }); } @@ -10086,20 +10113,21 @@ jQuery(async function () { await getStatusNovel(); }); - var button = $('#options_button'); - var menu = $('#options'); + const button = $('#options_button'); + const menu = $('#options'); + let isOptionsMenuVisible = false; function showMenu() { showBookmarksButtons(); - // menu.stop() menu.fadeIn(animation_duration); optionsPopper.update(); + isOptionsMenuVisible = true; } function hideMenu() { - // menu.stop(); menu.fadeOut(animation_duration); optionsPopper.update(); + isOptionsMenuVisible = false; } function isMouseOverButtonOrMenu() { @@ -10107,26 +10135,15 @@ jQuery(async function () { } button.on('click', function () { - if (menu.is(':visible')) { + if (isOptionsMenuVisible) { hideMenu(); } else { 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 () { - if (!isMouseOverButtonOrMenu() && menu.is(':visible')) { hideMenu(); } + if (!isOptionsMenuVisible) return; + if (!isMouseOverButtonOrMenu()) { hideMenu(); } }); /* $('#set_chat_scenario').on('click', setScenarioOverride); */ @@ -10522,22 +10539,28 @@ jQuery(async function () { }); $(document).on('click', '.extraMesButtonsHint', function (e) { - const elmnt = e.target; - $(elmnt).transition({ + const $hint = $(e.target); + const $buttons = $hint.siblings('.extraMesButtons'); + + $hint.transition({ opacity: 0, 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) { @@ -10548,23 +10571,36 @@ jQuery(async function () { // Check if the click was outside the relevant elements if (!$(e.target).closest('.extraMesButtons, .extraMesButtonsHint').length) { + const $visibleButtons = $('.extraMesButtons.visible'); + + if (!$visibleButtons.length) { + return; + } + + const $hiddenHints = $('.extraMesButtonsHint:hidden'); + // Transition out the .extraMesButtons first - $('.extraMesButtons:visible').transition({ + $visibleButtons.transition({ opacity: 0, duration: animation_duration, - easing: 'ease-in-out', + easing: animation_easing, 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 - $('.extraMesButtonsHint:not(:visible)').show().transition({ - opacity: .3, - duration: animation_duration, - easing: 'ease-in-out', - complete: function () { - $(this).css('opacity', ''); - }, - }); + $hiddenHints + .show() + .transition({ + opacity: 0.3, + duration: animation_duration, + easing: animation_easing, + complete: function () { + $(this).css('opacity', ''); + }, + }); }, }); } @@ -10748,8 +10784,9 @@ jQuery(async function () { } }); - $('#export_button').on('click', function (e) { - $('#export_format_popup').toggle(); + $('#export_button').on('click', function () { + isExportPopupOpen = !isExportPopupOpen; + $('#export_format_popup').toggle(isExportPopupOpen); exportPopper.update(); }); @@ -10760,6 +10797,10 @@ jQuery(async function () { return; } + $('#export_format_popup').hide(); + isExportPopupOpen = false; + exportPopper.update(); + // Save before exporting await createOrEditCharacter(); const body = { format, avatar_url: characters[this_chid].avatar }; @@ -10781,9 +10822,6 @@ jQuery(async function () { URL.revokeObjectURL(a.href); document.body.removeChild(a); } - - - $('#export_format_popup').hide(); }); //**************************CHAT IMPORT EXPORT*************************// $('#chat_import_button').click(function () { @@ -10855,15 +10893,18 @@ jQuery(async function () { }); $(document).on('click', '.drawer-opener', doDrawerOpenClick); + $('.drawer-toggle').on('click', doNavbarIconClick); $('html').on('touchstart mousedown', function (e) { var clickTarget = $(e.target); - if ($('#export_format_popup').is(':visible') + if (isExportPopupOpen && clickTarget.closest('#export_button').length == 0 && clickTarget.closest('#export_format_popup').length == 0) { $('#export_format_popup').hide(); + isExportPopupOpen = false; + exportPopper.update(); } const forbiddenTargets = [ @@ -10888,12 +10929,16 @@ jQuery(async function () { if ($('.openDrawer').length !== 0) { if (targetParentHasOpenDrawer === 0) { //console.log($('.openDrawer').not('.pinnedOpen').length); - $('.openDrawer').not('.pinnedOpen').addClass('resizing').slideToggle(200, 'swing', function () { - $(this).closest('.drawer-content').removeClass('resizing'); + $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => { + slideToggle(el, { + ...getSlideToggleOptions(), + onAnimationEnd: (el) => { + el.closest('.drawer-content').classList.remove('resizing'); + }, + }); }); $('.openIcon').not('.drawerPinnedOpen').toggleClass('closedIcon openIcon'); $('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer'); - } } } @@ -11059,14 +11104,6 @@ jQuery(async function () { case 'renameCharButton': renameCharacter(); break; - /*case 'dupe_button': - DupeChar(); - break; - case 'export_button': - $('#export_format_popup').toggle(); - exportPopper.update(); - break; - */ case 'import_character_info': await importEmbeddedWorldInfo(); saveCharacterDebounced(); diff --git a/public/scripts/RossAscends-mods.js b/public/scripts/RossAscends-mods.js index fb55e42dd..750e9cdd2 100644 --- a/public/scripts/RossAscends-mods.js +++ b/public/scripts/RossAscends-mods.js @@ -1,4 +1,4 @@ -import { DOMPurify, Bowser } from '../lib.js'; +import { DOMPurify, Bowser, slideToggle } from '../lib.js'; import { characters, @@ -19,6 +19,7 @@ import { menu_type, substituteParams, sendTextareaMessage, + getSlideToggleOptions, } from '../script.js'; import { @@ -748,8 +749,8 @@ export function initRossMods() { $(RightNavDrawerIcon).removeClass('drawerPinnedOpen'); if ($(RightNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) { - $(RightNavPanel).slideToggle(200, 'swing'); - $(RightNavDrawerIcon).toggleClass('openIcon closedIcon'); + slideToggle(RightNavPanel, getSlideToggleOptions()); + $(RightNavDrawerIcon).toggleClass('closedIcon openIcon'); $(RightNavPanel).toggleClass('openDrawer closedDrawer'); } } @@ -766,8 +767,8 @@ export function initRossMods() { $(LeftNavDrawerIcon).removeClass('drawerPinnedOpen'); if ($(LeftNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) { - $(LeftNavPanel).slideToggle(200, 'swing'); - $(LeftNavDrawerIcon).toggleClass('openIcon closedIcon'); + slideToggle(LeftNavPanel, getSlideToggleOptions()); + $(LeftNavDrawerIcon).toggleClass('closedIcon openIcon'); $(LeftNavPanel).toggleClass('openDrawer closedDrawer'); } } @@ -786,8 +787,8 @@ export function initRossMods() { if ($(WorldInfo).hasClass('openDrawer') && $('.openDrawer').length > 1) { console.debug('closing WI after lock removal'); - $(WorldInfo).slideToggle(200, 'swing'); - $(WIDrawerIcon).toggleClass('openIcon closedIcon'); + slideToggle(WorldInfo, getSlideToggleOptions()); + $(WIDrawerIcon).toggleClass('closedIcon openIcon'); $(WorldInfo).toggleClass('openDrawer closedDrawer'); } } diff --git a/public/scripts/extensions.js b/public/scripts/extensions.js index 0e6609322..789540349 100644 --- a/public/scripts/extensions.js +++ b/public/scripts/extensions.js @@ -417,26 +417,30 @@ async function addExtensionsButtonAndMenu() { const button = $('#extensionsMenuButton'); const dropdown = $('#extensionsMenu'); - //dropdown.hide(); + let isDropdownVisible = false; let popper = Popper.createPopper(button.get(0), dropdown.get(0), { placement: 'top-start', }); $(button).on('click', function () { - if (dropdown.is(':visible')) { + if (isDropdownVisible) { dropdown.fadeOut(animation_duration); + isDropdownVisible = false; } else { dropdown.fadeIn(animation_duration); + isDropdownVisible = true; } popper.update(); }); $('html').on('click', function (e) { + if (!isDropdownVisible) return; const clickTarget = $(e.target); const noCloseTargets = ['#sd_gen', '#extensionsMenuButton', '#roll_dice']; - if (dropdown.is(':visible') && !noCloseTargets.some(id => clickTarget.closest(id).length > 0)) { - $(dropdown).fadeOut(animation_duration); + if (!noCloseTargets.some(id => clickTarget.closest(id).length > 0)) { + dropdown.fadeOut(animation_duration); + isDropdownVisible = false; } }); } diff --git a/public/style.css b/public/style.css index 3246b2ca2..c9033bcad 100644 --- a/public/style.css +++ b/public/style.css @@ -2874,6 +2874,7 @@ input[type=search]:focus::-webkit-search-cancel-button { .mes_block .ch_name { max-width: 100%; + min-height: 22px; } /*applies to both groups and solos chars in the char list*/ @@ -4043,7 +4044,7 @@ input[type="range"]::-webkit-slider-thumb { .mes_button, .extraMesButtons>div { cursor: pointer; - transition: 0.3s ease-in-out; + transition: opacity 0.2s ease-in-out; filter: drop-shadow(0px 0px 2px black); opacity: 0.3; padding: 1px 3px;