fix: multi-choice filter styles

This commit is contained in:
2025-07-26 14:16:12 -05:00
parent f9ec089f8b
commit 0e13b74b3b
4 changed files with 42 additions and 65 deletions

View File

@@ -166,7 +166,6 @@ export default class DownloadOptionTr extends HTMLTableRowElement {
if (selectedOptions.length === 0 || if (selectedOptions.length === 0 ||
(selectedOptions.length === 1 && selectedOptions[0] === "") || (selectedOptions.length === 1 && selectedOptions[0] === "") ||
(selectedOptions.length === 1 && selectedOptions[0] === "-") ||
(selectedOptions.length === 1 && selectedOptions[0] === "n/a") (selectedOptions.length === 1 && selectedOptions[0] === "n/a")
) { ) {
return true; return true;

View File

@@ -19,6 +19,8 @@ export default class extends Controller {
"quality": "", "quality": "",
} }
defaultOptions = '<option value="">n/a</option><option value="-">-</option>';
static outlets = ['tv-episode-list'] static outlets = ['tv-episode-list']
static targets = ['resolution', 'codec', 'language', 'provider', 'season', 'quality', 'selectAll', 'downloadSelected'] static targets = ['resolution', 'codec', 'language', 'provider', 'season', 'quality', 'selectAll', 'downloadSelected']
static values = { static values = {
@@ -65,68 +67,33 @@ export default class extends Controller {
this.languages.push(language); this.languages.push(language);
} }
}); });
const preferred = JSON.parse(this.languageTarget.dataset.preferred);
this.languageTarget.innerHTML = '<option value="">n/a</option>'; this.languageTarget.innerHTML = this.#serializeSelectOptions(this.languages);
this.languageTarget.innerHTML += this.languages.sort() this.languageTarget.tomselect.items = preferred;
.map((language) => {
const preferred = this.languageTarget.dataset.preferred.split(',');
if (preferred.includes(language.toLowerCase())) {
return '<option value="'+language+'" selected>'+language+'</option>';
}
return '<option value="'+language+'">'+language+'</option>';
})
.join();
} }
addProviders(option) { addProviders(option) {
if (!this.providers.includes(option.provider)) { if (!this.providers.includes(option.provider)) {
this.providers.push(option.provider); this.providers.push(option.provider);
} }
const preferred = JSON.parse(this.providerTarget.dataset.preferred);
const preferred = this.providerTarget.dataset.preferred; this.providerTarget.innerHTML = this.#serializeSelectOptions(this.providers);
if (preferred) { this.providerTarget.tomselect.items = preferred;
this.providerTarget.innerHTML = '<option value="'+preferred+'" selected>'+preferred+'</option>';
this.providerTarget.innerHTML += '<option value="">n/a</option>';
} else {
this.providerTarget.innerHTML = '<option value="">n/a</option>';
}
this.providerTarget.innerHTML += this.providers.sort()
.map((provider) => {
const preferred = this.languageTarget.dataset.preferred;
if (preferred === provider) {
return;
}
return '<option value="' + provider + '">' + provider + '</option>'
})
.join();
} }
addQualities(option) { addQualities(option) {
if (!this.qualities.includes(option.quality)) { if (option.quality.toLowerCase() in this.reverseMappedQualitiesValue) {
if (option.quality.toLowerCase() in this.reverseMappedQualitiesValue) { let quality = this.reverseMappedQualitiesValue[option.quality.toLowerCase()];
this.qualities.push(option.quality); // converts api returned quality with a value the system recognizes
option.quality = quality;
if (!this.qualities.includes(option.quality)) {
this.qualities.push(quality);
} }
} }
const preferred = JSON.parse(this.qualityTarget.dataset.preferred) ?? [];
const preferred = this.qualityTarget.dataset.preferred; this.qualityTarget.innerHTML = this.#serializeSelectOptions(this.qualities);
if (preferred) { this.qualityTarget.tomselect.items = preferred;
this.qualityTarget.innerHTML = '<option value="'+preferred+'" selected>'+preferred+'</option>';
this.qualityTarget.innerHTML += '<option value="">n/a</option>';
} else {
this.qualityTarget.innerHTML = '<option value="">n/a</option>';
}
this.qualityTarget.innerHTML += this.qualities.sort()
.map((quality) => {
const preferred = this.qualityTarget.dataset.preferred;
if (preferred === quality) {
return;
}
return '<option value="' + quality + '">' + quality + '</option>'
})
.join();
} }
async filter() { async filter() {
@@ -169,7 +136,14 @@ export default class extends Controller {
} }
#fetchValuesFromNodeList(nodeList) { #fetchValuesFromNodeList(nodeList) {
console.log([...nodeList].map(option => option.value))
return [...nodeList].map(option => option.value) return [...nodeList].map(option => option.value)
} }
#serializeSelectOptions(options) {
return this.defaultOptions + options.sort()
.map((option) => {
return '<option value="' + option + '">' + option + '</option>'
})
.join();
}
} }

