Enhance card section filter: multi-term OR/AND, filtered count badge

Space-separated terms use OR logic, comma-separated use AND.
Count badge shows visible/total when filter is active.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-25 02:06:21 +03:00
parent d4a7c81296
commit a82eec7a06

View File

@@ -143,9 +143,9 @@ export class CardSection {
this._lastItems = items;
// Update count badge
// Update count badge (will be refined by _applyFilter if a filter is active)
const countEl = document.querySelector(`[data-cs-toggle="${this.sectionKey}"] .cs-count`);
if (countEl) countEl.textContent = items.length;
if (countEl && !this._filterValue) countEl.textContent = items.length;
const newMap = new Map(items.map(i => [i.key, i.html]));
const addCard = content.querySelector('.cs-add-card');
@@ -229,15 +229,32 @@ export class CardSection {
}
_applyFilter(content, query) {
const lower = query.toLowerCase();
const cards = content.querySelectorAll('.card, .template-card:not(.add-template-card)');
const addCard = content.querySelector('.cs-add-card');
const countEl = document.querySelector(`[data-cs-toggle="${this.sectionKey}"] .cs-count`);
const total = cards.length;
if (!query) {
cards.forEach(card => { card.style.display = ''; });
if (addCard) addCard.style.display = '';
if (countEl) countEl.textContent = total;
return;
}
const lower = query.toLowerCase();
// Comma-separated segments → AND; spaces within a segment → OR
const groups = lower.split(',').map(g => g.trim().split(/\s+/).filter(Boolean)).filter(g => g.length);
let visible = 0;
cards.forEach(card => {
const text = card.textContent.toLowerCase();
card.style.display = (!lower || text.includes(lower)) ? '' : 'none';
// Each group must have at least one matching term (AND of ORs)
const match = groups.every(orTerms => orTerms.some(term => text.includes(term)));
card.style.display = match ? '' : 'none';
if (match) visible++;
});
if (addCard) addCard.style.display = lower ? 'none' : '';
if (addCard) addCard.style.display = 'none';
if (countEl) countEl.textContent = `${visible}/${total}`;
}
}