mirror of
https://github.com/wilsonfreitas/awesome-quant.git
synced 2026-07-27 20:07:50 +00:00
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.
This commit is contained in:
@@ -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'<button class="tag tag-lang tag-cloud-item" '
|
||||
f'data-filter-type="language" data-filter-value="{esc(value)}" '
|
||||
f'style="font-size: {size:.2f}em;">{esc(value.lower())}</button>'
|
||||
)
|
||||
else: # category
|
||||
tags.append(
|
||||
f'<button class="tag tag-section tag-cloud-item" '
|
||||
f'data-filter-type="category" data-filter-value="{esc(value)}" '
|
||||
f'style="font-size: {size:.2f}em;">{esc(value)}</button>'
|
||||
)
|
||||
|
||||
if not tags:
|
||||
return ""
|
||||
|
||||
return f""" <div class="tag-cloud">
|
||||
<div class="tag-cloud-label">Popular filters:</div>
|
||||
<div class="tag-cloud-items">
|
||||
{chr(10).join(" " + tag for tag in tags)}
|
||||
</div>
|
||||
</div>"""
|
||||
|
||||
|
||||
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:
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{tag_cloud_html}
|
||||
|
||||
<div class="filter-bar" id="filter-bar" style="display:none">
|
||||
<span class="filter-label">Filtered by:</span>
|
||||
<span class="filter-value" id="filter-value"></span>
|
||||
|
||||
@@ -51,6 +51,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tag-cloud">
|
||||
<div class="tag-cloud-label">Popular filters:</div>
|
||||
<div class="tag-cloud-items">
|
||||
<button class="tag tag-lang tag-cloud-item" data-filter-type="language" data-filter-value="Python" style="font-size: 1.60em;">python</button>
|
||||
<button class="tag tag-section tag-cloud-item" data-filter-type="category" data-filter-value="Trading & Backtesting" style="font-size: 1.24em;">Trading & Backtesting</button>
|
||||
<button class="tag tag-section tag-cloud-item" data-filter-type="category" data-filter-value="Market Data & Data Sources" style="font-size: 1.20em;">Market Data & Data Sources</button>
|
||||
<button class="tag tag-section tag-cloud-item" data-filter-type="category" data-filter-value="Financial Instruments & Pricing" style="font-size: 1.16em;">Financial Instruments & Pricing</button>
|
||||
<button class="tag tag-lang tag-cloud-item" data-filter-type="language" data-filter-value="R" style="font-size: 1.15em;">r</button>
|
||||
<button class="tag tag-section tag-cloud-item" data-filter-type="category" data-filter-value="Reproducing Works, Training & Books" style="font-size: 1.11em;">Reproducing Works, Training & Books</button>
|
||||
<button class="tag tag-section tag-cloud-item" data-filter-type="category" data-filter-value="Portfolio Optimization & Risk Analysis" style="font-size: 1.08em;">Portfolio Optimization & Risk Analysis</button>
|
||||
<button class="tag tag-lang tag-cloud-item" data-filter-type="language" data-filter-value="Julia" style="font-size: 1.05em;">julia</button>
|
||||
<button class="tag tag-section tag-cloud-item" data-filter-type="category" data-filter-value="Technical Indicators" style="font-size: 1.05em;">Technical Indicators</button>
|
||||
<button class="tag tag-lang tag-cloud-item" data-filter-type="language" data-filter-value="JavaScript" style="font-size: 1.03em;">javascript</button>
|
||||
<button class="tag tag-lang tag-cloud-item" data-filter-type="language" data-filter-value="Rust" style="font-size: 1.02em;">rust</button>
|
||||
<button class="tag tag-lang tag-cloud-item" data-filter-type="language" data-filter-value="Java" style="font-size: 1.01em;">java</button>
|
||||
<button class="tag tag-lang tag-cloud-item" data-filter-type="language" data-filter-value="CPP" style="font-size: 1.00em;">cpp</button>
|
||||
<button class="tag tag-lang tag-cloud-item" data-filter-type="language" data-filter-value="Haskell" style="font-size: 1.00em;">haskell</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="filter-bar" id="filter-bar" style="display:none">
|
||||
<span class="filter-label">Filtered by:</span>
|
||||
<span class="filter-value" id="filter-value"></span>
|
||||
|
||||
@@ -363,6 +363,36 @@ button {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ===== Tag Cloud ===== */
|
||||
.tag-cloud {
|
||||
padding: 1rem 0 0.5rem 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.tag-cloud-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--ink-tertiary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.tag-cloud-items {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tag-cloud-item {
|
||||
transition: transform var(--transition), opacity var(--transition);
|
||||
}
|
||||
|
||||
.tag-cloud-item:hover {
|
||||
transform: scale(1.08);
|
||||
}
|
||||
|
||||
.filter-controls select {
|
||||
padding: 0.625rem 2rem 0.625rem 0.875rem;
|
||||
font-family: var(--font);
|
||||
|
||||
Reference in New Issue
Block a user