|
| 1 | +"""Tag index page generation.""" |
| 2 | + |
| 3 | +from pathlib import Path |
| 4 | + |
| 5 | +from jinja2 import Environment |
| 6 | + |
| 7 | +from rockgarden.content.models import Page |
| 8 | +from rockgarden.urls import get_url |
| 9 | + |
| 10 | + |
| 11 | +def normalize_tag(tag: str) -> str: |
| 12 | + """Normalize a tag to a URL-safe slug. |
| 13 | +
|
| 14 | + Strips leading '#' and lowercases. Tags 'Python', '#python', and 'python' |
| 15 | + all normalize to 'python'. |
| 16 | + """ |
| 17 | + return tag.lstrip("#").lower() |
| 18 | + |
| 19 | + |
| 20 | +def collect_tags(pages: list[Page]) -> dict[str, list[Page]]: |
| 21 | + """Return a mapping of normalized tag slug → list of pages with that tag. |
| 22 | +
|
| 23 | + Pages are included in the order they appear in the input list. Tags with |
| 24 | + no pages are not included. Result is sorted alphabetically by tag slug. |
| 25 | + """ |
| 26 | + tags: dict[str, list[Page]] = {} |
| 27 | + for page in pages: |
| 28 | + raw_tags = page.frontmatter.get("tags", []) |
| 29 | + if isinstance(raw_tags, str): |
| 30 | + raw_tags = [raw_tags] |
| 31 | + for tag in raw_tags: |
| 32 | + slug = normalize_tag(tag) |
| 33 | + if slug: |
| 34 | + tags.setdefault(slug, []).append(page) |
| 35 | + return dict(sorted(tags.items())) |
| 36 | + |
| 37 | + |
| 38 | +def build_tag_pages( |
| 39 | + tags: dict[str, list[Page]], |
| 40 | + env: Environment, |
| 41 | + site_config: dict, |
| 42 | + output: Path, |
| 43 | + clean_urls: bool = True, |
| 44 | +) -> None: |
| 45 | + """Generate /tags/<slug>/ and /tags/ pages in the output directory.""" |
| 46 | + tag_index_template = env.get_template("tag_index.html") |
| 47 | + tags_root_template = env.get_template("tags_root.html") |
| 48 | + |
| 49 | + for tag_slug, tagged_pages in tags.items(): |
| 50 | + page_entries = [ |
| 51 | + {"title": p.title, "url": get_url(p.slug, clean_urls)} |
| 52 | + for p in tagged_pages |
| 53 | + ] |
| 54 | + html = tag_index_template.render( |
| 55 | + tag=tag_slug, |
| 56 | + pages=page_entries, |
| 57 | + site=site_config, |
| 58 | + ) |
| 59 | + out_file = output / "tags" / tag_slug / "index.html" |
| 60 | + out_file.parent.mkdir(parents=True, exist_ok=True) |
| 61 | + out_file.write_text(html) |
| 62 | + |
| 63 | + tag_counts = {slug: len(pages) for slug, pages in tags.items()} |
| 64 | + html = tags_root_template.render( |
| 65 | + tags=tag_counts, |
| 66 | + site=site_config, |
| 67 | + ) |
| 68 | + out_file = output / "tags" / "index.html" |
| 69 | + out_file.parent.mkdir(parents=True, exist_ok=True) |
| 70 | + out_file.write_text(html) |
0 commit comments