mirror of
				https://github.com/SillyTavern/SillyTavern.git
				synced 2025-06-05 21:59:27 +02:00 
			
		
		
		
	User persona management block. Persona descriptions. Dummy personas. Change persona avatar
This commit is contained in:
		| @@ -2001,7 +2001,7 @@ | |||||||
|  |  | ||||||
|         <div id="user-settings-button" class="drawer"> |         <div id="user-settings-button" class="drawer"> | ||||||
|             <div class="drawer-toggle"> |             <div class="drawer-toggle"> | ||||||
|                 <div class="drawer-icon fa-solid fa-face-smile closedIcon" title="User Settings"></div> |                 <div class="drawer-icon fa-solid fa-user-cog closedIcon" title="User Settings"></div> | ||||||
|             </div> |             </div> | ||||||
|             <div id="user-settings-block" class="drawer-content closedDrawer"> |             <div id="user-settings-block" class="drawer-content closedDrawer"> | ||||||
|                 <div class="flex-container wide100p alignitemscenter spaceBetween"> |                 <div class="flex-container wide100p alignitemscenter spaceBetween"> | ||||||
| @@ -2009,7 +2009,7 @@ | |||||||
|                     <div id="version_display"></div> |                     <div id="version_display"></div> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div class="flex-container spaceEvenly"> |                 <div class="flex-container spaceEvenly"> | ||||||
|                     <div name="UI Customization" class="flex-container drawer25pWidth"> |                     <div name="UI Customization" class="flex-container drawer33pWidth"> | ||||||
|                         <div class="ui-settings"> |                         <div class="ui-settings"> | ||||||
|                             <h4><span data-i18n="UI Customization">UI Customization</span></h4> |                             <h4><span data-i18n="UI Customization">UI Customization</span></h4> | ||||||
|                             <div> |                             <div> | ||||||
| @@ -2098,13 +2098,25 @@ | |||||||
|                                     <span data-i18n="Movable UI Panels">Movable UI Panels</span> |                                     <span data-i18n="Movable UI Panels">Movable UI Panels</span> | ||||||
|                                 </label> |                                 </label> | ||||||
|  |  | ||||||
|  |                                 <div class="flex-container flexFlowColumn"> | ||||||
|  |                                     <h4 data-i18n="Send on Enter"> | ||||||
|  |                                         Send on Enter | ||||||
|  |                                     </h4> | ||||||
|  |                                     <select id="send_on_enter"> | ||||||
|  |                                         <option value="-1"><span data-i18n="Always disabled">Always disabled</span></option> | ||||||
|  |                                         <option value="0"><span data-i18n="Automatic (desktop)">Automatic (desktop)</span> | ||||||
|  |                                         </option> | ||||||
|  |                                         <option value="1"><span data-i18n="Always enabled">Always enabled</span></option> | ||||||
|  |                                     </select> | ||||||
|  |                                 </div> | ||||||
|  |  | ||||||
|                                 <div id="movingUIreset" class="menu_button whitespacenowrap" data-i18n="Reset Panels"> |                                 <div id="movingUIreset" class="menu_button whitespacenowrap" data-i18n="Reset Panels"> | ||||||
|                                     Reset Panels</div> |                                     Reset Panels</div> | ||||||
|                             </div> |                             </div> | ||||||
|                         </div> |                         </div> | ||||||
|  |  | ||||||
|                     </div> |                     </div> | ||||||
|                     <div id="UI-Theme-Block" class="flex-container flexFlowColumn drawer25pWidth"> |                     <div id="UI-Theme-Block" class="flex-container flexFlowColumn drawer33pWidth"> | ||||||
|                         <div id="color-picker-block" class="flex-container flexFlowColumn"> |                         <div id="color-picker-block" class="flex-container flexFlowColumn"> | ||||||
|                             <h4><span data-i18n="UI Colors">UI Colors</span></h4> |                             <h4><span data-i18n="UI Colors">UI Colors</span></h4> | ||||||
|                             <div class="flex-container"> |                             <div class="flex-container"> | ||||||
| @@ -2201,7 +2213,7 @@ | |||||||
|                         </div> |                         </div> | ||||||
|  |  | ||||||
|                     </div> |                     </div> | ||||||
|                     <div id="power-user-options-block" class="flex-container drawer25pWidth"> |                     <div id="power-user-options-block" class="flex-container drawer33pWidth"> | ||||||
|                         <div id="power-user-option-checkboxes"> |                         <div id="power-user-option-checkboxes"> | ||||||
|                             <h4 data-i18n="Power User Options">Power User Options</h4> |                             <h4 data-i18n="Power User Options">Power User Options</h4> | ||||||
|                             <label for="swipes-checkbox"> |                             <label for="swipes-checkbox"> | ||||||
| @@ -2253,36 +2265,12 @@ | |||||||
|                                 <span data-i18n="Never Resize Avatars">Never Resize Avatars</span> |                                 <span data-i18n="Never Resize Avatars">Never Resize Avatars</span> | ||||||
|                             </label> |                             </label> | ||||||
|  |  | ||||||
|                             <div id="reload_chat" class="menu_button whitespacenowrap" data-i18n="Reload Chat"> |  | ||||||
|                                 Reload Chat |  | ||||||
|                             </div> |  | ||||||
|                         </div> |  | ||||||
|  |  | ||||||
|                     </div> |  | ||||||
|  |  | ||||||
|                     <div name="NameAndAvatar" class="flex-container flexFlowColumn drawer25pWidth"> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                             <div class="inline-drawer wide100p flexFlowColumn"> |                             <div class="inline-drawer wide100p flexFlowColumn"> | ||||||
|  |  | ||||||
|                             <div class="flex-container flexFlowColumn"> |  | ||||||
|                                 <h4 data-i18n="Send on Enter"> |  | ||||||
|                                     Send on Enter |  | ||||||
|                                 </h4> |  | ||||||
|                                 <select id="send_on_enter"> |  | ||||||
|                                     <option value="-1"><span data-i18n="Always disabled">Always disabled</span></option> |  | ||||||
|                                     <option value="0"><span data-i18n="Automatic (desktop)">Automatic (desktop)</span> |  | ||||||
|                                     </option> |  | ||||||
|                                     <option value="1"><span data-i18n="Always enabled">Always enabled</span></option> |  | ||||||
|                                 </select> |  | ||||||
|                             </div> |  | ||||||
|  |  | ||||||
|                                 <div class="inline-drawer-toggle inline-drawer-header"> |                                 <div class="inline-drawer-toggle inline-drawer-header"> | ||||||
|                                     <b>Auto-swipe</b> |                                     <b>Auto-swipe</b> | ||||||
|                                     <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> |                                     <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> | ||||||
|                                 </div> |                                 </div> | ||||||
|                                 <div class="inline-drawer-content"> |                                 <div class="inline-drawer-content"> | ||||||
|  |  | ||||||
|                                     <label class="checkbox_label" for="auto_swipe"> |                                     <label class="checkbox_label" for="auto_swipe"> | ||||||
|                                         <input id="auto_swipe" type="checkbox" /> |                                         <input id="auto_swipe" type="checkbox" /> | ||||||
|                                         Enabled |                                         Enabled | ||||||
| @@ -2298,28 +2286,11 @@ | |||||||
|                                 </div> |                                 </div> | ||||||
|                             </div> |                             </div> | ||||||
|  |  | ||||||
|                         <div name="NameChanger"> |                             <div id="reload_chat" class="menu_button whitespacenowrap" data-i18n="Reload Chat"> | ||||||
|                             <h4 data-i18n="Name">Name</h4> |                                 Reload Chat | ||||||
|                             <div class="change_name"> |  | ||||||
|                                 <input id="your_name" name="your_name" placeholder="Enter your name" class="text_pole wide100p" maxlength="50" value="" autocomplete="off"> |  | ||||||
|                                 <div id="your_name_button" class="menu_button fa-solid fa-check" title="Click to set a new User Name"> |  | ||||||
|                             </div> |                             </div> | ||||||
|                                 <div id="lock_user_name" class="menu_button fa-solid fa-unlock" title="Click to lock your selected persona to the current chat. Click again to remove the lock."> |  | ||||||
|                                 </div> |  | ||||||
|                                 <div id="sync_name_button" class="menu_button fa-solid fa-sync" title="Click to set user name for all messages"> |  | ||||||
|                                 </div> |  | ||||||
|                             </div> |  | ||||||
|                         </div> |  | ||||||
|                         <div name="AvatarSelector"> |  | ||||||
|                             <h4 data-i18n="Your Avatar">Your Persona</h4> |  | ||||||
|                             <div id="user_avatar_block"> |  | ||||||
|                                 <div class="avatar_upload">+</div> |  | ||||||
|                         </div> |                         </div> | ||||||
|  |  | ||||||
|                             <form id="form_upload_avatar" action="javascript:void(null);" method="post" enctype="multipart/form-data"> |  | ||||||
|                                 <input type="file" id="avatar_upload_file" accept="image/*" name="avatar"> |  | ||||||
|                             </form> |  | ||||||
|                         </div> |  | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
| @@ -2383,6 +2354,60 @@ | |||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|  |  | ||||||
|  |         <div id="persona-management-button" class="drawer"> | ||||||
|  |             <div class="drawer-toggle"> | ||||||
|  |                 <div class="drawer-icon fa-solid fa-face-smile closedIcon" title="Persona Management"></div> | ||||||
|  |             </div> | ||||||
|  |             <div class="drawer-content closedDrawer"> | ||||||
|  |                 <div class="flex-container wide100p alignitemscenter spaceBetween"> | ||||||
|  |                     <h3><span data-i18n="Persona Management">Persona Management</span></h3> | ||||||
|  |  | ||||||
|  |                     <div id="persona-management-block" class="flex-container wide100p"> | ||||||
|  |                         <div class="flex1"> | ||||||
|  |                             <h4 data-i18n="Name">Name</h4> | ||||||
|  |                             <div class="change_name"> | ||||||
|  |                                 <input id="your_name" name="your_name" placeholder="Enter your name" class="text_pole wide100p" maxlength="50" value="" autocomplete="off"> | ||||||
|  |                                 <div id="your_name_button" class="menu_button fa-solid fa-check" title="Click to set a new User Name"> | ||||||
|  |                                 </div> | ||||||
|  |                                 <div id="lock_user_name" class="menu_button fa-solid fa-unlock" title="Click to lock your selected persona to the current chat. Click again to remove the lock."> | ||||||
|  |                                 </div> | ||||||
|  |                                 <div id="sync_name_button" class="menu_button fa-solid fa-sync" title="Click to set user name for all messages"> | ||||||
|  |                                 </div> | ||||||
|  |                             </div> | ||||||
|  |                             <div> | ||||||
|  |                                 <h4 data-i18n="Name">Persona Description</h4> | ||||||
|  |                                 <textarea id="persona_description" name="persona_description" placeholder="Example:
[{{user}} is a 28-year-old Romanian cat girl.]" class="text_pole textarea_compact" maxlength="5000" value="" autocomplete="off" rows="4"></textarea> | ||||||
|  |                                 <label for="persona_description_position">Position:</label> | ||||||
|  |                                 <select id="persona_description_position"> | ||||||
|  |                                     <option value="0">Before Character Card</option> | ||||||
|  |                                     <option value="1">After Character Card</option> | ||||||
|  |                                     <option value="2">Top of Author's Note</option> | ||||||
|  |                                     <option value="3">Bottom of Author's Note</option> | ||||||
|  |                                 </select> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                         <div class="flex1"> | ||||||
|  |                             <h4 data-i18n="Your Avatar" class="title_restorable"> | ||||||
|  |                                 <span>Your Persona</span> | ||||||
|  |                                 <div id="create_dummy_persona" class="menu_button menu_button_icon" title="Create a dummy persona"> | ||||||
|  |                                     <i class="fa-solid fa-person-circle-question fa-fw"></i> | ||||||
|  |                                     <span>Blank</span> | ||||||
|  |                                 </div> | ||||||
|  |                             </h4> | ||||||
|  |                             <div id="user_avatar_block"> | ||||||
|  |                                 <div class="avatar_upload">+</div> | ||||||
|  |                             </div> | ||||||
|  |  | ||||||
|  |                             <form id="form_upload_avatar" action="javascript:void(null);" method="post" enctype="multipart/form-data"> | ||||||
|  |                                 <input type="file" id="avatar_upload_file" accept="image/*" name="avatar"> | ||||||
|  |                                 <input type="hidden" id="avatar_upload_overwrite" name="overwrite_name" value=""> | ||||||
|  |                             </form> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|         <div id="rightNavHolder" class="drawer"> |         <div id="rightNavHolder" class="drawer"> | ||||||
|             <div id="unimportantYes" class="drawer-toggle drawer-header"> |             <div id="unimportantYes" class="drawer-toggle drawer-header"> | ||||||
|                 <div id="rightNavDrawerIcon" class="drawer-icon fa-solid fa-address-card  closedIcon" title="Character Management"> |                 <div id="rightNavDrawerIcon" class="drawer-icon fa-solid fa-address-card  closedIcon" title="Character Management"> | ||||||
| @@ -3369,8 +3394,8 @@ | |||||||
|                 </button> |                 </button> | ||||||
|             </div> |             </div> | ||||||
|             <div class="avatar-buttons avatar-buttons-bottom"> |             <div class="avatar-buttons avatar-buttons-bottom"> | ||||||
|                 <button class="menu_button set_user_info" title="Under construction"> |                 <button class="menu_button set_persona_image" title="Change persona image"> | ||||||
|                     <i class="fa-solid fa-circle-user"></i> |                     <i class="fa-solid fa-image"></i> | ||||||
|                 </button> |                 </button> | ||||||
|  |  | ||||||
|                 <button class="menu_button delete_avatar" title="Delete persona"> |                 <button class="menu_button delete_avatar" title="Delete persona"> | ||||||
|   | |||||||
							
								
								
									
										259
									
								
								public/script.js
									
									
									
									
									
								
							
							
						
						
									
										259
									
								
								public/script.js
									
									
									
									
									
								
							| @@ -69,6 +69,7 @@ import { | |||||||
|     formatInstructModeChat, |     formatInstructModeChat, | ||||||
|     formatInstructStoryString, |     formatInstructStoryString, | ||||||
|     formatInstructModePrompt, |     formatInstructModePrompt, | ||||||
|  |     persona_description_positions, | ||||||
| } from "./scripts/power-user.js"; | } from "./scripts/power-user.js"; | ||||||
|  |  | ||||||
| import { | import { | ||||||
| @@ -151,7 +152,7 @@ import { | |||||||
| import { EventEmitter } from './scripts/eventemitter.js'; | import { EventEmitter } from './scripts/eventemitter.js'; | ||||||
| import { context_settings, loadContextTemplatesFromSettings } from "./scripts/context-template.js"; | import { context_settings, loadContextTemplatesFromSettings } from "./scripts/context-template.js"; | ||||||
| import { markdownExclusionExt } from "./scripts/showdown-exclusion.js"; | import { markdownExclusionExt } from "./scripts/showdown-exclusion.js"; | ||||||
| import { setFloatingPrompt } from "./scripts/extensions/floating-prompt/index.js"; | import { NOTE_MODULE_NAME, metadata_keys, setFloatingPrompt, shouldWIAddPrompt } from "./scripts/extensions/floating-prompt/index.js"; | ||||||
|  |  | ||||||
| //exporting functions and vars for mods | //exporting functions and vars for mods | ||||||
| export { | export { | ||||||
| @@ -1554,6 +1555,28 @@ function cleanGroupMessage(getMessage) { | |||||||
|     return getMessage; |     return getMessage; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function getPersonaDescription(storyString) { | ||||||
|  |     if (!power_user.persona_description) { | ||||||
|  |         return storyString; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     switch (power_user.persona_description_position) { | ||||||
|  |         case persona_description_positions.BEFORE_CHAR: | ||||||
|  |             return `${power_user.persona_description}\n${storyString}`; | ||||||
|  |         case persona_description_positions.AFTER_CHAR: | ||||||
|  |             return `${storyString}\n${power_user.persona_description}`; | ||||||
|  |         default: | ||||||
|  |             if (shouldWIAddPrompt) { | ||||||
|  |                 const originalAN = extension_prompts[NOTE_MODULE_NAME].value | ||||||
|  |                 const ANWithDesc = persona_description_positions.TOP_AN | ||||||
|  |                     ? `${power_user.persona_description}\n${originalAN}` | ||||||
|  |                     : `${originalAN}\n${power_user.persona_description}`; | ||||||
|  |                 setExtensionPrompt(NOTE_MODULE_NAME, ANWithDesc, chat_metadata[metadata_keys.position], chat_metadata[metadata_keys.depth]); | ||||||
|  |             } | ||||||
|  |             return storyString; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| function getAllExtensionPrompts() { | function getAllExtensionPrompts() { | ||||||
|     const value = Object |     const value = Object | ||||||
|         .values(extension_prompts) |         .values(extension_prompts) | ||||||
| @@ -1998,12 +2021,6 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, | |||||||
|             console.log(`Core/all messages: ${coreChat.length}/${chat.length}`); |             console.log(`Core/all messages: ${coreChat.length}/${chat.length}`); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (main_api === 'openai') { |  | ||||||
|             message_already_generated = ''; // OpenAI doesn't have multigen |  | ||||||
|             setOpenAIMessages(coreChat); |  | ||||||
|             setOpenAIMessageExamples(mesExamplesArray); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         let storyString = ""; |         let storyString = ""; | ||||||
|  |  | ||||||
|         if (is_pygmalion) { |         if (is_pygmalion) { | ||||||
| @@ -2062,11 +2079,19 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject, | |||||||
|         setFloatingPrompt(); |         setFloatingPrompt(); | ||||||
|         // Add WI to prompt (and also inject WI to AN value via hijack) |         // Add WI to prompt (and also inject WI to AN value via hijack) | ||||||
|         let { worldInfoString, worldInfoBefore, worldInfoAfter } = await getWorldInfoPrompt(chat2, this_max_context); |         let { worldInfoString, worldInfoBefore, worldInfoAfter } = await getWorldInfoPrompt(chat2, this_max_context); | ||||||
|  |         // Add persona description to prompt | ||||||
|  |         storyString = getPersonaDescription(storyString); | ||||||
|         // Call combined AN into Generate |         // Call combined AN into Generate | ||||||
|         let allAnchors = getAllExtensionPrompts(); |         let allAnchors = getAllExtensionPrompts(); | ||||||
|         const afterScenarioAnchor = getExtensionPrompt(extension_prompt_types.AFTER_SCENARIO); |         const afterScenarioAnchor = getExtensionPrompt(extension_prompt_types.AFTER_SCENARIO); | ||||||
|         let zeroDepthAnchor = getExtensionPrompt(extension_prompt_types.IN_CHAT, 0, ' '); |         let zeroDepthAnchor = getExtensionPrompt(extension_prompt_types.IN_CHAT, 0, ' '); | ||||||
|  |  | ||||||
|  |         if (main_api === 'openai') { | ||||||
|  |             message_already_generated = ''; // OpenAI doesn't have multigen | ||||||
|  |             setOpenAIMessages(coreChat); | ||||||
|  |             setOpenAIMessageExamples(mesExamplesArray); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // Moved here to not overflow the Poe context with added prompt bits |         // Moved here to not overflow the Poe context with added prompt bits | ||||||
|         if (main_api == 'poe') { |         if (main_api == 'poe') { | ||||||
|             allAnchors = appendPoeAnchors(type, allAnchors); |             allAnchors = appendPoeAnchors(type, allAnchors); | ||||||
| @@ -3954,8 +3979,6 @@ function changeMainAPI() { | |||||||
| //////////////////////////////////////////////////// | //////////////////////////////////////////////////// | ||||||
|  |  | ||||||
| async function getUserAvatars() { | async function getUserAvatars() { | ||||||
|     $("#user_avatar_block").html(""); //RossAscends: necessary to avoid doubling avatars each refresh. |  | ||||||
|     $("#user_avatar_block").append('<div class="avatar_upload">+</div>'); |  | ||||||
|     const response = await fetch("/getuseravatars", { |     const response = await fetch("/getuseravatars", { | ||||||
|         method: "POST", |         method: "POST", | ||||||
|         headers: getRequestHeaders(), |         headers: getRequestHeaders(), | ||||||
| @@ -3967,6 +3990,8 @@ async function getUserAvatars() { | |||||||
|         const getData = await response.json(); |         const getData = await response.json(); | ||||||
|         //background = getData; |         //background = getData; | ||||||
|         //console.log(getData.length); |         //console.log(getData.length); | ||||||
|  |         $("#user_avatar_block").html(""); //RossAscends: necessary to avoid doubling avatars each refresh. | ||||||
|  |         $("#user_avatar_block").append('<div class="avatar_upload">+</div>'); | ||||||
|  |  | ||||||
|         for (var i = 0; i < getData.length; i++) { |         for (var i = 0; i < getData.length; i++) { | ||||||
|             //console.log(1); |             //console.log(1); | ||||||
| @@ -3977,6 +4002,56 @@ async function getUserAvatars() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function setPersonaDescription() { | ||||||
|  |     $("#persona_description").val(power_user.persona_description); | ||||||
|  |     $("#persona_description_position") | ||||||
|  |         .val(power_user.persona_description_position) | ||||||
|  |         .find(`option[value='${power_user.persona_description_position}']`) | ||||||
|  |         .attr("selected", true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function onPersonaDescriptionPositionInput() { | ||||||
|  |     power_user.persona_description_position = Number( | ||||||
|  |         $("#persona_description_position").find(":selected").val() | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     if (power_user.personas[user_avatar]) { | ||||||
|  |         let object = power_user.persona_descriptions[user_avatar]; | ||||||
|  |  | ||||||
|  |         if (!object) { | ||||||
|  |             object = { | ||||||
|  |                 description: power_user.persona_description, | ||||||
|  |                 position: power_user.persona_description_position, | ||||||
|  |             }; | ||||||
|  |             power_user.persona_descriptions[user_avatar] = object; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         object.position = power_user.persona_description_position; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     saveSettingsDebounced(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function onPersonaDescriptionInput() { | ||||||
|  |     power_user.persona_description = $("#persona_description").val(); | ||||||
|  |  | ||||||
|  |     if (power_user.personas[user_avatar]) { | ||||||
|  |         let object = power_user.persona_descriptions[user_avatar]; | ||||||
|  |  | ||||||
|  |         if (!object) { | ||||||
|  |             object = { | ||||||
|  |                 description: power_user.persona_description, | ||||||
|  |                 position: Number($("#persona_description_position").find(":selected").val()), | ||||||
|  |             }; | ||||||
|  |             power_user.persona_descriptions[user_avatar] = object; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         object.description = power_user.persona_description; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     saveSettingsDebounced(); | ||||||
|  | } | ||||||
|  |  | ||||||
| function highlightSelectedAvatar() { | function highlightSelectedAvatar() { | ||||||
|     $("#user_avatar_block").find(".avatar").removeClass("selected"); |     $("#user_avatar_block").find(".avatar").removeClass("selected"); | ||||||
|     $("#user_avatar_block") |     $("#user_avatar_block") | ||||||
| @@ -4053,9 +4128,20 @@ async function bindUserNameToPersona() { | |||||||
|         // If the user clicked ok and entered a name, bind the name to the persona |         // If the user clicked ok and entered a name, bind the name to the persona | ||||||
|         console.log(`Binding persona ${avatarId} to name ${personaName}`); |         console.log(`Binding persona ${avatarId} to name ${personaName}`); | ||||||
|         power_user.personas[avatarId] = personaName; |         power_user.personas[avatarId] = personaName; | ||||||
|  |         const descriptor = power_user.persona_descriptions[avatarId]; | ||||||
|  |         const isCurrentPersona = avatarId === user_avatar; | ||||||
|  |  | ||||||
|  |         // Create a description object if it doesn't exist | ||||||
|  |         if (!descriptor) { | ||||||
|  |             // If the user is currently using this persona, set the description to the current description | ||||||
|  |             power_user.persona_descriptions[avatarId] = { | ||||||
|  |                 description: isCurrentPersona ? power_user.persona_description : '', | ||||||
|  |                 position: isCurrentPersona ? power_user.persona_description_position : persona_description_positions.BEFORE_CHAR, | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // If the user is currently using this persona, update the name |         // If the user is currently using this persona, update the name | ||||||
|         if (avatarId === user_avatar) { |         if (isCurrentPersona) { | ||||||
|             console.log(`Auto-updating user name to ${personaName}`); |             console.log(`Auto-updating user name to ${personaName}`); | ||||||
|             setUserName(personaName); |             setUserName(personaName); | ||||||
|         } |         } | ||||||
| @@ -4063,10 +4149,33 @@ async function bindUserNameToPersona() { | |||||||
|         // If the user clicked ok, but didn't enter a name, delete the persona |         // If the user clicked ok, but didn't enter a name, delete the persona | ||||||
|         console.log(`Unbinding persona ${avatarId}`); |         console.log(`Unbinding persona ${avatarId}`); | ||||||
|         delete power_user.personas[avatarId]; |         delete power_user.personas[avatarId]; | ||||||
|  |         delete power_user.persona_descriptions[avatarId]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     saveSettingsDebounced(); |     saveSettingsDebounced(); | ||||||
|     await getUserAvatars(); |     await getUserAvatars(); | ||||||
|  |     setPersonaDescription(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function createDummyPersona() { | ||||||
|  |     const fetchResult = await fetch(default_avatar); | ||||||
|  |     const blob = await fetchResult.blob(); | ||||||
|  |     const file = new File([blob], "avatar.png", { type: "image/png" }); | ||||||
|  |     const formData = new FormData(); | ||||||
|  |     formData.append("avatar", file); | ||||||
|  |  | ||||||
|  |     jQuery.ajax({ | ||||||
|  |         type: "POST", | ||||||
|  |         url: "/uploaduseravatar", | ||||||
|  |         data: formData, | ||||||
|  |         beforeSend: () => { }, | ||||||
|  |         cache: false, | ||||||
|  |         contentType: false, | ||||||
|  |         processData: false, | ||||||
|  |         success: async function (data) { | ||||||
|  |             await getUserAvatars(); | ||||||
|  |         }, | ||||||
|  |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
| function updateUserLockIcon() { | function updateUserLockIcon() { | ||||||
| @@ -4093,12 +4202,75 @@ function setUserAvatar() { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         setUserName(personaName); |         setUserName(personaName); | ||||||
|  |  | ||||||
|  |         const descriptor = power_user.persona_descriptions[user_avatar]; | ||||||
|  |  | ||||||
|  |         if (descriptor) { | ||||||
|  |             power_user.persona_description = descriptor.description; | ||||||
|  |             power_user.persona_description_position = descriptor.position; | ||||||
|  |         } else { | ||||||
|  |             power_user.persona_description = ''; | ||||||
|  |             power_user.persona_description_position = persona_description_positions.BEFORE_CHAR; | ||||||
|  |             power_user.persona_descriptions[user_avatar] = { description: '', position: persona_description_positions.BEFORE_CHAR }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         setPersonaDescription(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| async function setUserInfo() { | async function uploadUserAvatar(e) { | ||||||
|     // TODO Replace with actual implementation |     const file = e.target.files[0]; | ||||||
|     callPopup('This functionality is under development.<br>Please check back later.', 'text'); |  | ||||||
|  |     if (!file) { | ||||||
|  |         $("#form_upload_avatar").trigger("reset"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const formData = new FormData($("#form_upload_avatar").get(0)); | ||||||
|  |  | ||||||
|  |     const dataUrl = await new Promise((resolve, reject) => { | ||||||
|  |         const reader = new FileReader(); | ||||||
|  |         reader.onload = resolve; | ||||||
|  |         reader.onerror = reject; | ||||||
|  |         reader.readAsDataURL(file); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     $('#dialogue_popup').addClass('large_dialogue_popup wide_dialogue_popup'); | ||||||
|  |     const confirmation = await callPopup(getCropPopup(dataUrl.target.result), 'avatarToCrop'); | ||||||
|  |     if (!confirmation) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let url = "/uploaduseravatar"; | ||||||
|  |  | ||||||
|  |     if (crop_data !== undefined) { | ||||||
|  |         url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     jQuery.ajax({ | ||||||
|  |         type: "POST", | ||||||
|  |         url: url, | ||||||
|  |         data: formData, | ||||||
|  |         beforeSend: () => { }, | ||||||
|  |         cache: false, | ||||||
|  |         contentType: false, | ||||||
|  |         processData: false, | ||||||
|  |         success: async function () { | ||||||
|  |             // If the user uploaded a new avatar, we want to make sure it's not cached | ||||||
|  |             const name = formData.get("overwrite_name"); | ||||||
|  |             if (name) { | ||||||
|  |                 await fetch(getUserAvatar(name), { cache: "no-cache" }); | ||||||
|  |                 reloadUserAvatar(); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             crop_data = undefined; | ||||||
|  |             await getUserAvatars(); | ||||||
|  |         }, | ||||||
|  |         error: (jqXHR, exception) => { }, | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     // Will allow to select the same file twice in a row | ||||||
|  |     $("#form_upload_avatar").trigger("reset"); | ||||||
| } | } | ||||||
|  |  | ||||||
| async function setDefaultPersona() { | async function setDefaultPersona() { | ||||||
| @@ -4179,6 +4351,7 @@ async function deleteUserAvatar() { | |||||||
|     if (request.ok) { |     if (request.ok) { | ||||||
|         console.log(`Deleted avatar ${avatarId}`); |         console.log(`Deleted avatar ${avatarId}`); | ||||||
|         delete power_user.personas[avatarId]; |         delete power_user.personas[avatarId]; | ||||||
|  |         delete power_user.persona_descriptions[avatarId]; | ||||||
|  |  | ||||||
|         if (avatarId === power_user.default_persona) { |         if (avatarId === power_user.default_persona) { | ||||||
|             toastr.warning('The default persona was deleted. You will need to set a new default persona.', 'Default persona deleted'); |             toastr.warning('The default persona was deleted. You will need to set a new default persona.', 'Default persona deleted'); | ||||||
| @@ -4215,6 +4388,7 @@ function lockUserNameToChat() { | |||||||
|             { timeOut: 10000, extendedTimeOut: 20000, }, |             { timeOut: 10000, extendedTimeOut: 20000, }, | ||||||
|         ); |         ); | ||||||
|         power_user.personas[user_avatar] = name1; |         power_user.personas[user_avatar] = name1; | ||||||
|  |         power_user.persona_descriptions[user_avatar] =  { description: '', position: persona_description_positions.BEFORE_CHAR }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     chat_metadata['persona'] = user_avatar; |     chat_metadata['persona'] = user_avatar; | ||||||
| @@ -4412,6 +4586,7 @@ async function getSettings(type) { | |||||||
|         user_avatar = settings.user_avatar; |         user_avatar = settings.user_avatar; | ||||||
|         reloadUserAvatar(); |         reloadUserAvatar(); | ||||||
|         highlightSelectedAvatar(); |         highlightSelectedAvatar(); | ||||||
|  |         setPersonaDescription(); | ||||||
|  |  | ||||||
|         //Load the API server URL from settings |         //Load the API server URL from settings | ||||||
|         api_server = settings.api_server; |         api_server = settings.api_server; | ||||||
| @@ -6264,56 +6439,21 @@ $(document).ready(function () { | |||||||
|  |  | ||||||
|     $(document).on("click", "#user_avatar_block .avatar", setUserAvatar); |     $(document).on("click", "#user_avatar_block .avatar", setUserAvatar); | ||||||
|     $(document).on("click", "#user_avatar_block .avatar_upload", function () { |     $(document).on("click", "#user_avatar_block .avatar_upload", function () { | ||||||
|         $("#avatar_upload_file").click(); |         $("#avatar_upload_overwrite").val(""); | ||||||
|  |         $("#avatar_upload_file").trigger('click'); | ||||||
|     }); |     }); | ||||||
|     $("#avatar_upload_file").on("change", async function (e) { |     $(document).on("click", "#user_avatar_block .set_persona_image", function () { | ||||||
|         const file = e.target.files[0]; |         const avatarId = $(this).closest('.avatar-container').find('.avatar').attr('imgfile'); | ||||||
|  |  | ||||||
|         if (!file) { |         if (!avatarId) { | ||||||
|  |             console.log('no imgfile'); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         const formData = new FormData($("#form_upload_avatar").get(0)); |         $("#avatar_upload_overwrite").val(avatarId); | ||||||
|  |         $("#avatar_upload_file").trigger('click'); | ||||||
|         const dataUrl = await new Promise((resolve, reject) => { |  | ||||||
|             const reader = new FileReader(); |  | ||||||
|             reader.onload = resolve; |  | ||||||
|             reader.onerror = reject; |  | ||||||
|             reader.readAsDataURL(file); |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         $('#dialogue_popup').addClass('large_dialogue_popup wide_dialogue_popup'); |  | ||||||
|         const confirmation = await callPopup(getCropPopup(dataUrl.target.result), 'avatarToCrop'); |  | ||||||
|         if (!confirmation) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         let url = "/uploaduseravatar"; |  | ||||||
|  |  | ||||||
|         if (crop_data !== undefined) { |  | ||||||
|             url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         jQuery.ajax({ |  | ||||||
|             type: "POST", |  | ||||||
|             url: url, |  | ||||||
|             data: formData, |  | ||||||
|             beforeSend: () => { }, |  | ||||||
|             cache: false, |  | ||||||
|             contentType: false, |  | ||||||
|             processData: false, |  | ||||||
|             success: function (data) { |  | ||||||
|                 if (data.path) { |  | ||||||
|                     appendUserAvatar(data.path); |  | ||||||
|                 } |  | ||||||
|                 crop_data = undefined; |  | ||||||
|             }, |  | ||||||
|             error: (jqXHR, exception) => { }, |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         // Will allow to select the same file twice in a row |  | ||||||
|         $("#form_upload_avatar").trigger("reset"); |  | ||||||
|     }); |     }); | ||||||
|  |     $("#avatar_upload_file").on("change", uploadUserAvatar); | ||||||
|  |  | ||||||
|     $(document).on("click", ".bg_example", async function () { |     $(document).on("click", ".bg_example", async function () { | ||||||
|         //when user clicks on a BG thumbnail... |         //when user clicks on a BG thumbnail... | ||||||
| @@ -7280,6 +7420,8 @@ $(document).ready(function () { | |||||||
|         setUserName($('#your_name').val()); |         setUserName($('#your_name').val()); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  |     $("#create_dummy_persona").on('click', createDummyPersona); | ||||||
|  |  | ||||||
|     $('#sync_name_button').on('click', async function () { |     $('#sync_name_button').on('click', async function () { | ||||||
|         const confirmation = await callPopup(`<h3>Are you sure?</h3>All user-sent messages in this chat will be attributed to ${name1}.`, 'confirm'); |         const confirmation = await callPopup(`<h3>Are you sure?</h3>All user-sent messages in this chat will be attributed to ${name1}.`, 'confirm'); | ||||||
|  |  | ||||||
| @@ -7323,8 +7465,9 @@ $(document).ready(function () { | |||||||
|     $(document).on('click', '.bind_user_name', bindUserNameToPersona); |     $(document).on('click', '.bind_user_name', bindUserNameToPersona); | ||||||
|     $(document).on('click', '.delete_avatar', deleteUserAvatar); |     $(document).on('click', '.delete_avatar', deleteUserAvatar); | ||||||
|     $(document).on('click', '.set_default_persona', setDefaultPersona); |     $(document).on('click', '.set_default_persona', setDefaultPersona); | ||||||
|     $(document).on('click', '.set_user_info', setUserInfo); |  | ||||||
|     $('#lock_user_name').on('click', lockUserNameToChat); |     $('#lock_user_name').on('click', lockUserNameToChat); | ||||||
|  |     $('#persona_description').on('input', onPersonaDescriptionInput); | ||||||
|  |     $('#persona_description_position').on('input', onPersonaDescriptionPositionInput); | ||||||
|  |  | ||||||
|     //**************************CHARACTER IMPORT EXPORT*************************// |     //**************************CHARACTER IMPORT EXPORT*************************// | ||||||
|     $("#character_import_button").click(function () { |     $("#character_import_button").click(function () { | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ import { selected_group } from "../../group-chats.js"; | |||||||
| import { ModuleWorkerWrapper, extension_settings, getContext, saveMetadataDebounced } from "../../extensions.js"; | import { ModuleWorkerWrapper, extension_settings, getContext, saveMetadataDebounced } from "../../extensions.js"; | ||||||
| import { registerSlashCommand } from "../../slash-commands.js"; | import { registerSlashCommand } from "../../slash-commands.js"; | ||||||
| import { getCharaFilename, debounce } from "../../utils.js"; | import { getCharaFilename, debounce } from "../../utils.js"; | ||||||
| export { MODULE_NAME }; | export { MODULE_NAME as NOTE_MODULE_NAME }; | ||||||
|  |  | ||||||
| const MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory | const MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory | ||||||
| const UPDATE_INTERVAL = 1000; | const UPDATE_INTERVAL = 1000; | ||||||
| @@ -222,6 +222,8 @@ function loadSettings() { | |||||||
| export function setFloatingPrompt() { | export function setFloatingPrompt() { | ||||||
|     const context = getContext(); |     const context = getContext(); | ||||||
|     if (!context.groupId && context.characterId === undefined) { |     if (!context.groupId && context.characterId === undefined) { | ||||||
|  |         console.debug('setFloatingPrompt: Not in a chat. Skipping.'); | ||||||
|  |         shouldWIAddPrompt = false; | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -243,6 +245,7 @@ export function setFloatingPrompt() { | |||||||
|     if (lastMessageNumber <= 0 || chat_metadata[metadata_keys.interval] <= 0) { |     if (lastMessageNumber <= 0 || chat_metadata[metadata_keys.interval] <= 0) { | ||||||
|         context.setExtensionPrompt(MODULE_NAME, ''); |         context.setExtensionPrompt(MODULE_NAME, ''); | ||||||
|         $('#extension_floating_counter').text('(disabled)'); |         $('#extension_floating_counter').text('(disabled)'); | ||||||
|  |         shouldWIAddPrompt = false; | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -75,6 +75,13 @@ const send_on_enter_options = { | |||||||
|     ENABLED: 1, |     ENABLED: 1, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export const persona_description_positions = { | ||||||
|  |     BEFORE_CHAR: 0, | ||||||
|  |     AFTER_CHAR: 1, | ||||||
|  |     TOP_AN: 2, | ||||||
|  |     BOTTOM_AN: 3, | ||||||
|  | } | ||||||
|  |  | ||||||
| let power_user = { | let power_user = { | ||||||
|     tokenizer: tokenizers.CLASSIC, |     tokenizer: tokenizers.CLASSIC, | ||||||
|     token_padding: 64, |     token_padding: 64, | ||||||
| @@ -158,6 +165,10 @@ let power_user = { | |||||||
|  |  | ||||||
|     personas: {}, |     personas: {}, | ||||||
|     default_persona: null, |     default_persona: null, | ||||||
|  |     persona_descriptions: {}, | ||||||
|  |  | ||||||
|  |     persona_description: '', | ||||||
|  |     persona_description_position: persona_description_positions.BEFORE_CHAR, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| let themes = []; | let themes = []; | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| import { saveSettings, callPopup, substituteParams, getTokenCount, getRequestHeaders, chat_metadata, this_chid, characters } from "../script.js"; | import { saveSettings, callPopup, substituteParams, getTokenCount, getRequestHeaders, chat_metadata, this_chid, characters } from "../script.js"; | ||||||
| import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, delay } from "./utils.js"; | import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, delay } from "./utils.js"; | ||||||
| import { getContext } from "./extensions.js"; | import { getContext } from "./extensions.js"; | ||||||
| import { metadata_keys, shouldWIAddPrompt } from "./extensions/floating-prompt/index.js"; | import { NOTE_MODULE_NAME, metadata_keys, shouldWIAddPrompt } from "./extensions/floating-prompt/index.js"; | ||||||
| import { registerSlashCommand } from "./slash-commands.js"; | import { registerSlashCommand } from "./slash-commands.js"; | ||||||
| import { deviceInfo } from "./RossAscends-mods.js"; | import { deviceInfo } from "./RossAscends-mods.js"; | ||||||
|  |  | ||||||
| @@ -867,9 +867,9 @@ async function checkWorldInfo(chat, maxContext) { | |||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     if (shouldWIAddPrompt) { |     if (shouldWIAddPrompt) { | ||||||
|         const originalAN = context.extensionPrompts['2_floating_prompt'].value; |         const originalAN = context.extensionPrompts[NOTE_MODULE_NAME].value; | ||||||
|         const ANWithWI = `\n${ANTopInjection.join("\n")}\n${originalAN}\n${ANBottomInjection.reverse().join("\n")}` |         const ANWithWI = `\n${ANTopInjection.join("\n")}\n${originalAN}\n${ANBottomInjection.reverse().join("\n")}` | ||||||
|         context.setExtensionPrompt('2_floating_prompt', ANWithWI, chat_metadata[metadata_keys.position], chat_metadata[metadata_keys.depth]); |         context.setExtensionPrompt(NOTE_MODULE_NAME, ANWithWI, chat_metadata[metadata_keys.position], chat_metadata[metadata_keys.depth]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return { worldInfoBefore, worldInfoAfter }; |     return { worldInfoBefore, worldInfoAfter }; | ||||||
|   | |||||||
| @@ -3734,6 +3734,13 @@ label[for="extensions_autoconnect"] { | |||||||
|     flex-grow: 1; |     flex-grow: 1; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .menu_button_icon { | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     width: fit-content; | ||||||
|  |     gap: 5px; | ||||||
|  | } | ||||||
|  |  | ||||||
| /*------------ TOP SIDE SETTINGS ----------------*/ | /*------------ TOP SIDE SETTINGS ----------------*/ | ||||||
|  |  | ||||||
| #top-settings-holder { | #top-settings-holder { | ||||||
| @@ -3743,10 +3750,10 @@ label[for="extensions_autoconnect"] { | |||||||
|     max-width: var(--sheldWidth); |     max-width: var(--sheldWidth); | ||||||
|     justify-content: center; |     justify-content: center; | ||||||
|     display: grid; |     display: grid; | ||||||
|     grid-template-columns: 10% 10% 10% 10% 10% 10% 10% 10%; |     grid-template-columns: 10% 10% 10% 10% 10% 10% 10% 10% 10%; | ||||||
|     z-index: 3000; |     z-index: 3000; | ||||||
|     position: relative; |     position: relative; | ||||||
|     grid-gap: 2%; |     grid-gap: 1%; | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -3824,6 +3831,10 @@ label[for="extensions_autoconnect"] { | |||||||
|     flex-basis: calc((var(--sheldWidth) / 4) - 16px); |     flex-basis: calc((var(--sheldWidth) / 4) - 16px); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .drawer33pWidth { | ||||||
|  |     flex-basis: calc((var(--sheldWidth) / 3) - 16px); | ||||||
|  | } | ||||||
|  |  | ||||||
| .drawer-content { | .drawer-content { | ||||||
|     background-color: var(--SmartThemeBlurTintColor); |     background-color: var(--SmartThemeBlurTintColor); | ||||||
|     color: var(--SmartThemeBodyColor); |     color: var(--SmartThemeBodyColor); | ||||||
| @@ -4409,7 +4420,7 @@ body.waifuMode #avatar_zoom_popup { | |||||||
|         aspect-ratio: 2 / 3; |         aspect-ratio: 2 / 3; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     .world_entry_thin_controls { |     .world_entry_thin_controls, #persona-management-block { | ||||||
|         flex-direction: column; |         flex-direction: column; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -4596,6 +4607,10 @@ body.waifuMode #avatar_zoom_popup { | |||||||
|         flex-basis: max(calc(100% / 4 - 10px), 190px); |         flex-basis: max(calc(100% / 4 - 10px), 190px); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     .drawer33pWidth { | ||||||
|  |         flex-basis: max(calc(100% / 3 - 10px), 190px); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     .expression-holder { |     .expression-holder { | ||||||
|         display: none; |         display: none; | ||||||
|     } |     } | ||||||
| @@ -4663,6 +4678,9 @@ body.waifuMode #avatar_zoom_popup { | |||||||
|     .drawer25pWidth { |     .drawer25pWidth { | ||||||
|         flex-basis: max(calc(100% / 2 - 10px), 180px); |         flex-basis: max(calc(100% / 2 - 10px), 180px); | ||||||
|     } |     } | ||||||
|  |     .drawer33pWidth { | ||||||
|  |         flex-basis: max(calc(100% / 2 - 10px), 180px); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| /*this part only only applies to iOS devices*/ | /*this part only only applies to iOS devices*/ | ||||||
|   | |||||||
| @@ -2223,7 +2223,7 @@ app.post('/uploaduseravatar', urlencodedParser, async (request, response) => { | |||||||
|  |  | ||||||
|         const image = await rawImg.cover(AVATAR_WIDTH, AVATAR_HEIGHT).getBufferAsync(jimp.MIME_PNG); |         const image = await rawImg.cover(AVATAR_WIDTH, AVATAR_HEIGHT).getBufferAsync(jimp.MIME_PNG); | ||||||
|  |  | ||||||
|         const filename = `${Date.now()}.png`; |         const filename = request.body.overwrite_name ?? `${Date.now()}.png`; | ||||||
|         const pathToNewFile = path.join(directories.avatars, filename); |         const pathToNewFile = path.join(directories.avatars, filename); | ||||||
|         fs.writeFileSync(pathToNewFile, image); |         fs.writeFileSync(pathToNewFile, image); | ||||||
|         fs.rmSync(pathToUpload); |         fs.rmSync(pathToUpload); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user