From 18011f86f3e9a723ac2c450f00f1647d9653db99 Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Fri, 20 Mar 2026 17:02:22 +0800 Subject: [PATCH] feat: merge duplicate entries across multiple categories Entries appearing in more than one category were previously emitted as separate rows. They are now deduplicated in build.py by URL, collecting all category and group names into lists. The template encodes those lists as pipe-delimited data attributes (data-cats, data-groups) and renders a tag button per category. The JS filter is updated to split on '||' and check for membership, so clicking any category tag correctly shows the merged row. Co-Authored-By: Claude --- website/build.py | 27 ++++++++++++++++++++------- website/static/main.js | 3 ++- website/templates/index.html | 14 ++++++++------ 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/website/build.py b/website/build.py index b19d65b..a2bf34a 100644 --- a/website/build.py +++ b/website/build.py @@ -243,29 +243,42 @@ def extract_entries( categories: list[dict], groups: list[dict], ) -> list[dict]: - """Flatten categories into individual library entries for table display.""" + """Flatten categories into individual library entries for table display. + + Entries appearing in multiple categories are merged into a single entry + with lists of categories and groups. + """ cat_to_group: dict[str, str] = {} for group in groups: for cat in group["categories"]: cat_to_group[cat["name"]] = group["name"] + seen: dict[str, dict] = {} # url -> entry entries: list[dict] = [] for cat in categories: group_name = cat_to_group.get(cat["name"], "Other") for entry in cat["entries"]: - entries.append( - { + url = entry["url"] + if url in seen: + existing = seen[url] + if cat["name"] not in existing["categories"]: + existing["categories"].append(cat["name"]) + if group_name not in existing["groups"]: + existing["groups"].append(group_name) + else: + merged = { "name": entry["name"], - "url": entry["url"], + "url": url, "description": entry["description"], - "category": cat["name"], - "group": group_name, + "categories": [cat["name"]], + "groups": [group_name], "stars": None, "owner": None, "last_commit_at": None, "also_see": entry["also_see"], } - ) + seen[url] = merged + entries.append(merged) return entries diff --git a/website/static/main.js b/website/static/main.js index ed04a55..9c7b159 100644 --- a/website/static/main.js +++ b/website/static/main.js @@ -59,7 +59,8 @@ function applyFilters() { // Category/group filter if (activeFilter) { - show = row.dataset[activeFilter.type] === activeFilter.value; + var attr = activeFilter.type === 'cat' ? row.dataset.cats : row.dataset.groups; + show = attr ? attr.split('||').indexOf(activeFilter.value) !== -1 : false; } // Text search diff --git a/website/templates/index.html b/website/templates/index.html index 8569016..9e8b25d 100644 --- a/website/templates/index.html +++ b/website/templates/index.html @@ -84,8 +84,8 @@ {% else %}—{% endif %} - -