diff --git a/js/lint_rules.ts b/js/lint_rules.ts index 2a60ccbbc..a464ced21 100644 --- a/js/lint_rules.ts +++ b/js/lint_rules.ts @@ -1,17 +1,50 @@ -const searchbar = document.getElementById("lint-rule-search"); +const searchbar = document.getElementById("lint-rule-search") as + | HTMLInputElement + | null; +const tagButtons = document.querySelectorAll( + "[data-tag-btn]", +); +const activeTags = new Set(); + +/** + * Shows or hides each rule box based on the current search query and active tag filters. + */ +function updateVisibility() { + const searchQuery = searchbar?.value ?? ""; + const allBoxes = document.querySelectorAll(".lint-rule-box"); + + for (const box of allBoxes) { + const matchesSearch = !searchQuery || box.id.includes(searchQuery); + const boxTags = (box.dataset.tags ?? "").split(",").filter(Boolean); + const matchesFilter = activeTags.size === 0 || + boxTags.some((tag) => activeTags.has(tag)); + + box.style.display = matchesSearch && matchesFilter ? "" : "none"; + } +} + +/** + * Toggles a tag filter button on or off and updates the rule list accordingly. + */ +function handleTagFilterButtonClick(button: HTMLButtonElement) { + const tag = button.dataset.tagBtn!; + const isActive = activeTags.has(tag); + + if (isActive) { + activeTags.delete(tag); + button.setAttribute("aria-pressed", "false"); + } else { + activeTags.add(tag); + button.setAttribute("aria-pressed", "true"); + } + + updateVisibility(); +} if (searchbar) { - searchbar.addEventListener("input", (e) => { - const query = e.currentTarget?.value; - - const allBoxes = document.querySelectorAll(".lint-rule-box"); - - for (const box of allBoxes) { - if (!box.id.includes(query)) { - box.style.display = "none"; - } else { - box.style.display = "block"; - } - } - }); + searchbar.addEventListener("input", updateVisibility); +} + +for (const button of tagButtons) { + button.addEventListener("click", () => handleTagFilterButtonClick(button)); } diff --git a/lint/index.page.tsx b/lint/index.page.tsx index c5ff39b99..1c2caf098 100644 --- a/lint/index.page.tsx +++ b/lint/index.page.tsx @@ -84,8 +84,15 @@ export default function LintRulesIndex(
    {TAGS.map((iconType) => ( -
  • - {getLintIcon(iconType)} {getReadableIconName(iconType)} +
  • +
  • ))}
@@ -96,6 +103,7 @@ export default function LintRulesIndex(