From 82320c9d232d7e65e85d780606c07be35e42e77f Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Wed, 21 Oct 2026 19:57:47 +0800 Subject: [PATCH 1/8] fix: remove animated sheen from hero background On narrow phone heroes the sheen, a diagonal light stripe sliding across for 54s after load, rendered as a near-vertical band sweeping sideways that read as a loading or progress bar. Co-Authored-By: Claude --- DESIGN.md | 4 ++-- website/static/main.js | 10 ---------- website/static/style.css | 22 ---------------------- website/templates/category.html | 1 - website/templates/index.html | 1 - website/templates/sponsorship.html | 1 - 6 files changed, 2 insertions(+), 37 deletions(-) diff --git a/DESIGN.md b/DESIGN.md index 2ac85446..d814817d 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -147,7 +147,7 @@ Hard-won sizing rules (do not relax): Depth comes from **tonal layers**, not heavy shadows. - The page is a quiet warm canvas (`--bg-page`). The content shell is slightly brighter paper (`--bg-paper`). CTA backgrounds and inline decorative blocks step up to `--bg-paper-strong`; the sponsor band steps further, to `--sponsor-bg`. -- The hero and the category guide band are the only places with real atmosphere: warm gradients on a dark earthy ground (`--hero-bg-start` → `--hero-bg-mid` → `--hero-bg-end`). Only the hero adds the subtle grid and slow sheen. The sheen and any other motion respect `prefers-reduced-motion`. +- The hero and the category guide band are the only places with real atmosphere: warm gradients on a dark earthy ground (`--hero-bg-start` → `--hero-bg-mid` → `--hero-bg-end`). Only the hero adds the subtle grid. The hero background holds still: a moving stripe on a narrow phone hero reads as a loading bar. Any motion elsewhere respects `prefers-reduced-motion`. - The footer is a single tonal block in `--footer-bg`, no internal gradients. - Two depth treatments are allowed and only these two. The search input combines a 1px inset highlight (`--search-inset`) with a soft warm drop shadow (`--search-shadow`, intensified by `--search-focus-shadow` on focus). The primary CTA button (`.hero-action-primary`) carries a warm drop shadow for press affordance. Both shadows are soft, warm-tinted, and tied to interactive elements. No new drop shadows on cards, panels, rows, or static decoration. - No glassmorphism as default decoration. @@ -169,7 +169,7 @@ The component vocabulary is small and table-led. Source of truth: `website/stati - **Table-driven index** (the hero of the page). Sticky header, sortable columns, click-to-expand rows that indent under the Name column. Modeled on placestoread.xyz. Not a card grid. - **Group rows**. Section, subcategory, and group pages list rows in README order. Section pages add one H2 row per use case; group pages add one per section, linking to that section's page. A note replaces the sort arrow until someone sorts a column, which flattens the list and hides the group rows. - **Filter tags** (`.tag`). `--accent-soft` background with `--accent-deep` text. Pill shape. Hover swaps to `--highlight` background with `--tag-hover-border` border and ink text. Active state uses the warm `--tag-active-start` → `--tag-active-end` gradient with hero-ink text. Tag variants (`tag-group`, `tag-source`) inherit the base `.tag` style today and differ only at narrow widths (`tag-group` hides under 960px). Add a new variant only when a real visual difference is needed. -- **Hero**. Magazine-cover headline, dark earthy ground, kicker and proof microcopy, primary CTA button using `--hero-btn-start` / `--hero-btn-end`. Subtle grid plus slow sheen. Respects `prefers-reduced-motion`. +- **Hero**. Magazine-cover headline, dark earthy ground, kicker and proof microcopy, primary CTA button using `--hero-btn-start` / `--hero-btn-end`. Subtle grid on a still background. - **Jump links**. One per use case in a category hero, plus one for the guide. Underlined like the intro's links, with a trailing ↓. Never tag-styled: tags filter the table or open another page, jump links only scroll. - **Guide band**. Everything in a category intro after its "How to choose" list. It sits below the table on the hero's dark gradient, with its H2 above the text. - **Sponsor band**. Sits below the hero on the home page and category pages, on `--sponsor-bg` with a `--line-strong` bottom border. Editorial layout, not a logo wall. Sponsor links share the global accent treatment; each sponsor name ends in a small ↗ in `--accent-deep` to mark it as an outbound link. diff --git a/website/static/main.js b/website/static/main.js index aa027eab..2259a5bf 100644 --- a/website/static/main.js +++ b/website/static/main.js @@ -78,16 +78,6 @@ if (window.location.hash === "#library-index") { ); } -// Pause hero animations when scrolled out of view -(function () { - const hero = document.querySelector(".hero"); - if (!hero || !("IntersectionObserver" in window)) return; - const observer = new IntersectionObserver(function (entries) { - hero.classList.toggle("offscreen", !entries[0].isIntersecting); - }); - observer.observe(hero); -})(); - function relativeTime(isoStr) { const date = new Date(isoStr); const now = new Date(); diff --git a/website/static/style.css b/website/static/style.css index 652dd864..c7996a32 100644 --- a/website/static/style.css +++ b/website/static/style.css @@ -177,25 +177,12 @@ kbd { pointer-events: none; } -.hero-sheen, .hero-noise { position: absolute; inset: 0; pointer-events: none; } -.hero-sheen { - background: - linear-gradient(118deg, transparent 35%, oklch(100% 0 0 / 0.09) 49%, transparent 63%); - transform: translateX(-30%); - animation: sheen-drift 18s linear 3; -} - -.hero.offscreen .hero-sheen, -.hero.offscreen .hero-noise { - animation-play-state: paused; -} - .hero-noise { opacity: 0.1; background-image: @@ -1725,15 +1712,6 @@ th[data-sort].sort-asc::after { } } -@keyframes sheen-drift { - from { - transform: translateX(-30%); - } - to { - transform: translateX(35%); - } -} - @media (max-width: 960px) { .hero-shell { padding-bottom: 2rem; diff --git a/website/templates/category.html b/website/templates/category.html index 89d4367c..b48362ab 100644 --- a/website/templates/category.html +++ b/website/templates/category.html @@ -8,7 +8,6 @@ {% endblock %} {% block header %}
-
diff --git a/website/templates/index.html b/website/templates/index.html index c4e18fba..ed141bad 100644 --- a/website/templates/index.html +++ b/website/templates/index.html @@ -4,7 +4,6 @@ {% endblock %} {% block header %}
-
diff --git a/website/templates/sponsorship.html b/website/templates/sponsorship.html index 4bd5cd95..3442a150 100644 --- a/website/templates/sponsorship.html +++ b/website/templates/sponsorship.html @@ -8,7 +8,6 @@ {% endblock %} {% block header %}
-
From 7ebd061a78874a12603951b863d84afdb6f2c50d Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Wed, 21 Oct 2026 19:58:50 +0800 Subject: [PATCH 2/8] feat: render build date as ISO 8601 in home, sponsorship, and llms.txt Co-Authored-By: Claude --- website/build.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/build.py b/website/build.py index 24b35b72..ee1c9650 100755 --- a/website/build.py +++ b/website/build.py @@ -833,7 +833,7 @@ def build(repo_root: Path) -> None: total_entries=total_entries, total_categories=len(categories), repo_stars=repo_stars, - build_date=build_date.strftime("%B %d, %Y"), + build_date=build_date.date().isoformat(), sponsors=sponsors, category_urls=category_urls, filter_urls=filter_urls, @@ -937,7 +937,7 @@ def build(repo_root: Path) -> None: hero_stats: list[str] = [] if repo_stars: hero_stats.append(f"{repo_stars}+ stars on GitHub") - hero_stats.append(f"Updated {build_date.strftime('%B %d, %Y')}") + hero_stats.append(f"Updated {build_date.date().isoformat()}") (sponsorship_dir / "index.html").write_text( tpl_sponsorship.render( hero_stats=hero_stats, @@ -994,7 +994,7 @@ def build(repo_root: Path) -> None: llms_template, readme_text=readme_text, subtitle=subtitle, - build_date=build_date.strftime("%Y/%m/%d"), + build_date=build_date.date().isoformat(), stars_data=stars_data, downloads_data=downloads_data, categories=categories, From 7516a5c4f667c45a73687419eac4458766ac66d7 Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Wed, 21 Oct 2026 20:03:15 +0800 Subject: [PATCH 3/8] 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 --- website/build.py | 2 +- website/static/style.css | 5 +++++ website/templates/index.html | 2 +- website/templates/sponsorship.html | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/website/build.py b/website/build.py index ee1c9650..9ab5e472 100755 --- a/website/build.py +++ b/website/build.py @@ -937,7 +937,7 @@ def build(repo_root: Path) -> None: hero_stats: list[str] = [] if repo_stars: hero_stats.append(f"{repo_stars}+ stars on GitHub") - hero_stats.append(f"Updated {build_date.date().isoformat()}") + hero_stats.append(f"Updated on {build_date.date().isoformat()}") (sponsorship_dir / "index.html").write_text( tpl_sponsorship.render( hero_stats=hero_stats, diff --git a/website/static/style.css b/website/static/style.css index c7996a32..1c393eda 100644 --- a/website/static/style.css +++ b/website/static/style.css @@ -326,6 +326,11 @@ kbd { letter-spacing: 0.02em; } +/* Keeps a stat whole, so the date never breaks at its hyphens */ +.proof-stat { + white-space: nowrap; +} + .hero-proof a { color: var(--hero-text); text-decoration: underline; diff --git a/website/templates/index.html b/website/templates/index.html index ed141bad..e31a7076 100644 --- a/website/templates/index.html +++ b/website/templates/index.html @@ -27,7 +27,7 @@

Awesome Python

{{ subtitle }}

- {% if repo_stars %}{{ repo_stars }}+ stars on GitHub{% endif %} {% if repo_stars and build_date %}/{% endif %} {% if build_date %}Updated {{ build_date }}{% endif %} {% if repo_stars or + {% if repo_stars %}{{ repo_stars }}+ stars on GitHub{% endif %} {% if repo_stars and build_date %}/{% endif %} {% if build_date %}Updated on {{ build_date }}{% endif %} {% if repo_stars or build_date %}/{% endif %} Maintained by @vinta and diff --git a/website/templates/sponsorship.html b/website/templates/sponsorship.html index 3442a150..9b344e97 100644 --- a/website/templates/sponsorship.html +++ b/website/templates/sponsorship.html @@ -37,7 +37,7 @@ {% if hero_stats %}

- {% for stat in hero_stats %}{{ stat }}{% if not loop.last %} + {% for stat in hero_stats %}{{ stat }}{% if not loop.last %} / {% endif %}{% endfor %}

{% endif %} From 9d4f372a79b30970f52013de63ceb73794d7b3c4 Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Wed, 21 Oct 2026 20:09:39 +0800 Subject: [PATCH 4/8] fix: shorten sponsorship email buttons and break address only after @ At phone width the two primary buttons labelled with the full address wrapped over three lines, and the address in the Get started sentence broke at its hyphen. Co-Authored-By: Claude --- website/static/style.css | 5 +++++ website/templates/sponsorship.html | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/website/static/style.css b/website/static/style.css index 1c393eda..ede5397f 100644 --- a/website/static/style.css +++ b/website/static/style.css @@ -1409,6 +1409,11 @@ th[data-sort].sort-asc::after { color: var(--accent); } +/* With the after "@", the address breaks only there, never at the domain's hyphen */ +.email-domain { + white-space: nowrap; +} + .sponsorship-lede { font-size: var(--text-2xl); line-height: 1.45; diff --git a/website/templates/sponsorship.html b/website/templates/sponsorship.html index 9b344e97..8239a27e 100644 --- a/website/templates/sponsorship.html +++ b/website/templates/sponsorship.html @@ -47,7 +47,7 @@ href="mailto:sponsorship@awesome-python.com?subject=Awesome%20Python%20Sponsorship" data-tier="general" class="hero-action hero-action-primary" - >Email sponsorship@awesome-python.comEmail us sponsorship@awesome-python.comsponsorship@ with the four items below.

@@ -273,7 +273,7 @@ href="mailto:sponsorship@awesome-python.com?subject=Awesome%20Python%20Sponsorship" data-tier="general" class="hero-action hero-action-primary" - >Email sponsorship@awesome-python.comEmail us
From b7964918f3dcd56ff8724150baae4e54b3866865 Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Wed, 21 Oct 2026 20:14:07 +0800 Subject: [PATCH 5/8] docs: add website change preview rule to AGENTS.md Co-Authored-By: Claude --- AGENTS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index ce6abc29..cf4b7568 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -18,3 +18,5 @@ Apply [CONTRIBUTING.md](CONTRIBUTING.md) (admission, entry format, ordering) whe ## Website Read [DESIGN.md](DESIGN.md) before changing anything under `website/templates/` or `website/static/`. + +When showing the user a website change, keep a desktop view and a phone view of the same branch build open at the same time, in separate browser tabs, so the user never has to switch the viewport. An emulated viewport can reset between turns, so build the phone view as a page of 375px-wide iframes (home, sponsorship, one category page) pointing at that build. Show each visual change as before/after images at both widths. From 28b03ce6b793073b325dbcded46caf1955d53758 Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Wed, 21 Oct 2026 20:17:42 +0800 Subject: [PATCH 6/8] fix: stack hero stats on phones instead of running them together On phones the hero stats ran together as one sentence, breaking wherever space ran out and leaving a "/" dangling at a line end. Co-Authored-By: Claude --- website/static/style.css | 8 ++++++++ website/templates/index.html | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/website/static/style.css b/website/static/style.css index ede5397f..8d9de77f 100644 --- a/website/static/style.css +++ b/website/static/style.css @@ -1786,6 +1786,14 @@ th[data-sort].sort-asc::after { } @media (max-width: 680px) { + .proof-stat { + display: block; + } + + .proof-sep { + display: none; + } + .hero-topbar { gap: 0.75rem; } diff --git a/website/templates/index.html b/website/templates/index.html index e31a7076..b1dd5bd7 100644 --- a/website/templates/index.html +++ b/website/templates/index.html @@ -27,11 +27,11 @@

Awesome Python

{{ subtitle }}

- {% if repo_stars %}{{ repo_stars }}+ stars on GitHub{% endif %} {% if repo_stars and build_date %}/{% endif %} {% if build_date %}Updated on {{ build_date }}{% endif %} {% if repo_stars or - build_date %}/{% endif %} Maintained by + {% if repo_stars %}{{ repo_stars }}+ stars on GitHub{% endif %} {% if repo_stars and build_date %}/{% endif %} {% if build_date %}Updated on {{ build_date }}{% endif %} {% if repo_stars or + build_date %}/{% endif %} Maintained by @vinta and - @JinyangWang27 + @JinyangWang27

Date: Wed, 21 Oct 2026 20:21:39 +0800 Subject: [PATCH 7/8] 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 --- website/build.py | 2 -- website/static/style.css | 2 +- website/templates/index.html | 3 +-- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/website/build.py b/website/build.py index 9ab5e472..1697e6e5 100755 --- a/website/build.py +++ b/website/build.py @@ -833,7 +833,6 @@ def build(repo_root: Path) -> None: total_entries=total_entries, total_categories=len(categories), repo_stars=repo_stars, - build_date=build_date.date().isoformat(), sponsors=sponsors, category_urls=category_urls, filter_urls=filter_urls, @@ -937,7 +936,6 @@ def build(repo_root: Path) -> None: hero_stats: list[str] = [] if repo_stars: hero_stats.append(f"{repo_stars}+ stars on GitHub") - hero_stats.append(f"Updated on {build_date.date().isoformat()}") (sponsorship_dir / "index.html").write_text( tpl_sponsorship.render( hero_stats=hero_stats, diff --git a/website/static/style.css b/website/static/style.css index 8d9de77f..50409547 100644 --- a/website/static/style.css +++ b/website/static/style.css @@ -326,7 +326,7 @@ kbd { letter-spacing: 0.02em; } -/* Keeps a stat whole, so the date never breaks at its hyphens */ +/* Keeps each stat whole when the line wraps */ .proof-stat { white-space: nowrap; } diff --git a/website/templates/index.html b/website/templates/index.html index b1dd5bd7..73c35419 100644 --- a/website/templates/index.html +++ b/website/templates/index.html @@ -27,8 +27,7 @@

Awesome Python

{{ subtitle }}

- {% if repo_stars %}{{ repo_stars }}+ stars on GitHub{% endif %} {% if repo_stars and build_date %}/{% endif %} {% if build_date %}Updated on {{ build_date }}{% endif %} {% if repo_stars or - build_date %}/{% endif %} Maintained by + {% if repo_stars %}{{ repo_stars }}+ stars on GitHub /{% endif %} Maintained by @vinta and @JinyangWang27 From 60d6cd8dd6d43e834f3aeecfc21593d8e22a1a23 Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Wed, 21 Oct 2026 20:37:51 +0800 Subject: [PATCH 8/8] style: align sponsor link with its label in the stacked sponsor band Below 960px the -1rem top margin on the sponsor link, meant for the side-by-side desktop layout, pulled the sponsor name closer to the link than the link sat to its own label, so the link read as part of the sponsor entry. Co-Authored-By: Claude --- website/static/style.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/website/static/style.css b/website/static/style.css index 50409547..8bba04b0 100644 --- a/website/static/style.css +++ b/website/static/style.css @@ -1734,6 +1734,16 @@ th[data-sort].sort-asc::after { grid-template-columns: 1fr; } + .sponsor-meta { + flex-direction: row; + justify-content: space-between; + align-items: baseline; + } + + .sponsor-link { + margin-block-start: 0; + } + .sponsorship-meta { position: static; }