Add rendering of indices for the entire site and each section

This commit is contained in:
2026-08-06 00:25:07 +02:00
parent 1c919954e1
commit bfa4f8c2fa
3 changed files with 110 additions and 3 deletions
+77 -1
View File
@@ -1,5 +1,8 @@
import logging import logging
from typing import Any, cast from typing import Any, cast
from urllib.parse import urlparse
from itertools import batched
from math import ceil
from omicron.ssg.content import ( from omicron.ssg.content import (
Content, Content,
@@ -11,7 +14,6 @@ from omicron.ssg.content import (
from pathlib import Path from pathlib import Path
import yaml import yaml
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
from pygments.formatters import HtmlFormatter
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@@ -31,6 +33,8 @@ class Site:
config = self.read_config() config = self.read_config()
self.name: str = config["name"] self.name: str = config["name"]
self.template: str = config["template"] 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.template_path: Path = Site.resolve_template_path(self.template)
self.output_path: Path = self.site_path / "output" self.output_path: Path = self.site_path / "output"
self.jinja_env = Environment(loader=FileSystemLoader(self.template_path)) self.jinja_env = Environment(loader=FileSystemLoader(self.template_path))
@@ -48,6 +52,23 @@ class Site:
raise ConfigError("template value missing from config") raise ConfigError("template value missing from config")
return cast(dict[str, Any], 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 @staticmethod
def resolve_template_path(template: str) -> Path: def resolve_template_path(template: str) -> Path:
path = Path(__file__).parent / "templates" / template path = Path(__file__).parent / "templates" / template
@@ -87,7 +108,61 @@ class Site:
self.content.append(content) self.content.append(content)
log.info("Discovered %d content items", len(self.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: 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.discover()
self.output_path.mkdir(parents=True, exist_ok=True) self.output_path.mkdir(parents=True, exist_ok=True)
(self.output_path / "pygments.css").write_text( (self.output_path / "pygments.css").write_text(
@@ -95,3 +170,4 @@ class Site:
) )
for content in self.content: for content in self.content:
content.render(self) content.render(self)
self.render_indices()
+2 -2
View File
@@ -4,11 +4,11 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}{{ site.name }}{% endblock %}</title> <title>{% block title %}{{ site.name }}{% endblock %}</title>
<link rel="stylesheet" href="/pygments.css"> <link rel="stylesheet" href="{{ site.base_dir }}pygments.css">
</head> </head>
<body> <body>
<header> <header>
<a href="/">{{ site.name }}</a> <a href="{{ site.base_dir }}">{{ site.name }}</a>
</header> </header>
<main> <main>
{% block main %}{% endblock %} {% block main %}{% endblock %}
+31
View File
@@ -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 %}<h1>{{ section }}</h1>{% endif %}
{% for item in items %}
<article>
<header>
<h2><a href="{{ site.base_dir }}{{ item.uri }}">{{ item.title }}</a></h2>
<time datetime="{{ item.created }}">{{ item.created }}</time>
</header>
{% if item.summary %}<p>{{ item.summary }}</p>{% endif %}
</article>
{% endfor %}
{% if total_pages > 1 %}
<nav>
{% if page_num > 1 %}
<a href="{{ site.base_dir }}{% if section %}{{ section }}/{% endif %}page-{{ page_num - 1 }}.html">← Newer</a>
{% endif %}
{% for p in range(1, total_pages + 1) %}
{% if p == page_num %}<strong>{{ p }}</strong>
{% else %}<a href="{{ site.base_dir }}{% if section %}{{ section }}/{% endif %}page-{{ p }}.html">{{ p }}</a>
{% endif %}
{% endfor %}
{% if page_num < total_pages %}
<a href="{{ site.base_dir }}{% if section %}{{ section }}/{% endif %}page-{{ page_num + 1 }}.html">Older →</a>
{% endif %}
</nav>
{% endif %}
{% endblock %}