View File

@@ -173,13 +173,19 @@ dialog[data-dialog-target="dialog"][closing] {
.item[data-ts-item] { .item[data-ts-item] {
background-image: none !important; background-image: none !important;
border: none; border: none;
@apply bg-orange-500; box-shadow: none;
text-shadow: none;
@apply bg-orange-500 rounded-ms font-bold;
} }
@apply border-b-2 border-b-orange-600 bg-transparent; @apply border-b-2 border-b-orange-600 bg-transparent;
} }
.ts-wrapper.plugin-remove_button:not(.rtl) .item .remove {
@apply border-l border-l-orange-600 !important;
}
} }
.ts-wrapper.plugin-remove_button:not(.rtl) .item .remove { .filter-label {
@apply border-l-orange-800; @apply flex flex-col gap-1 justify-between;
} }

View File

@@ -6,8 +6,8 @@
data-result-filter-tv-episode-list-outlet=".episode-list" data-result-filter-tv-episode-list-outlet=".episode-list"
data-action="change->result-filter#filter action-button:downloadSeason@window->result-filter#downloadSeason" data-action="change->result-filter#filter action-button:downloadSeason@window->result-filter#downloadSeason"
> >
<div class="w-full p-4 flex flex-col md:flex-row gap-4 bg-stone-500 text-md text-gray-500 dark:text-gray-50 rounded-lg"> <div class="filter-items w-full p-4 flex flex-col md:flex-row gap-4 bg-black/20 border-2 border-orange-500 text-md text-gray-500 dark:text-gray-50 rounded-lg">
<label for="resolution" class="flex flex-col gap-1"> <label for="resolution" class="filter-label">
Resolution Resolution
<select id="resolution" <select id="resolution"
multiple="multiple" multiple="multiple"
@@ -29,7 +29,7 @@
</select> </select>
</label> </label>
<label for="codec" class="flex flex-col gap-1"> <label for="codec" class="filter-label">
Codec Codec
<select id="codec" <select id="codec"
multiple="multiple" multiple="multiple"
@@ -49,7 +49,7 @@
</select> </select>
</label> </label>
<label for="language" class="flex flex-col gap-1"> <label for="language" class="filter-label">
Language Language
<select id="language" <select id="language"
multiple="multiple" multiple="multiple"
@@ -68,7 +68,7 @@
</select> </select>
</label> </label>
<label for="provider" class="flex flex-col gap-1"> <label for="provider" class="filter-label">
Provider Provider
<select id="provider" <select id="provider"
multiple="multiple" multiple="multiple"
@@ -87,27 +87,25 @@
</select> </select>
</label> </label>
<label for="quality" class="flex flex-col gap-1"> <label for="quality" class="filter-label">
Quality Quality
<select id="quality" <select id="quality"
multiple="multiple" multiple="multiple"
data-result-filter-target="quality" data-result-filter-target="quality"
class="px-1 py-0.5 bg-stone-100 text-gray-50" class="px-1 py-0.5 bg-stone-100 text-gray-50"
data-preferred="{{ this.userPreferences['quality']|json_encode }}"
{{ stimulus_controller('symfony/ux-autocomplete/autocomplete', { {{ stimulus_controller('symfony/ux-autocomplete/autocomplete', {
create: false, create: false,
tomSelectOptions: { tomSelectOptions: {
highlight: false, highlight: false,
} }
}) }} }) }}
{% if this.userPreferences['quality'] != null %}
data-preferred="{{ this.userPreferences['quality']|json_encode }}"
{% endif %}
> >
</select> </select>
</label> </label>
{% if results.media.mediaType == "tvshows" %} {% if results.media.mediaType == "tvshows" %}
<label for="season"> <label for="season" class="filter-label">
Season Season
<select id="season" name="season" value="1" data-result-filter-target="season" class="px-1 py-0.5 bg-stone-100 text-gray-800" <select id="season" name="season" value="1" data-result-filter-target="season" class="px-1 py-0.5 bg-stone-100 text-gray-800"
{{ stimulus_action('result_filter', 'setSeason', 'change') }} {{ stimulus_action('result_filter', 'setSeason', 'change') }}