diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6e68204..85a74ba 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -32,3 +32,23 @@ updates: applies-to: security-updates patterns: - '*' + # The docs toolchain is a separate install: docs.yml pip-installs + # docs/requirements-docs.txt to run MkDocs. + - package-ecosystem: pip + directory: /docs + schedule: + interval: weekly + day: monday + commit-message: + prefix: docs + labels: + - documentation + - automated + groups: + docs_toolchain: + patterns: + - '*' + docs_security: + applies-to: security-updates + patterns: + - '*' diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..4937e4b --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,96 @@ +name: Docs + +# Copy to .github/workflows/docs.yml. Before the first run, set the repository's +# Pages source to "GitHub Actions": Settings -> Pages -> Source, or +# `gh api -X POST repos/GeiserX//pages -f build_type=workflow` for a repo +# with no Pages yet. For a repo already publishing from a branch the API is a +# PUT, and its docs list `source.branch` and `source.path` as required, so the +# bare `-f build_type=workflow` PUT may 422: try it on CashPilot first and +# record which form worked. A deploy while the source is still a branch is +# expected to fail; that is the test that the switch happened. +# +# Never for a repo whose gh-pages branch holds a Helm chart index (index.yaml, +# artifacthub-repo.yml): Pumperly, LynxPrompt, genieacs-container, +# duplicacy-container. Those use docs-pages-helm.yml instead. +# +# Pull requests that touch the docs run the strict build, so a broken link, a +# missing page or an unreachable page fails the check instead of reaching the +# site. A push to main deploys, and only after the same build has passed. +# +# The site is published as a Pages artifact, never with `mkdocs gh-deploy`: +# no gh-pages branch, no `contents: write`, and one artifact is the whole site. +on: + push: + branches: + - main + paths: + - 'docs/**' + - 'mkdocs.yml' + - '.github/workflows/docs.yml' + # Add every file a page includes with pymdownx.snippets (for example + # docker-compose.yml, .env.example): a change to it must rebuild the + # site, and a rename must fail the build. + # No paths filter on pull requests, on purpose: a check skipped by a path + # filter stays Pending and blocks the merge once it is a required check + # (repos.md step 5 makes green checks required). The build takes seconds. + pull_request: + workflow_dispatch: + +# One run at a time per ref, in push order, never cancelled. Locking only the +# deploy job is not enough: an older push whose build finishes later would +# deploy last and publish a stale site. Pull requests get their own group. +concurrency: + group: pages-${{ github.ref }} + cancel-in-progress: false + +permissions: + contents: read + +jobs: + build: + name: build (strict) + # Public repo: GitHub-hosted runners are free and unlimited here, and the + # job runs on pull requests, so it must never touch a self-hosted runner. + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # This job never pushes; a persisted token is readable by pip and every MkDocs plugin. + persist-credentials: false + + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: '3.13' + cache: pip + cache-dependency-path: docs/requirements-docs.txt + + - name: Install dependencies + run: pip install -r docs/requirements-docs.txt + + # mkdocs.yml sets `strict: true`; the flag here keeps the build strict + # even if someone removes that line. + - name: Build + run: mkdocs build --strict + + - name: Upload the site + if: github.event_name != 'pull_request' + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 + with: + path: site + + deploy: + # Runs on push to main only, after the build job has passed. + if: github.event_name != 'pull_request' + needs: build + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 + + - id: deployment + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 diff --git a/.gitignore b/.gitignore index 995d54b..a2a43c7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ files/ output/ *.epub .DS_Store + +# MkDocs build output +site/ diff --git a/README.md b/README.md index c8f9d7c..ffa58ff 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ ePubLangMerger is an R/Shiny web application that merges two ePub files of the s - Pairs the `

` and `

` to `

