102 lines
3.1 KiB
Python
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
|