Skip to content

Commit d64b47b

Browse files
vintaclaude
andcommitted
feat(website): mirror index layout on category pages
Add search input, filter chips, no-results block, and back-to-top button to category/group/subcategory pages. Pass filter_urls_json to all page types so tag-chip navigation works site-wide. Fix JS so filter-clear and no-results-clear redirect to / on non-index pages instead of trying to filter a non-existent local table. Remove the now-redundant .category-results CSS overrides. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 0336942 commit d64b47b

5 files changed

Lines changed: 80 additions & 30 deletions

File tree

website/build.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,8 @@ def build(repo_root: Path) -> None:
339339
shutil.rmtree(site_dir)
340340
site_dir.mkdir(parents=True)
341341

342+
filter_urls_json = json.dumps(filter_urls, sort_keys=True, ensure_ascii=False).replace("</", "<\\/")
343+
342344
tpl_index = env.get_template("index.html")
343345
(site_dir / "index.html").write_text(
344346
tpl_index.render(
@@ -351,7 +353,7 @@ def build(repo_root: Path) -> None:
351353
build_date=build_date.strftime("%B %d, %Y"),
352354
sponsors=sponsors,
353355
category_urls=category_urls,
354-
filter_urls_json=json.dumps(filter_urls, sort_keys=True, ensure_ascii=False).replace("</", "<\\/"),
356+
filter_urls_json=filter_urls_json,
355357
),
356358
encoding="utf-8",
357359
)
@@ -371,6 +373,7 @@ def build(repo_root: Path) -> None:
371373
page_kind="category",
372374
category_urls=category_urls,
373375
current_path=category_path(category),
376+
filter_urls_json=filter_urls_json,
374377
),
375378
encoding="utf-8",
376379
)
@@ -394,6 +397,7 @@ def build(repo_root: Path) -> None:
394397
page_kind="group",
395398
category_urls=category_urls,
396399
current_path=group_path(group["slug"]),
400+
filter_urls_json=filter_urls_json,
397401
),
398402
encoding="utf-8",
399403
)
@@ -431,6 +435,7 @@ def build(repo_root: Path) -> None:
431435
parent_category=category,
432436
category_urls=category_urls,
433437
current_path=subcategory_path(category["slug"], sub["slug"]),
438+
filter_urls_json=filter_urls_json,
434439
),
435440
encoding="utf-8",
436441
)

