Commit Graph
95 Commits
Author SHA1 Message Date
Vinta ChenandClaude b58c1ff4a1 refactor: drop Odoo pick aliases the ERP intro no longer uses
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 23:13:13 +08:00
Vinta ChenandClaude b039f790ca feat: keep only the lead above the table for an intro without a pick list
An intro without a "How to choose" list, as a one-project category has no picks to compare, rendered all of its guide paragraphs above the table, pushing the table down. It now shows the lead above the table and moves the rest into the guide.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 23:13:13 +08:00
Vinta ChenandClaude 9177a2e8a7 fix: link full project names in intro picks that matched only part
Nine picks, such as "OpenAI Agents SDK", "MCP Python SDK", and "Jupyter Notebook", linked only part of the name or nothing, because the README lists those projects under their PyPI or repo names. The punctuation-guard test used "The Algorithms - Python", which now matches its alias in full, so it uses a made-up name instead.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 22:44:16 +08:00
Vinta ChenandClaude af95036e0e fix: link whole Odoo edition names in the ERP intro picks
"Odoo Online", "Odoo Community", and "Odoo Enterprise" matched only "Odoo", so each link stopped before the edition name.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 22:40:04 +08:00
Vinta ChenandClaude b69cb3f565 fix: link the whole "Ray Core" pick in the distributed computing intro
Only "Ray" matched the ray entry, so the link stopped before "Core".

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 22:38:40 +08:00
Vinta ChenandClaude 262d914e5d fix: correct site copy that described a tag filter and mixed terminology
Copy told visitors to tap a tag to filter and mentioned a filter although tags are plain links and no filter exists; casing and terminology were inconsistent.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 22:35:14 +08:00
Vinta ChenandClaude 11b72122c5 feat: drop the build date stat from the hero stats lines
The hero "Updated on" stat only restated when the site was last built.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 20:21:48 +08:00
Vinta ChenandClaude 7516a5c4f6 fix: keep each hero stat on one line and read "Updated on"
On phones the ISO date in the hero stat broke at its hyphen.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 20:03:15 +08:00
Vinta ChenandClaude 7ebd061a78 feat: render build date as ISO 8601 in home, sponsorship, and llms.txt
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 19:59:57 +08:00
Vinta ChenandClaude 786ebb4c78 feat(website): show the sponsor band on category pages
The sponsor band rendered only on the homepage, so visitors who entered on a category page and never opened the homepage saw no sponsors. Category, subcategory, group, and Stdlib pages now show the same band between the hero and the table.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 09:09:22 +08:00
Vinta ChenandClaude 69d35b2462 feat: tag sponsor links with UTM parameters
Sponsor links carried no UTM tags, so sponsors saw awesome-python clicks at best as generic referral traffic and could not tell README clicks from website clicks. README sponsor entries now carry utm_source=awesome-python&utm_medium=sponsorship&utm_campaign=sponsor&utm_content=readme, and the website build rewrites utm_content to website for the sponsor band. New sponsor entries in README.md need the same UTM suffix.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 09:09:22 +08:00
Vinta ChenandClaude 1ebff58bf9 feat: link category intro picks to their table rows
Picks in a "How to choose" list were plain text, so a reader had to hunt for the tool's row in the table.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-16 19:45:38 +08:00
Vinta ChenandClaude 170882bff5 refactor: fix lint findings from ruff 0.16 default rules
Ruff 0.16 enables 413 default rules (up from 59), so make lint failed with 11 findings, and it treated website/ modules as third-party.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 18:57:54 +08:00
Vinta ChenandClaude 38a4641e09 feat: improve subcategory page titles and meta descriptions
Subcategory titles such as "JWT for Authentication" lacked searchable words, and their boilerplate descriptions never named the listed projects and said "1 projects".

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-02 19:54:02 +08:00
Vinta ChenandClaude 3643d6d657 fix: derive sitemap lastmod from git history instead of build date
Every sitemap URL got the build date as lastmod, so all pages claimed a change on each daily deploy, and the sponsorship page used file mtime, which on CI's fresh checkout is also build time.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-02 19:48:50 +08:00
Vinta ChenandClaude c16dae14ef feat: show section intro lead on group pages
Group pages showed only tables, so visitors arriving from broad searches like "python ml library" got none of the which-one-to-pick guidance that each section's intro already gives.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-02 19:35:04 +08:00
Vinta ChenandClaude 775caf6a1e fix: stop repeating Python in group page titles
Group pages whose names start with "Python" got titles like "Python Python Language Libraries" in the title, og:title, and JSON-LD name.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-02 14:45:44 +08:00
Vinta ChenandClaude 2aa87f880b fix: drop doubled noun from category page titles
Category names ending in a plural noun (DevOps Tools, Web Frameworks, HTTP Clients, Stdlib) got titles like "Python DevOps Tools Libraries" in title, og:title, twitter:title, and JSON-LD name.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-02 14:44:13 +08:00
Vinta ChenandClaude f0ebe92155 fix: order category page JSON-LD ItemList to match rendered rows
Category pages' JSON-LD ItemList listed entries in download order while the table renders them in README (editorial) order, so structured-data positions didn't match the visible rows.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-27 14:47:00 +08:00
Vinta ChenandClaude 5b80c4ef6b fix: point description cross-reference links at category pages
Category pages render each README section's description as-is, so cross-reference links inside it pointed at README anchors (#package-management on Build Tools, #web-apis on Web Frameworks) that don't exist on those pages and led nowhere.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-27 09:10:59 +08:00
Vinta ChenandClaude 52915911d4 feat: link section use-case headings to their subcategory pages
With tags now pointing at section anchors instead of filtering in place, subcategory pages (74 clicks and 19.7K impressions in the last 3 months) had no other internal links pointing to them.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-27 00:34:07 +08:00
Vinta ChenandClaude 62a4e7c4e5 fix: make tags link to category pages instead of filtering in place
Clicking a category or group tag filtered the homepage table in place while rewriting the address bar to the category URL, so one URL rendered two different pages and readers never reached category pages with their intros and guides; category pages also showed a redundant self-referential filter bar.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-27 00:34:07 +08:00
Vinta ChenandClaude 2b9469c0ae feat: group category page rows by use case, restructure intro
Category pages sorted rows by downloads, which buried editorial leads (the Django ORM showed as row 7 of 7, tkinter as 14 of 14) against CONTRIBUTING.md's "position is the marker"; the full intro in the hero pushed the table 2.5 screens down on a phone; and every page repeated the same "Search every project in one place" H2.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-26 23:33:57 +08:00
Vinta ChenandClaude 9cc721f533 fix: match category meta titles to search query word order
Category page titles read "ORM Python Libraries", but people search "python orm", so the title word order didn't match the query.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-26 23:28:51 +08:00
Vinta ChenandClaude a74ca52860 feat: render per-category intro text above the entry list
Category pages carried no text of their own beyond the README one-line description, and most meta descriptions fell back to a generic "Explore N curated Python projects" line, which correlated with weak search rankings for category queries. This adds optional per-category intro markdown files rendered under the H1, with the first paragraph used as the meta description and links opening in a new tab, starting with the ORM category.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-26 19:42:22 +08:00
Vinta ChenandClaude c10264977e feat: serve redirect stubs for renamed and dissolved category slugs
Renamed or dissolved category slugs (e.g. /categories/web-servers/rpc/, /categories/code-analysis/code-linters/) returned 404, Search Console lists 7 of them, and each audit re-home was dropping the old URL's ranking.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-26 18:45:53 +08:00
Vinta ChenandClaude 0f677911f0 feat: add "Multiple on PyPI" badge for SDK monorepos
azure-sdk-for-python and google-cloud-python were rendering "Not on
PyPI", which is misleading. Both do ship on PyPI, just as many
per-service packages (azure-identity, azure-storage-blob,
google-cloud-storage, etc.) rather than under the repo name.

