pandoc-para 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. pandoc_para-0.2.0/.gitignore +33 -0
  2. pandoc_para-0.2.0/AUTHORS.rst +5 -0
  3. pandoc_para-0.2.0/CHANGELOG.md +48 -0
  4. pandoc_para-0.2.0/LICENSE +29 -0
  5. pandoc_para-0.2.0/PKG-INFO +69 -0
  6. pandoc_para-0.2.0/README.md +27 -0
  7. pandoc_para-0.2.0/docs/makefile +15 -0
  8. pandoc_para-0.2.0/docs/pages/builds.md +89 -0
  9. pandoc_para-0.2.0/docs/pages/configuration.md +57 -0
  10. pandoc_para-0.2.0/docs/pages/filters.md +67 -0
  11. pandoc_para-0.2.0/docs/pages/front-matter.md +38 -0
  12. pandoc_para-0.2.0/docs/pages/index.md +63 -0
  13. pandoc_para-0.2.0/docs/pages/install.md +46 -0
  14. pandoc_para-0.2.0/docs/pages/languages.md +54 -0
  15. pandoc_para-0.2.0/docs/pages/migrating.md +42 -0
  16. pandoc_para-0.2.0/docs/pages/profiles.md +90 -0
  17. pandoc_para-0.2.0/docs/pages/reference.md +248 -0
  18. pandoc_para-0.2.0/docs/parasite.toml +50 -0
  19. pandoc_para-0.2.0/pyproject.toml +175 -0
  20. pandoc_para-0.2.0/src/para/__init__.py +1 -0
  21. pandoc_para-0.2.0/src/para/__main__.py +3 -0
  22. pandoc_para-0.2.0/src/para/apps.py +315 -0
  23. pandoc_para-0.2.0/src/para/check.py +52 -0
  24. pandoc_para-0.2.0/src/para/config.py +411 -0
  25. pandoc_para-0.2.0/src/para/data.py +438 -0
  26. pandoc_para-0.2.0/src/para/defaults.toml +237 -0
  27. pandoc_para-0.2.0/src/para/deps.py +121 -0
  28. pandoc_para-0.2.0/src/para/filters.py +184 -0
  29. pandoc_para-0.2.0/src/para/graph.py +116 -0
  30. pandoc_para-0.2.0/src/para/helpers.py +198 -0
  31. pandoc_para-0.2.0/src/para/lang.py +115 -0
  32. pandoc_para-0.2.0/src/para/live.py +343 -0
  33. pandoc_para-0.2.0/src/para/media.py +251 -0
  34. pandoc_para-0.2.0/src/para/output.py +125 -0
  35. pandoc_para-0.2.0/src/para/panflute_filters.py +266 -0
  36. pandoc_para-0.2.0/src/para/record.py +191 -0
  37. pandoc_para-0.2.0/src/para/search.py +201 -0
  38. pandoc_para-0.2.0/src/para/settings.py +89 -0
  39. pandoc_para-0.2.0/src/para/site.py +700 -0
  40. pandoc_para-0.2.0/src/para/store.py +175 -0
  41. pandoc_para-0.2.0/src/para/templates/README.md +6 -0
  42. pandoc_para-0.2.0/src/para/templates/__init__.py +14 -0
  43. pandoc_para-0.2.0/src/para/templates/index.html +189 -0
  44. pandoc_para-0.2.0/src/para/templates/post.html +193 -0
  45. pandoc_para-0.2.0/src/para/templates/slidy.html +82 -0
  46. pandoc_para-0.2.0/src/para/theme/README.md +10 -0
  47. pandoc_para-0.2.0/src/para/theme/_css/bootblog.css +225 -0
  48. pandoc_para-0.2.0/src/para/theme/_css/bootstrap.css +10517 -0
  49. pandoc_para-0.2.0/src/para/theme/_css/code.css +85 -0
  50. pandoc_para-0.2.0/src/para/theme/_css/custom.css +183 -0
  51. pandoc_para-0.2.0/src/para/theme/_css/nikola_rst.css +79 -0
  52. pandoc_para-0.2.0/src/para/theme/_css/rst_base.css +474 -0
  53. pandoc_para-0.2.0/src/para/theme/_css/theme.css +237 -0
  54. pandoc_para-0.2.0/src/para/to_ast.py +216 -0
  55. pandoc_para-0.2.0/src/para/translate.py +31 -0
  56. pandoc_para-0.2.0/src/para/util.py +65 -0
  57. pandoc_para-0.2.0/tests/conftest.py +20 -0
  58. pandoc_para-0.2.0/tests/test_apps.py +103 -0
  59. pandoc_para-0.2.0/tests/test_check.py +21 -0
  60. pandoc_para-0.2.0/tests/test_data.py +95 -0
  61. pandoc_para-0.2.0/tests/test_deps.py +41 -0
  62. pandoc_para-0.2.0/tests/test_filters.py +75 -0
  63. pandoc_para-0.2.0/tests/test_front_matter.py +65 -0
  64. pandoc_para-0.2.0/tests/test_graph.py +45 -0
  65. pandoc_para-0.2.0/tests/test_lang.py +31 -0
  66. pandoc_para-0.2.0/tests/test_pdf.py +46 -0
  67. pandoc_para-0.2.0/tests/test_search.py +50 -0
  68. pandoc_para-0.2.0/tests/test_settings.py +69 -0
  69. pandoc_para-0.2.0/tests/test_store.py +50 -0
  70. pandoc_para-0.2.0/tests/test_translations.py +60 -0