website/static/main.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,10 @@ tags.forEach(function (tag) {
341341

342342
if (filterClear) {
343343
filterClear.addEventListener("click", function () {
344+
if (!isIndexPage()) {
345+
window.location.href = "/";
346+
return;
347+
}
344348
activeFilter = null;
345349
applyFilters();
346350
});
@@ -349,6 +353,10 @@ if (filterClear) {
349353
const noResultsClear = document.querySelector(".no-results-clear");
350354
if (noResultsClear) {
351355
noResultsClear.addEventListener("click", function () {
356+
if (!isIndexPage()) {
357+
window.location.href = "/";
358+
return;
359+
}
352360
if (searchInput) searchInput.value = "";
353361
activeFilter = null;
354362
applyFilters();
@@ -451,10 +459,8 @@ if (backToTop) {
451459
) {
452460
activeSort = { col: sort, order: order };
453461
}
454-
if (isIndexPage()) {
455-
const matched = urlToFilter[location.pathname];
456-
if (matched) activeFilter = matched;
457-
}
462+
const matched = urlToFilter[location.pathname];
463+
if (matched) activeFilter = matched;
458464
if (q || activeFilter || sort) {
459465
sortRows();
460466
}

website/static/style.css

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ kbd {
430430
.tag:focus-visible,
431431
.back-to-top:focus-visible,
432432
.no-results-clear:focus-visible,
433-
.category-table a:focus-visible,
433+
.table a:focus-visible,
434434
.footer a:focus-visible,
435435
.sort-btn:focus-visible {
436436
outline: 2px solid var(--accent);
@@ -498,19 +498,6 @@ kbd {
498498
text-decoration-color: oklch(100% 0 0 / 0.7);
499499
}
500500

501-
.category-results {
502-
padding-top: clamp(2.5rem, 5vw, 3.75rem);
503-
}
504-
505-
.category-results .results-intro {
506-
grid-template-columns: 1fr;
507-
gap: 0.6rem;
508-
}
509-
510-
.category-results .results-intro .results-note {
511-
justify-self: start;
512-
}
513-
514501
.sponsor-band {
515502
padding-block: clamp(2.5rem, 5.5vw, 4rem);
516503
background:

website/templates/category.html

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,58 @@ <h1>{{ category.name }}</h1>
3838
</header>
3939
{% endblock %}
4040
{% block content %}
41-
<section class="results-section category-results" id="category-index">
41+
<script type="application/json" id="filter-urls">{{ filter_urls_json | safe }}</script>
42+
<section class="results-section" id="library-index">
4243
<div class="results-intro section-shell" data-reveal>
4344
<div>
44-
<h2>Python Projects in {{ category.name }}</h2>
45+
<h2>Search every project in one place</h2>
4546
</div>
4647
<p class="results-note">
47-
Sorted by GitHub stars when available. Click any row for details.
48+
Press <kbd>/</kbd> to search. Tap a tag to filter. Click any row for
49+
details.
4850
</p>
4951
</div>
5052

51-
<h2 class="sr-only">{{ category.name }} results</h2>
53+
<div class="controls section-shell" data-reveal>
54+
<h2 class="sr-only">Search and filter</h2>
55+
<div class="search-wrap">
56+
<svg
57+
class="search-icon"
58+
width="16"
59+
height="16"
60+
viewBox="0 0 24 24"
61+
fill="none"
62+
stroke="currentColor"
63+
stroke-width="2.5"
64+
stroke-linecap="round"
65+
stroke-linejoin="round"
66+
>
67+
<circle cx="11" cy="11" r="8" />
68+
<line x1="21" y1="21" x2="16.65" y2="16.65" />
69+
</svg>
70+
<input
71+
type="search"
72+
class="search"
73+
placeholder="Search {{ entries | length }} projects in {{ category.name }}..."
74+
aria-label="Search projects"
75+
/>
76+
</div>
77+
<div class="filter-bar" aria-live="polite">
78+
<span>Filtering for <strong class="filter-value"></strong></span>
79+
<button class="filter-clear" aria-label="Clear filter">
80+
Clear filter
81+
</button>
82+
</div>
83+
</div>
84+
85+
<h2 class="sr-only">Results</h2>
5286
<div
5387
class="table-wrap"
5488
tabindex="0"
5589
role="region"
56-
aria-label="{{ category.name }} libraries table"
90+
aria-label="Libraries table"
5791
>
58-
<table class="table category-table">
92+
<table class="table">
5993
<thead>
6094
<tr>
6195
<th class="col-num"><span class="sr-only">Row number</span></th>
@@ -69,7 +103,11 @@ <h2 class="sr-only">{{ category.name }} results</h2>
69103
<button type="button" class="sort-btn">Last Commit</button>
70104
</th>
71105
<th class="col-cat">Tags</th>
72-
<th class="col-arrow"><span class="sr-only">Details</span></th>
106+
<th class="col-arrow">
107+
<button class="back-to-top" aria-label="Back to top">
108+
Top &uarr;
109+
</button>
110+
</th>
73111
</tr>
74112
</thead>
75113
<tbody>
@@ -79,7 +117,7 @@ <h2 class="sr-only">{{ category.name }} results</h2>
79117
data-tags="{{ entry.categories | join('||') }}{% if entry.subcategories %}||{{ entry.subcategories | map(attribute='value') | join('||') }}{% endif %}||{{ entry.groups | join('||') }}{% if entry.source_type == 'Built-in' %}||Built-in{% endif %}"
80118
tabindex="0"
81119
aria-expanded="false"
82-
aria-controls="category-expand-{{ loop.index }}"
120+
aria-controls="expand-{{ loop.index }}"
83121
>
84122
<td class="col-num">{{ loop.index }}</td>
85123
<td class="col-name">
@@ -145,7 +183,7 @@ <h2 class="sr-only">{{ category.name }} results</h2>
145183
</td>
146184
<td class="col-arrow"><span class="arrow">&rarr;</span></td>
147185
</tr>
148-
<tr class="expand-row" id="category-expand-{{ loop.index }}">
186+
<tr class="expand-row" id="expand-{{ loop.index }}">
149187
<td></td>
150188
<td colspan="4">
151189
<div class="expand-content">
@@ -188,6 +226,14 @@ <h2 class="sr-only">{{ category.name }} results</h2>
188226
</tbody>
189227
</table>
190228
</div>
229+
230+
<div class="no-results" hidden>
231+
<p>No projects match your search or filter.</p>
232+
<p class="no-results-hint">
233+
Try a broader term, or
234+
<button class="no-results-clear">browse all projects</button>.
235+
</p>
236+
</div>
191237
</section>
192238

193239
<section class="final-cta" data-reveal>
@@ -203,7 +249,13 @@ <h2>Know a project that belongs here?</h2>
203249
rel="noopener"
204250
>Submit a project</a
205251
>
206-
<a href="/" class="hero-action hero-action-secondary">Browse all</a>
252+
<a
253+
href="https://github.com/vinta/awesome-python"
254+
class="hero-action hero-action-secondary"
255+
target="_blank"
256+
rel="noopener"
257+
>Star the repository</a
258+
>
207259
</div>
208260
</div>
209261
</section>

website/tests/test_build.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ def test_build_creates_category_pages_with_metadata_and_links(self, tmp_path):
302302
assert 'href="https://example.com/w1"' in category_html
303303
assert "A widget." in category_html
304304
assert 'href="https://github.com/owner/w2"' in category_html
305-
assert '<table class="table category-table">' in category_html
305+
assert '<table class="table">' in category_html
306306
assert "42" in category_html
307307
assert "2026-01-01T00:00:00+00:00" in category_html
308308

0 commit comments

Comments
 (0)