Improve the multi-select behaviour/appearance and display how many selections are made/required

This commit is contained in:
Oliver 2026-02-01 01:19:39 -07:00
parent 0381df035e
commit 812583f33c
7 changed files with 75 additions and 20 deletions

View file

@ -4,6 +4,9 @@
"unsaved": "This change hasn't been saved, if you close without saving it will be undone."
},
"apps": {
"ArtBrowser": {
"selected": "{current}/{required} Selected"
},
"ArtistApp": {
"title": {
"create": "Create New Artist",

View file

@ -8,7 +8,7 @@ const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
const { FormDataExtended } = foundry.applications.ux;
const { deepClone } = foundry.utils;
const PAGE_SIZE = 52;
const PAGE_SIZE = 8;
export class ArtBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
// #region Options
@ -129,6 +129,26 @@ export class ArtBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
this.#onFilterSubmit.bind(this),
);
};
if (options.parts?.includes(`images`)) {
this._updateSelectedCount();
};
};
_updateSelectedCount() {
if (!this.rendered || this.selectMode === `single`) return;
const element = this.element.querySelector(`.selected-count`);
if (element) {
element.innerText = `${this.#selected.size} Selected`;
element.innerText = _loc(
`TB.apps.ArtBrowser.selected`,
{
current: this.#selected.size,
required: this.#selectCount,
},
);
};
};
async close(options) {
@ -157,7 +177,13 @@ export class ArtBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
meta: {
idp: this.id,
},
selectMode: this.selectMode,
is: {
multi: this.selectMode === `multi`,
single: this.selectMode === `single`,
},
can: {
upload: true,
},
};
};
@ -194,8 +220,6 @@ export class ArtBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
const images = [];
for (const [id, image] of allImages) {
image.id = id;
// Check if it matches the required filters
if (this.filters.name && !image.name.includes(this.filters.name)) {
continue;
@ -206,6 +230,10 @@ export class ArtBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
const hasAllTags = this.filters.tags.every(tag => image.tags.includes(tag));
if ((!hasAnArtist && hasArtistFilter) || !hasAllTags) { continue };
// Populate ephemeral data for rendering
image.id = id;
image.selected = this.#selected.has(imagePath(image));
// Convert all of the artist IDs into the actual data
image.artists = image.artists
.map(artistID => {
@ -271,15 +299,15 @@ export class ArtBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
const path = imagePath(image);
if (this.#selectCount > 1) {
if (this.#selected.has(path)) {
target.ariaPressed = false;
if (!target.checked) {
this.#selected.delete(path);
} else {
target.ariaPressed = true;
this.#selected.add(path);
};
if (this.#selected.size >= this.#selectCount) {
await this.#submit(Array.from(this.#selected));
} else {
this._updateSelectedCount();
};
} else {
await this.#submit(path);

View file

@ -30,18 +30,22 @@
gap: 8px;
border-radius: 4px;
overflow: hidden;
transition: background 100ms ease-in-out;
position: relative;
transition: all 100ms ease-in-out;
&.grid {
&:hover {
background: var(--color-cool-4);
}
&:hover, &:has(input[type="checkbox"]:checked) {
background: var(--color-warm-3);
}
img {
width: 100%;
aspect-ratio: 1;
object-fit: contain;
transition: all 100ms ease-in-out;
}
&:has(input[type="checkbox"]:checked) img {
transform: scale(0.85);
}
.details {
@ -50,6 +54,10 @@
gap: 4px;
padding: 0px 4px 4px;
}
input[type="checkbox"] {
position: absolute;
}
}
.paginated {

View file

@ -0,0 +1,3 @@
.token-browser > .window-content input[type="checkbox"] {
--checkbox-checked-color: var(--color-level-success-border);
}

View file

@ -6,6 +6,7 @@
/* Elements */
@import url("./elements/utils.css") layer(elements);
@import url("./elements/checkbox.css") layer(elements);
@import url("./elements/lists.css") layer(elements);
/* Apps */

View file

@ -6,18 +6,20 @@
src="{{tb-filePath image.path}}"
alt=""
>
{{#if (eq selectMode "single")}}
{{#if is.single}}
<button
data-action="select"
>
Select
</button>
{{else if (eq selectMode "multi")}}
<button
{{else if is.multi}}
<input
type="checkbox"
aria-label="Select image"
data-action="select"
aria-pressed="{{image.selected}}"
{{checked image.selected}}
>
Select (Multi)
</button>
{{/if}}
</li>

View file

@ -1,11 +1,21 @@
<div class="paginated">
<div class="row">
<button data-action="uploadImage">Upload Image</button>
{{#if can.upload}}
<button data-action="uploadImage">Upload Image</button>
{{/if}}
{{#if is.multi}}
<div class="grow"></div>
<div class="selected-count"></div>
{{/if}}
</div>
{{#if images}}
<ul class="image-list image-list--{{listLayout}}">
{{#each images as | image |}}
{{> (tb-filePath "templates/ArtBrowser/image/grid.hbs") image=image selectMode=@root.selectMode }}
{{>
(tb-filePath "templates/ArtBrowser/image/grid.hbs")
image=image
is=@root.is
}}
{{/each}}
</ul>
{{else}}