diff --git a/CHANGELOG.md b/CHANGELOG.md index 48f5bc8..fcabe44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,13 @@ Versionsnummern nach [Semantic Versioning](https://semver.org/lang/de/). - Seitenmarken (`--page-markers`) aus einem Kastentitel stehen jetzt vor dem Kasten statt im fetten Titel, wie bei Überschriften. +### Behoben + +- `pandoc/callouts.lua`: Die Kästen blieben ohne Rahmen, wenn man Pandoc zusätzlich `-H`/`--include-in-header` + übergab, und im EPUB hatten nur die Titelseite, nicht die Kapitel, das Kasten-CSS. Das CSS steht jetzt in + `pandoc/callouts.css`; der Filter setzt es bei HTML an den Anfang des Dokuments und fügt es bei EPUB den + Stylesheets hinzu (zusammen mit Pandocs Standard-CSS bzw. zu eigenen `css:`-Angaben). + ### Dokumentation - `--no-css-emphasis` lässt ``-Markierungen bestehen; diese steuert `--styles`. diff --git a/README.md b/README.md index af4040b..a9853b7 100644 --- a/README.md +++ b/README.md @@ -437,7 +437,8 @@ epub2md/ ├── models.py Dataclasses (Kapitel, Medien, Noten, Metadaten …) └── utils.py Slugs, YAML-Emitter, Pfadhelfer pandoc/ -└── callouts.lua Pandoc-Filter: '> [!TIP]'-Kästen → gerahmte Kästen (HTML/EPUB) bzw. Zitatblock mit Titel +├── callouts.lua Pandoc-Filter: '> [!TIP]'-Kästen → gerahmte Kästen (HTML/EPUB) bzw. Zitatblock mit Titel +└── callouts.css Gestaltung der Kästen (vom Filter eingebunden; muss neben callouts.lua liegen) ``` Statt BeautifulSoup wird direkt lxml verwendet: Es ist für die XHTML-Bäume ausreichend, schneller und diff --git a/pandoc/callouts.css b/pandoc/callouts.css new file mode 100644 index 0000000..479b1f7 --- /dev/null +++ b/pandoc/callouts.css @@ -0,0 +1,8 @@ +/* Info boxes written by epub2md (--boxes callout/html), used by pandoc/callouts.lua. */ +.callout, .box { border: 1px solid #c8ccd2; border-left: 0.35em solid #4a7bd0; border-radius: 0.3em; + background: #f5f8fc; padding: 0.4em 1em; margin: 1em 0; } +.callout > p:first-child { margin-top: 0.4em; } +.callout-tip { border-left-color: #2e9a4f; background: #f3faf5; } +.callout-important { border-left-color: #8250df; background: #f8f5fe; } +.callout-warning { border-left-color: #c58a00; background: #fffaf0; } +.callout-caution { border-left-color: #cf222e; background: #fff5f5; } diff --git a/pandoc/callouts.lua b/pandoc/callouts.lua index 3bd34a5..9fb7ff8 100644 --- a/pandoc/callouts.lua +++ b/pandoc/callouts.lua @@ -11,7 +11,9 @@ epub2md writes boxes as GitHub alerts / Obsidian callouts: Pandoc < 3.1.10 does not know this syntax and prints "[!TIP]" literally. This filter turns such block quotes into real boxes: - * HTML, EPUB:
with a bold label and a small stylesheet + * HTML, EPUB:
with a bold label, styled by callouts.css + (next to this filter; HTML: -]] +-- callouts.css next to this filter is the single source of the box styles. +local function read_file(path) + local fh = io.open(path, "r") + if not fh then + return nil + end + local text = fh:read("a") + fh:close() + return text +end + +local CSS_PATH = (PANDOC_SCRIPT_FILE and PANDOC_SCRIPT_FILE:match("^(.*[/\\])") or "") .. "callouts.css" +local CSS = read_file(CSS_PATH) +if not CSS then + io.stderr:write("callouts.lua: " .. CSS_PATH .. " nicht gefunden – Kästen ohne Rahmen\n") +end + +-- EPUB: a stylesheet in metadata `css` replaces Pandoc's default epub.css, so combine both in a temp file. +local function epub_stylesheet() + local default = "" + local pipe = io.popen("pandoc --print-default-data-file epub.css 2>/dev/null") + if pipe then + default = pipe:read("a") or "" + pipe:close() + end + local path = os.tmpname() -- small temp file; Pandoc reads it after the filter has finished + local fh = io.open(path, "w") + if not fh then + return nil + end + fh:write(default, "\n", CSS) + fh:close() + return path +end local lang = "de" @@ -79,15 +104,23 @@ local function Meta(meta) lang = l end end - if is_html() then - local includes = meta["header-includes"] - if includes == nil then - includes = pandoc.MetaList({}) - elseif includes.t ~= "MetaList" then - includes = pandoc.MetaList({ includes }) + if CSS and FORMAT:match("epub") then + local css = meta.css + local path = nil + if css == nil then -- no own stylesheet: default epub.css + ours; otherwise just add ours + path = epub_stylesheet() end - includes:insert(pandoc.MetaBlocks({ pandoc.RawBlock("html", CSS) })) - meta["header-includes"] = includes + if css == nil then + css = pandoc.List({}) + elseif pandoc.utils.type(css) ~= "List" then + css = pandoc.List({ css }) + end + if path then + css:insert(pandoc.MetaString(path)) + else + css:insert(pandoc.MetaString(CSS_PATH)) + end + meta.css = css end return meta end @@ -126,7 +159,16 @@ local function Div(div) return pandoc.BlockQuote(div.content) end +-- HTML: the stylesheet goes into the body, because a command-line -H replaces header-includes from a filter. +local function Pandoc(doc) + if CSS and FORMAT:match("html") and not FORMAT:match("epub") then + doc.blocks:insert(1, pandoc.RawBlock("html", "")) + end + return doc +end + return { { Meta = Meta }, { BlockQuote = BlockQuote, Div = Div }, + { Pandoc = Pandoc }, }