refactor(store): replace tag pills with category pills, fix sort dates

- Replace tag filter pills with category filter pills (less duplication)
- Prefer per-plugin last_updated over repo-wide pushed_at for sort

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-02-16 10:38:27 -05:00
parent 34a55b5a55
commit 4c2c7c0d17
3 changed files with 38 additions and 40 deletions

View File

@@ -684,14 +684,14 @@ button.bg-white {
opacity: 0.85; opacity: 0.85;
} }
/* Tag Filter Pills */ /* Category Filter Pills */
.tag-filter-pill { .category-filter-pill {
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
transition: all 0.15s ease; transition: all 0.15s ease;
} }
.tag-filter-pill[data-active="true"] { .category-filter-pill[data-active="true"] {
background-color: var(--color-info-bg); background-color: var(--color-info-bg);
border-color: var(--color-info); border-color: var(--color-info);
color: var(--color-info); color: var(--color-info);

View File

@@ -870,7 +870,7 @@ window.currentPluginConfig = null;
filterNew: false, filterNew: false,
filterInstalled: null, // null = all, true = installed only, false = not installed only filterInstalled: null, // null = all, true = installed only, false = not installed only
filterAuthors: [], filterAuthors: [],
filterTags: [], filterCategories: [],
persist() { persist() {
localStorage.setItem('storeSort', this.sort); localStorage.setItem('storeSort', this.sort);
@@ -882,7 +882,7 @@ window.currentPluginConfig = null;
this.filterNew = false; this.filterNew = false;
this.filterInstalled = null; this.filterInstalled = null;
this.filterAuthors = []; this.filterAuthors = [];
this.filterTags = []; this.filterCategories = [];
this.persist(); this.persist();
}, },
@@ -892,7 +892,7 @@ window.currentPluginConfig = null;
if (this.filterNew) count++; if (this.filterNew) count++;
if (this.filterInstalled !== null) count++; if (this.filterInstalled !== null) count++;
count += this.filterAuthors.length; count += this.filterAuthors.length;
count += this.filterTags.length; count += this.filterCategories.length;
return count; return count;
} }
}; };
@@ -5191,19 +5191,20 @@ function setupStoreFilterListeners() {
} }
// Tag pills (event delegation on container) // Tag pills (event delegation on container)
const tagsPills = document.getElementById('filter-tags-pills'); // Category pills (event delegation on container)
if (tagsPills && !tagsPills._listenerSetup) { const catsPills = document.getElementById('filter-categories-pills');
tagsPills._listenerSetup = true; if (catsPills && !catsPills._listenerSetup) {
tagsPills.addEventListener('click', (e) => { catsPills._listenerSetup = true;
const pill = e.target.closest('.tag-filter-pill'); catsPills.addEventListener('click', (e) => {
const pill = e.target.closest('.category-filter-pill');
if (!pill) return; if (!pill) return;
const tag = pill.dataset.tag; const cat = pill.dataset.category;
const idx = storeFilterState.filterTags.indexOf(tag); const idx = storeFilterState.filterCategories.indexOf(cat);
if (idx >= 0) { if (idx >= 0) {
storeFilterState.filterTags.splice(idx, 1); storeFilterState.filterCategories.splice(idx, 1);
pill.dataset.active = 'false'; pill.dataset.active = 'false';
} else { } else {
storeFilterState.filterTags.push(tag); storeFilterState.filterCategories.push(cat);
pill.dataset.active = 'true'; pill.dataset.active = 'true';
} }
applyStoreFiltersAndSort(); applyStoreFiltersAndSort();
@@ -5233,7 +5234,7 @@ function setupStoreFilterListeners() {
} }
const auth = document.getElementById('filter-author'); const auth = document.getElementById('filter-author');
if (auth) auth.value = ''; if (auth) auth.value = '';
document.querySelectorAll('.tag-filter-pill').forEach(p => { document.querySelectorAll('.category-filter-pill').forEach(p => {
p.dataset.active = 'false'; p.dataset.active = 'false';
}); });
applyStoreFiltersAndSort(); applyStoreFiltersAndSort();
@@ -5265,11 +5266,9 @@ function applyStoreFiltersAndSort() {
const authorSet = new Set(storeFilterState.filterAuthors); const authorSet = new Set(storeFilterState.filterAuthors);
plugins = plugins.filter(p => authorSet.has(p.author)); plugins = plugins.filter(p => authorSet.has(p.author));
} }
if (storeFilterState.filterTags.length > 0) { if (storeFilterState.filterCategories.length > 0) {
const tagSet = new Set(storeFilterState.filterTags); const catSet = new Set(storeFilterState.filterCategories);
plugins = plugins.filter(p => plugins = plugins.filter(p => catSet.has(p.category));
p.tags && p.tags.some(t => tagSet.has(t))
);
} }
// Apply sort // Apply sort
@@ -5289,8 +5288,9 @@ function applyStoreFiltersAndSort() {
break; break;
case 'newest': case 'newest':
plugins.sort((a, b) => { plugins.sort((a, b) => {
const dateA = a.last_updated_iso || a.last_updated || ''; // Prefer static per-plugin last_updated over GitHub pushed_at (which is repo-wide)
const dateB = b.last_updated_iso || b.last_updated || ''; const dateA = a.last_updated || a.last_updated_iso || '';
const dateB = b.last_updated || b.last_updated_iso || '';
return dateB.localeCompare(dateA); return dateB.localeCompare(dateA);
}); });
break; break;
@@ -5332,19 +5332,17 @@ function populateFilterControls() {
authorSelect.value = currentVal; authorSelect.value = currentVal;
} }
// Collect unique tags sorted by frequency (most common first) // Collect unique categories sorted alphabetically
const tagCounts = {}; const categories = [...new Set(
pluginStoreCache.forEach(p => { pluginStoreCache.map(p => p.category).filter(Boolean)
(p.tags || []).forEach(t => { tagCounts[t] = (tagCounts[t] || 0) + 1; }); )].sort();
});
const tags = Object.keys(tagCounts).sort((a, b) => tagCounts[b] - tagCounts[a]);
const tagsContainer = document.getElementById('filter-tags-container'); const catsContainer = document.getElementById('filter-categories-container');
const tagsPills = document.getElementById('filter-tags-pills'); const catsPills = document.getElementById('filter-categories-pills');
if (tagsContainer && tagsPills && tags.length > 0) { if (catsContainer && catsPills && categories.length > 0) {
tagsContainer.classList.remove('hidden'); catsContainer.classList.remove('hidden');
tagsPills.innerHTML = tags.map(tag => catsPills.innerHTML = categories.map(cat =>
`<button class="tag-filter-pill badge badge-info cursor-pointer" data-tag="${escapeHtml(tag)}" data-active="${storeFilterState.filterTags.includes(tag)}">${escapeHtml(tag)}</button>` `<button class="category-filter-pill badge badge-info cursor-pointer" data-category="${escapeHtml(cat)}" data-active="${storeFilterState.filterCategories.includes(cat)}">${escapeHtml(cat)}</button>`
).join(''); ).join('');
} }
} }

View File

@@ -216,12 +216,12 @@
</button> </button>
</div> </div>
<!-- Row 2: Tag Pills (populated dynamically) --> <!-- Row 2: Category Pills (populated dynamically) -->
<div id="filter-tags-container" class="hidden"> <div id="filter-categories-container" class="hidden">
<div class="flex items-center gap-2 flex-wrap"> <div class="flex items-center gap-2 flex-wrap">
<span class="text-xs font-medium text-gray-600 whitespace-nowrap">Tags:</span> <span class="text-xs font-medium text-gray-600 whitespace-nowrap">Categories:</span>
<div id="filter-tags-pills" class="flex flex-wrap gap-1.5"> <div id="filter-categories-pills" class="flex flex-wrap gap-1.5">
<!-- Dynamically populated tag pills --> <!-- Dynamically populated category pills -->
</div> </div>
</div> </div>
</div> </div>