` elements of both ePubs and interleaves them as XML siblings. - Names the merged file from the input filenames and their language codes. -- Serves a pair it has already merged from its cache, without merging it again. +- Within one browser session, hands back the cached book for any pair that gives the same output name, without a new merge. - Web UI: upload two ePub files, click "Go!" and download the result. - Command-line mode: `script.R` does the same merge without the UI, for scripts and batch runs. - Adds a `_2` suffix to every `id` attribute from the second ePub, so XHTML IDs never collide. @@ -36,14 +36,17 @@ curl -fsSLO https://raw.githubusercontent.com/GeiserX/ePubLangMerger/main/docker docker compose up -d ``` -Open http://localhost:3838. Manual install without Docker: [getting started](https://github.com/GeiserX/ePubLangMerger/blob/main/docs/getting-started.md). +Open http://localhost:3838. Manual install without Docker: [getting started](https://geiserx.github.io/ePubLangMerger/getting-started/#manual-installation-without-docker). ## Documentation -- [Getting started](https://github.com/GeiserX/ePubLangMerger/blob/main/docs/getting-started.md): prerequisites, Docker and manual install, first run. -- [Usage](https://github.com/GeiserX/ePubLangMerger/blob/main/docs/usage.md): the web UI, the command line and the filename convention. -- [How it works](https://github.com/GeiserX/ePubLangMerger/blob/main/docs/how-it-works.md): extract, parse, merge, reassemble. -- [Troubleshooting](https://github.com/GeiserX/ePubLangMerger/blob/main/docs/troubleshooting.md): the limits of the merge and what they look like. +The docs are at [geiserx.github.io/ePubLangMerger](https://geiserx.github.io/ePubLangMerger/). + +- [Getting started](https://geiserx.github.io/ePubLangMerger/getting-started/): prerequisites, Docker and manual install, first run. +- [Usage](https://geiserx.github.io/ePubLangMerger/usage/): the web UI, the command line and the filename convention. +- [How it works](https://geiserx.github.io/ePubLangMerger/how-it-works/): extract, parse, merge, reassemble. +- [Troubleshooting](https://geiserx.github.io/ePubLangMerger/troubleshooting/): the limits of the merge and what they look like. +- [Development](https://geiserx.github.io/ePubLangMerger/development/): tests, the image build and releases. Contributions: see [CONTRIBUTING.md](https://github.com/GeiserX/ePubLangMerger/blob/main/CONTRIBUTING.md). diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..534affb --- /dev/null +++ b/docs/development.md @@ -0,0 +1,47 @@ +# Development + +## Run from a checkout + +Clone the repository and install the R packages as in [Getting started](getting-started.md#manual-installation-without-docker), then start the app from the repository root: + +```r +shiny::runApp(".", port = 8080) +``` + +The code is four files: `ui.R` (the page), `server.R` (upload, merge and download), `utils.R` (`makeSibling` and `deriveOutputName`, shared by the app and the script) and `script.R` (the [command line](usage.md#command-line-batch)). + +## Test + +```bash +Rscript -e 'install.packages(c("testthat", "XML"), repos = "https://cloud.r-project.org/")' +Rscript -e 'testthat::test_dir("tests/testthat")' +``` + +The tests cover `deriveOutputName` and `makeSibling` in `utils.R`. Two `makeSibling` tests call `skip_on_ci()`: the XML package's in-place node edits crash with `free(): invalid pointer` on the CI runners, so those two run only on your machine. + +## Build the image + +```bash +docker build -t epublangmerger . +``` + +The image is `rocker/shiny:4.6` with the R packages installed and `server.R`, `ui.R`, `utils.R` and `www/` copied in, built for `linux/amd64` only. `script.R` and `docs/` are not in it. + +Every pull request runs `test` and `docker-build` from `ci.yml`, and the strict docs build from `docs.yml`. + +## Release + +1. Change the image tag in `docker-compose.yml` and in [Getting started](getting-started.md#docker) to the new version, and merge. +2. Push a tag `vX.Y.Z` on `main`. Never move an existing tag. +3. The Release workflow creates the GitHub release with generated notes, pushes `drumsergio/epublangmerger:X.Y.Z` and `latest` to Docker Hub for `linux/amd64`, and copies `README.md` to the Docker Hub description. + +## Docs + +The site is built by MkDocs Material from `docs/` and `mkdocs.yml`: + +```bash +pip install -r docs/requirements-docs.txt +mkdocs build --strict +``` + +The same strict build runs on every pull request, and a push to `main` that changes the docs deploys the site. How to send a change: [CONTRIBUTING.md](https://github.com/GeiserX/ePubLangMerger/blob/main/CONTRIBUTING.md). diff --git a/docs/images/icon.svg b/docs/images/icon.svg new file mode 100644 index 0000000..80cd2a6 --- /dev/null +++ b/docs/images/icon.svg @@ -0,0 +1 @@ +ePubLangMerger diff --git a/docs/images/logo.svg b/docs/images/logo.svg new file mode 100644 index 0000000..87f83d9 --- /dev/null +++ b/docs/images/logo.svg @@ -0,0 +1 @@ +ePubLangMerger diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..11ae167 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,88 @@ +--- +hide: + - navigation +--- + +# ePubLangMerger { .elm-visually-hidden } + +

