Skip to content

Commit c37ac13

Browse files
committed
feat: add exact tag match filter mode
1 parent 0834729 commit c37ac13

File tree

4 files changed

+46
-7
lines changed

4 files changed

+46
-7
lines changed

frontend/src/html/pages/account.html

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,8 +515,9 @@
515515
<span
516516
class="tagsFilterModeToggle"
517517
data-balloon-pos="right"
518-
data-balloon-length="large"
519-
aria-label="Tag filter mode: OR (any selected tag must match), AND (all selected tags must match)"
518+
data-balloon-length="xlarge"
519+
data-balloon-break
520+
aria-label="Tag filter mode:&#10;- OR (any selected tag must match)&#10;- AND (all selected tags must match)&#10;- EXACT (exactly the selected tags must match)"
520521
>
521522
<i class="fas fa-filter"></i>
522523
<span class="mode-text">OR</span>

frontend/src/ts/elements/account/result-filters.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -495,10 +495,10 @@ function updateTagsFilterModeIcon(): void {
495495
const modeTextElement = toggleElement.find(".mode-text");
496496

497497
if (filters.tagsFilterMode === "and") {
498-
toggleElement.addClass("mode-and");
499498
modeTextElement.text("AND");
499+
} else if (filters.tagsFilterMode === "exact") {
500+
modeTextElement.text("EXACT");
500501
} else {
501-
toggleElement.removeClass("mode-and");
502502
modeTextElement.text("OR");
503503
}
504504
}
@@ -941,7 +941,14 @@ $(".group.presetFilterButtons .filterBtns").on(
941941
);
942942

943943
$(document).on("click", ".pageAccount .tagsFilterModeToggle", () => {
944-
filters.tagsFilterMode = filters.tagsFilterMode === "or" ? "and" : "or";
944+
// Cycle between "or" -> "and" -> "exact" -> "or"
945+
if (filters.tagsFilterMode === "or") {
946+
filters.tagsFilterMode = "and";
947+
} else if (filters.tagsFilterMode === "and") {
948+
filters.tagsFilterMode = "exact";
949+
} else {
950+
filters.tagsFilterMode = "or";
951+
}
945952
save();
946953
updateTagsFilterModeIcon();
947954
selectChangeCallbackFn();
@@ -960,6 +967,6 @@ function verifyResultFiltersStructure(filterIn: ResultFilters): ResultFilters {
960967
return filter;
961968
}
962969

963-
export function getTagsFilterMode(): "and" | "or" {
970+
export function getTagsFilterMode(): "and" | "or" | "exact" {
964971
return filters.tagsFilterMode;
965972
}

frontend/src/ts/pages/account.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,37 @@ async function fillContent(): Promise<void> {
494494
tagHide = false;
495495
}
496496
}
497+
} else if (ResultFilters.getTagsFilterMode() === "exact") {
498+
// EXACT mode - show results where tags exactly match the selected filters
499+
// First, identify all the enabled tags
500+
const enabledTagIds: string[] = [];
501+
502+
// Loop through all valid tags to find which ones are enabled in the filter
503+
validTags.forEach((tagId) => {
504+
if (tagId !== "none" && ResultFilters.getFilter("tags", tagId)) {
505+
enabledTagIds.push(tagId);
506+
}
507+
});
508+
509+
if (enabledTagIds.length === 0) {
510+
// No tag filters enabled, show everything
511+
tagHide = false;
512+
} else {
513+
// Check if result tags exactly match the enabled filters (same number and same tags)
514+
const resultHasExactTags =
515+
result.tags.length === enabledTagIds.length &&
516+
enabledTagIds.every((tagId) => result.tags?.includes(tagId));
517+
518+
if (resultHasExactTags) {
519+
tagHide = false;
520+
} else if (
521+
ResultFilters.getFilter("tags", "none") &&
522+
result.tags.length === 0
523+
) {
524+
// Special case: "none" tag is enabled and result has no tags
525+
tagHide = false;
526+
}
527+
}
497528
}
498529
}
499530

packages/contracts/src/schemas/users.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export const ResultFiltersSchema = z.object({
5151
})
5252
.strict(),
5353
tags: z.record(z.string(), z.boolean()),
54-
tagsFilterMode: z.enum(["and", "or"]),
54+
tagsFilterMode: z.enum(["and", "or", "exact"]),
5555
language: z.record(LanguageSchema, z.boolean()),
5656
funbox: z.record(z.string(), z.boolean()),
5757
});

0 commit comments

Comments
 (0)