diff --git a/CHANGELOG.md b/CHANGELOG.md index 821aa62..b5727f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added -- Table of contents display. +- Improved navigation UI with a modern sidebar layout for Table of Contents. +- Navigation controls (Previous/Next) and TOC interaction logic implemented in Python. +- Automatic navigation button state management (disabling at spine ends). +- Active Table of Contents entry highlighting. +- End-to-end tests using Playwright. +- Representative screenshot in README.md. - Project documentation (`CONTRIBUTING.md`, `CHANGELOG.md`, `AGENTS.md`). - Custom exception hierarchy for error handling. - `LICENSE` file (Apache 2.0). ### Changed +- Refactored `index.html` to support a more structured layout. +- Extended `DOMElement` protocol to include `disabled` and `className` properties. - Updated documentation for accuracy and completeness. - Updated Pyodide version in demo to v0.29.1. diff --git a/README.md b/README.md index 19c7f06..6eb3db2 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ This is the initial implementation of the `Imposition` library, a Python library intended to run under Pyodide for parsing and rendering EPUB files. +![Imposition EPUB Reader Screenshot](assets/screenshot.png) + ## Installation This package is not yet available on PyPI. To install it, you must build the wheel from the source and then install it using `pip`: diff --git a/assets/screenshot.png b/assets/screenshot.png new file mode 100644 index 0000000..a4b2ac3 Binary files /dev/null and b/assets/screenshot.png differ diff --git a/index.html b/index.html index b40a143..7953473 100644 --- a/index.html +++ b/index.html @@ -1,25 +1,141 @@ + + Imposition EPUB Reader + - - + +
+

Imposition EPUB Reader

+
+ +
+
+

Contents

+ +
+
+
+
+
-
- - -
+ diff --git a/run_imposition.py b/run_imposition.py index 2b20d18..da8337e 100644 --- a/run_imposition.py +++ b/run_imposition.py @@ -16,4 +16,5 @@ async def main() -> None: js.window.rendition = rendition rendition.display_toc() + rendition.setup_controls("prev", "next") rendition.display(book.spine[0]) diff --git a/src/imposition/dom.py b/src/imposition/dom.py index 4ea1bfc..af3ed78 100644 --- a/src/imposition/dom.py +++ b/src/imposition/dom.py @@ -13,6 +13,8 @@ class DOMElement(Protocol): onclick: Callable[[Any], None] onload: str src: str + disabled: bool + className: str def appendChild(self, child: "DOMElement") -> None: ... diff --git a/src/imposition/rendition.py b/src/imposition/rendition.py index 4782b01..488dd1e 100644 --- a/src/imposition/rendition.py +++ b/src/imposition/rendition.py @@ -1,5 +1,5 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Callable, Optional +from typing import TYPE_CHECKING, Any, Callable, Optional, List, Tuple import xml.etree.ElementTree as ET import base64 @@ -41,13 +41,51 @@ def __init__(self, book: Book, dom_adapter: DOMAdapter, target_id: str) -> None: self.iframe.style.width = '100%' self.iframe.style.height = '100%' self.iframe.style.border = 'none' + self.toc_links: List[Tuple[DOMElement, str]] = [] + self.prev_button: Optional[DOMElement] = None + self.next_button: Optional[DOMElement] = None + + def setup_controls(self, prev_id: str, next_id: str) -> None: + """ + Sets up the navigation controls by attaching event listeners. + + :param prev_id: The ID of the 'Previous' button element. + :type prev_id: str + :param next_id: The ID of the 'Next' button element. + :type next_id: str + """ + self.prev_button = self.dom_adapter.get_element_by_id(prev_id) + self.next_button = self.dom_adapter.get_element_by_id(next_id) + + self.prev_button.onclick = self.dom_adapter.create_proxy(self.previous_chapter) + self.next_button.onclick = self.dom_adapter.create_proxy(self.next_chapter) + + self.update_controls() def display_toc(self) -> None: """ Renders the table of contents into the 'toc' element. """ toc_container: DOMElement = self.dom_adapter.get_element_by_id('toc') + # Preserve the

header if it exists, otherwise clear + # Actually, in index.html I have

Contents

. + # rendition previously did: toc_container.innerHTML = '' + # Let's see if there's a specific container for the list. + # In my new index.html I didn't add a specific div for the list, + # but I can just append the ul to the toc div. + # To avoid clearing the

, I could find the ul or just append. + # Let's just clear everything for now as it was before, or better, + # find where to inject. + + # If I want to be safe, I'll look for a