Andrew Ridgway bec1eaac87
Some checks failed
Test / test (push) Has been cancelled
first pass at the newspaper builder
2026-09-14 11:57:22 +10:00

45 lines
1.8 KiB
Python

"""generator layout + pagination.
Per BR2.1/BR2.3, US1/NFR2: flows articles into a classic column-based
multi-page A4 layout with page breaks at boundaries, page numbers and running
headers. Deterministic, stdlib-only.
"""
from __future__ import annotations
from .model import Article, Column, ColumnItem, Page
class ColumnFlow:
"""Flows placed items into columns/pages with running headers."""
def __init__(self, columns_per_page: int = 3, items_per_column: int = 4) -> None:
self.columns_per_page = columns_per_page
self.items_per_column = items_per_column
def flow(self, article_items: list[ColumnItem]) -> list[Page]:
pages: list[Page] = []
current: Column | None = None
page: Page | None = None
idx = 0
for item in article_items:
if page is None or current is None or len(current.items) >= self.items_per_column:
current = Column(column_index=0 if current is None else ((current.column_index + 1) % self.columns_per_page))
if page is None or (current.column_index == 0 and len(page.columns) >= self.columns_per_page):
page_number = len(pages) + 1
page = Page(page_number=page_number, columns=[], running_header=f"Page {page_number}")
pages.append(page)
page.columns.append(current)
idx += 1
current.items.append(item)
return pages or [Page(page_number=1, columns=[Column(column_index=0)], running_header="Page 1")]
def build_layout(articles: list[Article]) -> list[Page]:
"""Map articles into column items and flow them (BR2.1)."""
items: list[ColumnItem] = []
for a in articles:
items.append(ColumnItem(item_id=a.article_id, kind="article", source_ref=a.article_id))
flow = ColumnFlow()
return flow.flow(items)