From d0ab763d2ece3f23085fa1cfb6dd77d252fe7242 Mon Sep 17 00:00:00 2001 From: Cohee Date: Wed, 28 Jun 2023 18:26:23 +0300 Subject: [PATCH] [Feature Request] Filter via Tags on Group Chat's "Add Members" Search Box #388 --- public/index.html | 14 +++++-- public/script.js | 6 ++- public/scripts/group-chats.js | 29 ++++---------- public/scripts/tags.js | 72 ++++++++++++++++++++++++----------- public/style.css | 21 ++++++---- 5 files changed, 85 insertions(+), 57 deletions(-) diff --git a/public/index.html b/public/index.html index c3bdb114d..270e21fe8 100644 --- a/public/index.html +++ b/public/index.html @@ -2659,7 +2659,9 @@
- +
+
+
@@ -2695,7 +2697,7 @@
-
+
@@ -3265,7 +3267,11 @@
Avatar
-
+
+
+
+
+
@@ -3457,4 +3463,4 @@ - \ No newline at end of file + diff --git a/public/script.js b/public/script.js index f8854f162..7aebead7a 100644 --- a/public/script.js +++ b/public/script.js @@ -142,11 +142,12 @@ import { tag_map, tags, loadTagsSettings, - printTags, + printTagFilters, getTagsList, appendTagToList, createTagMapFromList, renameTagKey, + tag_filter_types, } from "./scripts/tags.js"; import { SECRET_KEYS, @@ -832,7 +833,8 @@ async function printCharacters() { $("#rm_print_characters_block").append(template); }); - printTags(); + printTagFilters(tag_filter_types.character); + printTagFilters(tag_filter_types.group_member); printGroups(); sortCharactersList(); favsToHotswap(); diff --git a/public/scripts/group-chats.js b/public/scripts/group-chats.js index ce673275d..5ab587d27 100644 --- a/public/scripts/group-chats.js +++ b/public/scripts/group-chats.js @@ -974,12 +974,19 @@ function select_group_chats(groupId, skipAnimation) { ? getThumbnailUrl('avatar', character.avatar) : default_avatar; const template = $("#group_member_template .group_member").clone(); + const isFav = character.fav || character.fav == 'true'; template.data("id", character.avatar); template.find(".avatar img").attr("src", avatar); template.find(".avatar img").attr("title", character.avatar); template.find(".ch_name").text(character.name); template.attr("chid", characters.indexOf(character)); - template.toggleClass('is_fav', character.fav || character.fav == 'true'); + template.find('.ch_fav').val(isFav); + template.toggleClass('is_fav', isFav); + + // Display inline tags + const tags = getTagsList(character.avatar); + const tagsElement = template.find('.tags'); + tags.forEach(tag => appendTagToList(tagsElement, tag, {})); if (!group) { template.find('[data-action="speak"]').hide(); @@ -999,7 +1006,6 @@ function select_group_chats(groupId, skipAnimation) { } sortGroupMembers("#rm_group_add_members .group_member"); - filterMembersByFavorites(false); const groupHasMembers = !!$("#rm_group_members").children().length; $("#rm_group_submit").prop("disabled", !groupHasMembers); @@ -1278,24 +1284,6 @@ async function createGroup() { } } -function toggleFilterByFavorites() { - filterMembersByFavorites(!fav_filter_on); -} - -function filterMembersByFavorites(value) { - fav_filter_on = value; - $('#group_fav_filter').toggleClass('fav_on', fav_filter_on); - - if (!fav_filter_on) { - $("#rm_group_add_members .group_member").removeClass('hiddenByFav'); - } else { - $("#rm_group_add_members .group_member").each(function () { - const isValidSearch = $(this).hasClass("is_fav"); - $(this).toggleClass('hiddenByFav', !isValidSearch); - }); - } -} - export async function createNewGroupChat(groupId) { const group = groups.find(x => x.id === groupId); @@ -1491,7 +1479,6 @@ function stopAutoModeGeneration() { jQuery(() => { $(document).on("click", ".group_select", selectGroup); $("#rm_group_filter").on("input", filterGroupMembers); - $("#group_fav_filter").on("click", toggleFilterByFavorites); $("#rm_group_submit").on("click", createGroup); $("#rm_group_scenario").on("click", setScenarioOverride); $("#rm_group_automode").on("input", function () { diff --git a/public/scripts/tags.js b/public/scripts/tags.js index a453c0f1d..7cfdb35cf 100644 --- a/public/scripts/tags.js +++ b/public/scripts/tags.js @@ -13,7 +13,7 @@ export { tags, tag_map, loadTagsSettings, - printTags, + printTagFilters, isElementTagged, getTagsList, appendTagToList, @@ -24,12 +24,28 @@ export { const random_id = () => Math.round(Date.now() * Math.random()).toString(); const TAG_LOGIC_AND = true; // switch to false to use OR logic for combining tags const CHARACTER_SELECTOR = '#rm_print_characters_block > div'; +const GROUP_MEMBER_SELECTOR = '#rm_group_add_members > div'; +const CHARACTER_FILTER_SELECTOR = '#rm_characters_block .rm_tag_filter'; +const GROUP_FILTER_SELECTOR = '#rm_group_chats_block .rm_tag_filter'; + +function getCharacterSelector(listSelector) { + if ($(listSelector).is(GROUP_FILTER_SELECTOR)) { + return GROUP_MEMBER_SELECTOR; + } + + return CHARACTER_SELECTOR; +} + +export const tag_filter_types = { + character: 0, + group_member: 1, +}; const ACTIONABLE_TAGS = { - FAV: { id: 1, name: 'Show only favorites', color: 'rgba(255, 255, 0, 0.5)', action: applyFavFilter, icon: 'fa-solid fa-star' }, - GROUP: { id: 0, name: 'Show only groups', color: 'rgba(100, 100, 100, 0.5)', action: filterByGroups, icon: 'fa-solid fa-users' }, - HINT: { id: 3, name: 'Show Tag List', color: 'rgba(150, 100, 100, 0.5)', action: onTagListHintClick, icon: 'fa-solid fa-tags' }, + FAV: { id: 1, name: 'Show only favorites', color: 'rgba(255, 255, 0, 0.5)', action: applyFavFilter, icon: 'fa-solid fa-star', class: 'filterByFavorites' }, + GROUP: { id: 0, name: 'Show only groups', color: 'rgba(100, 100, 100, 0.5)', action: filterByGroups, icon: 'fa-solid fa-users', class: 'filterByGroups' }, + HINT: { id: 3, name: 'Show Tag List', color: 'rgba(150, 100, 100, 0.5)', action: onTagListHintClick, icon: 'fa-solid fa-tags', class: 'showTagList' }, } const InListActionable = { @@ -48,14 +64,14 @@ const DEFAULT_TAGS = [ let tags = []; let tag_map = {}; -function applyFavFilter() { +function applyFavFilter(characterSelector) { const isSelected = $(this).hasClass('selected'); const displayFavoritesOnly = !isSelected; $(this).toggleClass('selected', displayFavoritesOnly); - $(CHARACTER_SELECTOR).removeClass('hiddenByFav'); + $(characterSelector).removeClass('hiddenByFav'); - $(CHARACTER_SELECTOR).each(function () { + $(characterSelector).each(function () { if (displayFavoritesOnly) { if ($(this).find(".ch_fav").length !== 0) { const shouldBeDisplayed = $(this).find(".ch_fav").val().toLowerCase().includes(true); @@ -67,13 +83,13 @@ function applyFavFilter() { updateVisibleDivs('#rm_print_characters_block', true); } -function filterByGroups() { +function filterByGroups(characterSelector) { const isSelected = $(this).hasClass('selected'); const displayGroupsOnly = !isSelected; $(this).toggleClass('selected', displayGroupsOnly); - $(CHARACTER_SELECTOR).removeClass('hiddenByGroup'); + $(characterSelector).removeClass('hiddenByGroup'); - $(CHARACTER_SELECTOR).each((_, element) => { + $(characterSelector).each((_, element) => { $(element).toggleClass('hiddenByGroup', displayGroupsOnly && !$(element).hasClass('group_select')); }); updateVisibleDivs('#rm_print_characters_block', true); @@ -195,7 +211,8 @@ function selectTag(event, ui, listSelector) { appendTagToList(getInlineListSelector(), tag, { removable: false }); addTagToMap(tag.id); saveSettingsDebounced(); - printTags(); + printTagFilters(tag_filter_types.character); + printTagFilters(tag_filter_types.group_member); // need to return false to keep the input clear return false; @@ -216,6 +233,8 @@ function appendTagToList(listElement, tag, { removable, selectable, action }) { return; } + const characterSelector = getCharacterSelector($(listElement)); + let tagElement = $('#tag_template .tag').clone(); tagElement.attr('id', tag.id); @@ -226,16 +245,20 @@ function appendTagToList(listElement, tag, { removable, selectable, action }) { const removeButton = tagElement.find(".tag_remove"); removable ? removeButton.show() : removeButton.hide(); + if (tag.class) { + tagElement.addClass(tag.class); + } + if (tag.icon) { tagElement.find('.tag_name').text('').attr('title', tag.name).addClass(tag.icon); } if (selectable) { - tagElement.on('click', () => onTagFilterClick.bind(tagElement)(listElement)); + tagElement.on('click', () => onTagFilterClick.bind(tagElement)(listElement, characterSelector)); } if (action) { - tagElement.on('click', () => action.bind(tagElement)()); + tagElement.on('click', () => action.bind(tagElement)(characterSelector)); tagElement.addClass('actionable'); } if (action && tag.id === 2) { @@ -245,7 +268,7 @@ function appendTagToList(listElement, tag, { removable, selectable, action }) { $(listElement).append(tagElement); } -function onTagFilterClick(listElement) { +function onTagFilterClick(listElement, characterSelector) { if ($(this).hasClass('selected')) { $(this).removeClass('selected'); $(this).addClass('excluded'); @@ -259,7 +282,7 @@ function onTagFilterClick(listElement) { const tagIds = [...($(listElement).find(".tag.selected:not(.actionable)").map((_, el) => $(el).attr("id")))]; const excludedTagIds = [...($(listElement).find(".tag.excluded:not(.actionable)").map((_, el) => $(el).attr("id")))]; - $(CHARACTER_SELECTOR).each((_, element) => applyFilterToElement(tagIds, excludedTagIds, element)); + $(characterSelector).each((_, element) => applyFilterToElement(tagIds, excludedTagIds, element)); updateVisibleDivs('#rm_print_characters_block', true); } @@ -282,7 +305,7 @@ function applyFilterToElement(tagIds, excludedTagIds, element) { function isElementTagged(element, tagId) { const isGroup = $(element).hasClass('group_select'); - const isCharacter = $(element).hasClass('character_select'); + const isCharacter = $(element).hasClass('character_select') || $(element).hasClass('group_member'); const idAttr = isGroup ? 'grid' : 'chid'; const elementId = $(element).attr(idAttr); const lookupValue = isCharacter ? characters[elementId].avatar : elementId; @@ -290,13 +313,13 @@ function isElementTagged(element, tagId) { return isTagged; } -function clearTagsFilter() { - $('#rm_tag_filter .tag').removeClass('selected'); - $(CHARACTER_SELECTOR).removeClass('hiddenByTag'); +function clearTagsFilter(characterSelector) { + $('.rm_tag_filter .tag').removeClass('selected'); + $(characterSelector).removeClass('hiddenByTag'); } -function printTags() { - const FILTER_SELECTOR = '#rm_tag_filter'; +function printTagFilters(type = tag_filter_types.character) { + const FILTER_SELECTOR = type === tag_filter_types.character ? CHARACTER_FILTER_SELECTOR : GROUP_FILTER_SELECTOR; const selectedTagIds = [...($(FILTER_SELECTOR).find(".tag.selected").map((_, el) => $(el).attr("id")))]; $(FILTER_SELECTOR).empty(); const characterTagIds = Object.values(tag_map).flat(); @@ -330,7 +353,8 @@ function onTagRemoveClick(event) { removeTagFromMap(tagId); $(`${getInlineListSelector()} .tag[id="${tagId}"]`).remove(); - printTags(); + printTagFilters(tag_filter_types.character); + printTagFilters(tag_filter_types.group_member); saveSettingsDebounced(); } @@ -350,6 +374,8 @@ function onCharacterCreateClick() { function onGroupCreateClick() { $("#groupTagList").empty(); + printTagFilters(tag_filter_types.character); + printTagFilters(tag_filter_types.group_member); } export function applyTagsOnCharacterSelect() { @@ -371,6 +397,8 @@ function applyTagsOnGroupSelect() { const tags = getTagsList(key); $("#groupTagList").empty(); + printTagFilters(tag_filter_types.character); + printTagFilters(tag_filter_types.group_member); for (const tag of tags) { appendTagToList("#groupTagList", tag, { removable: true }); diff --git a/public/style.css b/public/style.css index 39e127b41..8fc489c81 100644 --- a/public/style.css +++ b/public/style.css @@ -2433,7 +2433,7 @@ input[type="range"]::-webkit-slider-thumb { .mes_buttons .mes_edit, .mes_buttons .mes_bookmark, .extraMesButtonsHint, -#tagListHint, +.tagListHint, .extraMesButtons div { cursor: pointer; transition: 0.3s ease-in-out; @@ -2444,7 +2444,7 @@ input[type="range"]::-webkit-slider-thumb { .mes_buttons .mes_edit:hover, .mes_buttons .mes_bookmark:hover, .extraMesButtonsHint:hover, -#tagListHint:hover, +.tagListHint:hover, .extraMesButtons div:hover { opacity: 1; } @@ -2838,10 +2838,13 @@ h5 { text-shadow: none !important; } -#rm_tag_filter .tag:not(.actionable) { +.rm_tag_filter .tag:not(.actionable) { display: none; } +#rm_group_chats_block .tag.filterByGroups { + display: none; +} .tag.actionable { border-radius: 50%; @@ -2855,7 +2858,7 @@ h5 { align-items: center; } -#tagListHint { +.tagListHint { align-self: center; display: flex; margin-right: 10px; @@ -2927,7 +2930,7 @@ h5 { margin: 5px; } -#rm_tag_filter .tag { +.rm_tag_filter .tag { cursor: pointer; opacity: 0.6; filter: brightness(0.8); @@ -3151,15 +3154,17 @@ body .ui-widget-content li:hover { border-radius: 10px; } -.group_member .ch_name { +.group_member .group_member_name { flex-grow: 1; margin-left: 10px; overflow: hidden; text-overflow: ellipsis; width: calc(100% - 110px); display: flex; - align-items: center; gap: 5px; + height: 100%; + flex-direction: column; + justify-content: center; } .group_member_icon .flex-container { @@ -4935,4 +4940,4 @@ body.waifuMode .zoomed_avatar { background-color: var(--SmartThemeBlurTintColor); text-align: center; line-height: 14px; -} \ No newline at end of file +}