diff --git a/mkdocs.yml b/mkdocs.yml index 95b3478..5f10331 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -41,30 +41,6 @@ extra: link: https://pypi.org/project/mkdocs-exporter plugins: - - exporter: - - exporter-pdf: - concurrency: 16 - enabled: !ENV [MKDOCS_EXPORTER_PDF, true] - stylesheets: - - resources/stylesheets/pdf.scss - covers: - front: resources/templates/covers/front.html.j2 - back: resources/templates/covers/back.html.j2 - browser: - debug: false - headless: true - - exporter-aggregator: - enabled: true - output: .well-known/document.pdf - covers: limits - - exporter-extras: - buttons: - - title: Download as PDF - icon: material-file-download-outline - enabled: !!python/name:mkdocs_exporter.plugins.pdf.button.enabled - attributes: - href: !!python/name:mkdocs_exporter.plugins.pdf.button.href - download: !!python/name:mkdocs_exporter.plugins.pdf.button.download - search: lang: en - awesome-pages @@ -82,6 +58,34 @@ plugins: - social: cards_layout_options: background_color: '#EA2027' + - exporter: + formats: + pdf: + concurrency: 16 + enabled: !ENV [MKDOCS_EXPORTER_PDF, true] + stylesheets: + - resources/stylesheets/pdf.scss + covers: + front: resources/templates/covers/front.html.j2 + back: resources/templates/covers/back.html.j2 + browser: + debug: false + headless: true + aggregator: + enabled: true + output: .well-known/document.pdf + covers: all + buttons: + - title: View as PDF + icon: material-file-move-outline + enabled: !!python/name:mkdocs_exporter.formats.pdf.buttons.download.enabled + attributes: + target: _blank + href: !!python/name:mkdocs_exporter.formats.pdf.buttons.download.href + - title: Download as PDF + icon: material-file-download-outline + enabled: !!python/name:mkdocs_exporter.formats.pdf.buttons.download.enabled + attributes: !!python/name:mkdocs_exporter.formats.pdf.buttons.download.attributes markdown_extensions: - admonition diff --git a/mkdocs_exporter/config.py b/mkdocs_exporter/config.py index c20e011..eec8cb4 100644 --- a/mkdocs_exporter/config.py +++ b/mkdocs_exporter/config.py @@ -1,9 +1,41 @@ +from typing import Callable + from mkdocs.config import config_options as c from mkdocs.config.base import Config as BaseConfig +from mkdocs_exporter.formats.pdf.config import Config as PDFFormatConfig + + +class FormatsConfig(BaseConfig): + + """The PDF format configuration.""" + pdf = c.SubConfig(PDFFormatConfig) + + +class ButtonConfig(BaseConfig): + """The configuration of a button.""" + + enabled = c.Type((bool, Callable), default=True) + """Is the button enabled?""" + + title = c.Type((str, Callable)) + """The button's title.""" + + icon = c.Type((str, Callable)) + """The button's icon (typically, an SVG element).""" + + attributes = c.Type((dict, Callable), default={}) + """Some extra attributes to add to the button.""" + class Config(BaseConfig): """The plugin's configuration.""" theme = c.Optional(c.Theme(default=None)) """Override the theme used by your MkDocs instance.""" + + formats = c.SubConfig(FormatsConfig) + """The formats to generate.""" + + buttons = c.ListOfItems(c.SubConfig(ButtonConfig)) + """The buttons to add.""" diff --git a/mkdocs_exporter/plugins/__init__.py b/mkdocs_exporter/formats/__init__.py similarity index 100% rename from mkdocs_exporter/plugins/__init__.py rename to mkdocs_exporter/formats/__init__.py diff --git a/mkdocs_exporter/plugins/aggregator/__init__.py b/mkdocs_exporter/formats/pdf/__init__.py similarity index 100% rename from mkdocs_exporter/plugins/aggregator/__init__.py rename to mkdocs_exporter/formats/pdf/__init__.py diff --git a/mkdocs_exporter/formats/pdf/aggregator.py b/mkdocs_exporter/formats/pdf/aggregator.py new file mode 100644 index 0000000..b8e4555 --- /dev/null +++ b/mkdocs_exporter/formats/pdf/aggregator.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +import os + +from pypdf import PdfReader, PdfWriter + + +class Aggregator: + """Aggregates PDF documents together.""" + + + def open(self, path: str) -> Aggregator: + """Opens the aggregator.""" + + self.path = path + self.writer = PdfWriter() + + + def covers(self, mode: str) -> Aggregator: + """Defines the way of handling cover pages.""" + + self._covers = mode + + + def aggregate(self, pages: list) -> Aggregator: + """Aggregates pages together.""" + + for n, page in enumerate(pages): + if 'pdf' not in page.formats: + continue + + bounds = None + pdf = page.formats['pdf']['path'] + total = len(PdfReader(pdf).pages) + + if 'covers' in page.formats['pdf']: + covers = page.formats['pdf']['covers'] + + if self._covers == 'none': + bounds = (1 if covers['front'] else 0, (total - 1) if covers['back'] else total) + if self._covers == 'limits': + bounds = (1 if n != 0 and covers['front'] else 0, (total - 1) if n != (len(pages) - 1) and covers['back'] else total) + + self.writer.append(pdf, pages=bounds) + + + def save(self, metadata={}) -> Aggregator: + """Saves the aggregated document.""" + + os.makedirs(os.path.dirname(self.path), exist_ok=True) + + self.writer.add_metadata({'/Producer': 'MkDocs Exporter', **metadata}) + self.writer.write(self.path) + self.writer.close() + + self.writer = None + + return self diff --git a/mkdocs_exporter/plugins/pdf/browser.py b/mkdocs_exporter/formats/pdf/browser.py similarity index 97% rename from mkdocs_exporter/plugins/pdf/browser.py rename to mkdocs_exporter/formats/pdf/browser.py index 0e281b7..93af7f9 100644 --- a/mkdocs_exporter/plugins/pdf/browser.py +++ b/mkdocs_exporter/formats/pdf/browser.py @@ -13,6 +13,8 @@ class Browser: """A web browser instance.""" args = [ + '--disable-background-timer-throttling', + '--disable-renderer-backgrounding', '--allow-file-access-from-files' ] """The browser's arguments...""" diff --git a/mkdocs_exporter/plugins/extras/__init__.py b/mkdocs_exporter/formats/pdf/buttons/__init__.py similarity index 100% rename from mkdocs_exporter/plugins/extras/__init__.py rename to mkdocs_exporter/formats/pdf/buttons/__init__.py diff --git a/mkdocs_exporter/plugins/pdf/button.py b/mkdocs_exporter/formats/pdf/buttons/download.py similarity index 61% rename from mkdocs_exporter/plugins/pdf/button.py rename to mkdocs_exporter/formats/pdf/buttons/download.py index c1482cb..bb7a8e0 100644 --- a/mkdocs_exporter/plugins/pdf/button.py +++ b/mkdocs_exporter/formats/pdf/buttons/download.py @@ -10,17 +10,26 @@ def enabled(page: Page, **kwargs) -> bool: def href(page: Page, **kwargs) -> str: - """The button's 'href' attribute.""" + """The value of the 'href' attribute.""" - return os.path.relpath(page.formats['pdf']['path'], page.url) + return os.path.relpath(page.formats['pdf']['url'], page.url) def download(page: Page, **kwargs) -> str: - """The button's 'download' attribute.""" + """The value of the 'download' attribute.""" return page.title + os.path.extsep + 'pdf' +def attributes(page: Page, **kwargs) -> dict: + """The button's 'href' attribute.""" + + return { + 'href': href(page, **kwargs), + 'download': download(page, **kwargs), + } + + def icon(page: Page, **kwargs) -> str: """The button's icon.""" diff --git a/mkdocs_exporter/plugins/pdf/config.py b/mkdocs_exporter/formats/pdf/config.py similarity index 76% rename from mkdocs_exporter/plugins/pdf/config.py rename to mkdocs_exporter/formats/pdf/config.py index c82966a..ff3a51c 100644 --- a/mkdocs_exporter/plugins/pdf/config.py +++ b/mkdocs_exporter/formats/pdf/config.py @@ -25,6 +25,21 @@ class CoversConfig(BaseConfig): """The back cover template location.""" +class AggregatorConfig(BaseConfig): + + enabled = c.Type(bool, default=False) + """Is the aggregator enabled?""" + + output = c.Type(str, default='site.pdf') + """The aggregated PDF document output file path.""" + + covers = c.Choice(['none', 'all', 'limits'], default='all') + """The behaviour of cover pages.""" + + metadata = c.Type(dict, default={}) + """Some metadata to append to the PDF document.""" + + class Config(BaseConfig): """The plugin's configuration.""" @@ -51,3 +66,6 @@ class Config(BaseConfig): url = c.Optional(c.Type(str)) """The base URL that'll be prefixed to links with a relative path.""" + + aggregator = c.SubConfig(AggregatorConfig) + """The aggregator's configuration.""" diff --git a/mkdocs_exporter/plugins/pdf/plugin.py b/mkdocs_exporter/formats/pdf/plugin.py similarity index 69% rename from mkdocs_exporter/plugins/pdf/plugin.py rename to mkdocs_exporter/formats/pdf/plugin.py index d8c38a6..244f59c 100644 --- a/mkdocs_exporter/plugins/pdf/plugin.py +++ b/mkdocs_exporter/formats/pdf/plugin.py @@ -11,8 +11,9 @@ from mkdocs_exporter.page import Page from mkdocs_exporter.logging import logger -from mkdocs_exporter.plugins.pdf.config import Config -from mkdocs_exporter.plugins.pdf.renderer import Renderer +from mkdocs_exporter.formats.pdf.config import Config +from mkdocs_exporter.formats.pdf.renderer import Renderer +from mkdocs_exporter.formats.pdf.aggregator import Aggregator class Plugin(BasePlugin[Config]): @@ -25,14 +26,7 @@ def __init__(self): self.watch: list[str] = [] self.renderer: Optional[Renderer] = None self.tasks: list[types.CoroutineType] = [] - self.loop: asyncio.AbstractEventLoopPolicy = asyncio.new_event_loop() - - - def on_startup(self, **kwargs) -> None: - """Invoked when the plugin is starting...""" - - nest_asyncio.apply(self.loop) - asyncio.set_event_loop(self.loop) + self.loop: Optional[asyncio.AbstractEventLoopPolicy] = None def on_config(self, config: dict) -> None: @@ -57,6 +51,7 @@ def on_serve(self, server: LiveReloadServer, **kwargs) -> LiveReloadServer: return server + @event_priority(100) def on_page_markdown(self, markdown: str, page: Page, config: Config, **kwargs) -> str: """Invoked when the page's markdown has been loaded.""" @@ -95,6 +90,11 @@ def on_pre_build(self, **kwargs) -> None: if not self._enabled(): return + self.loop = asyncio.new_event_loop() + + nest_asyncio.apply(self.loop) + asyncio.set_event_loop(self.loop) + self.renderer = Renderer(options=self.config) for stylesheet in self.config.stylesheets: @@ -103,6 +103,7 @@ def on_pre_build(self, **kwargs) -> None: self.renderer.add_script(script) + @event_priority(90) def on_pre_page(self, page: Page, config: dict, **kwargs): """Invoked before building the page.""" @@ -116,39 +117,38 @@ def on_pre_page(self, page: Page, config: dict, **kwargs): fullpath = os.path.join(directory, filename) page.formats['pdf'] = { - 'path': os.path.relpath(fullpath, config['site_dir']) + 'path': fullpath, + 'url': os.path.relpath(fullpath, config['site_dir']) } - @event_priority(-75) - def on_post_page(self, html: str, page: Page, config: dict) -> Optional[str]: + @event_priority(90) + def on_post_page(self, html: str, page: Page, **kwargs) -> Optional[str]: """Invoked after a page has been built.""" if not self._enabled(page) and 'pdf' in page.formats: del page.formats['pdf'] - if 'pdf' not in page.formats: - return html page.html = html - async def render(page: Page) -> None: - logger.info("[mkdocs-exporter.pdf] Rendering '%s'...", page.file.src_path) + if 'pdf' in page.formats: + async def render(page: Page) -> None: + logger.info("[mkdocs-exporter.pdf] Rendering '%s'...", page.file.src_path) - html = self.renderer.preprocess(page) - pdf = await self.renderer.render(html) + html = self.renderer.preprocess(page) + pdf = await self.renderer.render(html) - page.html = None + with open(page.formats['pdf']['path'], 'wb+') as file: + file.write(pdf) + logger.info("[mkdocs-exporter.pdf] File written to '%s'!", file.name) - with open(os.path.join(config['site_dir'], page.formats['pdf']['path']), 'wb+') as file: - file.write(pdf) - logger.info("[mkdocs-exporter.pdf] File written to '%s'!", file.name) - - self.tasks.append(render(page)) + self.tasks.append(render(page)) return page.html - def on_post_build(self, **kwargs) -> None: + @event_priority(-100) + def on_post_build(self, config: dict, **kwargs) -> None: """Invoked after the build process.""" if not self._enabled(): @@ -167,8 +167,40 @@ async def limit(coroutine: Coroutine) -> Coroutine: self.loop.run_until_complete(self.renderer.dispose()) self.tasks.clear() + self.loop = None self.renderer = None + nest_asyncio.apply(self.loop) + asyncio.set_event_loop(self.loop) + + if self.config.get('aggregator', {})['enabled']: + aggregator = Aggregator() + aggregator_config = self.config.get('aggregator', {}) + + aggregator.open(os.path.join(config['site_dir'], aggregator_config['output'])) + aggregator.covers(aggregator_config['covers']) + aggregator.aggregate(self.pages) + aggregator.save(metadata=aggregator_config['metadata']) + + + @event_priority(-100) + def on_nav(self, nav, **kwargs): + """Invoked when the navigation is ready.""" + + def flatten(items): + pages = [] + + for item in items: + if item.is_page: + pages.append(item) + if item.is_section: + pages = pages + flatten(item.children) + + return pages + + self.nav = nav + self.pages = flatten(nav) + def _enabled(self, page: Page = None) -> bool: """Is the plugin enabled for this page?""" diff --git a/mkdocs_exporter/plugins/pdf/preprocessor.py b/mkdocs_exporter/formats/pdf/preprocessor.py similarity index 100% rename from mkdocs_exporter/plugins/pdf/preprocessor.py rename to mkdocs_exporter/formats/pdf/preprocessor.py diff --git a/mkdocs_exporter/plugins/pdf/renderer.py b/mkdocs_exporter/formats/pdf/renderer.py similarity index 95% rename from mkdocs_exporter/plugins/pdf/renderer.py rename to mkdocs_exporter/formats/pdf/renderer.py index ae100af..54eee33 100644 --- a/mkdocs_exporter/plugins/pdf/renderer.py +++ b/mkdocs_exporter/formats/pdf/renderer.py @@ -7,9 +7,9 @@ from mkdocs_exporter.page import Page from mkdocs_exporter.resources import js -from mkdocs_exporter.plugins.pdf.browser import Browser +from mkdocs_exporter.formats.pdf.browser import Browser from mkdocs_exporter.renderer import Renderer as BaseRenderer -from mkdocs_exporter.plugins.pdf.preprocessor import Preprocessor +from mkdocs_exporter.formats.pdf.preprocessor import Preprocessor class Renderer(BaseRenderer): diff --git a/mkdocs_exporter/helpers.py b/mkdocs_exporter/helpers.py new file mode 100644 index 0000000..187cb85 --- /dev/null +++ b/mkdocs_exporter/helpers.py @@ -0,0 +1,14 @@ +from collections import UserDict + + +def resolve(object, *args, **kwargs): + """Resolves a callable.""" + + if callable(object): + return resolve(object(*args, **kwargs), *args, **kwargs) + if isinstance(object, list): + return [resolve(v, *args, **kwargs) for v in object] + if isinstance(object, (dict, UserDict)): + return {k: resolve(v, *args, **kwargs) for k, v in object.items()} + + return object diff --git a/mkdocs_exporter/plugin.py b/mkdocs_exporter/plugin.py index a676272..d352355 100644 --- a/mkdocs_exporter/plugin.py +++ b/mkdocs_exporter/plugin.py @@ -1,10 +1,15 @@ +from typing import Type + from mkdocs.plugins import BasePlugin -from mkdocs_exporter.page import Page from mkdocs.plugins import event_priority -from mkdocs_exporter.config import Config from mkdocs.structure.files import File, Files + +from mkdocs_exporter.page import Page +from mkdocs_exporter.config import Config +from mkdocs_exporter.helpers import resolve from mkdocs_exporter.preprocessor import Preprocessor from mkdocs_exporter.themes.factory import Factory as ThemeFactory +from mkdocs_exporter.formats.pdf.plugin import Plugin as PDFFormatPlugin class Plugin(BasePlugin[Config]): @@ -17,11 +22,25 @@ def __init__(self) -> None: self.stylesheets: list[File] = [] - def on_config(self, config: dict) -> None: + @event_priority(100) + def on_config(self, config: dict, *args, **kwargs) -> None: """Invoked when the configuration has been loaded.""" self.theme = ThemeFactory.create(self.config.theme or config['theme']) + def register(key, plugin: Type[Plugin], config_data: dict) -> Plugin: + """Registers a MkDocs plugin dynamically.""" + + key = 'exporter-' + key + + config.plugins[key] = plugin() + config.plugins[key].config = config_data + + config.plugins[key].on_config(config, *args, **kwargs) + + if 'pdf' in self.config.formats: + register('pdf', PDFFormatPlugin, self.config['formats']['pdf']) + def on_pre_build(self, **kwargs) -> None: """Invoked before the build process starts.""" @@ -29,6 +48,7 @@ def on_pre_build(self, **kwargs) -> None: self.stylesheets.clear() + @event_priority(100) def on_pre_page(self, page: Page, **kwargs) -> None: """Invoked after a page has been built.""" @@ -44,6 +64,11 @@ def on_post_page(self, html: str, page: Page, **kwargs) -> str: preprocessor = Preprocessor(theme=page.theme) preprocessor.preprocess(html) + + for button in [*self.config.buttons, *page.meta.get('buttons', [])]: + if resolve(button.get('enabled', True), page=page): + preprocessor.button(**resolve(button, page=page)) + preprocessor.remove('*[data-decompose="true"]') preprocessor.teleport() diff --git a/mkdocs_exporter/plugins/aggregator/config.py b/mkdocs_exporter/plugins/aggregator/config.py deleted file mode 100644 index d09a418..0000000 --- a/mkdocs_exporter/plugins/aggregator/config.py +++ /dev/null @@ -1,18 +0,0 @@ -from mkdocs.config import config_options as c -from mkdocs.config.base import Config as BaseConfig - - -class Config(BaseConfig): - """The plugin's configuration.""" - - enabled = c.Type(bool, default=True) - """Is the plugin enabled?""" - - metadata = c.Type(dict, default={}) - """The metadata to append to the PDF.""" - - output = c.Type(str, default='site.pdf') - """The output file path.""" - - covers = c.Choice(['all', 'none', 'limits'], default='all') - """The way that cover pages will be handled.""" diff --git a/mkdocs_exporter/plugins/aggregator/plugin.py b/mkdocs_exporter/plugins/aggregator/plugin.py deleted file mode 100644 index c05c938..0000000 --- a/mkdocs_exporter/plugins/aggregator/plugin.py +++ /dev/null @@ -1,70 +0,0 @@ -import os - -from pypdf import PdfReader, PdfWriter - -from mkdocs.plugins import BasePlugin -from mkdocs.plugins import event_priority - -from mkdocs_exporter.logging import logger -from mkdocs_exporter.plugins.aggregator.config import Config - - -class Plugin(BasePlugin[Config]): - """The plugin.""" - - @event_priority(-100) - def on_nav(self, nav, **kwargs): - """Invoked when the navigation is ready.""" - - def flatten(items): - pages = [] - - for item in items: - if item.is_page: - pages.append(item) - if item.is_section: - pages = pages + flatten(item.children) - - return pages - - self.nav = nav - self.pages = flatten(nav) - - - def on_post_build(self, config, **kwargs): - """Invoked once the build is done.""" - - if not self.config.get('enabled'): - return - - logger.info('[mkdocs-exporter.aggregator] Generating aggregated PDF document...') - - aggregate = PdfWriter() - destination = os.path.join(config['site_dir'], self.config['output']) - - os.makedirs(os.path.dirname(destination), exist_ok=True) - - for n, page in enumerate(self.pages): - if 'pdf' not in page.formats: - continue - - pages = None - pdf = os.path.join(config['site_dir'], page.formats['pdf']['path']) - total = len(PdfReader(pdf).pages) - - if 'covers' in page.formats['pdf']: - covers = page.formats['pdf']['covers'] - - if self.config['covers'] == 'none': - pages = (1 if covers['front'] else 0, (total - 1) if covers['back'] else total) - if self.config['covers'] == 'limits': - pages = (1 if n != 0 and covers['front'] else 0, (total - 1) if n != (len(self.pages) - 1) and covers['back'] else total) - - aggregate.append(pdf, pages=pages) - - if len(aggregate.pages) > 0: - aggregate.add_metadata({'/Producer': 'MkDocs Exporter', **self.config['metadata']}) - aggregate.write(destination) - logger.info("[mkdocs-exporter.aggregator] Aggregated PDF document written to '%s'!", destination) - - aggregate.close() diff --git a/mkdocs_exporter/plugins/extras/config.py b/mkdocs_exporter/plugins/extras/config.py deleted file mode 100644 index 26d3531..0000000 --- a/mkdocs_exporter/plugins/extras/config.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Callable - -from mkdocs.config import config_options as c -from mkdocs.config.base import Config as BaseConfig - - -class ButtonConfig(BaseConfig): - """The configuration of a button.""" - - enabled = c.Type((bool, Callable), default=True) - """Is the button enabled?""" - - title = c.Type((str, Callable)) - """The button's title.""" - - icon = c.Type((str, Callable)) - """The button's icon (typically, an SVG element).""" - - attributes = c.Type((dict, Callable), default={}) - """Some extra attributes to add to the button.""" - - -class Config(BaseConfig): - """The plugin's configuration.""" - - enabled = c.Type(bool, default=True) - """Is the plugin enabled?""" - - buttons = c.ListOfItems(c.SubConfig(ButtonConfig)) - """The buttons to add.""" diff --git a/mkdocs_exporter/plugins/extras/plugin.py b/mkdocs_exporter/plugins/extras/plugin.py deleted file mode 100644 index 1518a15..0000000 --- a/mkdocs_exporter/plugins/extras/plugin.py +++ /dev/null @@ -1,47 +0,0 @@ -from typing import Optional -from collections import UserDict - -from mkdocs.plugins import BasePlugin -from mkdocs.plugins import event_priority - -from mkdocs_exporter.page import Page -from mkdocs_exporter.preprocessor import Preprocessor -from mkdocs_exporter.plugins.extras.config import Config - - -class Plugin(BasePlugin[Config]): - """The plugin.""" - - - def on_config(self, *args, **kwargs) -> None: - """Invoked when the configuration has been loaded.""" - - pass - - - @event_priority(-85) - def on_post_page(self, html: str, page: Page, config: dict, **kwargs) -> Optional[str]: - """Invoked after a page has been built.""" - - if not self.config.enabled: - return - - def resolve(object): - if callable(object): - return resolve(object(page, config=config)) - if isinstance(object, list): - return [resolve(v) for v in object] - if isinstance(object, (dict, UserDict)): - return {k: resolve(v) for k, v in object.items()} - - return object - - preprocessor = Preprocessor(theme=page.theme) - - preprocessor.preprocess(html) - - for button in [*self.config.buttons, *page.meta.get('buttons', [])]: - if resolve(button.get('enabled', True)): - preprocessor.button(**resolve(button)) - - return preprocessor.done() diff --git a/mkdocs_exporter/plugins/pdf/__init__.py b/mkdocs_exporter/plugins/pdf/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/mkdocs_exporter/resources/js/pdf.js b/mkdocs_exporter/resources/js/pdf.js index 8c2b629..d13bce6 100644 --- a/mkdocs_exporter/resources/js/pdf.js +++ b/mkdocs_exporter/resources/js/pdf.js @@ -4,7 +4,7 @@ window.PagedConfig = { * The settings. */ settings: { - maxChars: 1e9 + maxChars: 1e32 }, /** diff --git a/mkdocs_exporter/themes/readthedocs/theme.py b/mkdocs_exporter/themes/readthedocs/theme.py index 5eacff4..260b0af 100644 --- a/mkdocs_exporter/themes/readthedocs/theme.py +++ b/mkdocs_exporter/themes/readthedocs/theme.py @@ -29,7 +29,6 @@ def button(self, preprocessor: Preprocessor, title: str, icon: str, attributes: button = preprocessor.html.new_tag('a', title=title, attrs={'class': 'btn btn-neutral float-right', **attributes}) button.string = title - target = preprocessor.html.find('div', {'class': 'document'}) if target: diff --git a/poetry.lock b/poetry.lock index f7f17a7..8f18839 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "babel" @@ -92,13 +92,13 @@ test = ["flake8", "isort", "pytest"] [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.6.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, + {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, ] [[package]] @@ -1596,13 +1596,13 @@ test = ["pytest", "ruff"] [[package]] name = "typing-extensions" -version = "4.12.0" +version = "4.12.1" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, - {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, + {file = "typing_extensions-4.12.1-py3-none-any.whl", hash = "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a"}, + {file = "typing_extensions-4.12.1.tar.gz", hash = "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index 497d414..3c34b76 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "mkdocs-exporter" -version = "5.3.1" +version = "6.0.0" repository = "https://github.com/adrienbrignon/mkdocs-exporter" keywords = ["mkdocs", "pdf", "exporter"] description = "A highly-configurable plugin for MkDocs that exports your pages to PDF files."