diff --git a/website/build.py b/website/build.py index 9164ca1a..70bbdc14 100644 --- a/website/build.py +++ b/website/build.py @@ -678,12 +678,7 @@ def build(repo_root: Path) -> None: filter_urls: dict[str, str] = dict(category_urls) for group in parsed_groups: filter_urls[group["name"]] = group_path(group["slug"]) - for entry in entries: - for sub in entry.get("subcategories", []): - filter_urls[sub["value"]] = sub["url"] builtin_entries = [e for e in entries if e.get("source_type") == BUILTIN_FILTER] - if builtin_entries: - filter_urls[BUILTIN_FILTER] = BUILTIN_PATH env = Environment( loader=FileSystemLoader(website / "templates"), @@ -696,7 +691,6 @@ def build(repo_root: Path) -> None: shutil.rmtree(site_dir) site_dir.mkdir(parents=True) - filter_urls_json = json.dumps(filter_urls, sort_keys=True, ensure_ascii=False).replace(" None: sponsors=sponsors, category_urls=category_urls, filter_urls=filter_urls, - filter_urls_json=filter_urls_json, homepage_json_ld=homepage_json_ld, ), encoding="utf-8", @@ -762,7 +755,6 @@ def build(repo_root: Path) -> None: category_urls=category_urls, current_path=current_path, filter_urls=filter_urls, - filter_urls_json=filter_urls_json, parent_category=parent_category, group_categories=group_categories, category_json_ld=category_json_ld, diff --git a/website/static/main.js b/website/static/main.js index 307e3f92..919aefd4 100644 --- a/website/static/main.js +++ b/website/static/main.js @@ -10,15 +10,10 @@ const defaultSort = table && table.dataset.defaultSort === "editorial" ? { col: "editorial", order: "asc" } : { col: "downloads", order: "desc" }; -let activeFilter = null; let activeSort = defaultSort; const searchInput = document.querySelector(".search"); -const filterBar = document.querySelector(".filter-bar"); -const filterValue = document.querySelector(".filter-value"); -const filterClear = document.querySelector(".filter-clear"); const noResults = document.querySelector(".no-results"); const rows = document.querySelectorAll(".table tbody tr.row"); -const tags = document.querySelectorAll(".tag"); const tbody = document.querySelector(".table tbody"); const groupRows = document.querySelectorAll(".table tbody tr.group-row"); @@ -145,7 +140,7 @@ function collapseAll() { function applyFilters() { const query = searchInput ? searchInput.value.toLowerCase().trim() : ""; - const descRowsVisible = !isIndexDocument || activeFilter !== null; + const descRowsVisible = !isIndexDocument; let visibleCount = 0; collapseAll(); @@ -153,12 +148,7 @@ function applyFilters() { rows.forEach(function (row) { let show = true; - if (activeFilter) { - const rowTags = row.dataset.tags; - show = rowTags ? rowTags.split("||").includes(activeFilter) : false; - } - - if (show && query) { + if (query) { if (!row._searchText) { let text = row.textContent.toLowerCase(); if (row._descRow) { @@ -200,35 +190,12 @@ function applyFilters() { if (noResults) noResults.hidden = visibleCount > 0; - tags.forEach(function (tag) { - tag.classList.toggle("active", activeFilter === tag.dataset.value); - }); - - if (filterBar) { - if (activeFilter) { - filterBar.classList.add("visible"); - if (filterValue) filterValue.textContent = activeFilter; - } else { - filterBar.classList.remove("visible"); - } - } - updateURL(); } -const filterUrlsScript = document.getElementById("filter-urls"); -const filterToUrl = filterUrlsScript - ? JSON.parse(filterUrlsScript.textContent) - : {}; - const isIndexDocument = location.pathname === "/" || location.pathname === "/index.html"; -const urlToFilter = {}; -Object.keys(filterToUrl).forEach(function (k) { - urlToFilter[filterToUrl[k]] = k; -}); - function buildQueryString() { const params = new URLSearchParams(); const query = searchInput ? searchInput.value.trim() : ""; @@ -243,9 +210,7 @@ function buildQueryString() { function updateURL() { if (!isIndexDocument) return; - const path = - activeFilter && filterToUrl[activeFilter] ? filterToUrl[activeFilter] : "/"; - history.replaceState(null, "", path + buildQueryString()); + history.replaceState(null, "", "/" + buildQueryString()); } function getSortValue(row, col) { @@ -340,8 +305,8 @@ function updateSortIndicators() { // Expand/collapse: event delegation on tbody if (tbody) { tbody.addEventListener("click", function (e) { - // Don't toggle if clicking a link or tag button - if (e.target.closest("a") || e.target.closest(".tag")) return; + // Don't toggle if clicking a link + if (e.target.closest("a")) return; let row = e.target.closest("tr.row"); if (!row) { @@ -370,36 +335,6 @@ if (tbody) { }); } -tags.forEach(function (tag) { - tag.addEventListener("click", function (e) { - e.preventDefault(); - const value = tag.dataset.value; - const url = tag.dataset.url; - if (isIndexDocument) { - activeFilter = activeFilter === value ? null : value; - if (activeFilter && url) { - history.pushState(null, "", url + buildQueryString()); - } else { - history.pushState(null, "", "/" + buildQueryString()); - } - applyFilters(); - } else if (url) { - window.location.href = url + "#library-index"; - } - }); -}); - -if (filterClear) { - filterClear.addEventListener("click", function () { - if (!isIndexDocument) { - window.location.href = "/#library-index"; - return; - } - activeFilter = null; - applyFilters(); - }); -} - const noResultsClear = document.querySelector(".no-results-clear"); if (noResultsClear) { noResultsClear.addEventListener("click", function () { @@ -408,7 +343,6 @@ if (noResultsClear) { return; } if (searchInput) searchInput.value = ""; - activeFilter = null; applyFilters(); }); } @@ -451,7 +385,6 @@ if (searchInput) { } if (e.key === "Escape" && document.activeElement === searchInput) { searchInput.value = ""; - activeFilter = null; applyFilters(); searchInput.blur(); } @@ -512,20 +445,8 @@ if (backToTop) { ) { activeSort = { col: sort, order: order }; } - const matched = urlToFilter[location.pathname]; - if (matched) activeFilter = matched; - if (q || activeFilter || sort) { + if (q || sort) { sortRows(); } - if (activeFilter) { - applyFilters(); - } updateSortIndicators(); })(); - -window.addEventListener("popstate", function () { - if (!isIndexDocument) return; - const matched = urlToFilter[location.pathname]; - activeFilter = matched || null; - applyFilters(); -}); diff --git a/website/static/style.css b/website/static/style.css index f7bddd67..4e067c06 100644 --- a/website/static/style.css +++ b/website/static/style.css @@ -265,8 +265,7 @@ kbd { .hero-topbar-link:active, .hero-action:active, -.tag:active, -.filter-clear:active { +.tag:active { transform: translateY(1px); } @@ -436,7 +435,6 @@ kbd { .hero-topbar-link:focus-visible, .hero-category-link:focus-visible, .search:focus-visible, -.filter-clear:focus-visible, .tag:focus-visible, .jump-link:focus-visible, .back-to-top:focus-visible, @@ -771,51 +769,6 @@ kbd { 0 1.6rem 3rem -2rem var(--search-focus-shadow); } -.filter-bar { - display: flex; - align-items: center; - gap: 0.75rem; - min-height: 2.3rem; - font-size: var(--text-sm); - color: var(--ink-soft); - opacity: 0; - transform: translateY(-0.4rem); - pointer-events: none; - transition: - opacity 180ms ease, - transform 180ms cubic-bezier(0.22, 1, 0.36, 1); -} - -.filter-bar.visible { - opacity: 1; - transform: translateY(0); - pointer-events: auto; -} - -.filter-bar strong { - color: var(--ink); -} - -.filter-clear { - border: 1px solid var(--line); - border-radius: 999px; - background: var(--bg-paper); - color: var(--ink-soft); - padding: 0.42rem 0.82rem; - cursor: pointer; - transition: - border-color 180ms ease, - color 180ms ease, - background-color 180ms ease, - transform 180ms ease; -} - -.filter-clear:hover { - color: var(--ink); - background: var(--accent-soft); - border-color: oklch(68% 0.08 58 / 0.5); -} - .table-wrap { width: 100%; border-top: 1px solid var(--line); diff --git a/website/templates/category.html b/website/templates/category.html index a9618aef..7528da00 100644 --- a/website/templates/category.html +++ b/website/templates/category.html @@ -78,7 +78,6 @@ {% macro entry_rows(entry, index) %} {% for subcat in entry.subcategories %} - + {{ subcat.name }} {% endfor %} @@ -132,8 +131,6 @@ {{ cat }} {% endfor %} @@ -142,8 +139,6 @@ {{ entry.groups[0] }} @@ -152,8 +147,6 @@ Stdlib @@ -211,7 +204,6 @@ {% endmacro %} -
{% if entry_groups %} @@ -255,12 +247,6 @@ aria-label="Search projects" />
-
- Filtering for - -

Results

diff --git a/website/templates/index.html b/website/templates/index.html index b5540624..e4d95d10 100644 --- a/website/templates/index.html +++ b/website/templates/index.html @@ -96,7 +96,6 @@
{% endif %} -
@@ -132,12 +131,6 @@ aria-label="Search projects" />
-
- Filtering for - -

Results

@@ -175,7 +168,6 @@ {% for entry in entries %} {% for subcat in entry.subcategories %} - + {{ subcat.name }} {% endfor %} {% for cat in entry.categories %} {{ cat }} {% endfor %} {{ entry.groups[0] }} @@ -245,8 +233,6 @@ Stdlib diff --git a/website/tests/test_build.py b/website/tests/test_build.py index cfebc616..f2448e90 100644 --- a/website/tests/test_build.py +++ b/website/tests/test_build.py @@ -280,7 +280,6 @@ class TestBuild: parser.feed(category_html) assert 'href="/categories/widgets/"' in index_html - assert 'data-value="Widgets"' in index_html assert parser.title.strip() == "Python Widgets Libraries - Awesome Python" assert parser.meta_by_name["description"] == "Widget libraries. Also see awesome-widgets. Explore 2 curated Python projects in Widgets." assert parser.links_by_rel["canonical"] == "https://awesome-python.com/categories/widgets/" @@ -816,75 +815,6 @@ class TestBuild: {"@type": "ListItem", "position": 2, "name": "Sponsorship", "item": "https://awesome-python.com/sponsorship/"}, ] - def test_index_embeds_filter_urls_json(self, tmp_path): - readme = textwrap.dedent("""\ - # T - - ## Projects - - **AI & ML** - - ## Deep Learning - - - [dl1](https://example.com/dl1) - DL. - - ## Machine Learning - - - Classical - - - [ml1](https://example.com/ml1) - ML. - - # Contributing - - Done. - """) - self._copy_real_templates(tmp_path) - (tmp_path / "README.md").write_text(readme, encoding="utf-8") - build(tmp_path) - - site = tmp_path / "website" / "output" - index_html = (site / "index.html").read_text(encoding="utf-8") - - marker = '", start) - data = json.loads(index_html[start:end]) - - assert data["Deep Learning"] == "/categories/deep-learning/" - assert data["Machine Learning"] == "/categories/machine-learning/" - assert data["AI & ML"] == "/categories/ai-ml/" - assert data["Machine Learning > Classical"] == "/categories/machine-learning/classical/" - - def test_filter_urls_json_escapes_closing_script_tag(self, tmp_path): - readme = textwrap.dedent("""\ - # T - - ## Projects - - ## Sneaky - - - [a](https://example.com) - A. - - # Contributing - - Done. - """) - self._copy_real_templates(tmp_path) - (tmp_path / "README.md").write_text(readme, encoding="utf-8") - build(tmp_path) - - site = tmp_path / "website" / "output" - index_html = (site / "index.html").read_text(encoding="utf-8") - - marker = '", start) - block = index_html[start:end] - assert "" not in block - data = json.loads(block) - assert any("Sneaky" in key for key in data) - def test_build_creates_group_pages(self, tmp_path): readme = textwrap.dedent("""\ # T @@ -925,7 +855,7 @@ class TestBuild: assert "wf1" in web_dev assert "dl1" not in web_dev - def test_tag_buttons_have_data_url(self, tmp_path): + def test_tags_link_to_pages_and_subcategory_anchors(self, tmp_path): readme = textwrap.dedent("""\ # T @@ -950,11 +880,14 @@ class TestBuild: site = tmp_path / "website" / "output" index_html = (site / "index.html").read_text(encoding="utf-8") - assert 'data-value="Deep Learning"' in index_html - assert 'data-url="/categories/deep-learning/"' in index_html - assert 'data-value="AI & ML"' in index_html or 'data-value="AI & ML"' in index_html - assert 'data-url="/categories/ai-ml/"' in index_html - assert 'data-url="/categories/deep-learning/vision/"' in index_html + category_html = (site / "categories" / "deep-learning" / "index.html").read_text(encoding="utf-8") + + for html in (index_html, category_html): + assert 'href="/categories/deep-learning/#vision"' in html + assert 'href="/categories/ai-ml/"' in html + assert "data-url=" not in html + assert 'href="/categories/deep-learning/"' in index_html + assert 'id="vision"' in category_html _REDIRECT_README = textwrap.dedent("""\ # Awesome Python