Support custom corpus documentation templates
Mount a "custom" directory into the kalamar container, so users can
describe their own corpus in the KorAP user interface: Kalamar serves a
documentation page from there whenever it does not ship one itself, so a
doc/corpus.html.ep becomes the corpus page. Ship examples for that page,
for an optional references page, and for the corpus part of the
references page.
The directory defaults to ./custom and can be relocated with
KALAMAR_TEMPLATES.
Also allow overriding the kalamar image via KALAMAR_IMAGE, which is
needed to try this out on a Kalamar built from an unreleased version.
The references page needs the citation partial of Kalamar 0.66 or later.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Change-Id: I8d964c996c15aa1d4ea85f18be223d737ed6d528
diff --git a/custom/.gitignore b/custom/.gitignore
new file mode 100644
index 0000000..01e9755
--- /dev/null
+++ b/custom/.gitignore
@@ -0,0 +1,5 @@
+# Only the examples are part of the repository; the templates you derive from
+# them are yours and stay untracked.
+*.html.ep
+*.html.md
+!*.example
diff --git a/custom/README.md b/custom/README.md
new file mode 100644
index 0000000..e46af40
--- /dev/null
+++ b/custom/README.md
@@ -0,0 +1,39 @@
+# Custom Kalamar templates
+
+This directory is mounted into the Kalamar container at
+`/kalamar/templates/custom`. Kalamar renders a documentation page from here
+whenever it does not ship one of its own -- so a `doc/corpus.html.ep` becomes
+the corpus page -- and templates here can be referred to explicitly as
+`custom/...`. No configuration, no rebuilt image.
+
+To describe your own corpus, copy an example, drop the `.example` suffix and
+edit it:
+
+```bash
+cp custom/doc/corpus.html.ep.example custom/doc/corpus.html.ep
+$EDITOR custom/doc/corpus.html.ep
+docker compose restart kalamar
+```
+
+| file | replaces |
+|------|----------|
+| `doc/corpus.html.ep` | the corpus page, served at `/doc/corpus` |
+| `doc/citation.html.ep` | adds a references page at `/doc/citation` |
+| `partial/citation/corpus.html.ep` | the corpus part of the references page, passed to it as `corpus_citation` |
+
+The references page assembles three sections: your corpus references plus the
+shipped KorAP and annotation-tool references, which you normally keep as they
+are.
+
+Templates are [Mojolicious templates][mojo-templates]: mostly HTML, with
+`<%= ... %>` for embedded Perl. Files ending in `.html.md` are rendered as
+Markdown instead, which is handy for longer prose.
+
+For a translated page, put a copy under a language directory, e.g.
+`de/doc/corpus.html.ep` for German; visitors get it based on their browser
+language, with the unprefixed file as the default.
+
+Files that do not correspond to a Kalamar template -- such as the `.example`
+files here -- are simply ignored.
+
+[mojo-templates]: https://docs.mojolicious.org/Mojolicious/Guides/Rendering#Embedded-Perl
diff --git a/custom/doc/citation.html.ep.example b/custom/doc/citation.html.ep.example
new file mode 100644
index 0000000..1b8b3fb
--- /dev/null
+++ b/custom/doc/citation.html.ep.example
@@ -0,0 +1,15 @@
+%# Adds a references page at /doc/citation. Copy this file to
+%# doc/citation.html.ep (without the .example suffix).
+%#
+%# The page is assembled from three parts: the references for your corpus,
+%# plus the KorAP and annotation-tool references that Kalamar ships and you
+%# normally keep unchanged. Pass your own corpus references as shown below;
+%# see partial/citation/corpus.html.ep.example.
+%#
+%# Kalamar's documentation menu has no entry for this page, so link it from
+%# your corpus page (see doc/corpus.html.ep.example).
+% layout 'main', title => 'KorAP: ' . loc('Nav_citation', 'References');
+
+%= page_title
+
+%= include 'partial/citation', corpus_citation => 'custom/partial/citation/corpus'
diff --git a/custom/doc/corpus.html.ep.example b/custom/doc/corpus.html.ep.example
new file mode 100644
index 0000000..379ccf6
--- /dev/null
+++ b/custom/doc/corpus.html.ep.example
@@ -0,0 +1,18 @@
+%# Describes the corpus this KorAP instance serves. Copy this file to
+%# doc/corpus.html.ep (without the .example suffix) and edit it; it then
+%# replaces Kalamar's placeholder page behind the "Corpus" menu entry.
+%# Lines starting with %# are comments and never appear in the page.
+% layout 'main', title => 'KorAP: ' . loc('Nav_corpus');
+
+%= page_title
+
+<section>
+ <p>
+ This KorAP instance serves the <strong>Example Corpus</strong>, a
+ collection of ... texts with ... million tokens, compiled by ... .
+ </p>
+ <p>
+ The texts are annotated with ... . Please refer to the
+ <a href="citation">references</a> when citing the corpus.
+ </p>
+</section>
diff --git a/custom/partial/citation/corpus.html.ep.example b/custom/partial/citation/corpus.html.ep.example
new file mode 100644
index 0000000..3505983
--- /dev/null
+++ b/custom/partial/citation/corpus.html.ep.example
@@ -0,0 +1,14 @@
+%# References for your own corpus. Copy this file to
+%# partial/citation/corpus.html.ep (without the .example suffix) and refer to
+%# it from your references page as
+%# %= include 'partial/citation', corpus_citation => 'custom/partial/citation/corpus'
+%#
+%# The <span class="Z3988"> below is optional: it carries the reference as
+%# COinS metadata, which lets reference managers such as Zotero import the
+%# entry with one click. Leave it out if you do not need that.
+<section>
+ <h4><%= loc 'corpusPub' %></h4>
+
+ <p class="bibentry">Doe, Jane/Roe, Richard (2026): <cite><a class="extern" href="https://example.org/corpus">The Example Corpus</a></cite>.<br />Example Town: Example Institute. <a class="extern" href="https://doi.org/10.0000/example">https://doi.org/10.0000/example</a>.
+ </p>
+</section>