Highlight personas from current chat in popup

2253990898b6772ee58771df694a203b8db8717e

Wolfsblvt <wolfsblvt@gmail.com>

3 files changed, +31 -4Ignore whitespace
public/script.js+1 -0
@@ -9994,6 +9994,7 @@ jQuery(async function () {
99949994 const message = t`The following personas are connected to the current character.\n\nClick on a persona to select it for the current character.\nShift + Click to unlink the persona from the character.`;
99959995 const selectedPersona = await askForPersonaSelection(t`Persona Connections`, message, connections, {
99969996 okButton: t`Ok`,
9997+ highlightPersonas: true,
99979998 shiftClickHandler: (element, ev) => {
99989999
999910000 const personaId = $(element).attr('data-pid');
public/scripts/personas.js+26 -4
@@ -22,7 +22,7 @@ import {
2222} from '../script.js';
2323import { persona_description_positions, power_user } from './power-user.js';
2424import { getTokenCountAsync } from './tokenizers.js';
2525import { PAGINATION_TEMPLATE, debounce, delay, download, ensureImageFormatSupported, flashHighlight, getBase64Async, getCharIndex, onlyUnique, parseJsonFile } from './utils.js';
2626import { debounce_timeout } from './constants.js';
2727import { FILTER_TYPES, FilterHelper } from './filters.js';
2828import { groups, selected_group } from './group-chats.js';
@@ -40,6 +40,8 @@ import { saveMetadataDebounced } from './extensions.js';
4040
4141/** @typedef {'chat' | 'character' | 'default'} PersonaLockType Type of the persona lock */
4242
43+const USER_AVATAR_PATH = 'User Avatars/';
44+
4345let savePersonasPage = 0;
4446const GRID_STORAGE_KEY = 'Personas_GridView';
4547const DEFAULT_DEPTH = 2;
@@ -58,7 +60,7 @@ function switchPersonaGridView() {
5860 * @returns {string} User avatar URL
5961 */
6062export function getUserAvatar(avatarImg) {
6163 return `User Avatars/${USER_AVATAR_PATH}${avatarImg}`;
6264}
6365
6466export function initUserAvatar(avatar) {
@@ -486,6 +488,17 @@ export function setPersonaDescription() {
486488 updatePersonaConnectionsAvatarList();
487489}
488490
491+/**
492+ * Gets a list of all personas in the current chat.
493+ *
494+ * @returns {string[]} An array of persona identifiers
495+ */
496+function getPersonasOfCurrentChat() {
497+ const personas = chat.filter(message => String(message.force_avatar).startsWith(USER_AVATAR_PATH))
498+ .map(message => message.force_avatar.replace(USER_AVATAR_PATH, ''))
499+ .filter(onlyUnique);
500+ return personas;
501+}
489502
490503/**
491504 * Builds a list of persona avatars and populates the given block element with them.
@@ -547,9 +560,10 @@ export function updatePersonaConnectionsAvatarList() {
547560 * @param {Object} [options] - Optional settings for the popup
548561 * @param {string} [options.okButton='None'] - The label for the OK button
549562 * @param {(element: HTMLElement, ev: MouseEvent) => any} [options.shiftClickHandler] - A function to handle shift-click
563+ * @param {boolean|string[]} [options.highlightPersonas=false] - Whether to highlight personas - either by providing a list of persona keys, or true to highlight all present in current chat
550564 * @returns {Promise<string?>} - A promise that resolves to the selected persona id or null if no selection was made
551565 */
552566export async function askForPersonaSelection(title, text, personas, { okButton = 'None', shiftClickHandler = undefined, highlightPersonas = false } = {}) {
553567 const content = document.createElement('div');
554568 const titleElement = document.createElement('h3');
555569 titleElement.textContent = title;
@@ -569,6 +583,8 @@ export async function askForPersonaSelection(title, text, personas, { okButton =
569583 else
570584 personaListBlock.textContent = '[No personas]';
571585
586+ const personasToHighlight = highlightPersonas instanceof Array ? highlightPersonas : (highlightPersonas ? getPersonasOfCurrentChat() : []);
587+
572588 // Make the persona blocks clickable and close the popup
573589 personaListBlock.querySelectorAll('.avatar[data-type="persona"]').forEach(block => {
574590 if (!(block instanceof HTMLElement)) return;
@@ -581,6 +597,12 @@ export async function askForPersonaSelection(title, text, personas, { okButton =
581597 }
582598 });
583599 }
600+
601+ if (personasToHighlight && personasToHighlight.includes(block.dataset.pid)) {
602+ block.classList.add('is_active');
603+ block.title = block.title + '\n\n' + t`Was used in current chat.`;
604+ if (block.classList.contains('is_fav')) block.title = block.title + '\n' + t`Is your default persona.`;
605+ }
584606 });
585607
586608 const popup = new Popup(content, POPUP_TYPE.TEXT, '', { okButton: okButton });
@@ -1225,7 +1247,7 @@ async function loadPersonaForCurrentChat() {
12251247 } else {
12261248 chatPersona = await askForPersonaSelection(t`Select Persona`,
12271249 t`Multiple personas are connected to this character.\nSelect a persona to use for this chat.`,
1228- connectedPersonas);
1250+ connectedPersonas, { highlightPersonas: true });
12291251 }
12301252 }
12311253
public/style.css+4 -0
@@ -3151,6 +3151,10 @@ input[type=search]:focus::-webkit-search-cancel-button {
31513151 color: var(--golden);
31523152}
31533153
3154+.avatar.is_active {
3155+ outline: 2px solid var(--active);
3156+}
3157+
31543158#fav_chara_wrap {
31553159 display: flex;
31563160 margin: 5px 0px;