pypi_name_overrides.json already recorded that distinction in its
reason field; those two entries now carry an optional "badge" value
that build.py reads into the PyPI Downloads column. The other sixteen
no-count entries (cpython, renpy, agent skill repos, etc.) keep
"Not on PyPI" since that remains accurate for them.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-23 01:28:33 +08:00
Vinta ChenandClaude 733021ae5b feat: add Bundled badge for entries shipped inside a larger project
django.db.models, geodjango, httpx.URL and uv audit were rendering
"Not on PyPI" alongside eighteen genuinely standalone projects that
simply are not packaged on PyPI, conflating two different reasons for
a missing download count.

These four entries now carry a "(part of X)" description prefix in
README.md, mirroring the existing "(Python standard library)"
convention. build.py reads that prefix into a bundled flag that both
templates render as a "Bundled" badge.

The prefix approach was chosen over a separate data file so README.md
stays the single source of content truth, and over inferring from the
entry name because geodjango is neither dotted nor spaced and would
have been missed. Redundant tail wording was trimmed from the
httpx.URL, geodjango and uv audit descriptions now that the prefix
names the parent.

The new entry format is documented in CONTRIBUTING.md and the
vocabulary in CONTEXT.md.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-23 01:09:20 +08:00
Vinta ChenandClaude 2fc0edd565 feat: rename Built-in source type to Stdlib and show it in downloads column
Standard-library entries rendered "Not on PyPI" in the PyPI Downloads
column, which read like missing data rather than a deliberate category
— the build already forces downloads to None for them so they never
pick up a same-named PyPI backport. They now render a "Stdlib" badge
instead, while genuine non-PyPI entries keep "Not on PyPI".

