Add persona connection states to persona list - Show persona connection/lock states in persona list (chat & char lock) - Refactor persona images url to 'data-avatar-id' attribute - Try make persona blocks' height consistent - Fix persona list not correctly updating selected persona on navigating pages - Fix group/char difference not correctly working - Create common style template for hover-able images buttons/tags where the label only appears on hover
| @@ -96,11 +96,6 @@ body.charListGrid #rm_print_characters_block .group_select .group_name_block, | |||
| 96 | flex-direction: column; | 96 | flex-direction: column; |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | #user_avatar_block.gridView .avatar-container .avatar-buttons { | ||
| 100 | flex-wrap: wrap; | ||
| 101 | justify-content: space-evenly; | ||
| 102 | } | ||
| 103 | |||
| 104 | body.charListGrid #rm_print_characters_block .bogus_folder_select .character_select_container, | 99 | body.charListGrid #rm_print_characters_block .bogus_folder_select .character_select_container, |
| 105 | body.charListGrid #rm_print_characters_block .character_select .character_select_container, | 100 | body.charListGrid #rm_print_characters_block .character_select .character_select_container, |
| 106 | body.charListGrid #rm_print_characters_block .group_select .group_select_container, | 101 | body.charListGrid #rm_print_characters_block .group_select .group_select_container, |
| @@ -5470,27 +5470,20 @@ | |||
| 5470 | <div class="flex-container wide100pLess70px character_select_container"> | 5470 | <div class="flex-container wide100pLess70px character_select_container"> |
| 5471 | <div class="wide100p character_name_block"> | 5471 | <div class="wide100p character_name_block"> |
| 5472 | <span class="ch_name flex1"></span> | 5472 | <span class="ch_name flex1"></span> |
| 5473 | <div class="avatar-buttons"> | ||
| 5474 | <!-- <button class="menu_button bind_user_name" title="Bind user name to that avatar" data-i18n="[title]Bind user name to that avatar"> | ||
| 5475 | <i class="fa-fw fa-solid fa-user-edit fa-sm"></i> | ||
| 5476 | </button> | ||
| 5477 | <button class="menu_button set_persona_image" title="Change persona image" data-i18n="[title]Change persona image"> | ||
| 5478 | <i class="fa-fw fa-solid fa-image fa-sm"></i> | ||
| 5479 | </button> | ||
| 5480 | |||
| 5481 | <button class="menu_button set_default_persona" title="Select this as default persona for the new chats." data-i18n="[title]Select this as default persona for the new chats."> | ||
| 5482 | <i class="fa-fw fa-solid fa-crown fa-sm"></i> | ||
| 5483 | </button> | ||
| 5484 | |||
| 5485 | <button class="menu_button duplicate_persona" title="Duplicate persona" data-i18n="[title]Duplicate persona"> | ||
| 5486 | <i class="fa-fw fa-solid fa-clone fa-sm"></i> | ||
| 5487 | </button> | ||
| 5488 | <button class="menu_button delete_avatar" title="Delete persona" data-i18n="[title]Delete persona"> | ||
| 5489 | <i class="fa-fw fa-solid fa-trash-alt fa-sm"></i> | ||
| 5490 | </button> --> | ||
| 5491 | </div> | ||
| 5492 | </div> | 5473 | </div> |
| 5493 | <div class="ch_description"></div> | 5474 | <div class="ch_description"></div> |
| 5475 | <div class="avatar_container_states buttons_block"> | ||
| 5476 | <div class="locked_to_chat_label avatar_state has_hover_label menu_button menu_button_icon disabled" title="Persona is locked to the current chat" data-i18n="[title]Persona is locked to the current chat"> | ||
| 5477 | <i class="icon fa-solid fa-lock fa-fw"></i> | ||
| 5478 | <i class="label_icon icon fa-solid fa-comments fa-fw"></i> | ||
| 5479 | <div class="label" data-i18n="Chat">Chat</div> | ||
| 5480 | </div> | ||
| 5481 | <div class="locked_to_character_label avatar_state has_hover_label menu_button menu_button_icon disabled " title="Persona is locked to the current character" data-i18n="[title]Persona is locked to the current character"> | ||
| 5482 | <i class="icon fa-solid fa-lock fa-fw"></i> | ||
| 5483 | <i class="label_icon icon fa-solid fa-user fa-fw"></i> | ||
| 5484 | <div class="label" data-i18n="Character">Character</div> | ||
| 5485 | </div> | ||
| 5486 | </div> | ||
| 5494 | </div> | 5487 | </div> |
| 5495 | </div> | 5488 | </div> |
| 5496 | </div> | 5489 | </div> |
| @@ -10,7 +10,6 @@ import { | |||
| 10 | getRequestHeaders, | 10 | getRequestHeaders, |
| 11 | getThumbnailUrl, | 11 | getThumbnailUrl, |
| 12 | groupToEntity, | 12 | groupToEntity, |
| 13 | menu_type, | ||
| 14 | name1, | 13 | name1, |
| 15 | name2, | 14 | name2, |
| 16 | reloadCurrentChat, | 15 | reloadCurrentChat, |
| @@ -40,6 +39,15 @@ import { saveMetadataDebounced } from './extensions.js'; | |||
| 40 | 39 | ||
| 41 | /** @typedef {'chat' | 'character' | 'default'} PersonaLockType Type of the persona lock */ | 40 | /** @typedef {'chat' | 'character' | 'default'} PersonaLockType Type of the persona lock */ |
| 42 | 41 | ||
| 42 | /** | ||
| 43 | * @typedef {object} PersonaState | ||
| 44 | * @property {string} avatarId - The avatar id of the persona | ||
| 45 | * @property {boolean} default - Whether this persona is the default one for all new chats | ||
| 46 | * @property {object} locked - An object containing the lock states | ||
| 47 | * @property {boolean} locked.chat - Whether the persona is locked to the currently open chat | ||
| 48 | * @property {boolean} locked.character - Whether the persona is locked to the currently open character or group | ||
| 49 | */ | ||
| 50 | |||
| 43 | const USER_AVATAR_PATH = 'User Avatars/'; | 51 | const USER_AVATAR_PATH = 'User Avatars/'; |
| 44 | 52 | ||
| 45 | let savePersonasPage = 0; | 53 | let savePersonasPage = 0; |
| @@ -66,7 +74,7 @@ export function getUserAvatar(avatarImg) { | |||
| 66 | export function initUserAvatar(avatar) { | 74 | export function initUserAvatar(avatar) { |
| 67 | user_avatar = avatar; | 75 | user_avatar = avatar; |
| 68 | reloadUserAvatar(); | 76 | reloadUserAvatar(); |
| 69 | highlightSelectedAvatar(); | 77 | updatePersonaUIStates(); |
| 70 | } | 78 | } |
| 71 | 79 | ||
| 72 | /** | 80 | /** |
| @@ -74,19 +82,14 @@ export function initUserAvatar(avatar) { | |||
| 74 | * @param {string} imgfile Link to an image file | 82 | * @param {string} imgfile Link to an image file |
| 75 | */ | 83 | */ |
| 76 | export function setUserAvatar(imgfile, { toastPersonaNameChange = true } = {}) { | 84 | export function setUserAvatar(imgfile, { toastPersonaNameChange = true } = {}) { |
| 77 | user_avatar = imgfile && typeof imgfile === 'string' ? imgfile : $(this).attr('imgfile'); | 85 | user_avatar = imgfile && typeof imgfile === 'string' ? imgfile : $(this).attr('data-avatar-id'); |
| 78 | reloadUserAvatar(); | 86 | reloadUserAvatar(); |
| 79 | highlightSelectedAvatar(); | 87 | updatePersonaUIStates(); |
| 80 | selectCurrentPersona({ toastPersonaNameChange: toastPersonaNameChange }); | 88 | selectCurrentPersona({ toastPersonaNameChange: toastPersonaNameChange }); |
| 81 | saveSettingsDebounced(); | 89 | saveSettingsDebounced(); |
| 82 | $('.zoomed_avatar[forchar]').remove(); | 90 | $('.zoomed_avatar[forchar]').remove(); |
| 83 | } | 91 | } |
| 84 | 92 | ||
| 85 | function highlightSelectedAvatar() { | ||
| 86 | $('#user_avatar_block .avatar-container').removeClass('selected'); | ||
| 87 | $(`#user_avatar_block .avatar-container[imgfile="${user_avatar}"]`).addClass('selected'); | ||
| 88 | } | ||
| 89 | |||
| 90 | function reloadUserAvatar(force = false) { | 93 | function reloadUserAvatar(force = false) { |
| 91 | $('.mes').each(function () { | 94 | $('.mes').each(function () { |
| 92 | const avatarImg = $(this).find('.avatar img'); | 95 | const avatarImg = $(this).find('.avatar img'); |
| @@ -146,24 +149,32 @@ function verifyPersonaSearchSortRule() { | |||
| 146 | 149 | ||
| 147 | /** | 150 | /** |
| 148 | * Gets a rendered avatar block. | 151 | * Gets a rendered avatar block. |
| 149 | * @param {string} name Avatar file name | 152 | * @param {string} avatarId Avatar file name |
| 150 | * @returns {JQuery<HTMLElement>} Avatar block | 153 | * @returns {JQuery<HTMLElement>} Avatar block |
| 151 | */ | 154 | */ |
| 152 | function getUserAvatarBlock(name) { | 155 | function getUserAvatarBlock(avatarId) { |
| 153 | const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; | 156 | const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; |
| 154 | const template = $('#user_avatar_template .avatar-container').clone(); | 157 | const template = $('#user_avatar_template .avatar-container').clone(); |
| 155 | const personaName = power_user.personas[name]; | 158 | const personaName = power_user.personas[avatarId]; |
| 156 | const personaDescription = power_user.persona_descriptions[name]?.description; | 159 | const personaDescription = power_user.persona_descriptions[avatarId]?.description; |
| 160 | |||
| 157 | template.find('.ch_name').text(personaName || '[Unnamed Persona]'); | 161 | template.find('.ch_name').text(personaName || '[Unnamed Persona]'); |
| 158 | template.find('.ch_description').text(personaDescription || $('#user_avatar_block').attr('no_desc_text')).toggleClass('text_muted', !personaDescription); | 162 | template.find('.ch_description').text(personaDescription || $('#user_avatar_block').attr('no_desc_text')).toggleClass('text_muted', !personaDescription); |
| 159 | template.attr('imgfile', name); | 163 | template.attr('data-avatar-id', avatarId); |
| 160 | template.find('.avatar').attr('imgfile', name).attr('title', name); | 164 | template.find('.avatar').attr('data-avatar-id', avatarId).attr('title', avatarId); |
| 161 | template.toggleClass('default_persona', name === power_user.default_persona); | 165 | template.toggleClass('default_persona', avatarId === power_user.default_persona); |
| 162 | let avatarUrl = getUserAvatar(name); | 166 | let avatarUrl = getUserAvatar(avatarId); |
| 163 | if (isFirefox) { | 167 | if (isFirefox) { |
| 164 | avatarUrl += '?t=' + Date.now(); | 168 | avatarUrl += '?t=' + Date.now(); |
| 165 | } | 169 | } |
| 166 | template.find('img').attr('src', avatarUrl); | 170 | template.find('img').attr('src', avatarUrl); |
| 171 | |||
| 172 | // Make sure description block has at least three rows. Otherwise height looks inconsistent. I don't have a better idea for this. | ||
| 173 | const currentText = template.find('.ch_description').text(); | ||
| 174 | if (currentText.split('\n').length < 3) { | ||
| 175 | template.find('.ch_description').text(currentText + '\n\xa0\n\xa0'); | ||
| 176 | } | ||
| 177 | |||
| 167 | $('#user_avatar_block').append(template); | 178 | $('#user_avatar_block').append(template); |
| 168 | return template; | 179 | return template; |
| 169 | } | 180 | } |
| @@ -218,7 +229,7 @@ export async function getUserAvatars(doRender = true, openPageAt = '') { | |||
| 218 | for (const item of data) { | 229 | for (const item of data) { |
| 219 | $(listId).append(getUserAvatarBlock(item)); | 230 | $(listId).append(getUserAvatarBlock(item)); |
| 220 | } | 231 | } |
| 221 | highlightSelectedAvatar(); | 232 | updatePersonaUIStates(); |
| 222 | }, | 233 | }, |
| 223 | afterSizeSelectorChange: function (e) { | 234 | afterSizeSelectorChange: function (e) { |
| 224 | localStorage.setItem(storageKey, e.target.value); | 235 | localStorage.setItem(storageKey, e.target.value); |
| @@ -486,7 +497,7 @@ export function setPersonaDescription() { | |||
| 486 | $('#persona_lore_button').toggleClass('world_set', !!power_user.persona_description_lorebook); | 497 | $('#persona_lore_button').toggleClass('world_set', !!power_user.persona_description_lorebook); |
| 487 | countPersonaDescriptionTokens(); | 498 | countPersonaDescriptionTokens(); |
| 488 | 499 | ||
| 489 | updatePersonaLockIcons(); | 500 | updatePersonaUIStates(); |
| 490 | updatePersonaConnectionsAvatarList(); | 501 | updatePersonaConnectionsAvatarList(); |
| 491 | } | 502 | } |
| 492 | 503 | ||
| @@ -780,7 +791,7 @@ function selectCurrentPersona({ toastPersonaNameChange = true } = {}) { | |||
| 780 | toastr.success(`Persona ${personaName} selected and auto-locked to current chat`, t`Persona Selected`); | 791 | toastr.success(`Persona ${personaName} selected and auto-locked to current chat`, t`Persona Selected`); |
| 781 | } | 792 | } |
| 782 | saveMetadataDebounced(); | 793 | saveMetadataDebounced(); |
| 783 | updatePersonaLockIcons(); | 794 | updatePersonaUIStates(); |
| 784 | } | 795 | } |
| 785 | 796 | ||
| 786 | // As the last step, inform user if the persona is only temporarily chosen | 797 | // As the last step, inform user if the persona is only temporarily chosen |
| @@ -806,8 +817,8 @@ function selectCurrentPersona({ toastPersonaNameChange = true } = {}) { | |||
| 806 | * @returns {boolean} Whether the connection is locked | 817 | * @returns {boolean} Whether the connection is locked |
| 807 | */ | 818 | */ |
| 808 | export function isPersonaConnectionLocked(connection) { | 819 | export function isPersonaConnectionLocked(connection) { |
| 809 | return (menu_type === 'character_edit' && connection.type === 'character' && connection.id === characters[this_chid]?.avatar) | 820 | return (!selected_group && connection.type === 'character' && connection.id === characters[this_chid]?.avatar) |
| 810 | || (menu_type === 'group_edit' && connection.type === 'group' && connection.id === selected_group); | 821 | || (selected_group && connection.type === 'group' && connection.id === selected_group); |
| 811 | } | 822 | } |
| 812 | 823 | ||
| 813 | /** | 824 | /** |
| @@ -894,7 +905,7 @@ async function unlockPersona(type = 'chat') { | |||
| 894 | throw new Error(`Unknown persona lock type: ${type}`); | 905 | throw new Error(`Unknown persona lock type: ${type}`); |
| 895 | } | 906 | } |
| 896 | 907 | ||
| 897 | updatePersonaLockIcons(); | 908 | updatePersonaUIStates(); |
| 898 | } | 909 | } |
| 899 | 910 | ||
| 900 | /** | 911 | /** |
| @@ -969,7 +980,7 @@ async function lockPersona(type = 'chat') { | |||
| 969 | throw new Error(`Unknown persona lock type: ${type}`); | 980 | throw new Error(`Unknown persona lock type: ${type}`); |
| 970 | } | 981 | } |
| 971 | 982 | ||
| 972 | updatePersonaLockIcons(); | 983 | updatePersonaUIStates(); |
| 973 | } | 984 | } |
| 974 | 985 | ||
| 975 | 986 | ||
| @@ -1149,7 +1160,7 @@ function getOrCreatePersonaDescriptor() { | |||
| 1149 | 1160 | ||
| 1150 | async function toggleDefaultPersonaClicked(e) { | 1161 | async function toggleDefaultPersonaClicked(e) { |
| 1151 | e?.stopPropagation(); | 1162 | e?.stopPropagation(); |
| 1152 | const avatarId = $(e.currentTarget).closest('.avatar-container').find('.avatar').attr('imgfile'); | 1163 | const avatarId = $(e.currentTarget).closest('.avatar-container').find('.avatar').attr('data-avatar-id'); |
| 1153 | if (avatarId) { | 1164 | if (avatarId) { |
| 1154 | await toggleDefaultPersona(avatarId); | 1165 | await toggleDefaultPersona(avatarId); |
| 1155 | } else { | 1166 | } else { |
| @@ -1213,26 +1224,62 @@ async function toggleDefaultPersona(avatarId, { quiet: quiet = false } = {}) { | |||
| 1213 | 1224 | ||
| 1214 | saveSettingsDebounced(); | 1225 | saveSettingsDebounced(); |
| 1215 | await getUserAvatars(true, avatarId); | 1226 | await getUserAvatars(true, avatarId); |
| 1216 | updatePersonaLockIcons(); | 1227 | updatePersonaUIStates(); |
| 1217 | } | 1228 | } |
| 1218 | 1229 | ||
| 1219 | function updatePersonaLockIcons() { | 1230 | /** |
| 1220 | const isDefaultPersona = power_user.default_persona === user_avatar; | 1231 | * Returns an object with 3 properties that describe the state of the given persona |
| 1221 | $('#lock_persona_default').toggleClass('locked', isDefaultPersona); | 1232 | * |
| 1222 | 1233 | * - default: Whether this persona is the default one for all new chats | |
| 1223 | const hasChatLock = chat_metadata['persona'] == user_avatar; | 1234 | * - locked: An object containing the lock states |
| 1224 | $('#lock_user_name').toggleClass('locked', hasChatLock); | 1235 | * - chat: Whether the persona is locked to the currently open chat |
| 1225 | $('#lock_user_name i.icon').toggleClass('fa-lock', hasChatLock); | 1236 | * - character: Whether the persona is locked to the currently open character or group |
| 1226 | $('#lock_user_name i.icon').toggleClass('fa-unlock', !hasChatLock); | 1237 | * @param {string} avatarId - The avatar id of the persona to get the state for |
| 1238 | * @returns {PersonaState} An object describing the state of the given persona | ||
| 1239 | */ | ||
| 1240 | function getPersonaStates(avatarId) { | ||
| 1241 | const isDefaultPersona = power_user.default_persona === avatarId; | ||
| 1242 | const hasChatLock = chat_metadata['persona'] == avatarId; | ||
| 1227 | 1243 | ||
| 1228 | /** @type {PersonaConnection[]} */ | 1244 | /** @type {PersonaConnection[]} */ |
| 1229 | const connections = power_user.persona_descriptions[user_avatar]?.connections; | 1245 | const connections = power_user.persona_descriptions[avatarId]?.connections; |
| 1230 | const hasCharLock = !!connections?.some(c => | 1246 | const hasCharLock = !!connections?.some(c => |
| 1231 | (menu_type === 'character_edit' && c.type === 'character' && c.id === characters[this_chid]?.avatar) | 1247 | (!selected_group && c.type === 'character' && c.id === characters[this_chid]?.avatar) |
| 1232 | || (menu_type === 'group_edit' && c.type === 'group' && c.id === selected_group)); | 1248 | || (selected_group && c.type === 'group' && c.id === selected_group)); |
| 1233 | $('#lock_persona_to_char').toggleClass('locked', hasCharLock); | 1249 | |
| 1234 | $('#lock_persona_to_char i.icon').toggleClass('fa-lock', hasCharLock); | 1250 | return { |
| 1235 | $('#lock_persona_to_char i.icon').toggleClass('fa-unlock', !hasCharLock); | 1251 | avatarId: avatarId, |
| 1252 | default: isDefaultPersona, | ||
| 1253 | locked: { | ||
| 1254 | chat: hasChatLock, | ||
| 1255 | character: hasCharLock, | ||
| 1256 | }, | ||
| 1257 | }; | ||
| 1258 | } | ||
| 1259 | |||
| 1260 | function updatePersonaUIStates() { | ||
| 1261 | // Update the persona list | ||
| 1262 | $('#user_avatar_block .avatar-container').each(function () { | ||
| 1263 | const avatarId = $(this).attr('data-avatar-id'); | ||
| 1264 | const states = getPersonaStates(avatarId); | ||
| 1265 | $(this).toggleClass('default_persona', states.default); | ||
| 1266 | $(this).toggleClass('locked_to_chat', states.locked.chat); | ||
| 1267 | $(this).toggleClass('locked_to_character', states.locked.character); | ||
| 1268 | $(this).toggleClass('selected', avatarId === user_avatar); | ||
| 1269 | }); | ||
| 1270 | |||
| 1271 | // Buttons for the persona panel on the right | ||
| 1272 | const personaStates = getPersonaStates(user_avatar); | ||
| 1273 | |||
| 1274 | $('#lock_persona_default').toggleClass('locked', personaStates.default); | ||
| 1275 | |||
| 1276 | $('#lock_user_name').toggleClass('locked', personaStates.locked.chat); | ||
| 1277 | $('#lock_user_name i.icon').toggleClass('fa-lock', personaStates.locked.chat); | ||
| 1278 | $('#lock_user_name i.icon').toggleClass('fa-unlock', !personaStates.locked.chat); | ||
| 1279 | |||
| 1280 | $('#lock_persona_to_char').toggleClass('locked', personaStates.locked.character); | ||
| 1281 | $('#lock_persona_to_char i.icon').toggleClass('fa-lock', personaStates.locked.character); | ||
| 1282 | $('#lock_persona_to_char i.icon').toggleClass('fa-unlock', !personaStates.locked.character); | ||
| 1236 | } | 1283 | } |
| 1237 | 1284 | ||
| 1238 | async function loadPersonaForCurrentChat({ doRender = false } = {}) { | 1285 | async function loadPersonaForCurrentChat({ doRender = false } = {}) { |
| @@ -1315,7 +1362,7 @@ async function loadPersonaForCurrentChat({ doRender = false } = {}) { | |||
| 1315 | } | 1362 | } |
| 1316 | } | 1363 | } |
| 1317 | 1364 | ||
| 1318 | updatePersonaLockIcons(); | 1365 | updatePersonaUIStates(); |
| 1319 | } | 1366 | } |
| 1320 | 1367 | ||
| 1321 | /** | 1368 | /** |
| @@ -1325,7 +1372,7 @@ async function loadPersonaForCurrentChat({ doRender = false } = {}) { | |||
| 1325 | * @returns {string[]} - An array of persona keys that are connected to the given character key | 1372 | * @returns {string[]} - An array of persona keys that are connected to the given character key |
| 1326 | */ | 1373 | */ |
| 1327 | export function getConnectedPersonas(characterKey = undefined) { | 1374 | export function getConnectedPersonas(characterKey = undefined) { |
| 1328 | characterKey ??= menu_type === 'group_edit' ? selected_group : characters[this_chid]?.avatar; | 1375 | characterKey ??= selected_group || characters[this_chid]?.avatar; |
| 1329 | const connectedPersonas = Object.entries(power_user.persona_descriptions) | 1376 | const connectedPersonas = Object.entries(power_user.persona_descriptions) |
| 1330 | .filter(([_, desc]) => desc.connections?.some(conn => conn.type === 'character' && conn.id === characterKey)) | 1377 | .filter(([_, desc]) => desc.connections?.some(conn => conn.type === 'character' && conn.id === characterKey)) |
| 1331 | .map(([key, _]) => key); | 1378 | .map(([key, _]) => key); |
| @@ -1339,9 +1386,9 @@ export function getConnectedPersonas(characterKey = undefined) { | |||
| 1339 | */ | 1386 | */ |
| 1340 | 1387 | ||
| 1341 | export function getCurrentConnectionObj() { | 1388 | export function getCurrentConnectionObj() { |
| 1342 | if (menu_type === 'group_edit') | 1389 | if (selected_group) |
| 1343 | return { type: 'group', id: selected_group }; | 1390 | return { type: 'group', id: selected_group }; |
| 1344 | if (menu_type == 'character_edit') | 1391 | if (characters[this_chid]?.avatar) |
| 1345 | return { type: 'character', id: characters[this_chid]?.avatar }; | 1392 | return { type: 'character', id: characters[this_chid]?.avatar }; |
| 1346 | return null; | 1393 | return null; |
| 1347 | } | 1394 | } |
| @@ -1538,7 +1585,7 @@ export function initPersonas() { | |||
| 1538 | $('#avatar_upload_file').on('change', changeUserAvatar); | 1585 | $('#avatar_upload_file').on('change', changeUserAvatar); |
| 1539 | 1586 | ||
| 1540 | $(document).on('click', '#user_avatar_block .avatar-container', function () { | 1587 | $(document).on('click', '#user_avatar_block .avatar-container', function () { |
| 1541 | const imgfile = $(this).attr('imgfile'); | 1588 | const imgfile = $(this).attr('data-avatar-id'); |
| 1542 | setUserAvatar(imgfile); | 1589 | setUserAvatar(imgfile); |
| 1543 | 1590 | ||
| 1544 | // force firstMes {{user}} update on persona switch | 1591 | // force firstMes {{user}} update on persona switch |
| @@ -222,6 +222,37 @@ table.responsiveTable { | |||
| 222 | animation-name: flash; | 222 | animation-name: flash; |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | .has_hover_label .label_icon { | ||
| 226 | transition: opacity var(--animation-duration) ease, max-width var(--animation-duration) ease; | ||
| 227 | } | ||
| 228 | .has_hover_label .label { | ||
| 229 | transition: opacity var(--animation-duration-slow) ease, max-width var(--animation-duration-slow) ease; | ||
| 230 | /* Prevent double gap on hidden icon */ | ||
| 231 | margin-left: -5px; | ||
| 232 | } | ||
| 233 | |||
| 234 | .has_hover_label .label_icon, | ||
| 235 | .has_hover_label .label { | ||
| 236 | transition-delay: var(--animation-duration-slow); | ||
| 237 | } | ||
| 238 | .has_hover_label.fast .label_icon, | ||
| 239 | .has_hover_label.fast .label { | ||
| 240 | transition-delay: var(--animation-duration); | ||
| 241 | } | ||
| 242 | |||
| 243 | .has_hover_label .label_icon, | ||
| 244 | .has_hover_label:hover .label { | ||
| 245 | opacity: 1; | ||
| 246 | max-width: 100px; | ||
| 247 | } | ||
| 248 | |||
| 249 | .has_hover_label:hover .label_icon, | ||
| 250 | .has_hover_label .label { | ||
| 251 | opacity: 0; | ||
| 252 | max-width: 0; | ||
| 253 | overflow: hidden; | ||
| 254 | } | ||
| 255 | |||
| 225 | /* Keyboard/focus navigation styling */ | 256 | /* Keyboard/focus navigation styling */ |
| 226 | /* Mimic the outline of keyboard navigation for most most focusable controls */ | 257 | /* Mimic the outline of keyboard navigation for most most focusable controls */ |
| 227 | .interactable { | 258 | .interactable { |
| @@ -2805,6 +2836,7 @@ select option:not(:checked) { | |||
| 2805 | .menu_button.disabled { | 2836 | .menu_button.disabled { |
| 2806 | filter: brightness(75%) grayscale(1); | 2837 | filter: brightness(75%) grayscale(1); |
| 2807 | opacity: 0.5; | 2838 | opacity: 0.5; |
| 2839 | cursor: inherit; | ||
| 2808 | pointer-events: none; | 2840 | pointer-events: none; |
| 2809 | } | 2841 | } |
| 2810 | 2842 | ||
| @@ -2880,8 +2912,7 @@ select option:not(:checked) { | |||
| 2880 | } | 2912 | } |
| 2881 | 2913 | ||
| 2882 | #form_character_search_form .menu_button, | 2914 | #form_character_search_form .menu_button, |
| 2883 | #GroupFavDelOkBack .menu_button, | 2915 | #GroupFavDelOkBack .menu_button { |
| 2884 | .avatar-container .menu_button { | ||
| 2885 | margin: 0; | 2916 | margin: 0; |
| 2886 | height: fit-content; | 2917 | height: fit-content; |
| 2887 | padding: 5px; | 2918 | padding: 5px; |
| @@ -2915,8 +2946,9 @@ select option:not(:checked) { | |||
| 2915 | width: max-content; | 2946 | width: max-content; |
| 2916 | } | 2947 | } |
| 2917 | 2948 | ||
| 2918 | #persona-management-block .menu_button { | 2949 | #persona-management-block .avatar_container_states .menu_button { |
| 2919 | filter: grayscale(0.5); | 2950 | padding: 3px 5px; |
| 2951 | pointer-events: initial; | ||
| 2920 | } | 2952 | } |
| 2921 | 2953 | ||
| 2922 | #persona_controls .persona_name { | 2954 | #persona_controls .persona_name { |
| @@ -3321,28 +3353,6 @@ grammarly-extension { | |||
| 3321 | z-index: 35; | 3353 | z-index: 35; |
| 3322 | } | 3354 | } |
| 3323 | 3355 | ||
| 3324 | .avatar-container .avatar-buttons { | ||
| 3325 | display: flex; | ||
| 3326 | flex-direction: row; | ||
| 3327 | gap: 3px; | ||
| 3328 | opacity: 0.3; | ||
| 3329 | transition: opacity 0.25s ease-in-out; | ||
| 3330 | } | ||
| 3331 | |||
| 3332 | .avatar-container .avatar-buttons:hover { | ||
| 3333 | opacity: 1; | ||
| 3334 | } | ||
| 3335 | |||
| 3336 | .avatar-container .avatar-buttons .menu_button { | ||
| 3337 | padding: 3px; | ||
| 3338 | } | ||
| 3339 | |||
| 3340 | /* Ross should be able to handle this later */ | ||
| 3341 | /*.big-avatars .avatar-buttons{ | ||
| 3342 | justify-content: center; | ||
| 3343 | width: fit-content; | ||
| 3344 | }*/ | ||
| 3345 | |||
| 3346 | .avatar_div .avatar { | 3356 | .avatar_div .avatar { |
| 3347 | /* margin-left: 4px; | 3357 | /* margin-left: 4px; |
| 3348 | margin-right: 10px; | 3358 | margin-right: 10px; |
| @@ -3603,6 +3613,7 @@ grammarly-extension { | |||
| 3603 | 3613 | ||
| 3604 | .menu_button { | 3614 | .menu_button { |
| 3605 | color: var(--SmartThemeBodyColor); | 3615 | color: var(--SmartThemeBodyColor); |
| 3616 | filter: grayscale(0.5); | ||
| 3606 | background-color: var(--SmartThemeBlurTintColor); | 3617 | background-color: var(--SmartThemeBlurTintColor); |
| 3607 | border: 1px solid var(--SmartThemeBorderColor); | 3618 | border: 1px solid var(--SmartThemeBorderColor); |
| 3608 | border-radius: 5px; | 3619 | border-radius: 5px; |
| @@ -3622,8 +3633,8 @@ grammarly-extension { | |||
| 3622 | min-width: calc(1.25em + 12px); | 3633 | min-width: calc(1.25em + 12px); |
| 3623 | } | 3634 | } |
| 3624 | 3635 | ||
| 3625 | .menu_button:hover, | 3636 | .menu_button:not(.disabled):hover, |
| 3626 | .menu_button.active { | 3637 | .menu_button:not(.disabled).active { |
| 3627 | background-color: var(--white30a); | 3638 | background-color: var(--white30a); |
| 3628 | } | 3639 | } |
| 3629 | 3640 | ||
| @@ -3876,11 +3887,28 @@ input[type='checkbox'].del_checkbox { | |||
| 3876 | color: var(--golden); | 3887 | color: var(--golden); |
| 3877 | } | 3888 | } |
| 3878 | 3889 | ||
| 3890 | .avatar-container .avatar_state .fa-lock { | ||
| 3891 | color: var(--active); | ||
| 3892 | } | ||
| 3893 | |||
| 3894 | .avatar-container:not(.locked_to_chat) .locked_to_chat_label { | ||
| 3895 | display: none; | ||
| 3896 | } | ||
| 3897 | .avatar-container:not(.locked_to_character) .locked_to_character_label { | ||
| 3898 | display: none; | ||
| 3899 | } | ||
| 3900 | |||
| 3879 | #lock_persona_default.locked i.icon { | 3901 | #lock_persona_default.locked i.icon { |
| 3880 | color: var(--golden); | 3902 | color: var(--golden); |
| 3881 | } | 3903 | } |
| 3882 | #lock_user_name.locked i.icon, | 3904 | |
| 3883 | #lock_persona_to_char.locked i.icon { | 3905 | #lock_user_name.locked .icon, |
| 3906 | .avatar-container.locked_to_chat .locked_to_chat_label .icon { | ||
| 3907 | color: var(--SmartThemeQuoteColor); | ||
| 3908 | } | ||
| 3909 | |||
| 3910 | #lock_persona_to_char.locked .icon, | ||
| 3911 | .avatar-container.locked_to_character .locked_to_character_label .icon { | ||
| 3884 | color: var(--active); | 3912 | color: var(--active); |
| 3885 | } | 3913 | } |
| 3886 | 3914 | ||