Add rendering of indices for the entire site and each section
This commit is contained in:
+77
-1
@@ -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()
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}{{ site.name }}{% endblock %}</title>
|
||||
<link rel="stylesheet" href="/pygments.css">
|
||||
<link rel="stylesheet" href="{{ site.base_dir }}pygments.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<a href="/">{{ site.name }}</a>
|
||||
<a href="{{ site.base_dir }}">{{ site.name }}</a>
|
||||
</header>
|
||||
<main>
|
||||
{% block main %}{% endblock %}
|
||||
|
||||
@@ -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 %}
|
||||
Reference in New Issue
Block a user