The filter tag is renamed to match, so the source-type value, the row
filter tag, and the synthetic category heading all read Stdlib now.
The literal "Built-in" strings scattered through build.py are routed
through the existing BUILTIN_FILTER constant so the label lives in one
place. The category page slug stays "built-in" so the public URL
/categories/built-in/ does not break.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-23 01:01:17 +08:00
Vinta Chen ee8089d0d5 add build date to llms.txt 2026-08-16 20:16:05 +08:00
Vinta ChenandClaude 30c9f18bc2 feat: annotate llms.txt entries with PyPI download counts
Entries now end with "(PyPI downloads/month: N, GitHub stars: M)" where
known, replacing the stars-only note, since download counts are the
list's stated primary evidence signal. annotate_entries_with_stars is
renamed to annotate_entries_with_stats and looks downloads up by the
first link's display name, skipping category-index bullets (which link
into the site itself) and Built-in entries (which would otherwise hit
same-named PyPI backports like logging or asyncio).

The intro now mirrors the README subtitle verbatim with the
project/category totals on their own line below, and the "opinionated
catalog" wording is gone since the shortlist ADR is literally titled
"shortlist, not a catalog".

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-16 19:43:52 +08:00
Vinta ChenandClaude d3fec1f7fa feat: default-sort the website table by downloads per month
Entries with a download count now sort first (descending), with
stars, then Built-in, then name as fallback tiers for entries that
lack a count. main.js mirrors this in its default activeSort, clean
URL check, and third-click reset target. Sorting by stars remains one
header click away.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-16 19:15:21 +08:00
Vinta ChenandClaude cc804b1de2 feat: add Downloads/Month column to website table
Sourced from website/data/pypi_downloads.tsv the same way
github_stars.json feeds the stars column. The new sortable column
sits between GitHub Stars and Last Commit on the homepage and
category pages, formatted with thousands separators like stars, with
an em dash when no PyPI data exists. Rows are matched by normalized
README display name; Built-in entries never show counts since
same-named PyPI packages are stdlib backports (e.g. the asyncio
package).

Below 960px the column hides and the count moves into the expand
row, mirroring the existing Last Commit treatment. main.js gains the
downloads sort branch and URL param.

