From 7974eeacdf5412dd8fe58bbe533efab61dbd1a0f Mon Sep 17 00:00:00 2001
From: Vinta Chen
Date: Mon, 26 Oct 2026 10:46:44 +0800
Subject: [PATCH 1/9] fix: render group page category list as collapsible
details
Group pages rendered "Browse by category" with a plain div heading instead of the homepage's details/summary, so the two-column grid never applied, the arrow showed but did nothing, and the list didn't collapse on phones.
Co-Authored-By: Claude
---
website/templates/category.html | 32 ++++++++++++++++++++------------
1 file changed, 20 insertions(+), 12 deletions(-)
diff --git a/website/templates/category.html b/website/templates/category.html
index 4399505c..c1a49186 100644
--- a/website/templates/category.html
+++ b/website/templates/category.html
@@ -56,18 +56,26 @@
{% if group_categories %}
-
- {% for sub in group_categories %}
- -
- {{ sub.name }}
-
- {% endfor %}
-
+
+
+ Browse by category
+
+
+ {% for sub in group_categories %}
+ -
+ {{ sub.name }}
+
+ {% endfor %}
+
+
+
{% endif %}
From a7df2a9f0ef2953be0e9e423bd6c6099fee9aa22 Mon Sep 17 00:00:00 2001
From: Vinta Chen
Date: Mon, 26 Oct 2026 10:49:11 +0800
Subject: [PATCH 2/9] refactor: share the hero category nav between home and
category pages
The "Browse by category" markup was duplicated in index.html and category.html, and the two copies had drifted.
Co-Authored-By: Claude
---
website/templates/_category_nav.html | 22 ++++++++++++++++++++++
website/templates/category.html | 23 +----------------------
website/templates/index.html | 23 +----------------------
3 files changed, 24 insertions(+), 44 deletions(-)
create mode 100644 website/templates/_category_nav.html
diff --git a/website/templates/_category_nav.html b/website/templates/_category_nav.html
new file mode 100644
index 00000000..c6f60bd6
--- /dev/null
+++ b/website/templates/_category_nav.html
@@ -0,0 +1,22 @@
+
diff --git a/website/templates/category.html b/website/templates/category.html
index c1a49186..b64af1a3 100644
--- a/website/templates/category.html
+++ b/website/templates/category.html
@@ -55,28 +55,7 @@
{% if group_categories %}
-
+ {%+ with nav_categories = group_categories %}{% include "_category_nav.html" %}{% endwith +%}
{% endif %}
diff --git a/website/templates/index.html b/website/templates/index.html
index fcea908b..af081acb 100644
--- a/website/templates/index.html
+++ b/website/templates/index.html
@@ -50,28 +50,7 @@
-
+ {%+ with nav_categories = categories %}{% include "_category_nav.html" %}{% endwith +%}
{% endblock %}
From f02791ac58af33d5306dceef8087de6ba63b305b Mon Sep 17 00:00:00 2001
From: Vinta Chen
Date: Mon, 26 Oct 2026 10:53:55 +0800
Subject: [PATCH 3/9] refactor: extract the Contribute CTA into a shared
partial
Co-Authored-By: Claude
---
website/templates/_final_cta.html | 23 +++++++++++++++++++++++
website/templates/category.html | 24 +-----------------------
website/templates/index.html | 24 +-----------------------
3 files changed, 25 insertions(+), 46 deletions(-)
create mode 100644 website/templates/_final_cta.html
diff --git a/website/templates/_final_cta.html b/website/templates/_final_cta.html
new file mode 100644
index 00000000..95c7c58b
--- /dev/null
+++ b/website/templates/_final_cta.html
@@ -0,0 +1,23 @@
+
+
+
Contribute
+
Know a project that belongs here?
+
Tell us what it does and why it stands out.
+
+
+
diff --git a/website/templates/category.html b/website/templates/category.html
index b64af1a3..cdadd21f 100644
--- a/website/templates/category.html
+++ b/website/templates/category.html
@@ -324,27 +324,5 @@
{% endif %}
-
-
-
Contribute
-
Know a project that belongs here?
-
Tell us what it does and why it stands out.
-
-
-
+{% include "_final_cta.html" +%}
{% endblock %}
diff --git a/website/templates/index.html b/website/templates/index.html
index af081acb..b6b1e578 100644
--- a/website/templates/index.html
+++ b/website/templates/index.html
@@ -266,27 +266,5 @@
-
-
-
Contribute
-
Know a project that belongs here?
-
Tell us what it does and why it stands out.
-
-
-
+{% include "_final_cta.html" +%}
{% endblock %}
From f4191b274619a75f9d550ce2a899f0a87e8a3cc4 Mon Sep 17 00:00:00 2001
From: Vinta Chen
Date: Mon, 26 Oct 2026 10:55:51 +0800
Subject: [PATCH 4/9] refactor: extract shared projects table macro
Co-Authored-By: Claude
---
website/templates/_projects_table.html | 74 ++++++++++++++++++++++++++
website/templates/category.html | 74 ++------------------------
website/templates/index.html | 74 ++------------------------
3 files changed, 80 insertions(+), 142 deletions(-)
create mode 100644 website/templates/_projects_table.html
diff --git a/website/templates/_projects_table.html b/website/templates/_projects_table.html
new file mode 100644
index 00000000..193000e3
--- /dev/null
+++ b/website/templates/_projects_table.html
@@ -0,0 +1,74 @@
+{% macro projects_table(count, scope, editorial=false) %}
+
+
Search and filter
+
+
+
+
+
+
+ Results
+
+
+
+
+ | Row number |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+ Tags |
+
+
+ |
+
+
+
+{{ caller() }}
+
+
+
+
+
+
No projects match your search.
+
+ Try a broader term, or
+ .
+
+
+{% endmacro %}
diff --git a/website/templates/category.html b/website/templates/category.html
index cdadd21f..10fa0bd5 100644
--- a/website/templates/category.html
+++ b/website/templates/category.html
@@ -1,4 +1,5 @@
{% extends "base.html" %}
+{% from "_projects_table.html" import projects_table %}
{% block title %}{{ category_title }}{% endblock %}
{% block description %}{{ category_description }}{% endblock %}
{% block canonical_url %}{{ category_url }}{% endblock %}
@@ -216,66 +217,7 @@
-
-
Search and filter
-
-
-
-
-
-
- Results
-
-
-
-
- | Row number |
-
-
- |
-
-
- |
-
-
- |
-
-
- |
- Tags |
-
-
- |
-
-
-
+ {% call projects_table(entries | length, "in " ~ category.name, entry_groups) %}
{% if entry_groups %}
{% set row = namespace(index=0) %}
{% for group in entry_groups %}
@@ -302,17 +244,7 @@
{{ entry_rows(entry, loop.index) }}
{% endfor %}
{% endif %}
-
-
-
-
-
-
No projects match your search.
-
- Try a broader term, or
- .
-
-
+ {% endcall %}
{% if guide_html %}
diff --git a/website/templates/index.html b/website/templates/index.html
index b6b1e578..8d0a4385 100644
--- a/website/templates/index.html
+++ b/website/templates/index.html
@@ -1,4 +1,5 @@
{% extends "base.html" %}
+{% from "_projects_table.html" import projects_table %}
{% block extra_head %}
{% endblock %}
@@ -68,66 +69,7 @@
-
-
Search and filter
-
-
-
-
-
-
- Results
-
-
-
-
- | Row number |
-
-
- |
-
-
- |
-
-
- |
-
-
- |
- Tags |
-
-
- |
-
-
-
+ {% call projects_table(entries | length, "across " ~ total_categories ~ " categories") %}
{% for entry in entries %}
{% endfor %}
-
-
-
-
-
-
No projects match your search.
-
- Try a broader term, or
- .
-
-
+ {% endcall %}
{% include "_final_cta.html" +%}
From aa6f632ed835deb905056d65511b4353454384c0 Mon Sep 17 00:00:00 2001
From: Vinta Chen
Date: Mon, 26 Oct 2026 10:57:03 +0800
Subject: [PATCH 5/9] refactor: share entry rows macro between home and
category pages
Co-Authored-By: Claude
---
website/templates/_entry_rows.html | 133 ++++++++++++++++++++++++++++
website/templates/category.html | 134 +----------------------------
website/templates/index.html | 125 +--------------------------
3 files changed, 136 insertions(+), 256 deletions(-)
create mode 100644 website/templates/_entry_rows.html
diff --git a/website/templates/_entry_rows.html b/website/templates/_entry_rows.html
new file mode 100644
index 00000000..5629aff2
--- /dev/null
+++ b/website/templates/_entry_rows.html
@@ -0,0 +1,133 @@
+{% macro entry_rows(entry, index, home=false) %}
+ {# On section and subcategory pages the group heading already names the row's use case #}
+ {% set grouped_page = entry_groups and not group_categories %}
+ {% set section_path = "/categories/" ~ parent_category.slug ~ "/" if parent_category else current_path %}
+
+ | {{ index }} |
+
+ {{ entry.name }}
+ {% if entry.subcategories %}{{ entry.subcategories[0].name }}{%
+ else %}{{ entry.categories[0] if home else category.name }}{% endif %}
+ |
+
+ {% if entry.downloads is not none %}{{
+ "{:,}".format(entry.downloads) }}{% elif entry.source_type ==
+ 'Stdlib' %}Stdlib{% elif
+ entry.bundled %}Bundled{% elif
+ entry.badge %}{{ entry.badge }}{%
+ else %}Not on PyPI{% endif %}
+ |
+
+ {% if entry.stars is not none %}{{ "{:,}".format(entry.stars) }}{%
+ elif entry.source_type %}{{ entry.source_type }}{% else %}—{% endif %}
+ |
+
+ {% if entry.last_commit_at %}{% else %}—{% endif %}
+ |
+
+ {% for subcat in entry.subcategories %}
+
+ {{ subcat.name }}
+
+ {% endfor %}
+ {% for cat in entry.categories %}
+ {{ cat }}
+ {% endfor %}
+ {% if entry.groups %}
+ {% set group_url = filter_urls[entry.groups[0]] %}
+
+ {{ entry.groups[0] }}
+
+ {% endif %}
+ {% if entry.source_type == 'Stdlib' %}
+
+ Stdlib
+
+ {% endif %}
+ |
+ → |
+
+ {% if entry.description %}
+
+ |
+
+ {{ entry.description | safe }}
+ |
+
+ {% endif %}
+
+ |
+
+
+ {% if entry.also_see %}
+
+ Also see: {% for see in entry.also_see %} {{ see.name }}{% if not loop.last %}, {% endif %}{% endfor %}
+
+ {% endif %}
+
+
+ |
+ |
+
+{% endmacro %}
diff --git a/website/templates/category.html b/website/templates/category.html
index 10fa0bd5..80f3753a 100644
--- a/website/templates/category.html
+++ b/website/templates/category.html
@@ -1,5 +1,6 @@
{% extends "base.html" %}
{% from "_projects_table.html" import projects_table %}
+{% from "_entry_rows.html" import entry_rows with context %}
{% block title %}{{ category_title }}{% endblock %}
{% block description %}{{ category_description }}{% endblock %}
{% block canonical_url %}{{ category_url }}{% endblock %}
@@ -62,139 +63,6 @@
{% endblock %}
{% block content %}
-{% macro entry_rows(entry, index) %}
- {# On section and subcategory pages the group heading already names the row's use case #}
- {% set grouped_page = entry_groups and not group_categories %}
- {% set section_path = "/categories/" ~ parent_category.slug ~ "/" if parent_category else current_path %}
-
- | {{ index }} |
-
- {{ entry.name }}
- {% if entry.subcategories %}{{ entry.subcategories[0].name }}{%
- else %}{{ category.name }}{% endif %}
- |
-
- {% if entry.downloads is not none %}{{
- "{:,}".format(entry.downloads) }}{% elif entry.source_type ==
- 'Stdlib' %}Stdlib{% elif
- entry.bundled %}Bundled{% elif
- entry.badge %}{{ entry.badge }}{%
- else %}Not on PyPI{% endif %}
- |
-
- {% if entry.stars is not none %}{{ "{:,}".format(entry.stars) }}{%
- elif entry.source_type %}{{ entry.source_type }}{% else %}—{% endif %}
- |
-
- {% if entry.last_commit_at %}{% else %}—{% endif %}
- |
-
- {% for subcat in entry.subcategories %}
-
- {{ subcat.name }}
-
- {% endfor %}
- {% for cat in entry.categories %}
- {{ cat }}
- {% endfor %}
- {% if entry.groups %}
- {% set group_url = filter_urls[entry.groups[0]] %}
-
- {{ entry.groups[0] }}
-
- {% endif %}
- {% if entry.source_type == 'Stdlib' %}
-
- Stdlib
-
- {% endif %}
- |
- → |
-
- {% if entry.description %}
-
- |
-
- {{ entry.description | safe }}
- |
-
- {% endif %}
-
- |
-
-
- {% if entry.also_see %}
-
- Also see: {% for see in entry.also_see %} {{ see.name }}{% if not loop.last %}, {% endif %}{% endfor %}
-
- {% endif %}
-
-
- |
- |
-
-{% endmacro %}
{% include "_sponsor_band.html" %}
diff --git a/website/templates/index.html b/website/templates/index.html
index 8d0a4385..35a8235a 100644
--- a/website/templates/index.html
+++ b/website/templates/index.html
@@ -1,5 +1,6 @@
{% extends "base.html" %}
{% from "_projects_table.html" import projects_table %}
+{% from "_entry_rows.html" import entry_rows with context %}
{% block extra_head %}
{% endblock %}
@@ -71,129 +72,7 @@
{% call projects_table(entries | length, "across " ~ total_categories ~ " categories") %}
{% for entry in entries %}
-
- | {{ loop.index }} |
-
- {{ entry.name }}
- {% if entry.subcategories %}{{ entry.subcategories[0].name }}{%
- else %}{{ entry.categories[0] }}{% endif %}
- |
-
- {% if entry.downloads is not none %}{{
- "{:,}".format(entry.downloads) }}{% elif entry.source_type ==
- 'Stdlib' %}Stdlib{% elif
- entry.bundled %}Bundled{% elif
- entry.badge %}{{ entry.badge }}{%
- else %}Not on PyPI{% endif %}
- |
-
- {% if entry.stars is not none %}{{ "{:,}".format(entry.stars) }}{%
- elif entry.source_type %}{{ entry.source_type }}{% else %}—{% endif %}
- |
-
- {% if entry.last_commit_at %}{% else %}—{% endif %}
- |
-
- {% for subcat in entry.subcategories %}
-
- {{ subcat.name }}
-
- {% endfor %} {% for cat in entry.categories %}
- {{ cat }}
- {% endfor %}
-
- {{ entry.groups[0] }}
-
- {% if entry.source_type == 'Stdlib' %}
-
- Stdlib
-
- {% endif %}
- |
- → |
-
- {% if entry.description %}
-
- |
-
- {{ entry.description | safe }}
- |
-
- {% endif %}
-
- |
-
-
- {% if entry.also_see %}
-
- Also see: {% for see in entry.also_see %} {{ see.name }}{% if not loop.last %}, {% endif %}{% endfor %}
-
- {% endif %}
-
-
- |
- |
-
+ {{ entry_rows(entry, loop.index, home=true) }}
{% endfor %}
{% endcall %}
From a1e6058986ecc2d852adbe0755385900998fd422 Mon Sep 17 00:00:00 2001
From: Vinta Chen
Date: Mon, 26 Oct 2026 10:57:55 +0800
Subject: [PATCH 6/9] refactor: extract site topbar into a shared template
partial
Co-Authored-By: Claude
---
website/templates/_topbar.html | 20 ++++++++++++++++++++
website/templates/category.html | 15 +--------------
website/templates/index.html | 14 +-------------
website/templates/sponsorship.html | 14 +-------------
4 files changed, 23 insertions(+), 40 deletions(-)
create mode 100644 website/templates/_topbar.html
diff --git a/website/templates/_topbar.html b/website/templates/_topbar.html
new file mode 100644
index 00000000..0fcde817
--- /dev/null
+++ b/website/templates/_topbar.html
@@ -0,0 +1,20 @@
+
diff --git a/website/templates/category.html b/website/templates/category.html
index 80f3753a..4ec943e8 100644
--- a/website/templates/category.html
+++ b/website/templates/category.html
@@ -13,20 +13,7 @@
-
+ {%+ with all_projects = true %}{% include "_topbar.html" %}{% endwith +%}
{% if parent_category %}
diff --git a/website/templates/index.html b/website/templates/index.html
index 35a8235a..165e77d3 100644
--- a/website/templates/index.html
+++ b/website/templates/index.html
@@ -9,19 +9,7 @@
-
+ {%+ with home = true %}{% include "_topbar.html" %}{% endwith +%}
diff --git a/website/templates/sponsorship.html b/website/templates/sponsorship.html
index 72c5bc2d..cafbfda1 100644
--- a/website/templates/sponsorship.html
+++ b/website/templates/sponsorship.html
@@ -11,19 +11,7 @@