#!/usr/bin/env python3 import json import os import shutil from dataclasses import dataclass from datetime import datetime from pathlib import Path import jinja2 from typst import Compiler @dataclass class CompiledPage: url: str title: str date: datetime class Builder: def __init__(self, site_dir: Path, static_dir: Path, public_dir: Path) -> None: self.site_dir = site_dir self.content_dir = site_dir / 'content' self.static_dir = static_dir self.public_dir = public_dir self.compiler = Compiler(root=site_dir) def _compile_typst_page(self, path: Path) -> CompiledPage: relative_path = path.relative_to(self.content_dir) print(f'Typst: {relative_path}') output_path = self.public_dir / relative_path.with_suffix('.html') output_path.parent.mkdir(parents=True, exist_ok=True) self.compiler.compile(input=path, output=output_path) metadata = json.loads( self.compiler.query( selector='', field='value', one=True, ) ) return CompiledPage( url=str(relative_path.with_suffix('.html')), title=metadata['title'], date=datetime( year=metadata['date_year'], month=metadata['date_month'], day=metadata['date_day'], ), ) def _compile_typst_pages(self) -> list[CompiledPage]: return [self._compile_typst_page(path) for path in self.content_dir.rglob('*.typ')] def _compile_index_page(self, pages: list[CompiledPage]) -> None: pages.sort(key=lambda page: page.date) template = jinja2.Template((self.site_dir / 'index.html').read_text()) (self.public_dir / 'index.html').write_text(template.render(pages=pages)) def build(self) -> None: print(f'Removing {str(self.public_dir)!r}...') shutil.rmtree(self.public_dir, ignore_errors=True) self.public_dir.mkdir(parents=True, exist_ok=True) print('Linking static directory...') (self.public_dir / 'static').symlink_to(self.static_dir) pages = self._compile_typst_pages() print('Building index page...') self._compile_index_page(pages) def main() -> None: repo_dir = Path(__file__).parent site_dir = repo_dir / 'site' public_dir = repo_dir / 'public' static_dir = repo_dir / 'static' os.environ['TYPST_FEATURES'] = 'html' builder = Builder(site_dir=site_dir, static_dir=static_dir, public_dir=public_dir) builder.build() if __name__ == '__main__': main()