Tag Folders: inline info for groups and avatars

- Add list of character avatars to folders (overflow hidden)
- Add and/or move count of characters for both groups and folders in overview
- Add name list of all chars for groups, above tags
- Replace alt texts of all avatar images with the entity name
- Made title/mouseover tooltip more useful with separation between types and their names
- refactored CSS usage of avatar sizes to global variables
- grid view alignment changes
This commit is contained in:
Wolfsblvt 2024-02-28 06:05:04 +01:00
parent 1faf8b7ee2
commit c0e112d195
7 changed files with 202 additions and 68 deletions

View File

@ -254,3 +254,4 @@
1px -1px 0px black;
opacity: 1;
}

View File

@ -1,3 +1,9 @@
:root {
--big-avatar-height-factor: 1.8;
--big-avatar-width-factor: 1.2;
--big-avatar-border-factor: 5;
}
body.tts .mes[is_system="true"] .mes_narrate {
display: none;
}
@ -21,7 +27,7 @@ body.square-avatars .avatar,
body.square-avatars .avatar img,
body.square-avatars .hotswapAvatar,
body.square-avatars .hotswapAvatar img {
border-radius: 2px !important;
border-radius: var(--avatar-base-border-radius) !important;
}
/*char list grid mode*/
@ -89,10 +95,12 @@ body.charListGrid #rm_print_characters_block .group_select .group_name_block {
width: 100%;
}
body.charListGrid #rm_print_characters_block .bogus_folder_counter_block,
body.charListGrid #rm_print_characters_block .ch_description,
body.charListGrid #rm_print_characters_block .tags_inline,
body.charListGrid #rm_print_characters_block .character_version,
body.charListGrid #rm_print_characters_block .bogus_folder_unit,
body.charListGrid #rm_print_characters_block .group_select_unit,
body.charListGrid #rm_print_characters_block .group_select_block_list,
body.charListGrid #rm_print_characters_block .ch_avatar_url,
#user_avatar_block.gridView .avatar-container .ch_description {
display: none;
@ -106,12 +114,12 @@ body.big-avatars .bogus_folder_select .avatar {
}
body:not(.big-avatars) .avatar {
border-radius: 50%;
border-radius: var(--avatar-base-border-radius-round);
}
body.big-avatars .avatar {
width: 60px;
height: 90px;
width: calc(var(--avatar-base-height) * var(--big-avatar-width-factor));
height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor));
/* width: unset; */
border-style: none;
display: flex;
@ -120,33 +128,33 @@ body.big-avatars .avatar {
align-items: center;
/* align-self: unset; */
overflow: visible;
border-radius: 10px;
border-radius: calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor));
flex: 1
}
body.big-avatars #user_avatar_block .avatar,
body.big-avatars #user_avatar_block .avatar_upload {
height: 90px;
width: 60px;
border-radius: 10px;
width: calc(var(--avatar-base-height) * var(--big-avatar-width-factor));
height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor));
border-radius: calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor));
}
body.big-avatars #user_avatar_block .avatar img {
height: 90px;
width: 60px;
width: calc(var(--avatar-base-height) * var(--big-avatar-width-factor));
height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor));
}
body.big-avatars .avatar img {
width: 60px;
height: 90px;
width: calc(var(--avatar-base-height) * var(--big-avatar-width-factor));
height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor));
object-fit: cover;
object-position: center;
border: 1px solid var(--SmartThemeBorderColor);
border-radius: 10px;
border-radius: calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor));
}
body:not(.big-avatars) .avatar_collage {
min-width: 50px;
min-width: var(--avatar-base-width);
aspect-ratio: 1 / 1;
}
@ -155,8 +163,8 @@ body:not(.big-avatars) .avatar_collage img {
}
body.big-avatars .avatar_collage {
min-width: 60px;
max-width: 60px;
min-width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor));
max-width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor));
aspect-ratio: 2 / 3;
}
@ -169,42 +177,68 @@ body.big-avatars .avatar-container .ch_description {
text-overflow: unset;
}
body.big-avatars .avatars_inline .avatar,
body.big-avatars .avatars_inline .avatar img {
width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor) * var(--inline-avatar-factor));
height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor) * var(--inline-avatar-factor));
}
body.big-avatars .bogus_folder_avatars_block {
flex-wrap: wrap;
overflow: hidden;
height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor) * var(--inline-avatar-factor) + 2 * var(--avatar-base-border-radius));
/* margin-top: calc(var(--avatar-base-height) * var(--big-avatar-height-factor) * var(--inline-avatar-factor) * 0.2); */
}
body.big-avatars .bogus_folder_avatars_block .avatar {
margin: calc(var(--avatar-base-border-radius)) 0;
}
body:not(.big-avatars) .avatars_inline .avatar_collage {
min-width: calc(var(--avatar-base-width) * var(--inline-avatar-factor));
}
body.big-avatars .avatars_inline .avatar_collage {
min-width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor) * var(--inline-avatar-factor));
max-width: calc(var(--avatar-base-width) * var(--big-avatar-width-factor) * var(--inline-avatar-factor));
}
/* border radius for big avatars collages */
body.big-avatars .collage_2 .img_1 {
border-radius: 10px 0 0 10px !important;
border-radius: calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) 0 0 calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) !important;
}
body.big-avatars .collage_2 .img_2 {
border-radius: 0 10px 10px 0 !important;
border-radius: 0 calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) 0 !important;
}
body.big-avatars .collage_3 .img_1 {
border-radius: 10px 0 0 0 !important;
border-radius: calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) 0 0 0 !important;
}
body.big-avatars .collage_3 .img_2 {
border-radius: 0 10px 0 0 !important;
border-radius: 0 calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) 0 0 !important;
}
body.big-avatars .collage_3 .img_3 {
border-radius: 0 0 10px 10px !important;
border-radius: 0 0 calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) !important;
}
body.big-avatars .collage_4 .img_1 {
border-radius: 10px 0 0 0 !important;
border-radius: calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) 0 0 0 !important;
}
body.big-avatars .collage_4 .img_2 {
border-radius: 0 10px 0 0 !important;
border-radius: 0 calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) 0 0 !important;
}
body.big-avatars .collage_4 .img_3 {
border-radius: 0 0 0 10px !important;
border-radius: 0 0 0 calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) !important;
}
body.big-avatars .collage_4 .img_4 {
border-radius: 0 0 10px 0 !important;
border-radius: 0 0 calc(var(--avatar-base-border-radius) * var(--big-avatar-border-factor)) 0 !important;
}

