Files
omicron-ssg/omicron/ssg/output/index.py
T

102 lines
3.1 KiB
Python

import logging
from pathlib import Path
from math import ceil
from itertools import batched
from typing import TYPE_CHECKING, Literal
from omicron.ssg.output.output import Output
from omicron.ssg.output.content import Content
log = logging.getLogger(__name__)
if TYPE_CHECKING:
from omicron.ssg.site import Site # for static checking with mypy
else:
Site = "omicron.ssg.site.Site" # for runtime checking with beartype
class Index(Output):
def __init__(
self,
site: Site,
kind: Literal["root", "section", "tag"],
items: list[Content],
page_num: int,
total_pages: int,
label: str | None,
):
super().__init__(site, Index.build_path(kind, page_num, label))
self.kind = kind
self.items = items
self.page_num = page_num
self.total_pages = total_pages
self.label = label
def pagination_url(self, n: int) -> str:
path = Index.build_path(self.kind, n, self.label)
return self.site.by_path[path].url
@staticmethod
def build_path(
kind: Literal["root", "section", "tag"],
page_num: int,
label: str | None,
) -> Path:
if page_num == 1:
file = Path("index.html")
else:
file = Path(f"page-{page_num}/index.html")
if kind == "root":
path = file
elif kind == "section":
assert label, "label can't be None if kind is not root"
path = Path(label) / file
else:
assert label, "label can't be None if kind is not root"
path = Path("tags") / label / file
return path
def write(self) -> None:
template = self.site.jinja_env.get_template("index.html")
html = template.render(site=self.site, page=self)
dest = self.site.output_path / self.destination
dest.parent.mkdir(parents=True, exist_ok=True)
dest.write_text(html, encoding="utf-8")
log.debug("Wrote %s", dest)
def make_index_pages(
site: Site,
items: list[Content],
kind: Literal["root", "section", "tag"],
label: str | None,
items_per_page: int,
) -> list[Index]:
sorted_items = sorted(items, key=lambda c: c.created, reverse=True)
if not sorted_items:
log.warning(
"No content for %s index%s, generating empty page",
kind,
f" ({label})" if label else "",
)
return [Index(site, kind, [], 1, 1, label)]
num_pages = ceil(len(sorted_items) / items_per_page)
return [
Index(site, kind, list(page_items), i + 1, num_pages, label)
for i, page_items in enumerate(batched(sorted_items, items_per_page))
]
def discover_index(site: Site) -> list[Index]:
outputs: list[Index] = []
outputs.extend(
make_index_pages(site, site.content, "root", None, site.items_per_page)
)
for section, items in site.by_section.items():
outputs.extend(
make_index_pages(site, items, "section", section, site.items_per_page)
)
for tag, items in site.by_tag.items():
outputs.extend(make_index_pages(site, items, "tag", tag, site.items_per_page))
return outputs