diff --git a/pyproject.toml b/pyproject.toml index 4f4db28..dbcdcbe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ dependencies = [ "jinja2>=3.1.6", "marko[codehilite]>=2.1.4", "python-frontmatter>=1.1.0", + "rich>=14.0.0", "starlette>=0.47.1", "typer>=0.16.0", "uvicorn>=0.34.3", diff --git a/src/zona/builder.py b/src/zona/builder.py index a41befb..26a868a 100644 --- a/src/zona/builder.py +++ b/src/zona/builder.py @@ -1,6 +1,7 @@ +from rich import print from zona.models import Item, Metadata, ItemType from zona import markdown as zmd -from zona import templates as tmpl +from zona.templates import Templater from zona import util from pathlib import Path import frontmatter @@ -74,21 +75,24 @@ def discover(root: Path, out_dir: Path) -> list[Item]: item.destination = ( out_dir / relative.parent / name / "index.html" ) + rel_url = item.destination.parent.relative_to(out_dir) + item.url = "" if rel_url == Path(".") else rel_url.as_posix() items.append(item) return items def build(root: Path, items: list[Item]): - env = tmpl.init_templates(root / "templates") + templater = Templater(root / "templates") for item in items: dst = item.destination + print(item) # create parent dirs if needed if item.type == ItemType.MARKDOWN: assert item.content is not None # parse markdown and render as html raw_html = zmd.md_to_html(item.content) # TODO: test this - rendered = tmpl.render_item(item, raw_html, env) + rendered = templater.render_item(item, raw_html) util.ensure_parents(dst) dst.write_text(rendered, encoding="utf-8") else: diff --git a/src/zona/models.py b/src/zona/models.py index 4f23a5f..c3be79c 100644 --- a/src/zona/models.py +++ b/src/zona/models.py @@ -9,9 +9,10 @@ class Metadata: title: str date: date description: str | None - style: str | None = "static/style.css" + style: str | None = "/static/style.css" header: bool = True footer: bool = True + template: str = "page.html" class ItemType(Enum): diff --git a/src/zona/templates.py b/src/zona/templates.py index f5e9609..a9e3979 100644 --- a/src/zona/templates.py +++ b/src/zona/templates.py @@ -1,19 +1,48 @@ from pathlib import Path from jinja2 import Environment, FileSystemLoader, select_autoescape from zona.models import Item +from zona.markdown import md_to_html -def init_templates(template_dir: Path) -> Environment: - return Environment( - loader=FileSystemLoader(template_dir), - autoescape=select_autoescape(["html", "xml"]), - ) +def get_header(template_dir: Path) -> str | None: + md_header = template_dir / "header.md" + html_header = template_dir / "header.html" + if md_header.exists(): + return md_to_html(md_header.read_text()) + elif html_header.exists(): + return html_header.read_text() -def render_item(item: Item, content: str, env: Environment) -> str: - template = env.get_template("post.html") - meta = item.metadata - assert meta is not None - return template.render( - title=meta.title, content=content, url=item.url, metadata=meta - ) +def get_footer(template_dir: Path) -> str | None: + md_footer = template_dir / "footer.md" + html_footer = template_dir / "footer.html" + if md_footer.exists(): + return md_to_html(md_footer.read_text()) + elif html_footer.exists(): + return html_footer.read_text() + + +class Templater: + def __init__(self, template_dir: Path): + self.env: Environment = Environment( + loader=FileSystemLoader(template_dir), + autoescape=select_autoescape(["html", "xml"]), + ) + self.template_dir: Path = template_dir + self.header: str | None = get_header(template_dir) + self.footer: str | None = get_footer(template_dir) + + def render_item(self, item: Item, content: str) -> str: + env = self.env + meta = item.metadata + assert meta is not None + template = env.get_template(meta.template) + header = self.header if self.header and meta.header else False + footer = self.footer if self.footer and meta.footer else False + return template.render( + content=content, + url=item.url, + metadata=meta, + header=header, + footer=footer, + ) diff --git a/tests/test_builder.py b/tests/test_builder.py index f61f7ee..cce7cd7 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -147,7 +147,7 @@ p { style.write_text(style_content) items = discover(tmp_path, outd) - build(items) + build(tmp_path, items) html = (outd / "post" / "index.html").read_text() assert html.strip() == "