View File

@ -5006,10 +5006,16 @@
<div class="avatar">
<img src="">
</div>
<div class="flex-container wide100pLess70px gap5px group_name_block">
<div class="ch_name"></div>
<div class="flex-container wide100pLess70px gap5px group_select_container">
<div class="wide100p group_name_block character_name_block">
<div class="ch_name"></div>
<small class="group_select_unit" data="characters">group of</small>
<small class="character_version group_select_counter">5</small>
<small class="group_select_unit" data="characters">characters</small>
</div>
<i class='group_fav_icon fa-solid fa-star'></i>
<input class="ch_fav" value="" hidden />
<div class="group_select_block_list"></div>
<div class="tags tags_inline"></div>
</div>
</div>
@ -5022,14 +5028,18 @@
<div class="flex-container wide100pLess70px character_select_container">
<div class="wide100p character_name_block">
<span class="ch_name"></span>
<small class="character_version bogus_folder_counter"></small>
<small class="bogus_folder_unit" data="characters">characters</small>
</div>
<div class="bogus_folder_counter_block">
<span class="bogus_folder_counter"></span>
<span data="character card(s)">character card(s)</span>
</div>
<div class="bogus_folder_avatars_block avatars_inline tags tags_inline"></div>
</div>
</div>
</div>
<div id="bogus_folder_inline_character_template" class="template_element">
<div class="avatar flex alignitemscenter textAlignCenter">
<img src="">
</div>
</div>
<div id="bogus_folder_back_template" class="template_element">
<div class="bogus_folder_select flex-container wide100p alignitemsflexstart" id="BogusFolderBack" tagid="back">
<div class="avatar flex alignitemscenter textAlignCenter">

