Fix quality selector

This commit is contained in:
DariusIII
2026-02-18 10:57:29 +01:00
parent 922af10beb
commit 08050309d8
2 changed files with 87 additions and 22 deletions
@@ -1,5 +1,6 @@
/**
* Alpine.data('qualityFilter') - Resolution and source filter buttons
* CSP-safe: Uses click handler with data attributes instead of inline expressions
*/
import Alpine from '@alpinejs/csp';
@@ -12,20 +13,71 @@ Alpine.data('qualityFilter', () => ({
init() {
this.totalReleases = this.$el.querySelectorAll('.release-item').length;
this.visibleCount = this.totalReleases;
// Set up click handlers via event delegation
this.$el.addEventListener('click', (e) => {
const resBtn = e.target.closest('[data-resolution]');
if (resBtn) {
const filter = resBtn.getAttribute('data-resolution');
if (filter) {
this.activeResolution = filter;
this._updateButtonStyles();
this._applyFilters();
}
return;
}
const srcBtn = e.target.closest('[data-source]');
if (srcBtn) {
const filter = srcBtn.getAttribute('data-source');
if (filter) {
this.activeSource = filter;
this._updateButtonStyles();
this._applyFilters();
}
}
});
// Initial button styles
this._updateButtonStyles();
},
setResolution(filter) {
this.activeResolution = filter;
this._applyFilters();
},
/**
* Update button active/inactive styles
*/
_updateButtonStyles() {
// Resolution buttons
this.$el.querySelectorAll('[data-resolution]').forEach(btn => {
const filter = btn.getAttribute('data-resolution');
const isActive = filter === this.activeResolution;
setSource(filter) {
this.activeSource = filter;
this._applyFilters();
},
// Remove all state classes first
btn.classList.remove('bg-blue-600', 'text-white', 'hover:bg-blue-700');
btn.classList.remove('bg-gray-200', 'dark:bg-gray-700', 'text-gray-700', 'dark:text-gray-300', 'hover:bg-gray-300', 'dark:hover:bg-gray-600');
isActiveResolution(f) { return this.activeResolution === f; },
isActiveSource(f) { return this.activeSource === f; },
if (isActive) {
btn.classList.add('bg-blue-600', 'text-white', 'hover:bg-blue-700');
} else {
btn.classList.add('bg-gray-200', 'dark:bg-gray-700', 'text-gray-700', 'dark:text-gray-300', 'hover:bg-gray-300', 'dark:hover:bg-gray-600');
}
});
// Source buttons
this.$el.querySelectorAll('[data-source]').forEach(btn => {
const filter = btn.getAttribute('data-source');
const isActive = filter === this.activeSource;
// Remove all state classes first
btn.classList.remove('bg-purple-600', 'text-white', 'hover:bg-purple-700');
btn.classList.remove('bg-gray-200', 'dark:bg-gray-700', 'text-gray-700', 'dark:text-gray-300', 'hover:bg-gray-300', 'dark:hover:bg-gray-600');
if (isActive) {
btn.classList.add('bg-purple-600', 'text-white', 'hover:bg-purple-700');
} else {
btn.classList.add('bg-gray-200', 'dark:bg-gray-700', 'text-gray-700', 'dark:text-gray-300', 'hover:bg-gray-300', 'dark:hover:bg-gray-600');
}
});
},
countText() {
if (this.activeResolution === 'all' && this.activeSource === 'all') return '(' + this.totalReleases + ' total)';
@@ -47,8 +99,13 @@ Alpine.data('qualityFilter', () => ({
else matchS = name.includes(s);
}
if (matchR && matchS) { item.style.display = ''; visible++; }
else item.style.display = 'none';
if (matchR && matchS) {
item.style.removeProperty('display');
item.classList.remove('hidden');
visible++;
} else {
item.style.setProperty('display', 'none', 'important');
}
});
this.visibleCount = visible;
}
+18 -10
View File
@@ -144,11 +144,11 @@
<!-- All Available Releases -->
@if(isset($releases) && count($releases) > 0)
<div class="mt-8 pt-8 border-t border-gray-200">
<div class="mt-8 pt-8 border-t border-gray-200" x-data="qualityFilter">
<div class="mb-6">
<h2 class="text-2xl font-bold text-gray-900 dark:text-gray-100 mb-4">
Available Releases
<span class="text-lg font-normal text-gray-500" id="release-count">({{ count($releases) }} total)</span>
<span class="text-lg font-normal text-gray-500" x-text="countText()"></span>
</h2>
<!-- Filter Buttons -->
@@ -156,16 +156,20 @@
<!-- Resolution Filters -->
<div class="flex flex-wrap gap-2 items-center">
<span class="text-sm font-medium text-gray-700 dark:text-gray-300 mr-2">Resolution:</span>
<button class="resolution-filter-btn active px-4 py-2 rounded-lg text-sm font-medium transition bg-blue-600 text-white hover:bg-blue-700" data-filter="all">
<button data-resolution="all"
class="px-4 py-2 rounded-lg text-sm font-medium transition bg-blue-600 text-white hover:bg-blue-700">
<i class="fas fa-list mr-1"></i> All
</button>
<button class="resolution-filter-btn px-4 py-2 rounded-lg text-sm font-medium transition bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600" data-filter="720p">
<button data-resolution="720p"
class="px-4 py-2 rounded-lg text-sm font-medium transition bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600">
<i class="fas fa-tv mr-1"></i> 720p
</button>
<button class="resolution-filter-btn px-4 py-2 rounded-lg text-sm font-medium transition bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600" data-filter="1080p">
<button data-resolution="1080p"
class="px-4 py-2 rounded-lg text-sm font-medium transition bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600">
<i class="fas fa-desktop mr-1"></i> 1080p
</button>
<button class="resolution-filter-btn px-4 py-2 rounded-lg text-sm font-medium transition bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600" data-filter="2160p">
<button data-resolution="2160p"
class="px-4 py-2 rounded-lg text-sm font-medium transition bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600">
<i class="fas fa-film mr-1"></i> 2160p / 4K
</button>
</div>
@@ -173,16 +177,20 @@
<!-- Source Filters -->
<div class="flex flex-wrap gap-2 items-center">
<span class="text-sm font-medium text-gray-700 dark:text-gray-300 mr-2">Source:</span>
<button class="source-filter-btn active px-4 py-2 rounded-lg text-sm font-medium transition bg-purple-600 text-white hover:bg-purple-700" data-filter="all">
<button data-source="all"
class="px-4 py-2 rounded-lg text-sm font-medium transition bg-purple-600 text-white hover:bg-purple-700">
<i class="fas fa-list mr-1"></i> All
</button>
<button class="source-filter-btn px-4 py-2 rounded-lg text-sm font-medium transition bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600" data-filter="bluray">
<button data-source="bluray"
class="px-4 py-2 rounded-lg text-sm font-medium transition bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600">
<i class="fas fa-compact-disc mr-1"></i> Bluray
</button>
<button class="source-filter-btn px-4 py-2 rounded-lg text-sm font-medium transition bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600" data-filter="web-dl">
<button data-source="web-dl"
class="px-4 py-2 rounded-lg text-sm font-medium transition bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600">
<i class="fas fa-cloud-download-alt mr-1"></i> WEB-DL
</button>
<button class="source-filter-btn px-4 py-2 rounded-lg text-sm font-medium transition bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600" data-filter="webrip">
<button data-source="webrip"
class="px-4 py-2 rounded-lg text-sm font-medium transition bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600">
<i class="fas fa-globe mr-1"></i> WEBRip
</button>
</div>