+ ePubLangMerger: two languages, one book, side by side +

+ +

+ Docker Pulls + GitHub Stars + Release + License: GPL-3.0-or-later +

+ +--- + +**ePubLangMerger** takes two ePub files of the same book in two languages and makes one ePub in which every paragraph and heading of the second language comes right after the matching one in the first. Reading a translation next to the original otherwise means two books open at once and finding your place twice on every page, and bilingual editions exist for few books. It is a small web page that runs in Docker, plus a script for batch runs. Start with [Getting started](getting-started.md), then [Usage](usage.md). + +
+ +- :material-docker: **[Getting started](getting-started.md)** + + --- + + Start the container with the shipped compose file, or run the app from R without Docker. + +- :material-book-open-page-variant-outline: **[Usage](usage.md)** + + --- + + Upload the two ePubs, the language you want first as the first file, click Go! and download the merged book. + +- :material-console: **[Command line](usage.md#command-line-batch)** + + --- + + `script.R` merges a pair without the web page, for scripts and many books in a row. + +- :material-alert-circle-outline: **[Troubleshooting](troubleshooting.md)** + + --- + + Why pairs drift apart, what is not merged, and what to put in a bug report. + +
+ +## What it does + +- Puts each `

` and `

` to `

` of the second language right after the element in the same position in the first language, chapter by chapter. +- Keeps the rest of the first ePub as it is: its images, styles, table of contents and metadata. +- Adds `_2` to every `id` it copies from the second ePub, so the copies do not repeat the ids of the first language. +- Names the result from the two file names: `MyBook_EN.epub` and `MyBook_ES.epub` give `MyBook_EN_ES.epub`. See [the filename convention](usage.md#filename-convention). +- Merging the same pair again in the same browser session returns the first result without redoing the work. + +## How it runs + +- One container, `drumsergio/epublangmerger`, pinned to a release tag in the shipped `docker-compose.yml`, built for `linux/amd64` only. It serves the page on port 3838 with Shiny Server. +- Without Docker: R 4.x with the `shiny`, `XML`, `stringr` and `Rcompression` packages, on the port you choose. See [Getting started](getting-started.md#manual-installation-without-docker). +- A merge unpacks both books, edits the chapter files of the first and zips the result. [How it works](how-it-works.md) has the four steps. + +## What it does not do + +- It does not match paragraphs by meaning. It pairs them by position, so two editions that split paragraphs differently drift apart. See [Troubleshooting](troubleshooting.md). +- Text outside `

` and `

` to `

` elements, such as list items and table cells, stays in the first language only. +- It reads chapters only from the `OEBPS/` folder, and only files whose names end in `.xhtml`. +- It does not change the book's title or language in its metadata: a reader shows those of the first ePub. +- It accepts files of up to 50 MB each, and it has no login: anyone who can reach port 3838 can use it. + +## Privacy + +- The books stay on the machine that runs the app. It makes no network requests of its own. +- The unpacked books and the merged file sit in a temporary folder for your browser session and are deleted when the session ends. + +## Getting help + +- Something broken: read [Troubleshooting](troubleshooting.md), then open an [issue](https://github.com/GeiserX/ePubLangMerger/issues) with the details it lists. +- A security problem: follow the [security policy](https://github.com/GeiserX/ePubLangMerger/blob/main/SECURITY.md), never a public issue. +- What changed between versions: the [releases on GitHub](https://github.com/GeiserX/ePubLangMerger/releases). +- Running the tests, building the image and releasing: [Development](development.md). +- Other ePub tools: [AskePub](https://github.com/GeiserX/AskePub), a Telegram bot that annotates ePubs with GPT-4, and [epub-and-vtt-to-llm](https://github.com/GeiserX/epub-and-vtt-to-llm), which fine-tunes LLMs on ePub and subtitle text. + +## License + +ePubLangMerger is released under the [GPL-3.0-or-later](https://github.com/GeiserX/ePubLangMerger/blob/main/LICENSE) license. It is built on [Shiny](https://shiny.posit.co/) and the [XML](https://cran.r-project.org/package=XML) package. diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt new file mode 100644 index 0000000..d3504c7 --- /dev/null +++ b/docs/requirements-docs.txt @@ -0,0 +1 @@ +mkdocs-material==9.7.7 diff --git a/docs/stylesheets/theme.css b/docs/stylesheets/theme.css new file mode 100644 index 0000000..aa78d27 --- /dev/null +++ b/docs/stylesheets/theme.css @@ -0,0 +1,150 @@ +/* docs/stylesheets/theme.css: the site takes its colours from the banner. + * + * banner.svg weaves coral strips (#ff7a59, shaded to #b8472f) through cyan + * strips (#4cc9f0, shaded to #2a86a8), one colour per language, and sets the + * name in white serif on a #15131f plate. The header and the dark page use + * the plate; links are cyan and turn coral on hover. mkdocs.yml sets + * `primary: custom` and `accent: custom`, so Material paints nothing until + * these variables exist. + */ +:root { + --md-primary-fg-color: #15131f; /* banner plate */ + --md-primary-fg-color--light: #1e1b2b; + --md-primary-fg-color--dark: #0f0d17; /* the gaps in the weave */ + --md-primary-bg-color: #ffffff; /* banner wordmark */ + --md-primary-bg-color--light: #b9b3c9; /* banner tagline */ + + --md-accent-fg-color: #ff7a59; /* coral strip */ + --md-accent-fg-color--transparent: #ff7a591a; +} + +/* Dark scheme: the page body uses the plate colour too, so the header and + the page read as one surface. #4cc9f0 on #15131f is 9.5:1, #ff7a59 7.2:1. */ +[data-md-color-scheme="slate"] { + --md-default-bg-color: #15131f; + --md-code-bg-color: #1e1b2b; + --md-typeset-a-color: #4cc9f0; +} + +/* Light scheme: #4cc9f0 on white is 1.9:1 and #ff7a59 2.6:1, too faint. + #1f7390 is the cyan at 5.4:1 and #b8472f, the banner's own coral shade, + is 5.3:1. */ +[data-md-color-scheme="default"] { + --md-typeset-a-color: #1f7390; + --md-accent-fg-color: #b8472f; + --md-accent-fg-color--transparent: #b8472f1a; +} + +/* Fixed logo size so it does not crowd the site name. */ +.md-header__button.md-logo img, +.md-header__button.md-logo svg { + height: 1.6rem; + width: 1.6rem; +} + +/* The site name, set the way banner.svg sets the wordmark: a bold serif. + * The banner draws it in a Palatino-style face as outlines; the header uses + * the closest installed serif, no web font. + * + * Only the first topic is styled. Material puts the site name in one + * .md-header__topic and the page title in a second one, and swaps them on + * scroll. Styling both would change every page title too. */ +.md-header__topic:first-child .md-ellipsis { + color: #ffffff; + font-family: "Palatino Linotype", Palatino, "Book Antiqua", "URW Palladio L", P052, Georgia, serif; + font-weight: 700; + letter-spacing: 0; +} + +/* Keep the mark and the name close, so they read as one unit. */ +.md-header__button.md-logo { + padding-right: 0.2rem; +} + +.md-header__title { + margin-left: 0.2rem; +} + +/* Buttons. + * + * Material paints .md-button in --md-primary-fg-color, the header colour. On + * the dark page that is also the page background, so a button would show as + * plain text. Outline buttons take the link colour instead. */ +.md-typeset .md-button { + color: var(--md-typeset-a-color); + border-color: var(--md-typeset-a-color); + border-radius: 0.5rem; +} + +.md-typeset .md-button:focus, +.md-typeset .md-button:hover { + background-color: var(--md-typeset-a-color); + border-color: var(--md-typeset-a-color); + color: #15131f; +} + +[data-md-color-scheme="default"] .md-typeset .md-button:focus, +[data-md-color-scheme="default"] .md-typeset .md-button:hover { + color: #ffffff; +} + +.md-typeset .md-button--primary, +.md-typeset .md-button--primary:focus, +.md-typeset .md-button--primary:hover { + /* White on #1f7390 is 5.4:1. */ + background: #1f7390; + border-color: transparent; + color: #ffffff; +} + +/* Grid cards: the border picks up the coral on hover, the second strip of + the weave next to the cyan links. */ +.md-typeset .grid.cards > ul > li, +.md-typeset .grid > .card { + border-radius: 0.5rem; +} + +.md-typeset .grid.cards > ul > li:focus-within, +.md-typeset .grid.cards > ul > li:hover, +.md-typeset .grid > .card:focus-within, +.md-typeset .grid > .card:hover { + border-color: var(--md-accent-fg-color); +} + +/* The home page keeps an H1 for search, screen readers and the browser tab. + The banner under it already shows the name, so the H1 is hidden visually. + Use it as: # ePubLangMerger { .elm-visually-hidden } */ +.md-typeset h1.elm-visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0 0 0 0); + white-space: nowrap; + border: 0; +} + +/* Phone-sized screenshots on the home page (the merged book, one per + language order): side by side on a wide screen, each with a caption. */ +.md-typeset .elm-phone-gallery { + display: grid; + grid-template-columns: repeat(2, minmax(0, 16rem)); + justify-content: center; + gap: 1.2rem; + margin: 1em 0; +} + +.md-typeset .elm-phone-gallery figure { + margin: 0; +} + +.md-typeset .elm-phone-gallery img { + border-radius: 0.4rem; +} + +.md-typeset .elm-phone-gallery figcaption { + margin-top: 0.3rem; + font-size: 0.7rem; +} diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 242a699..ee88440 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -12,8 +12,18 @@ ## Quotes, lists or boxes are not merged -- **Cause:** only `

` and `

` through `

` elements are merged. The tool skips other block elements such as `
`, `
` and `
    `. -- **Fix:** none today; those elements appear in the first language only. +- **Cause:** only `

    ` and `

    ` through `

    ` elements are merged, wherever they sit: a `

    ` inside a `

    ` or a `
    ` is merged, but text written straight into a list item (`
  • `), a table cell or a `
    ` without a `

    ` is not. +- **Fix:** none today; that text appears in the first language only. + +## The merged book is the first ePub, unchanged + +- **Cause:** the tool reads only the chapter files inside `OEBPS/` whose names end in `.xhtml`. When the first ePub keeps its chapters anywhere else (`OPS/`, `EPUB/text/`, the top of the archive) or names them `.html`, there is nothing to merge, and the tool zips the first ePub as it was. When the second ePub is the one laid out that way, the merge stops with `Error: subscript out of bounds`. +- **Fix:** none in the tool today. An ePub is a ZIP file: list it (`unzip -l book.epub`) before merging and check that both keep their chapters as `OEBPS/*.xhtml`. + +## A new file gives the same merged book as before + +- **Cause:** within one browser session the tool keeps each merged book under its output name, and hands it back for any later pair that gives the same output name, without a new merge. The output name comes from the first file's name and only the language code of the second (see [Usage](usage.md)), so after merging `MyBook_EN.epub` with `MyBook_ES.epub`, pairing `MyBook_EN.epub` with a different book named `Other_ES.epub` gives the same `MyBook_EN_ES.epub` and the old result. +- **Fix:** reload the page to start a new session. Renaming a file helps only when it changes the output name. ## The reader shows the title or language of the first ePub @@ -22,4 +32,4 @@ ## Reporting a bug -Open an issue at https://github.com/GeiserX/ePubLangMerger/issues with the two input filenames, how you ran the tool (Docker, R or `script.R`), the error message or the R console output, and, if you can share them, the two ePubs. +Open an [issue](https://github.com/GeiserX/ePubLangMerger/issues) with the two input filenames, how you ran the tool (Docker, R or `script.R`), the error message or the R console output, and, if you can share them, the two ePubs. diff --git a/docs/usage.md b/docs/usage.md index e3ba590..cadd072 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -23,6 +23,8 @@ Rscript script.R ./books MyBook_EN.epub MyBook_ES.epub ./output Use it in scripts or to merge many books in a row. +`script.R` is not in the Docker image. Run it from a checkout with the R packages installed, as in [Getting started](getting-started.md#manual-installation-without-docker). + ## Filename convention The tool expects input filenames in the format `Title_LangCode.epub`, for example `MyBook_EN.epub` and `MyBook_ES.epub`. The tool reads the last underscore-separated part of each name as the language code, and the merged file combines both codes: `MyBook_EN_ES.epub`. A name with no underscore gives `_merged.epub`. diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..4a60497 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,143 @@ +site_name: ePubLangMerger +site_url: https://geiserx.github.io/ePubLangMerger/ +site_description: Merge two ePub files of the same book in different languages into one bilingual ebook for parallel reading. +repo_url: https://github.com/GeiserX/ePubLangMerger +repo_name: GeiserX/ePubLangMerger +edit_uri: edit/main/docs/ + +# A warning is a broken link, a missing page or a page nobody can reach. All of +# them fail the build, locally and in CI, so nobody has to remember --strict. +strict: true + +theme: + name: material + language: en + logo: images/logo.svg + favicon: images/icon.svg + # Dark first: the first palette entry is the default, and the banner is dark. + palette: + - scheme: slate + primary: custom + accent: custom + toggle: + icon: material/brightness-4 + name: Switch to light mode + - scheme: default + primary: custom + accent: custom + toggle: + icon: material/brightness-7 + name: Switch to dark mode + features: + - navigation.tabs + - navigation.sections + - navigation.expand + - navigation.top + - content.code.copy + - content.action.edit + - search.highlight + - search.suggest + - toc.follow + icon: + repo: fontawesome/brands/github + +# MkDocs reports most link problems as `info`, which --strict ignores. Every +# line here promotes one of them to a warning so the build fails on it: +# nav.omitted_files a Markdown file under docs/ that is in no nav entry and +# not in exclude_docs (a page nobody can reach, published +# at a public URL anyway); +# nav.not_found a nav entry whose file does not exist; +# links.not_found a relative link to a page or file that does not exist; +# links.anchors a link to a heading that does not exist; +# links.absolute_links a link written as /path/ (breaks under the +# /ePubLangMerger/ prefix of the site); +# links.unrecognized_links a relative link that leaves docs/ (../README.md). +# Repo files are linked by absolute GitHub URL instead. +validation: + nav: + omitted_files: warn + not_found: warn + absolute_links: warn + links: + not_found: warn + anchors: warn + absolute_links: warn + unrecognized_links: warn + +plugins: + - search + # No page has been renamed, so there is nothing to redirect. When one is, + # add `mkdocs-redirects==1.2.2` to docs/requirements-docs.txt and uncomment: + # - redirects: + # redirect_maps: + # old-name.md: new-name.md + +markdown_extensions: + - admonition + - pymdownx.details + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format + - pymdownx.tabbed: + alternate_style: true + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + # base_path includes the repository root, so a page can include a file that + # ships (docker-compose.yml) word for word with `--8<-- "docker-compose.yml"`. + # check_paths makes a missing include fail the build instead of rendering an + # empty block. No page includes a file today; the day one does, add that file + # to the push paths of docs.yml. + - pymdownx.snippets: + base_path: + - . + - docs + check_paths: true + - pymdownx.mark + - attr_list + - md_in_html + # Renders :material-xxx: shortcodes as icons. The grid cards on index.md use + # them; without this they print as literal text. + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + - tables + - toc: + permalink: true + +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/GeiserX/ePubLangMerger + - icon: fontawesome/brands/docker + link: https://hub.docker.com/r/drumsergio/epublangmerger + +extra_css: + - stylesheets/theme.css + +# Files under docs/ that are not pages. MkDocs publishes every Markdown file in +# docs/ whether or not it is in the nav, so anything that is not a page must be +# listed here. A page is a lowercase kebab-case .md file; anything with a +# capital letter (ROADMAP.md, CHANGELOG.md) is a repo-facing note, and design/, +# research/ and notes/ hold material read on GitHub. This repo has no note +# under docs/ today; the block keeps the next one off the site. +exclude_docs: | + [A-Z]*.md + design/ + research/ + notes/ + requirements-docs.txt + +# The nav title must equal the page's H1. +nav: + - Home: index.md + - Get started: + - Getting started: getting-started.md + - Usage: usage.md + - Reference: + - How it works: how-it-works.md + - Troubleshooting: troubleshooting.md + - Development: + - Development: development.md