View File

@ -1159,18 +1159,53 @@ export async function selectCharacterById(id) {
function getTagBlock(item, entities) {
let count = 0;
let subEntities = [];
for (const entity of entities) {
if (entitiesFilter.isElementTagged(entity, item.id)) {
count++;
subEntities.push(entity);
}
}
const template = $('#bogus_folder_template .bogus_folder_select').clone();
template.attr({ 'tagid': item.id, 'id': `BogusFolder${item.id}` });
template.find('.avatar').css({ 'background-color': item.color, 'color': item.color2 });
template.find('.ch_name').text(item.name);
template.find('.avatar').css({ 'background-color': item.color, 'color': item.color2 }).attr('title', `[Folder] ${item.name}`);
template.find('.ch_name').text(item.name).attr('title', `[Folder] ${item.name}`);;
template.find('.bogus_folder_counter').text(count);
// Fill inline character images
const inlineAvatars = template.find('.bogus_folder_avatars_block');
for (const entitiy of subEntities) {
const id = entitiy.id;
// Populate the template
const avatarTemplate = $('#bogus_folder_inline_character_template .avatar').clone();
let this_avatar = default_avatar;
if (entitiy.item.avatar != 'none') {
this_avatar = getThumbnailUrl('avatar', entitiy.item.avatar);
}
avatarTemplate.attr({ 'chid': id, 'id': `CharID${id}` });
avatarTemplate.find('img').attr('src', this_avatar).attr('alt', entitiy.item.name);
avatarTemplate.attr('title', `[Character] ${entitiy.item.name}`);
avatarTemplate.toggleClass('is_fav', entitiy.item.fav || entitiy.item.fav == 'true');
avatarTemplate.find('.ch_fav').val(entitiy.item.fav);
// If this is a group, we need to hack slightly. We still want to keep most of the css classes and layout, but use a group avatar instead.
if (entitiy.type === 'group') {
const grpTemplate = getGroupAvatar(entitiy.item);
avatarTemplate.addClass(grpTemplate.attr('class'));
avatarTemplate.empty();
avatarTemplate.append(grpTemplate.children());
avatarTemplate.attr('title', `Group: ${entitiy.item.name}`);
}
inlineAvatars.append(avatarTemplate);
}
return template;
}
@ -1200,9 +1235,9 @@ function getCharacterBlock(item, id) {
// Populate the template
const template = $('#character_template .character_select').clone();
template.attr({ 'chid': id, 'id': `CharID${id}` });
template.find('img').attr('src', this_avatar);
template.find('.avatar').attr('title', item.avatar);
template.find('.ch_name').text(item.name);
template.find('img').attr('src', this_avatar).attr('alt', item.name);
template.find('.avatar').attr('title', `[Character] ${item.name}`);
template.find('.ch_name').text(item.name).attr('title', `[Character] ${item.name}`);
if (power_user.show_card_avatar_urls) {
template.find('.ch_avatar_url').text(item.avatar);
}

View File

@ -523,13 +523,27 @@ async function getGroups() {
}
export function getGroupBlock(group) {
let count = 0;
let namesList = [];
// Build inline name list
if (Array.isArray(group.members) && group.members.length) {
for (const member of group.members) {
count++;
const character = characters.find(x => x.avatar === member || x.name === member);
namesList.push(`<span class="group_ch_name">${character.name}</span>`);
}
}
const template = $('#group_list_template .group_select').clone();
template.data('id', group.id);
template.attr('grid', group.id);
template.find('.ch_name').text(group.name);
template.find('.ch_name').text(group.name).attr('title', `[Group] ${group.name}`);
template.find('.group_fav_icon').css('display', 'none');
template.addClass(group.fav ? 'is_fav' : '');
template.find('.ch_fav').val(group.fav);
template.find('.group_select_counter').text(count);
template.find('.group_select_block_list').append(namesList.join(''));
// Display inline tags
const tags = getTagsList(group.id);
@ -565,11 +579,11 @@ function isValidImageUrl(url) {
function getGroupAvatar(group) {
if (!group) {
return $(`<div class="avatar"><img src="${default_avatar}"></div>`);
return $(`<div class="avatar" title="[Group] ${group.name}"><img src="${default_avatar}"></div>`);
}
// if isDataURL or if it's a valid local file url
if (isValidImageUrl(group.avatar_url)) {
return $(`<div class="avatar"><img src="${group.avatar_url}"></div>`);
return $(`<div class="avatar" title="[Group] ${group.name}"><img src="${group.avatar_url}"></div>`);
}
const memberAvatars = [];
@ -595,6 +609,7 @@ function getGroupAvatar(group) {
groupAvatar.find(`.img_${i + 1}`).attr('src', memberAvatars[i]);
}
groupAvatar.attr('title', `[Group] ${group.name}`);
return groupAvatar;
}
@ -606,6 +621,7 @@ function getGroupAvatar(group) {
// default avatar
const groupAvatar = $('#group_avatars_template .collage_1').clone();
groupAvatar.find('.img_1').attr('src', group.avatar_url || system_avatar);
groupAvatar.attr('title', `[Group] ${group.name}`);
return groupAvatar;
}

View File

@ -567,14 +567,8 @@ function onViewTagsListClick() {
list.append(tagContainer);
const sortedTags = sortTags(tags);
// var highestSortOrder = sortedTags.reduce((max, tag) => tag.sort_order !== undefined ? Math.max(max, tag.sort_order) : max, -1);
for (const tag of sortedTags) {
// // For drag&drop to work we need a sort_order defined, so set it but not save. Gets persisted if there are any tag settings changes
// if (tag.sort_order === undefined) {
// tag.sort_order = ++highestSortOrder;
// }
appendViewTagToList(tagContainer, tag, everything);
}

View File

@ -96,6 +96,12 @@
/*styles for the color picker*/
--tool-cool-color-picker-btn-bg: transparent;
--tool-cool-color-picker-btn-border-color: transparent;
--avatar-base-height: 50px;
--avatar-base-width: 50px;
--avatar-base-border-radius: 2px;
--avatar-base-border-radius-round: 50%;
--inline-avatar-factor: 0.6;
}
* {
@ -849,8 +855,8 @@ hr {
}
.add_avatar {
border: 2px solid var(--SmartThemeBodyColor);
margin: 2px;
border: var(--avatar-base-border-radius) solid var(--SmartThemeBodyColor);
margin: var(--avatar-base-border-radius);
cursor: pointer;
transition: filter 0.2s ease-in-out;
}
@ -860,14 +866,14 @@ hr {
}
.avatar {
width: 50px;
height: 50px;
width: var(--avatar-base-width);
height: var(--avatar-base-height);
border-style: none;
flex: 1;
}
.last_mes .mesAvatarWrapper {
padding-bottom: 50px;
padding-bottom: var(--avatar-base-height);
}
.mes .avatar {
@ -880,8 +886,8 @@ hr {
.hotswapAvatar,
.hotswapAvatar .avatar {
width: 50px !important;
height: 50px !important;
width: var(--avatar-base-width) !important;
height: var(--avatar-base-height) !important;
border-style: none;
}
@ -901,10 +907,10 @@ hr {
.hotswapAvatar .avatar_collage,
.hotswapAvatar.group_select {
border-radius: 50% !important;
border-radius: var(--avatar-base-border-radius-round) !important;
position: relative;
overflow: hidden;
min-width: 50px !important;
min-width: var(--avatar-base-width) !important;
}
.hotswapAvatar.group_select .avatar.avatar_collage img {
@ -916,21 +922,21 @@ hr {
}
.hotswapAvatar .avatar {
width: 50px !important;
height: 50px !important;
width: var(--avatar-base-width) !important;
height: var(--avatar-base-height) !important;
object-fit: cover;
object-position: center center;
border-radius: 50% !important;
border-radius: var(--avatar-base-border-radius-round) !important;
box-shadow: 0 0 5px var(--black50a);
}
.hotswapAvatar img,
.avatar img {
width: 50px;
height: 50px;
width: var(--avatar-base-width);
height: var(--avatar-base-height);
object-fit: cover;
object-position: center center;
border-radius: 50%;
border-radius: var(--avatar-base-border-radius-round);
border: 1px solid var(--SmartThemeBorderColor);
/*--black30a*/
box-shadow: 0 0 5px var(--black50a);
@ -950,6 +956,43 @@ hr {
outline-color: var(--SmartThemeBorderColor);
}
.avatars_inline .avatar,
.avatars_inline .avatar img {
width: calc(var(--avatar-base-width) * var(--inline-avatar-factor));
height: calc(var(--avatar-base-height) * var(--inline-avatar-factor));
}
.bogus_folder_avatars_block {
flex-wrap: wrap;
overflow: hidden;
height: calc(var(--avatar-base-height) * var(--inline-avatar-factor) + 2 * var(--avatar-base-border-radius));
/* margin-top: calc(var(--avatar-base-height) * var(--inline-avatar-factor) * 0.2); */
}
.bogus_folder_avatars_block .avatar {
margin: calc(var(--avatar-base-border-radius)) 0;
}
.group_select_block_list {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
gap: 0.2rem;
align-items: flex-end;
flex-basis: 100%;
}
.group_select_block_list .group_ch_name:not(:last-child):not(:nth-last-child(2)):after {
content: ", ";
font-size: calc(var(--mainFontSize) * 0.9);
}
.group_select_block_list .group_ch_name:nth-last-child(2):after {
content: " & ";
font-size: calc(var(--mainFontSize) * 0.9);
}
.mes_block {
padding-top: 0;
padding-left: 10px;
@ -1778,7 +1821,8 @@ input[type=search]:focus::-webkit-search-cancel-button {
.character_select.is_fav .avatar,
.group_select.is_fav .avatar,
.group_member.is_fav .avatar {
.group_member.is_fav .avatar,
.avatar.is_fav {
outline: 2px solid var(--golden);
}
@ -1842,8 +1886,8 @@ input[type=search]:focus::-webkit-search-cancel-button {
cursor: pointer;
margin-bottom: 1px;
width: 100%;
outline: 2px solid transparent;
border: 2px solid transparent;
outline: var(--avatar-base-border-radius) solid transparent;
border: var(--avatar-base-border-radius) solid transparent;
}
.avatar-container .character_select_container {
@ -2297,18 +2341,18 @@ input[type="checkbox"]:not(#nav-toggle):not(#rm_button_panel_pin):not(#lm_button
.avatar-container .avatar {
cursor: pointer;
border-radius: 50%;
border-radius: var(--avatar-base-border-radius-round);
align-self: center;
outline: 2px solid transparent;
outline: var(--avatar-base-border-radius) solid transparent;
flex: unset;
}
.avatar-container.selected {
border: 2px solid rgba(255, 255, 255, 0.7);
border: var(--avatar-base-border-radius) solid rgba(255, 255, 255, 0.7);
}
.avatar-container.default_persona .avatar {
outline: 2px solid var(--golden);
outline: var(--avatar-base-border-radius) solid var(--golden);
}
.avatar-container.default_persona .set_default_persona {