From dc54c140e278ac95285e73166ef2b47c28be5c36 Mon Sep 17 00:00:00 2001 From: Wilson Freitas Date: Sat, 28 Mar 2026 13:03:32 -0300 Subject: [PATCH] Add tag cloud with popular filters above search input New features: - Tag cloud displays 8 most popular languages and 6 most popular categories - Tags have variable font sizes based on frequency (larger = more common) - Tags are clickable and trigger the same filtering as table row tags - Positioned above search input for easy discovery - Styled with hover effects and responsive layout - Shows both language and category tags mixed together The tag cloud helps users quickly discover popular filters without needing to scroll through the entire table. --- site/generate.py | 78 +++++++++++++++++++++++++++++++++++++++++++ site/index.html | 20 +++++++++++ site/static/style.css | 30 +++++++++++++++++ 3 files changed, 128 insertions(+) diff --git a/site/generate.py b/site/generate.py index c010e8d..2c8565f 100644 --- a/site/generate.py +++ b/site/generate.py @@ -199,6 +199,79 @@ def build_tags_html(e: dict) -> str: return "\n ".join(tags) +def build_tag_cloud(entries: list[dict]) -> str: + """Build a tag cloud of popular languages and categories.""" + from collections import Counter + + # Count language frequencies + lang_counts = Counter() + for e in entries: + langs = [l.strip() for l in e.get("languages", e.get("language", "")).split(",") if l.strip()] + lang_counts.update(langs) + + # Remove non-language sections + skip = {"Commercial & Proprietary Services", "Related Lists", "Reproducing Works, Training & Books", "Cross-Language Frameworks"} + for s in skip: + lang_counts.pop(s, None) + + # Count category frequencies + cat_counts = Counter(e.get("category", "") for e in entries if e.get("category")) + + # Get top items + top_langs = lang_counts.most_common(8) # Top 8 languages + top_cats = cat_counts.most_common(6) # Top 6 categories + + if not top_langs and not top_cats: + return "" + + # Combine and sort by frequency + all_items = [] + for lang, count in top_langs: + all_items.append(("language", lang, count)) + for cat, count in top_cats: + all_items.append(("category", cat, count)) + + # Sort by count descending + all_items.sort(key=lambda x: x[2], reverse=True) + + # Calculate size scale (1.0 to 1.6x) + if all_items: + min_count = min(item[2] for item in all_items) + max_count = max(item[2] for item in all_items) + count_range = max_count - min_count if max_count > min_count else 1 + else: + min_count = max_count = count_range = 1 + + tags = [] + esc = html.escape + for tag_type, value, count in all_items: + # Calculate font size: 1.0 to 1.6 + size = 1.0 + ((count - min_count) / count_range * 0.6) if count_range > 0 else 1.0 + + if tag_type == "language": + tags.append( + f'' + ) + else: # category + tags.append( + f'' + ) + + if not tags: + return "" + + return f"""
+
Popular filters:
+
+ {chr(10).join(" " + tag for tag in tags)} +
+
""" + + def generate_html(entries: list[dict]) -> str: """Generate the full HTML page from project entries.""" languages = sorted( @@ -216,6 +289,9 @@ def generate_html(entries: list[dict]) -> str: ) ) + # Generate tag cloud + tag_cloud_html = build_tag_cloud(entries) + # Build table rows rows = [] for i, e in enumerate(entries, 1): @@ -350,6 +426,8 @@ def generate_html(entries: list[dict]) -> str: +{tag_cloud_html} + +
+
Popular filters:
+
+ + + + + + + + + + + + + + +
+
+