diff --git a/omicron/ssg/site.py b/omicron/ssg/site.py index e5956c4..320e76e 100644 --- a/omicron/ssg/site.py +++ b/omicron/ssg/site.py @@ -1,5 +1,8 @@ import logging from typing import Any, cast +from urllib.parse import urlparse +from itertools import batched +from math import ceil from omicron.ssg.content import ( Content, @@ -11,7 +14,6 @@ from omicron.ssg.content import ( from pathlib import Path import yaml from jinja2 import Environment, FileSystemLoader -from pygments.formatters import HtmlFormatter log = logging.getLogger(__name__) @@ -31,6 +33,8 @@ class Site: config = self.read_config() self.name: str = config["name"] self.template: str = config["template"] + self.items_per_page: int = int(config.get("items_per_page", 20)) + self.origin, self.base_dir = Site.parse_base_uri(config.get("base_uri")) self.template_path: Path = Site.resolve_template_path(self.template) self.output_path: Path = self.site_path / "output" self.jinja_env = Environment(loader=FileSystemLoader(self.template_path)) @@ -48,6 +52,23 @@ class Site: raise ConfigError("template value missing from config") return cast(dict[str, Any], config) + @staticmethod + def parse_base_uri(value: str | None) -> tuple[str, str]: + if not value: + return ("", "/") + parsed = urlparse(value) + if parsed.scheme and parsed.netloc: + origin = f"{parsed.scheme}://{parsed.netloc}" + elif parsed.netloc: + origin = f"//{parsed.netloc}" + else: + origin = "" + + path = parsed.path + if not path.endswith("/"): + path += "/" + return (origin, path) + @staticmethod def resolve_template_path(template: str) -> Path: path = Path(__file__).parent / "templates" / template @@ -87,7 +108,61 @@ class Site: self.content.append(content) log.info("Discovered %d content items", len(self.content)) + def render_single_index_page( + self, + out_dir: Path, + items: tuple[Content, ...], + page_num: int, + total_pages: int, + section: str | None, + ) -> None: + template = self.jinja_env.get_template("index.html") + html = template.render( + site=self, + items=items, + page_num=page_num, + total_pages=total_pages, + section=section, + ) + out_file = out_dir / f"page-{page_num}.html" + out_file.write_text(html, encoding="utf-8") + + def render_index_pages( + self, + items: list[Content], + out_dir: Path, + section: str | None, + ) -> None: + out_dir.mkdir(parents=True, exist_ok=True) + if not items: + log.warning("No content, generating empty index page") + self.render_single_index_page(out_dir, (), 1, 1, section) + else: + num_pages = ceil(len(items) / self.items_per_page) + for i, page_items in enumerate(batched(items, self.items_per_page)): + self.render_single_index_page( + out_dir, page_items, i + 1, num_pages, section + ) + index = out_dir / "index.html" + if index.exists() or index.is_symlink(): + index.unlink() + index.symlink_to("page-1.html") + + def render_indices(self) -> None: + sorted_all = sorted(self.content, key=lambda c: c.created, reverse=True) + self.render_index_pages(sorted_all, self.output_path, None) + for section, items in self.by_section.items(): + sorted_items = sorted(items, key=lambda c: c.created, reverse=True) + self.render_index_pages(sorted_items, self.output_path / section, section) + def build(self) -> None: + if not self.origin: + log.warning( + "base_uri config value is missing a domain name, " + "can't add canonical uri to content" + ) + if not self.base_dir.startswith("/"): + raise ConfigError("base_uri config value must be an absolute path") self.discover() self.output_path.mkdir(parents=True, exist_ok=True) (self.output_path / "pygments.css").write_text( @@ -95,3 +170,4 @@ class Site: ) for content in self.content: content.render(self) + self.render_indices() diff --git a/omicron/ssg/templates/plain/base.html b/omicron/ssg/templates/plain/base.html index 60cb912..849e9a7 100644 --- a/omicron/ssg/templates/plain/base.html +++ b/omicron/ssg/templates/plain/base.html @@ -4,11 +4,11 @@ {% block title %}{{ site.name }}{% endblock %} - +
- {{ site.name }} + {{ site.name }}
{% block main %}{% endblock %} diff --git a/omicron/ssg/templates/plain/index.html b/omicron/ssg/templates/plain/index.html new file mode 100644 index 0000000..8135e06 --- /dev/null +++ b/omicron/ssg/templates/plain/index.html @@ -0,0 +1,31 @@ +{% extends "base.html" %} + +{% block title %}{% if section %}{{ section }} — {% endif %}{{ site.name }}{% if page_num > 1 %} — Page {{ page_num }}{% endif %}{% endblock %} + +{% block main %} +{% if section %}

{{ section }}

{% endif %} +{% for item in items %} +
+
+

{{ item.title }}

+ +
+ {% if item.summary %}

{{ item.summary }}

{% endif %} +
+{% endfor %} +{% if total_pages > 1 %} + +{% endif %} +{% endblock %}