@@ -0,0 +1,33 @@
1
+ # Python
2
+ *.py[cod]
3
+ __pycache__/
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+
8
+ # environments
9
+ .pixi/
10
+ .venv/
11
+ venv*/
12
+ .env
13
+
14
+ # tools' caches
15
+ .pytest_cache/
16
+ .ruff_cache/
17
+ .mypy_cache/
18
+ .dmypy.json
19
+ .coverage
20
+ .coverage.*
21
+ coverage.xml
22
+ htmlcov/
23
+ .benchmarks/
24
+
25
+ # editors and OS
26
+ .idea/
27
+ .vscode/
28
+ .DS_Store
29
+ *~
30
+ .*.sw[po]
31
+ *.bak
32
+
33
+ # the docs' build (docs/output/, docs/.para/) is ignored by docs/.gitignore
@@ -0,0 +1,5 @@
1
+
2
+ Authors
3
+ =======
4
+
5
+ * Kolen Cheung - https://github.com/ickc
@@ -0,0 +1,48 @@
1
+ # Revision history for `para`
2
+
3
+ ## v0.2.0
4
+
5
+ A rewrite around records, output profiles and incremental builds. The package is
6
+ `para` (on PyPI as `pandoc-para`), the site generator `para.site` (`from para.site
7
+ import Config, cli`); the command is `parasite`.
8
+
9
+ - **Configuration:** a site is configured by `parasite.toml`, merged over
10
+ `para/defaults.toml`, which documents every key. A site's `run.py` is no longer
11
+ needed (see the docs' migration page).
12
+ - **Pipeline:** sources are read into records (URL, title, dates, category, tags,
13
+ description, search text, links, citations, outputs, media). Listings, feeds, the
14
+ sitemap, search and the post graph come from records, and every file goes through one
15
+ output tree. That tree refuses two producers of one path, writes only changed bytes,
16
+ and reports or prunes (`--prune`) what the build no longer produces.
17
+ - **Incremental builds:** a record store (`.para/store.sqlite`). A source is read again
18
+ only when its bytes, the site's code, pandoc, config, or a file its read touched
19
+ changed; `--full` ignores the store.
20
+ - **Output profiles:** a source has an output per profile (`format: [html, slides]`).
21
+ Content for some outputs uses Quarto's `.content-visible`/`.content-hidden`, and an
22
+ output can have its own metadata (`format: NAME: metadata:`) and pandoc variables.
23
+ Also `output-file`, and `format-links` with a profile's `label`.
24
+ - **PDF output:** a `pdf` profile, Typst by default, dated by the page, so a PDF is the
25
+ same from build to build.
26
+ - **Languages:** BCP 47 tags, with lookups from the most specific to the least.
27
+ Translations: `x.LANG.md` beside `x.md`, or made by OpenCC
28
+ (`pandoc-para[opencc]`), linked with `hreflang`.
29
+ - **Filters by name:** Python (`module:function`) or installed Lua filters, chosen per
30
+ document with `filters: [name, -name]`.
31
+ - **Media:** copied by reference (`[media.folders]`): only what pages use. After the
32
+ build, lychee checks every link offline, and the build fails on broken ones.
33
+ - **Search:** Pagefind (`pandoc-para[search]`), indexing the records in the site's
34
+ language, with tags and categories as filters, deterministic from build to build.
35
+ - **Post graph:** `graph.json`, a local graph on each page, and `/graph/` (needs
36
+ `pandoc-para[graph]`, paragraphic ≥ 0.2).
37
+ - **Listings:** `description` instead of teasers, falling back to `subtitle`. The front
38
+ page shows the newest posts, with an archive by year. Categories form a tree, and
39
+ feeds carry the newest posts. Copyright years come from the pages' own dates.
40
+ - **Removed:** parsl (now a thread pool, `--jobs`), urlpath, tipuesearch,
41
+ previous/next links, and the retired front-matter keys (`status`, `previewimage`,
42
+ `slug`, …; para.site warns).
43
+ - **Output:** well-formed XHTML; pandoc ≥ 3.11's `--math-method`.
44
+ - **Requirements:** Python ≥ 3.12 and pandoc ≥ 3.1.
45
+
46
+ ## v0.1.0
47
+
48
+ First release and proof of concept.
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2021, Kolen Cheung
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,69 @@
1
+ Metadata-Version: 2.5
2
+ Name: pandoc-para
3
+ Version: 0.2.0
4
+ Summary: para.site: a pandoc-first static site generator
5
+ Project-URL: Homepage, https://github.com/ickc/parasite
6
+ Project-URL: Repository, https://github.com/ickc/parasite
7
+ Author-email: Kolen Cheung <christian.kolen@gmail.com>
8
+ License-Expression: BSD-3-Clause
9
+ License-File: AUTHORS.rst
10
+ License-File: LICENSE
11
+ Keywords: pandoc,static site generator
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Programming Language :: Python :: Implementation :: CPython
21
+ Classifier: Topic :: Software Development :: Build Tools
22
+ Requires-Python: >=3.12
23
+ Requires-Dist: custom-inherit>=2.4
24
+ Requires-Dist: defopt>=7
25
+ Requires-Dist: feedgen>=1
26
+ Requires-Dist: panflute<2.4,>=2.3.1
27
+ Provides-Extra: extras
28
+ Requires-Dist: coloredlogs>=14; extra == 'extras'
29
+ Requires-Dist: livereload>=2; extra == 'extras'
30
+ Requires-Dist: watchdog>=2; extra == 'extras'
31
+ Provides-Extra: graph
32
+ Requires-Dist: paragraphic<0.3,>=0.2; extra == 'graph'
33
+ Provides-Extra: opencc
34
+ Requires-Dist: opencc>=1.1; extra == 'opencc'
35
+ Provides-Extra: search
36
+ Requires-Dist: pagefind[bin]>=1.5; extra == 'search'
37
+ Provides-Extra: tests
38
+ Requires-Dist: coverage; extra == 'tests'
39
+ Requires-Dist: pytest; extra == 'tests'
40
+ Requires-Dist: pytest-cov; extra == 'tests'
41
+ Description-Content-Type: text/markdown
42
+
43
+ # para.site
44
+
45
+ A pandoc-first static site generator: websites from documents pandoc can read, with
46
+ listings, categories and tags, feeds, a sitemap, search, a graph of how the pages link,
47
+ and builds that redo only what changed. A site is configured by one file,
48
+ `parasite.toml`.
49
+
50
+ The Python package is `para` (on PyPI as `pandoc-para` for now: `pip install
51
+ pandoc-para`), the site generator its module `para.site`, and the command `parasite`:
52
+
53
+ ```python
54
+ from para import site
55
+ ```
56
+
57
+ Documentation: <https://ickc.github.io/parasite/> (its source is `docs/`, built with
58
+ para.site).
59
+
60
+ ## Develop
61
+
62
+ ```sh
63
+ pixi run test
64
+ make docs
65
+ ```
66
+
67
+ ## Licence
68
+
69
+ BSD-3-Clause.
@@ -0,0 +1,27 @@
1
+ # para.site
2
+
3
+ A pandoc-first static site generator: websites from documents pandoc can read, with
4
+ listings, categories and tags, feeds, a sitemap, search, a graph of how the pages link,
5
+ and builds that redo only what changed. A site is configured by one file,
6
+ `parasite.toml`.
7
+
8
+ The Python package is `para` (on PyPI as `pandoc-para` for now: `pip install
9
+ pandoc-para`), the site generator its module `para.site`, and the command `parasite`:
10
+
11
+ ```python
12
+ from para import site
13
+ ```
14
+
15
+ Documentation: <https://ickc.github.io/parasite/> (its source is `docs/`, built with
16
+ para.site).
17
+
18
+ ## Develop
19
+
20
+ ```sh
21
+ pixi run test
22
+ make docs
23
+ ```
24
+
25
+ ## Licence
26
+
27
+ BSD-3-Clause.
@@ -0,0 +1,15 @@
1
+ # para.site's documentation, built with para.site (pandoc, and para with its search extra)
2
+
3
+ .PHONY: docs serve clean
4
+ docs: pages/reference.md
5
+ parasite
6
+
7
+ # every key, from para.site's own defaults
8
+ pages/reference.md: ../src/para/defaults.toml
9
+ python -c 'import sys; src = open(sys.argv[1]).read(); open(sys.argv[2], "w").write("---\ntitle: Every key\ndescription: para.site\x27s defaults.toml, which a site\x27s parasite.toml is merged over.\n---\n\n<!-- written by docs/makefile from src/para/defaults.toml: do not edit -->\n\nA site\x27s `parasite.toml` is merged over this file (see [parasite.toml](../configuration/)).\n\n```toml\n" + src + "```\n")' $< $@
10
+
11
+ serve: docs
12
+ python -m http.server --directory output 8000
13
+
14
+ clean:
15
+ rm -rf output .para
@@ -0,0 +1,89 @@
1
+ ---
2
+ title: How it builds
3
+ description: Read, record, derive, render, write; and only what changed.
4
+ ---
5
+
6
+ # The steps
7
+
8
+ 1. **Discover** the sources of each collection.
9
+ 2. **Read** each into a pandoc document, with the read filters.
10
+ 3. **Record** it: a small summary of the page (URL, title, dates, category, tags,
11
+ description, search text, links, citations, its outputs, the media it uses).
12
+ 4. **Derive** what crosses pages from the records alone: listings, categories, tags,
13
+ the archive, feeds, the sitemap, search, the graph, the site's copyright years.
14
+ 5. **Render** each page in each of its profiles, and the derived pages. A page's
15
+ document is dropped once rendered.
16
+ 6. **Write**: every file through one output tree.
17
+
18
+ Pages are read and rendered in a thread pool: most of the work is pandoc, in its own
19
+ processes.
20
+
21
+ # Only what changed
22
+
23
+ The records are kept in `.para/store.sqlite` (ignore it in git). A build reads a source
24
+ again only when its **read key** changed, and renders a page again only when its
25
+ **render key** changed or a file it produced is gone:
26
+
27
+ - the **site key**: the code (the Python modules loaded, the installed packages,
28
+ para's own files), pandoc and its data folder, the configuration, and the files
29
+ the configuration names for every page (`[read]`'s `--metadata-file` and the like,
30
+ the profiles' own templates, `pandoc-crossref.yaml`). Any change here reads everything
31
+ again;
32
+ - a **read key**: the site key and the source's bytes. And a record is used only while
33
+ the files its read touched are unchanged: its links' and images' files (or that they
34
+ were missing), the media it references and what those reference, its bibliography and
35
+ style if it cites, a translation's primary, and the files and folders its text names
36
+ (a table's CSV, a gallery's folder). So a bibliography edit reads again the pages that
37
+ cite, and a new photo the page whose gallery has it. A filter that reads a file the
38
+ document does not name can say so with `para.deps.touch(path)`;
39
+ - a **render key**: the read key, the page's copyright years, its link to a report and
40
+ its translations.
41
+
42
+ A derived page is rendered again when its document changed. `parasite --full` ignores
43
+ the store. A rebuild with nothing changed takes about a third of a second for a site of a
44
+ hundred pages.
45
+
46
+ # The output tree
47
+
48
+ Every file has one producer: a page, a derived page, a copied folder, a minified bundle,
49
+ a medium, a site-wide file. Two producers of one path is an error. A file is written
50
+ only when its bytes change, so an unchanged page keeps its modification time. Files in
51
+ the output folder that no step produced (a deleted page's) are reported, and removed
52
+ with `parasite --prune`.
53
+
54
+ # Media
55
+
56
+ `[media.folders]` are copied **by reference**: only the files the pages use, from their
57
+ images and links, raw HTML (`src`, `href`, `data`, `poster`, `url(…)`), their `image`,
58
+ and what those files use in turn (an HTML plot's scripts, an SVG's images, a style
59
+ sheet's). `[files]` are copied whole.
60
+
61
+ Media in a source itself (a notebook's outputs) are written next to the page; a PDF
62
+ image becomes SVG, which a browser can show.
63
+
64
+ # Search
65
+
66
+ With `[search] enabled` and `pandoc-para[search]` installed, para.site indexes the
67
+ records with [Pagefind](https://pagefind.app/) and makes the search page (`[search]
68
+ page`). The index is sharded: one more page changes a few of its files. The search box
69
+ in the navigation sends `?q=` to it. Every page is indexed in the site's language
70
+ (Pagefind searches the index of the search page's language only). Tags and categories
71
+ are its filters, and a page's tags are searched as its words.
72
+
73
+ # Links
74
+
75
+ With [lychee](https://lychee.cli.rs) installed, para.site checks the output's links when
76
+ the build is done, offline: every link and media reference from the site's files to its
77
+ files must resolve, or the build fails (the output is written either way; a build that
78
+ serves or watches only logs them). This guards the media copied by reference: a
79
+ reference para.site did not see would be a broken link here. lychee reads the HTML, raw
80
+ HTML and `<style>` elements included, but not `style` attributes or CSS files.
81
+
82
+ Links known to be broken are excluded by `[check] exclude`, regular expressions of
83
+ URLs (a site's file is a `file://` URL); `[check] links = false` turns the check off.
84
+
85
+ # The post graph
86
+
87
+ With `[graph] enabled` and `pandoc-para[graph]` installed, para.site writes `graph.json`
88
+ from the records (links, citations, external links, a page's other outputs) and the
89
+ `/graph/` page; every page gets a graph of its neighbours.
@@ -0,0 +1,57 @@
1
+ ---
2
+ title: parasite.toml
3
+ description: A site's configuration, as data.
4
+ ---
5
+
6
+ A site is a folder with a `parasite.toml`. `parasite` builds the site in the working
7
+ directory from it.
8
+
9
+ # Merged over the defaults
10
+
11
+ para.site has a `defaults.toml`, which documents every key: see [every key](../reference/).
12
+ A site's `parasite.toml` is merged over it:
13
+
14
+ - tables, key by key: a site writes only what differs;
15
+ - anything else (strings, numbers, lists) replaced whole;
16
+ - `[files]`, `[media.folders]`, `[minify.css]` and `[minify.js]` replaced whole too, as
17
+ they list a site's own entries;
18
+ - `[filters]` in the site's order: its filters first, then the defaults it does not
19
+ mention.
20
+
21
+ # The parts
22
+
23
+ | table | what |
24
+ |---|---|
25
+ | `[site]` | URL, title, description, author, language, time zone, logo, copyright, output folder, drafts |
26
+ | `[listing]` | the front page, categories, tags and the archive, or none |
27
+ | `[feeds]`, `[sitemap]`, `[search]`, `[graph]` | what else is written |
28
+ | `[[sources]]` | collections: folders of sources, their extensions, whether they are listed posts, their output profiles |
29
+ | `[read]`, `[read.EXT]` | pandoc's options for reading, for every source and per input format |
30
+ | `[filters.NAME]` | the filters a site may use (see [filters](../filters/)) |
31
+ | `[profiles.NAME]` | output profiles: writer, template, URL rule, options, filters, the page's parts (see [output profiles](../profiles/)) |
32
+ | `[files]` | folders of site files, copied whole |
33
+ | `[media.folders]` | folders of media, copied by reference: only what pages use |
34
+ | `[minify.css]`, `[minify.js]` | style sheets and scripts bundled and minified |
35
+ | `[mathjax]` | MathJax's configuration, as a table |
36
+
37
+ # In strings
38
+
39
+ `{root}` becomes the relative path from the page to the site's root (`..`, `../..`, or `.`
40
+ at the top), and `{years}` the copyright years (a post's own, from its `date` to its
41
+ `date-modified`; a page without dates has the site's). The footer also has `{author}`
42
+ and `{email}`. No other braces are touched, so scripts need no escaping.
43
+
44
+ # By language
45
+
46
+ A string can instead be a table by language, used for the page's `lang`:
47
+
48
+ ```toml
49
+ [site]
50
+ lang = "zh_tw"
51
+ title = { en = "KcIc", zh_tw = "祺" }
52
+ ```
53
+
54
+ # On the command line
55
+
56
+ The settings that are fields of the build (`parasite --help`) can be overridden there,
57
+ for one build: `parasite --include-draft`, `parasite --full`, `parasite --prune`.
@@ -0,0 +1,67 @@
1
+ ---
2
+ title: Filters
3
+ description: The code a site runs, named in its parasite.toml.
4
+ ---
5
+
6
+ A site lists the filters it may use in `[filters.NAME]`, in the order they run. A filter
7
+ is code from something you installed, never a path in the site: Python, a function
8
+ taking and returning a panflute document named as an importable `module:function`; or
9
+ Lua, by name, found where packages install Lua filters (the environment's
10
+ `share/pandoc/filters/`, as pandoc-forge's packages do) or in pandoc's user data
11
+ directory.
12
+
13
+ ```toml
14
+ [filters.amsthm]
15
+ lua = "amsthm"
16
+ default = true
17
+
18
+ [filters.pannb]
19
+ python = "pannb:main"
20
+ inputs = ["ipynb"]
21
+ default = true
22
+
23
+ [filters.texp]
24
+ python = "texp.panflute_filter:main"
25
+ ```
26
+
27
+ | key | meaning |
28
+ |---|---|
29
+ | `python` | the function, `module:function` |
30
+ | `lua` | the Lua filter's name (`amsthm` is `amsthm.lua`) |
31
+ | `at` | `"read"` (the default): after reading, for every output; `"render"`: for an output whose profile names it in its `filters`, or of a document that names it |
32
+ | `inputs` | a read filter for these input formats only (extensions without the dot) |
33
+ | `default` | a read filter runs on every document |
34
+
35
+ A document chooses among them with Quarto's key, by name:
36
+
37
+ ```yaml
38
+ filters: [texp, -pantable]
39
+ ```
40
+
41
+ turns `texp` on and `pantable` (a default) off. A name the site does not list fails that
42
+ page, with a message saying where to add it; a path is refused. The filters run in the
43
+ site's order, not the document's, so two documents with the same filters run them the
44
+ same way.
45
+
46
+ Read filters run after pandoc's own (the `--filter` and `--citeproc` of
47
+ `[read] options`), Lua ones in a pandoc call of their own. A Lua render filter runs in
48
+ the call that writes the output, after the Python ones, so that `FORMAT` is the
49
+ output's.
50
+
51
+ para.site's own: `lightgallery-from-dir` (read: a gallery from a folder of photos),
52
+ `lightgallery` and `mathjax-bold-ell` (render: MathJax has no bold ℓ, so
53
+ `\mathbf{\ell}` is written `\pmb{\ell}` in HTML).
54
+
55
+ pandoc's JSON filters (pandoc-crossref) and citeproc are pandoc options: put them in
56
+ `[read] options`. WebAssembly filters are planned.
57
+
58
+ # From other tools
59
+
60
+ Each has its own key for a document's filters; para.site reads none of them yet:
61
+
62
+ | tool | key |
63
+ |---|---|
64
+ | Quarto | `filters:`, names or paths, with `at:` for the stage |
65
+ | panflute | `panflute-filters:`, with `panflute-path:` |
66
+ | panzer | `style:`, naming a set of filters defined elsewhere |
67
+ | pandocomatic | `pandocomatic_:` |
@@ -0,0 +1,38 @@
1
+ ---
2
+ title: Front matter
3
+ description: The keys para.site reads from a document's metadata.
4
+ ---
5
+
6
+ A document's metadata is pandoc's: YAML front matter in Markdown, the first raw cell of a
7
+ notebook. pandoc's own keys keep pandoc's meaning; where Quarto has the same idea,
8
+ para.site uses Quarto's name.
9
+
10
+ | key | meaning |
11
+ |---|---|
12
+ | `title`, `subtitle`, `author`, `abstract` | pandoc's |
13
+ | `lang` | the page's language, a BCP 47 tag (see [languages](../languages/)); a translation's comes from its file name |
14
+ | `date` | when it was first published; a post needs one. An ISO 8601 date or date-time, in the site's time zone unless it says otherwise |
15
+ | `date-modified` | when its content last changed, by hand. A post's copyright runs from `date` to `date-modified` |
16
+ | `description` | one or two plain sentences, for listings, `<meta name="description">` and search; shown under the title. Without one, the `subtitle` is used |
17
+ | `category` | one per post, a path (`so-uk/meetings`). It defaults to the source's folder, so it is rarely written; a category lists its subcategories' posts too |
18
+ | `tags` | a list; each tag has a page |
19
+ | `draft: true` | built only with `--include-draft`, and never listed |
20
+ | `image`, `image-alt` | its thumbnail in listings, from the site's root, and the thumbnail's text (else the title) |
21
+ | `format` | its output profiles (see [output profiles](../profiles/)) |
22
+ | `format-links` | which of its other outputs an output links to, by each profile's `label`: `true` all, `false` none, or a list of profile names. Without it, slides link to the page beside them (Report) |
23
+ | `output-file` | an output's file name, in its folder, as an exception to the URL rules: at the top level the first output's, under `format: NAME:` that output's |
24
+
25
+ # Keys from parasite ≤ 0.1
26
+
27
+ para.site warns about these and otherwise ignores them:
28
+
29
+ | key | instead |
30
+ |---|---|
31
+ | `<!-- more -->` (a teaser) | `description` |
32
+ | `status: draft` | `draft: true` |
33
+ | `status: featured` | nothing: the front page shows the newest posts |
34
+ | `previewimage` | `image` |
35
+ | `slug`, `pretty_url`, `url_type` | the source's path |
36
+ | `type` | nothing |
37
+ | `sidebar_toc` | `toc` |
38
+ | `temp` | nothing |
@@ -0,0 +1,63 @@
1
+ ---
2
+ title: para.site
3
+ subtitle: A pandoc-first static site generator
4
+ ---
5
+
6
+ para.site builds websites from documents pandoc can read: Markdown, Jupyter notebooks,
7
+ and anything else pandoc has a reader for. Its documents, metadata and templates are
8
+ pandoc's own. It adds what a site needs around them: listings, categories and tags, an
9
+ archive, feeds, a sitemap, search, a graph of how the pages link, and builds that redo
10
+ only what changed.
11
+
12
+ The Python package is `para` (on PyPI as `pandoc-para` for now), the site generator is
13
+ its module `para.site`, and the command is `parasite`:
14
+
15
+ ```python
16
+ from para import site
17
+ ```
18
+
19
+ # Why
20
+
21
+ - **pandoc first.** No syntax of its own: no shortcodes, no extensions to Markdown.
22
+ A source is a pandoc document; its options are pandoc's options.
23
+ - **Configured as data.** A site is described by one file, `parasite.toml`. Code runs
24
+ only as filters you named, from packages you installed.
25
+ - **One source, several outputs.** A talk can be a page and its slides, from one file
26
+ (see [output profiles](profiles/)).
27
+ - **Incremental.** A build reads and renders only what changed; a rebuild with nothing
28
+ changed takes a fraction of a second (see [how it builds](builds/)).
29
+ - **Valid XHTML.** Every page is well-formed.
30
+
31
+ # A site in a minute
32
+
33
+ A folder with a `parasite.toml`:
34
+
35
+ ```toml
36
+ [site]
37
+ url = "https://example.org/"
38
+ title = "My site"
39
+ author = "Me"
40
+ ```
41
+
42
+ and Markdown files under `posts/` (dated, listed) and `pages/` (not listed):
43
+
44
+ ```markdown
45
+ ---
46
+ title: Hello
47
+ date: 2026-10-11
48
+ tags: [hello]
49
+ ---
50
+
51
+ The first post.
52
+ ```
53
+
54
+ Then, in that folder:
55
+
56
+ ```sh
57
+ parasite
58
+ ```
59
+
60
+ writes the site to `output/`. `parasite --help` lists what the command line can
61
+ override.
62
+
63
+ These pages are themselves built with para.site: see `docs/` in its repository.
@@ -0,0 +1,46 @@
1
+ ---
2
+ title: Install
3
+ ---
4
+
5
+ ::: note
6
+ On PyPI the distribution is `pandoc-para` for now (the name `para` is requested); it
7
+ installs the package `para` and the command `parasite`.
8
+ :::
9
+
10
+ para.site needs Python ≥ 3.12 and pandoc ≥ 3.1. pandoc is not on PyPI: install it from
11
+ [pandoc.org](https://pandoc.org/installing.html) or conda-forge.
12
+
13
+ # With pixi or conda
14
+
15
+ ```sh
16
+ pixi add pandoc
17
+ pixi add --pypi pandoc-para
18
+ ```
19
+
20
+ # With pip
21
+
22
+ ```sh
23
+ pip install pandoc-para
24
+ ```
25
+
26
+ # Optional parts
27
+
28
+ | extra | for |
29
+ |---|---|
30
+ | `pandoc-para[search]` | search, with [Pagefind](https://pagefind.app/) (its binary comes with it) |
31
+ | `pandoc-para[extras]` | coloured logs; watching sources and serving the site while you write |
32
+ | `pandoc-para[graph]` | the post graph, with [paragraphic](https://github.com/ickc/paragraphic) |
33
+
34
+ The check of the output's links needs [lychee](https://lychee.cli.rs) (`pixi add
35
+ lychee`; see [builds](../builds/)).
36
+
37
+ Filters a site uses (pantable, pannb, …) are installed like any package, then named in
38
+ its `parasite.toml` (see [filters](../filters/)).
39
+
40
+ # From the source
41
+
42
+ ```sh
43
+ git clone https://github.com/ickc/parasite
44
+ cd parasite
45
+ pixi run test
46
+ ```
@@ -0,0 +1,54 @@
1
+ ---
2
+ title: Languages
3
+ description: A site's language, a page's, and translations written beside each other or made by conversion.
4
+ ---
5
+
6
+ # Language tags
7
+
8
+ Languages are [BCP 47](https://www.rfc-editor.org/info/bcp47) tags, which name the
9
+ written language: `en`, `zh-Hant` (Traditional Chinese), `zh-Hans` (Simplified), and if
10
+ needed more specific ones, such as `zh-Hant-HK`. `[site] lang` is the site's; a page sets
11
+ its own with `lang` in its front matter. Tags are written in any case, and `_` is read as
12
+ `-`: Nikola's `zh_tw` is `zh-TW`, Chinese as used in Taiwan, a region rather than a
13
+ script.
14
+
15
+ A value by language, such as `title = { en = "…", zh-Hant = "…" }` or a profile's `nav`,
16
+ is looked up from the most specific tag to the least: a page in `zh-Hant-HK` takes the
17
+ `zh-Hant` value, then `zh`'s, then the site language's.
18
+
19
+ # Translations
20
+
21
+ Each of the site's other languages is a table of `[translations]`:
22
+
23
+ ```toml
24
+ [site]
25
+ lang = "zh-Hant"
26
+
27
+ [translations.en]
28
+ [translations.zh-Hans]
29
+ convert = "hk2s"
30
+ ```
31
+
32
+ **Written by hand.** `x.en.md` is the English translation of `x.md`, next to it. Its
33
+ outputs are written beside the primary's, in the same folder: `x/index.html` and
34
+ `x/index.en.html` (slides: `present.html` and `present.en.html`). So its relative links
35
+ and media work as they are written in `x.md`. Front matter it does not set (the date,
36
+ tags, category, image, `format`) is `x.md`'s; its title, description and body are its
37
+ own. `x.en.md` without an `x.md` is a page in English, at `x/`.
38
+
39
+ **Made by conversion.** With `convert`, an [OpenCC](https://github.com/BYVoid/OpenCC)
40
+ conversion (`hk2s`, `t2s`, `tw2s`, `s2t`, `s2hk`, `s2tw`, …), each page in the site's
41
+ language (or `from`) that has no written translation gets one: its text and metadata
42
+ converted, its code, URLs and raw HTML left as they are. It needs `pandoc-para[opencc]`. A
43
+ value by language the site does not give for that language (its title, the `nav`) is
44
+ the source language's, converted.
45
+
46
+ **Between them.** Each version of a page links to the others: `<link rel="alternate"
47
+ hreflang>` in its head, and a line under the byline naming each language (`name` in its
48
+ table, else its own name: 繁體中文, 简体中文, English, …). Listings, tag and category
49
+ pages, feeds and the post graph show each page once, its primary version; the sitemap
50
+ lists every version, and search every version but conversions (the same text in
51
+ another script).
52
+
53
+ Not yet: listings, feeds and search per language, as a site per language under its own
54
+ folder; the theme's words for more languages than English and Chinese.