The deploy workflow fetches the TSV via the new
make fetch_pypi_downloads target with a daily actions/cache
fallback, mirroring the stars fetch, but non-fatal: the column
degrades to dashes when the fetch fails, unlike stars which the
build requires.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-16 17:52:04 +08:00
Vinta Chen 32ae78fd96 fix: improve website SEO metadata 2026-06-07 03:08:43 +08:00
Vinta Chen 10c06fb26d add category links in llms.txt 2026-05-07 20:00:56 +08:00
Vinta Chen 6c18b6447e feat: use explicit Projects section in README 2026-05-04 21:24:57 +08:00
Vinta Chen 921d47b455 remove index.md 2026-05-04 17:11:34 +08:00
Vinta Chen 3510db9df9 update llms.txt 2026-05-04 17:05:05 +08:00
Vinta Chen 509ebaff7a use file modification time as lastmod in sitemap 2026-05-04 16:24:52 +08:00
Vinta ChenandClaude 9379e0a42c style(sitemap): pretty-print generated sitemap.xml with 2-space indent
Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-03 20:16:13 +08:00
Vinta ChenandClaude c886e470b6 feat(website): lead category meta description with real description when present, count first as fallback
Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-03 19:57:31 +08:00
Vinta ChenandClaude 2f398acefb fix(seo): align JSON-LD with Yoast/RankMath conventions
- Wrap category pages in a self-contained @graph (WebSite + CollectionPage)
- Set canonical @id on CollectionPage to its URL (no hash fragment)
- Expand isPartOf to typed object {"@type": "WebSite", "@id": ...}
- Extract _website_node() and ISPARTOF_WEBSITE constants to avoid repetition
- Update tests to assert @graph structure on category pages

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-03 19:31:14 +08:00
Vinta ChenandClaude 86d2aa7e01 feat(website): add CollectionPage JSON-LD to category, group, and subcategory pages
Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-03 19:23:14 +08:00
Vinta ChenandClaude b2910d59c8 feat(website): add homepage JSON-LD with WebSite, CollectionPage, ItemList for SEO/AEO
Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-03 19:18:15 +08:00
Vinta Chen a068219684 fix(website): type build template entries 2026-05-03 12:08:41 +08:00
Vinta ChenandClaude 38b54caabb fix(website): trim sponsorship page nav and hero stats
Remove the 'All projects' nav link and total_entries hero stat from the
sponsorship page. Rename 'View the repository' CTA to 'View on GitHub'.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-03 11:45:07 +08:00
Vinta ChenandClaude ee01a0bade refactor(website): extract render_category, replace slugify filter with filter_urls map
- Extract render_category() helper to deduplicate the three category/group/builtin
  rendering blocks in build.py
- Replace synthetic dict literals with synthetic_category() helper
- Rewrite subcategory rendering to avoid O(n²) loop using precomputed dicts
- Pass filter_urls (not just JSON) to templates so Jinja can look up group URLs
  directly instead of applying the slugify filter at render time
- Remove slugify from env.filters (no longer used in templates)
- Replace isIndexPage() wrapper with isIndexDocument constant in main.js
- Fix: call applyFilters() on page load when activeFilter is set
- Remove dead else branch in tag click handler (category pages with no URL)
- Switch .hero-category-links from CSS columns to CSS grid for more even layout
- Remove max-width cap on .category-subtitle

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-03 11:38:22 +08:00
Vinta ChenandClaude c68b985d7c feat(website): add /sponsorship/ landing page
Adds a dedicated sponsorship page at /sponsorship/ built from the Jinja2
template, with hero stats, tier cards, and CSS. Updates the index.html
sponsor sidebar link to point to /sponsorship/ instead of the GitHub
SPONSORSHIP.md. Adds the URL to the sitemap and test fixtures.

Also renames .impeccable.md to DESIGN.md.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-03 09:35:39 +08:00
Vinta ChenandClaude 64781112d8 feat(website): add Browse by category nav to group page hero
Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-03 09:08:37 +08:00
Vinta ChenandClaude 70a8255289 feat(website): add /categories/built-in/ page for Built-in tag filter
Register Built-in as a navigable filter path alongside regular category
and group slugs, emit the page during build, add it to the sitemap, and
wire the Built-in tag buttons in index.html and category.html to navigate
there via data-url.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-03 08:35:55 +08:00