diff --git a/.cache/plugin/social/0007b7e33cd1d9ce62e0452e9480b9bb.png b/.cache/plugin/social/0007b7e33cd1d9ce62e0452e9480b9bb.png new file mode 100644 index 0000000..ad27f01 Binary files /dev/null and b/.cache/plugin/social/0007b7e33cd1d9ce62e0452e9480b9bb.png differ diff --git a/.cache/plugin/social/0288f06f0791b86f230add45b613db8e.png b/.cache/plugin/social/0288f06f0791b86f230add45b613db8e.png new file mode 100644 index 0000000..77c9f35 Binary files /dev/null and b/.cache/plugin/social/0288f06f0791b86f230add45b613db8e.png differ diff --git a/.cache/plugin/social/040cf27a409c7237c40098dfbadea2c8.png b/.cache/plugin/social/040cf27a409c7237c40098dfbadea2c8.png new file mode 100644 index 0000000..eff6f06 Binary files /dev/null and b/.cache/plugin/social/040cf27a409c7237c40098dfbadea2c8.png differ diff --git a/.cache/plugin/social/0631c5b54f1cf7c6652bdf45b9d54bd9.png b/.cache/plugin/social/0631c5b54f1cf7c6652bdf45b9d54bd9.png new file mode 100644 index 0000000..b591b9c Binary files /dev/null and b/.cache/plugin/social/0631c5b54f1cf7c6652bdf45b9d54bd9.png differ diff --git a/.cache/plugin/social/0bf2e9873eedf6a089518bc14fdb3310.png b/.cache/plugin/social/0bf2e9873eedf6a089518bc14fdb3310.png new file mode 100644 index 0000000..0b116e4 Binary files /dev/null and b/.cache/plugin/social/0bf2e9873eedf6a089518bc14fdb3310.png differ diff --git a/.cache/plugin/social/11dbd7b16fa165a58253daaee29cf3c7.png b/.cache/plugin/social/11dbd7b16fa165a58253daaee29cf3c7.png new file mode 100644 index 0000000..4244a2e Binary files /dev/null and b/.cache/plugin/social/11dbd7b16fa165a58253daaee29cf3c7.png differ diff --git a/.cache/plugin/social/12422945c45d2896c9a9f79944f26d0f.png b/.cache/plugin/social/12422945c45d2896c9a9f79944f26d0f.png new file mode 100644 index 0000000..61e1e5d Binary files /dev/null and b/.cache/plugin/social/12422945c45d2896c9a9f79944f26d0f.png differ diff --git a/.cache/plugin/social/1418b3bdf2b1114de35f785603670321.png b/.cache/plugin/social/1418b3bdf2b1114de35f785603670321.png new file mode 100644 index 0000000..98167f9 Binary files /dev/null and b/.cache/plugin/social/1418b3bdf2b1114de35f785603670321.png differ diff --git a/.cache/plugin/social/17f368cc261bf824174d44dbc9d487fc.png b/.cache/plugin/social/17f368cc261bf824174d44dbc9d487fc.png new file mode 100644 index 0000000..c946452 Binary files /dev/null and b/.cache/plugin/social/17f368cc261bf824174d44dbc9d487fc.png differ diff --git a/.cache/plugin/social/20cd98e58499a41ef154c19278c68a88.png b/.cache/plugin/social/20cd98e58499a41ef154c19278c68a88.png new file mode 100644 index 0000000..1cc4d6a Binary files /dev/null and b/.cache/plugin/social/20cd98e58499a41ef154c19278c68a88.png differ diff --git a/.cache/plugin/social/22035a8312a9af9a24083f62bc302316.png b/.cache/plugin/social/22035a8312a9af9a24083f62bc302316.png new file mode 100644 index 0000000..6e409e1 Binary files /dev/null and b/.cache/plugin/social/22035a8312a9af9a24083f62bc302316.png differ diff --git a/.cache/plugin/social/24130501e2cc9c10e815597883592d88.png b/.cache/plugin/social/24130501e2cc9c10e815597883592d88.png new file mode 100644 index 0000000..46ebad1 Binary files /dev/null and b/.cache/plugin/social/24130501e2cc9c10e815597883592d88.png differ diff --git a/.cache/plugin/social/2c4c386f51f89622c7b8dccfee82f1e1.png b/.cache/plugin/social/2c4c386f51f89622c7b8dccfee82f1e1.png new file mode 100644 index 0000000..bae224c Binary files /dev/null and b/.cache/plugin/social/2c4c386f51f89622c7b8dccfee82f1e1.png differ diff --git a/.cache/plugin/social/2c6d37f3bc38efa43ed4126a559c73c1.png b/.cache/plugin/social/2c6d37f3bc38efa43ed4126a559c73c1.png new file mode 100644 index 0000000..9f794f1 Binary files /dev/null and b/.cache/plugin/social/2c6d37f3bc38efa43ed4126a559c73c1.png differ diff --git a/.cache/plugin/social/329d6c1d7b525393cad4631906ea217b.png b/.cache/plugin/social/329d6c1d7b525393cad4631906ea217b.png new file mode 100644 index 0000000..16be9a2 Binary files /dev/null and b/.cache/plugin/social/329d6c1d7b525393cad4631906ea217b.png differ diff --git a/.cache/plugin/social/39c171c296aef53a0d0daf9e9cbd78f1.png b/.cache/plugin/social/39c171c296aef53a0d0daf9e9cbd78f1.png new file mode 100644 index 0000000..af2db5c Binary files /dev/null and b/.cache/plugin/social/39c171c296aef53a0d0daf9e9cbd78f1.png differ diff --git a/.cache/plugin/social/43bcef98ea93f16d74018cd6cbd25af1.png b/.cache/plugin/social/43bcef98ea93f16d74018cd6cbd25af1.png new file mode 100644 index 0000000..9871489 Binary files /dev/null and b/.cache/plugin/social/43bcef98ea93f16d74018cd6cbd25af1.png differ diff --git a/.cache/plugin/social/45daf23fa3112ab3500f10a23a0d4a70.png b/.cache/plugin/social/45daf23fa3112ab3500f10a23a0d4a70.png new file mode 100644 index 0000000..ed095d0 Binary files /dev/null and b/.cache/plugin/social/45daf23fa3112ab3500f10a23a0d4a70.png differ diff --git a/.cache/plugin/social/46d549324f90824540d965df8be6229d.png b/.cache/plugin/social/46d549324f90824540d965df8be6229d.png new file mode 100644 index 0000000..69894dd Binary files /dev/null and b/.cache/plugin/social/46d549324f90824540d965df8be6229d.png differ diff --git a/.cache/plugin/social/4f3aa83023cd42b60bf8368bb7b93fa0.png b/.cache/plugin/social/4f3aa83023cd42b60bf8368bb7b93fa0.png new file mode 100644 index 0000000..816366c Binary files /dev/null and b/.cache/plugin/social/4f3aa83023cd42b60bf8368bb7b93fa0.png differ diff --git a/.cache/plugin/social/515b08b85f23912f48cc75e7346a557d.png b/.cache/plugin/social/515b08b85f23912f48cc75e7346a557d.png new file mode 100644 index 0000000..608fa32 Binary files /dev/null and b/.cache/plugin/social/515b08b85f23912f48cc75e7346a557d.png differ diff --git a/.cache/plugin/social/53616d92b8ddf256c15dc8d354fb2d37.png b/.cache/plugin/social/53616d92b8ddf256c15dc8d354fb2d37.png new file mode 100644 index 0000000..73be9fa Binary files /dev/null and b/.cache/plugin/social/53616d92b8ddf256c15dc8d354fb2d37.png differ diff --git a/.cache/plugin/social/545c4710afea40613b58c9dacfdcd1bc.png b/.cache/plugin/social/545c4710afea40613b58c9dacfdcd1bc.png new file mode 100644 index 0000000..dfe4955 Binary files /dev/null and b/.cache/plugin/social/545c4710afea40613b58c9dacfdcd1bc.png differ diff --git a/.cache/plugin/social/5a34409c4fc751dc33912898332b819d.png b/.cache/plugin/social/5a34409c4fc751dc33912898332b819d.png new file mode 100644 index 0000000..835ec90 Binary files /dev/null and b/.cache/plugin/social/5a34409c4fc751dc33912898332b819d.png differ diff --git a/.cache/plugin/social/5d2121c73f62feed6e8c1afa1c86d2ba.png b/.cache/plugin/social/5d2121c73f62feed6e8c1afa1c86d2ba.png new file mode 100644 index 0000000..8ed26d7 Binary files /dev/null and b/.cache/plugin/social/5d2121c73f62feed6e8c1afa1c86d2ba.png differ diff --git a/.cache/plugin/social/6d23516473f266a80fa645e40ff076c0.png b/.cache/plugin/social/6d23516473f266a80fa645e40ff076c0.png new file mode 100644 index 0000000..04d63e3 Binary files /dev/null and b/.cache/plugin/social/6d23516473f266a80fa645e40ff076c0.png differ diff --git a/.cache/plugin/social/75b87442adca7e1bfe15d6b22e726783.png b/.cache/plugin/social/75b87442adca7e1bfe15d6b22e726783.png new file mode 100644 index 0000000..19c2975 Binary files /dev/null and b/.cache/plugin/social/75b87442adca7e1bfe15d6b22e726783.png differ diff --git a/.cache/plugin/social/7e19849778fb923f7fc3219ebac71c86.png b/.cache/plugin/social/7e19849778fb923f7fc3219ebac71c86.png new file mode 100644 index 0000000..0939660 Binary files /dev/null and b/.cache/plugin/social/7e19849778fb923f7fc3219ebac71c86.png differ diff --git a/.cache/plugin/social/803d2a0b7c36ba216a71315683976371.png b/.cache/plugin/social/803d2a0b7c36ba216a71315683976371.png new file mode 100644 index 0000000..5db7b30 Binary files /dev/null and b/.cache/plugin/social/803d2a0b7c36ba216a71315683976371.png differ diff --git a/.cache/plugin/social/83356e57dc7fc6b538657ba79fb803aa.png b/.cache/plugin/social/83356e57dc7fc6b538657ba79fb803aa.png new file mode 100644 index 0000000..6ae53f2 Binary files /dev/null and b/.cache/plugin/social/83356e57dc7fc6b538657ba79fb803aa.png differ diff --git a/.cache/plugin/social/8804b6baf50d2bdfb1f125bd39c4b35e.png b/.cache/plugin/social/8804b6baf50d2bdfb1f125bd39c4b35e.png new file mode 100644 index 0000000..2957b36 Binary files /dev/null and b/.cache/plugin/social/8804b6baf50d2bdfb1f125bd39c4b35e.png differ diff --git a/.cache/plugin/social/8bd9a2a8bbb59a38a8686eb586808ec6.png b/.cache/plugin/social/8bd9a2a8bbb59a38a8686eb586808ec6.png new file mode 100644 index 0000000..107e862 Binary files /dev/null and b/.cache/plugin/social/8bd9a2a8bbb59a38a8686eb586808ec6.png differ diff --git a/.cache/plugin/social/97caa17fa50c79824a011049ebf0bdd2.png b/.cache/plugin/social/97caa17fa50c79824a011049ebf0bdd2.png new file mode 100644 index 0000000..58601f5 Binary files /dev/null and b/.cache/plugin/social/97caa17fa50c79824a011049ebf0bdd2.png differ diff --git a/.cache/plugin/social/9d60a009fda7be9fb5711af18f65945c.png b/.cache/plugin/social/9d60a009fda7be9fb5711af18f65945c.png new file mode 100644 index 0000000..b0b05d7 Binary files /dev/null and b/.cache/plugin/social/9d60a009fda7be9fb5711af18f65945c.png differ diff --git a/.cache/plugin/social/9fc3d708f0eccc618c4ff158446c6f2a.png b/.cache/plugin/social/9fc3d708f0eccc618c4ff158446c6f2a.png new file mode 100644 index 0000000..d6a9fda Binary files /dev/null and b/.cache/plugin/social/9fc3d708f0eccc618c4ff158446c6f2a.png differ diff --git a/.cache/plugin/social/a1030b7ef9ba74facb88ff5f20b24429.png b/.cache/plugin/social/a1030b7ef9ba74facb88ff5f20b24429.png new file mode 100644 index 0000000..7fcfa88 Binary files /dev/null and b/.cache/plugin/social/a1030b7ef9ba74facb88ff5f20b24429.png differ diff --git a/.cache/plugin/social/ad51a3505269562f1638f62d52737f4e.png b/.cache/plugin/social/ad51a3505269562f1638f62d52737f4e.png new file mode 100644 index 0000000..1e2c4ed Binary files /dev/null and b/.cache/plugin/social/ad51a3505269562f1638f62d52737f4e.png differ diff --git a/.cache/plugin/social/c2e035935b9941a72917f3ec539cac51.png b/.cache/plugin/social/c2e035935b9941a72917f3ec539cac51.png new file mode 100644 index 0000000..492f82c Binary files /dev/null and b/.cache/plugin/social/c2e035935b9941a72917f3ec539cac51.png differ diff --git a/.cache/plugin/social/c32e1a44d5d6fa123b3186f80fac03f1.png b/.cache/plugin/social/c32e1a44d5d6fa123b3186f80fac03f1.png new file mode 100644 index 0000000..329646b Binary files /dev/null and b/.cache/plugin/social/c32e1a44d5d6fa123b3186f80fac03f1.png differ diff --git a/.cache/plugin/social/cbfa23b26443ac4bbf3599b080e0a655.png b/.cache/plugin/social/cbfa23b26443ac4bbf3599b080e0a655.png new file mode 100644 index 0000000..8bdfa1a Binary files /dev/null and b/.cache/plugin/social/cbfa23b26443ac4bbf3599b080e0a655.png differ diff --git a/.cache/plugin/social/cc7e52f9f90341512b82f6a87612de71.png b/.cache/plugin/social/cc7e52f9f90341512b82f6a87612de71.png new file mode 100644 index 0000000..eb5609f Binary files /dev/null and b/.cache/plugin/social/cc7e52f9f90341512b82f6a87612de71.png differ diff --git a/.cache/plugin/social/cfed85599015597db17f7f185c2c823d.png b/.cache/plugin/social/cfed85599015597db17f7f185c2c823d.png new file mode 100644 index 0000000..1f9a2d7 Binary files /dev/null and b/.cache/plugin/social/cfed85599015597db17f7f185c2c823d.png differ diff --git a/.cache/plugin/social/d907428e80f009fdaf394f8019e7b863.png b/.cache/plugin/social/d907428e80f009fdaf394f8019e7b863.png new file mode 100644 index 0000000..3b34e92 Binary files /dev/null and b/.cache/plugin/social/d907428e80f009fdaf394f8019e7b863.png differ diff --git a/.cache/plugin/social/dcccd5407ffcb8e5ea117510c525a7df.png b/.cache/plugin/social/dcccd5407ffcb8e5ea117510c525a7df.png new file mode 100644 index 0000000..fb797d3 Binary files /dev/null and b/.cache/plugin/social/dcccd5407ffcb8e5ea117510c525a7df.png differ diff --git a/.cache/plugin/social/dcfb957fdd8b70cf316b211bbb26e25a.png b/.cache/plugin/social/dcfb957fdd8b70cf316b211bbb26e25a.png new file mode 100644 index 0000000..129da71 Binary files /dev/null and b/.cache/plugin/social/dcfb957fdd8b70cf316b211bbb26e25a.png differ diff --git a/.cache/plugin/social/edf66810a6884c49a73ef1dc5723871e.png b/.cache/plugin/social/edf66810a6884c49a73ef1dc5723871e.png new file mode 100644 index 0000000..a897ce8 Binary files /dev/null and b/.cache/plugin/social/edf66810a6884c49a73ef1dc5723871e.png differ diff --git a/.cache/plugin/social/fonts/Roboto/Black Italic.ttf b/.cache/plugin/social/fonts/Roboto/Black Italic.ttf new file mode 100644 index 0000000..b2c6aca Binary files /dev/null and b/.cache/plugin/social/fonts/Roboto/Black Italic.ttf differ diff --git a/.cache/plugin/social/fonts/Roboto/Black.ttf b/.cache/plugin/social/fonts/Roboto/Black.ttf new file mode 100644 index 0000000..0112e7d Binary files /dev/null and b/.cache/plugin/social/fonts/Roboto/Black.ttf differ diff --git a/.cache/plugin/social/fonts/Roboto/Bold Italic.ttf b/.cache/plugin/social/fonts/Roboto/Bold Italic.ttf new file mode 100644 index 0000000..bcfdab4 Binary files /dev/null and b/.cache/plugin/social/fonts/Roboto/Bold Italic.ttf differ diff --git a/.cache/plugin/social/fonts/Roboto/Bold.ttf b/.cache/plugin/social/fonts/Roboto/Bold.ttf new file mode 100644 index 0000000..43da14d Binary files /dev/null and b/.cache/plugin/social/fonts/Roboto/Bold.ttf differ diff --git a/.cache/plugin/social/fonts/Roboto/Italic.ttf b/.cache/plugin/social/fonts/Roboto/Italic.ttf new file mode 100644 index 0000000..1b5eaa3 Binary files /dev/null and b/.cache/plugin/social/fonts/Roboto/Italic.ttf differ diff --git a/.cache/plugin/social/fonts/Roboto/Light Italic.ttf b/.cache/plugin/social/fonts/Roboto/Light Italic.ttf new file mode 100644 index 0000000..2d277af Binary files /dev/null and b/.cache/plugin/social/fonts/Roboto/Light Italic.ttf differ diff --git a/.cache/plugin/social/fonts/Roboto/Light.ttf b/.cache/plugin/social/fonts/Roboto/Light.ttf new file mode 100644 index 0000000..e7307e7 Binary files /dev/null and b/.cache/plugin/social/fonts/Roboto/Light.ttf differ diff --git a/.cache/plugin/social/fonts/Roboto/Medium Italic.ttf b/.cache/plugin/social/fonts/Roboto/Medium Italic.ttf new file mode 100644 index 0000000..fc36a47 Binary files /dev/null and b/.cache/plugin/social/fonts/Roboto/Medium Italic.ttf differ diff --git a/.cache/plugin/social/fonts/Roboto/Medium.ttf b/.cache/plugin/social/fonts/Roboto/Medium.ttf new file mode 100644 index 0000000..ac0f908 Binary files /dev/null and b/.cache/plugin/social/fonts/Roboto/Medium.ttf differ diff --git a/.cache/plugin/social/fonts/Roboto/Regular.ttf b/.cache/plugin/social/fonts/Roboto/Regular.ttf new file mode 100644 index 0000000..ddf4bfa Binary files /dev/null and b/.cache/plugin/social/fonts/Roboto/Regular.ttf differ diff --git a/.cache/plugin/social/fonts/Roboto/Thin Italic.ttf b/.cache/plugin/social/fonts/Roboto/Thin Italic.ttf new file mode 100644 index 0000000..084f9c0 Binary files /dev/null and b/.cache/plugin/social/fonts/Roboto/Thin Italic.ttf differ diff --git a/.cache/plugin/social/fonts/Roboto/Thin.ttf b/.cache/plugin/social/fonts/Roboto/Thin.ttf new file mode 100644 index 0000000..2e0dee6 Binary files /dev/null and b/.cache/plugin/social/fonts/Roboto/Thin.ttf differ diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 9b27f1c..0000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.vscode/settings.json -./.cache diff --git a/Collections.md b/docs/Collections.md similarity index 100% rename from Collections.md rename to docs/Collections.md diff --git a/Configuration.md b/docs/Configuration.md similarity index 93% rename from Configuration.md rename to docs/Configuration.md index b2d1a57..49d4b32 100644 --- a/Configuration.md +++ b/docs/Configuration.md @@ -1,13 +1,3 @@ ---- -title: Configuration -description: -published: true -date: 2024-02-01T16:20:59.571Z -tags: -editor: markdown -dateCreated: 2024-02-01T16:20:57.032Z ---- - All configuration is done inside the application, no extra config is required in files.
At first boot you will be redirected to the settings page. diff --git a/Contributing.md b/docs/Contributing.md similarity index 100% rename from Contributing.md rename to docs/Contributing.md diff --git a/Glossary.md b/docs/Glossary.md similarity index 98% rename from Glossary.md rename to docs/Glossary.md index c91089c..3824fbc 100644 --- a/Glossary.md +++ b/docs/Glossary.md @@ -1,13 +1,3 @@ ---- -title: Glossary -description: -published: true -date: 2024-02-01T16:21:03.544Z -tags: -editor: markdown -dateCreated: 2024-02-01T16:21:00.733Z ---- - ## Rule glossary This glossary describes the available rules that can be used in maintainerr. diff --git a/Installation.md b/docs/Installation.md similarity index 100% rename from Installation.md rename to docs/Installation.md diff --git a/LICENSE b/docs/LICENSE similarity index 97% rename from LICENSE rename to docs/LICENSE index 77f41d2..8cee26b 100644 --- a/LICENSE +++ b/docs/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Jorenn92 +Copyright (c) 2023 YDKMLT84 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Rules.md b/docs/Rules.md similarity index 100% rename from Rules.md rename to docs/Rules.md diff --git a/Tutorials/Tutorial_S01E01.md b/docs/Tutorials/Tutorial_S01E01.md similarity index 100% rename from Tutorials/Tutorial_S01E01.md rename to docs/Tutorials/Tutorial_S01E01.md diff --git a/Tutorials/Tutorial_S01E02.md b/docs/Tutorials/Tutorial_S01E02.md similarity index 100% rename from Tutorials/Tutorial_S01E02.md rename to docs/Tutorials/Tutorial_S01E02.md diff --git a/Tutorials/Tutorial_S01E03.md b/docs/Tutorials/Tutorial_S01E03.md similarity index 100% rename from Tutorials/Tutorial_S01E03.md rename to docs/Tutorials/Tutorial_S01E03.md diff --git a/docs/Tutorials/index.md b/docs/Tutorials/index.md new file mode 100644 index 0000000..bf7f6cf --- /dev/null +++ b/docs/Tutorials/index.md @@ -0,0 +1,4 @@ +--- +title: Tutorials +--- +## This is a placeholder for the tutorials landing page. diff --git a/docs/blog/index.md b/docs/blog/index.md new file mode 100644 index 0000000..c58f16c --- /dev/null +++ b/docs/blog/index.md @@ -0,0 +1,2 @@ +# Blog + diff --git a/docs/extensions/preview.py b/docs/extensions/preview.py new file mode 100644 index 0000000..e10294b --- /dev/null +++ b/docs/extensions/preview.py @@ -0,0 +1,224 @@ + +# Copyright (c) 2016-2024 Martin Donath + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +from __future__ import annotations + +import logging + +from material.utilities.filter import FileFilter, FilterConfig +from mkdocs.structure.pages import _RelativePathTreeprocessor +from markdown import Extension, Markdown +from markdown.treeprocessors import Treeprocessor +from mkdocs.exceptions import ConfigurationError +from urllib.parse import urlparse +from xml.etree.ElementTree import Element + +# ----------------------------------------------------------------------------- +# Classes +# ----------------------------------------------------------------------------- + +class PreviewProcessor(Treeprocessor): + """ + A Markdown treeprocessor to enable instant previews on links. + + Note that this treeprocessor is dependent on the `relpath` treeprocessor + registered programmatically by MkDocs before rendering a page. + """ + + def __init__(self, md: Markdown, config: dict): + """ + Initialize the treeprocessor. + + Arguments: + md: The Markdown instance. + config: The configuration. + """ + super().__init__(md) + self.config = config + + def run(self, root: Element): + """ + Run the treeprocessor. + + Arguments: + root: The root element of the parsed Markdown document. + """ + at = self.md.treeprocessors.get_index_for_name("relpath") + + # Hack: Python Markdown has no notion of where it is, i.e., which file + # is being processed. This seems to be a deliberate design decision, as + # it is not possible to access the file path of the current page, but + # it might also be an oversight that is now impossible to fix. However, + # since this extension is only useful in the context of Material for + # MkDocs, we can assume that the _RelativePathTreeprocessor is always + # present, telling us the file path of the current page. If that ever + # changes, we would need to wrap this extension in a plugin, but for + # the time being we are sneaky and will probably get away with it. + processor = self.md.treeprocessors[at] + if not isinstance(processor, _RelativePathTreeprocessor): + raise TypeError("Relative path processor not registered") + + # Normalize configurations + configurations = self.config["configurations"] + configurations.append({ + "sources": self.config.get("sources"), + "targets": self.config.get("targets") + }) + + # Walk through all configurations - @todo refactor so that we don't + # iterate multiple times over the same elements + for configuration in configurations: + + # Skip, if the configuration defines nothing – we could also fix + # this in the file filter, but we first fix it here and check if + # it generalizes well enough to other inclusion/exclusion sites, + # because here, it would hinder the ability to automaticaly + # include all sources, while excluding specific targets. + if ( + not configuration.get("sources") and + not configuration.get("targets") + ): + continue + + # Skip if page should not be considered + filter = get_filter(configuration, "sources") + if not filter(processor.file): + continue + + # Walk through all links and add preview attributes + filter = get_filter(configuration, "targets") + for el in root.iter("a"): + href = el.get("href") + if not href: + continue + + # Skip footnotes + if "footnote-ref" in el.get("class", ""): + continue + + # Skip external links + url = urlparse(href) + if url.scheme or url.netloc: + continue + + # Add preview attribute to internal links + for path in processor._possible_target_uris( + processor.file, url.path, + processor.config.use_directory_urls + ): + target = processor.files.get_file_from_path(path) + if not target: + continue + + # Include, if filter matches + if filter(target): + el.set("data-preview", "") + +# ----------------------------------------------------------------------------- + +class PreviewExtension(Extension): + """ + A Markdown extension to enable instant previews on links. + + This extensions allows to automatically add the `data-preview` attribute to + internal links matching specific criteria, so Material for MkDocs renders a + nice preview on hover as part of a tooltip. It is the recommended way to + add previews to links in a programmatic way. + """ + + def __init__(self, *args, **kwargs): + """ + """ + self.config = { + "configurations": [[], "Filter configurations"], + "sources": [{}, "Link sources"], + "targets": [{}, "Link targets"] + } + super().__init__(*args, **kwargs) + + def extendMarkdown(self, md: Markdown): + """ + Register Markdown extension. + + Arguments: + md: The Markdown instance. + """ + md.registerExtension(self) + + # Create and register treeprocessor - we use the same priority as the + # `relpath` treeprocessor, the latter of which is guaranteed to run + # after our treeprocessor, so we can check the original Markdown URIs + # before they are resolved to URLs. + processor = PreviewProcessor(md, self.getConfigs()) + md.treeprocessors.register(processor, "preview", 0) + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- + +def get_filter(settings: dict, key: str): + """ + Get file filter from settings. + + Arguments: + settings: The settings. + key: The key in the settings. + + Returns: + The file filter. + """ + config = FilterConfig() + config.load_dict(settings.get(key) or {}) + + # Validate filter configuration + errors, warnings = config.validate() + for _, w in warnings: + log.warning( + f"Error reading filter configuration in '{key}':\n" + f"{w}" + ) + for _, e in errors: + raise ConfigurationError( + f"Error reading filter configuration in '{key}':\n" + f"{e}" + ) + + # Return file filter + return FileFilter(config = config) # type: ignore + +def makeExtension(**kwargs): + """ + Register Markdown extension. + + Arguments: + **kwargs: Configuration options. + + Returns: + The Markdown extension. + """ + return PreviewExtension(**kwargs) + +# ----------------------------------------------------------------------------- +# Data +# ----------------------------------------------------------------------------- + +# Set up logging +log = logging.getLogger("mkdocs.material.extensions.preview") diff --git a/images/GitHub-Logo.png b/docs/images/GitHub-Logo.png similarity index 100% rename from images/GitHub-Logo.png rename to docs/images/GitHub-Logo.png diff --git a/images/banner3.png b/docs/images/banner3.png similarity index 100% rename from images/banner3.png rename to docs/images/banner3.png diff --git a/images/classroom.jpg b/docs/images/classroom.jpg similarity index 100% rename from images/classroom.jpg rename to docs/images/classroom.jpg diff --git a/images/collections-screenshot.png b/docs/images/collections-screenshot.png similarity index 100% rename from images/collections-screenshot.png rename to docs/images/collections-screenshot.png diff --git a/images/discord_icon.svg b/docs/images/discord_icon.svg similarity index 100% rename from images/discord_icon.svg rename to docs/images/discord_icon.svg diff --git a/images/discord_meta.png b/docs/images/discord_meta.png similarity index 100% rename from images/discord_meta.png rename to docs/images/discord_meta.png diff --git a/images/docker_icon.svg b/docs/images/docker_icon.svg similarity index 100% rename from images/docker_icon.svg rename to docs/images/docker_icon.svg diff --git a/images/favicon.ico b/docs/images/favicon.ico similarity index 100% rename from images/favicon.ico rename to docs/images/favicon.ico diff --git a/images/final-screenshot.png b/docs/images/final-screenshot.png similarity index 100% rename from images/final-screenshot.png rename to docs/images/final-screenshot.png diff --git a/images/logo.png b/docs/images/logo.png similarity index 100% rename from images/logo.png rename to docs/images/logo.png diff --git a/images/logo.svg b/docs/images/logo.svg similarity index 100% rename from images/logo.svg rename to docs/images/logo.svg diff --git a/images/logo_black.svg b/docs/images/logo_black.svg similarity index 100% rename from images/logo_black.svg rename to docs/images/logo_black.svg diff --git a/images/logo_icon.svg b/docs/images/logo_icon.svg similarity index 100% rename from images/logo_icon.svg rename to docs/images/logo_icon.svg diff --git a/images/main-screenshot.png b/docs/images/main-screenshot.png similarity index 100% rename from images/main-screenshot.png rename to docs/images/main-screenshot.png diff --git a/images/movie_poster.png b/docs/images/movie_poster.png similarity index 100% rename from images/movie_poster.png rename to docs/images/movie_poster.png diff --git a/images/rules-screenshot.png b/docs/images/rules-screenshot.png similarity index 100% rename from images/rules-screenshot.png rename to docs/images/rules-screenshot.png diff --git a/images/screenshot-1.png b/docs/images/screenshot-1.png similarity index 100% rename from images/screenshot-1.png rename to docs/images/screenshot-1.png diff --git a/images/screenshot-2.png b/docs/images/screenshot-2.png similarity index 100% rename from images/screenshot-2.png rename to docs/images/screenshot-2.png diff --git a/images/screenshot_discord_comment.png b/docs/images/screenshot_discord_comment.png similarity index 100% rename from images/screenshot_discord_comment.png rename to docs/images/screenshot_discord_comment.png diff --git a/images/screenshot_plex_collection.png b/docs/images/screenshot_plex_collection.png similarity index 100% rename from images/screenshot_plex_collection.png rename to docs/images/screenshot_plex_collection.png diff --git a/images/spinner.svg b/docs/images/spinner.svg similarity index 100% rename from images/spinner.svg rename to docs/images/spinner.svg diff --git a/images/welcome_discord.png b/docs/images/welcome_discord.png similarity index 100% rename from images/welcome_discord.png rename to docs/images/welcome_discord.png diff --git a/index.md b/docs/index.md similarity index 100% rename from index.md rename to docs/index.md diff --git a/docs/overrides/hooks/shortcodes.py b/docs/overrides/hooks/shortcodes.py new file mode 100644 index 0000000..faba233 --- /dev/null +++ b/docs/overrides/hooks/shortcodes.py @@ -0,0 +1,283 @@ +# Copyright (c) 2016-2024 Martin Donath + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +from __future__ import annotations + +import posixpath +import re + +from mkdocs.config.defaults import MkDocsConfig +from mkdocs.structure.files import File, Files +from mkdocs.structure.pages import Page +from re import Match + +# ----------------------------------------------------------------------------- +# Hooks +# ----------------------------------------------------------------------------- + +# @todo +def on_page_markdown( + markdown: str, *, page: Page, config: MkDocsConfig, files: Files +): + + # Replace callback + def replace(match: Match): + type, args = match.groups() + args = args.strip() + if type == "version": + if args.startswith("insiders-"): + return _badge_for_version_insiders(args, page, files) + else: + return _badge_for_version(args, page, files) + elif type == "sponsors": return _badge_for_sponsors(page, files) + elif type == "flag": return flag(args, page, files) + elif type == "option": return option(args) + elif type == "setting": return setting(args) + elif type == "feature": return _badge_for_feature(args, page, files) + elif type == "plugin": return _badge_for_plugin(args, page, files) + elif type == "extension": return _badge_for_extension(args, page, files) + elif type == "utility": return _badge_for_utility(args, page, files) + elif type == "example": return _badge_for_example(args, page, files) + elif type == "default": + if args == "none": return _badge_for_default_none(page, files) + elif args == "computed": return _badge_for_default_computed(page, files) + else: return _badge_for_default(args, page, files) + + # Otherwise, raise an error + raise RuntimeError(f"Unknown shortcode: {type}") + + # Find and replace all external asset URLs in current page + return re.sub( + r"", + replace, markdown, flags = re.I | re.M + ) + +# ----------------------------------------------------------------------------- +# Helper functions +# ----------------------------------------------------------------------------- + +# Create a flag of a specific type +def flag(args: str, page: Page, files: Files): + type, *_ = args.split(" ", 1) + if type == "experimental": return _badge_for_experimental(page, files) + elif type == "required": return _badge_for_required(page, files) + elif type == "customization": return _badge_for_customization(page, files) + elif type == "metadata": return _badge_for_metadata(page, files) + elif type == "multiple": return _badge_for_multiple(page, files) + raise RuntimeError(f"Unknown type: {type}") + +# Create a linkable option +def option(type: str): + _, *_, name = re.split(r"[.:]", type) + return f"[`{name}`](#+{type}){{ #+{type} }}\n\n" + +# Create a linkable setting - @todo append them to the bottom of the page +def setting(type: str): + _, *_, name = re.split(r"[.*]", type) + return f"`{name}` {{ #{type} }}\n\n[{type}]: #{type}\n\n" + +# ----------------------------------------------------------------------------- + +# Resolve path of file relative to given page - the posixpath always includes +# one additional level of `..` which we need to remove +def _resolve_path(path: str, page: Page, files: Files): + path, anchor, *_ = f"{path}#".split("#") + path = _resolve(files.get_file_from_path(path), page) + return "#".join([path, anchor]) if anchor else path + +# Resolve path of file relative to given page - the posixpath always includes +# one additional level of `..` which we need to remove +def _resolve(file: File, page: Page): + path = posixpath.relpath(file.src_uri, page.file.src_uri) + return posixpath.sep.join(path.split(posixpath.sep)[1:]) + +# ----------------------------------------------------------------------------- + +# Create badge +def _badge(icon: str, text: str = "", type: str = ""): + classes = f"mdx-badge mdx-badge--{type}" if type else "mdx-badge" + return "".join([ + f"", + *([f"{icon}"] if icon else []), + *([f"{text}"] if text else []), + f"", + ]) + +# Create sponsors badge +def _badge_for_sponsors(page: Page, files: Files): + icon = "material-heart" + href = _resolve_path("insiders/index.md", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Sponsors only')", + type = "heart" + ) + +# Create badge for version +def _badge_for_version(text: str, page: Page, files: Files): + spec = text + path = f"changelog/index.md#{spec}" + + # Return badge + icon = "material-tag-outline" + href = _resolve_path("conventions.md#version", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Minimum version')", + text = f"[{text}]({_resolve_path(path, page, files)})" if spec else "" + ) + +# Create badge for version of Insiders +def _badge_for_version_insiders(text: str, page: Page, files: Files): + spec = text.replace("insiders-", "") + path = f"insiders/changelog/index.md#{spec}" + + # Return badge + icon = "material-tag-heart-outline" + href = _resolve_path("conventions.md#version-insiders", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Minimum version')", + text = f"[{text}]({_resolve_path(path, page, files)})" if spec else "" + ) + +# Create badge for feature +def _badge_for_feature(text: str, page: Page, files: Files): + icon = "material-toggle-switch" + href = _resolve_path("conventions.md#feature", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Optional feature')", + text = text + ) + +# Create badge for plugin +def _badge_for_plugin(text: str, page: Page, files: Files): + icon = "material-floppy" + href = _resolve_path("conventions.md#plugin", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Plugin')", + text = text + ) + +# Create badge for extension +def _badge_for_extension(text: str, page: Page, files: Files): + icon = "material-language-markdown" + href = _resolve_path("conventions.md#extension", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Markdown extension')", + text = text + ) + +# Create badge for utility +def _badge_for_utility(text: str, page: Page, files: Files): + icon = "material-package-variant" + href = _resolve_path("conventions.md#utility", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Third-party utility')", + text = text + ) + +# Create badge for example +def _badge_for_example(text: str, page: Page, files: Files): + return "\n".join([ + _badge_for_example_download(text, page, files), + _badge_for_example_view(text, page, files) + ]) + +# Create badge for example view +def _badge_for_example_view(text: str, page: Page, files: Files): + icon = "material-folder-eye" + href = f"https://mkdocs-material.github.io/examples/{text}/" + return _badge( + icon = f"[:{icon}:]({href} 'View example')", + type = "right" + ) + +# Create badge for example download +def _badge_for_example_download(text: str, page: Page, files: Files): + icon = "material-folder-download" + href = f"https://mkdocs-material.github.io/examples/{text}.zip" + return _badge( + icon = f"[:{icon}:]({href} 'Download example')", + text = f"[`.zip`]({href})", + type = "right" + ) + +# Create badge for default value +def _badge_for_default(text: str, page: Page, files: Files): + icon = "material-water" + href = _resolve_path("conventions.md#default", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Default value')", + text = text + ) + +# Create badge for empty default value +def _badge_for_default_none(page: Page, files: Files): + icon = "material-water-outline" + href = _resolve_path("conventions.md#default", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Default value is empty')" + ) + +# Create badge for computed default value +def _badge_for_default_computed(page: Page, files: Files): + icon = "material-water-check" + href = _resolve_path("conventions.md#default", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Default value is computed')" + ) + +# Create badge for metadata property flag +def _badge_for_metadata(page: Page, files: Files): + icon = "material-list-box-outline" + href = _resolve_path("conventions.md#metadata", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Metadata property')" + ) + +# Create badge for required value flag +def _badge_for_required(page: Page, files: Files): + icon = "material-alert" + href = _resolve_path("conventions.md#required", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Required value')" + ) + +# Create badge for customization flag +def _badge_for_customization(page: Page, files: Files): + icon = "material-brush-variant" + href = _resolve_path("conventions.md#customization", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Customization')" + ) + +# Create badge for multiple instance flag +def _badge_for_multiple(page: Page, files: Files): + icon = "material-inbox-multiple" + href = _resolve_path("conventions.md#multiple-instances", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Multiple instances')" + ) + +# Create badge for experimental flag +def _badge_for_experimental(page: Page, files: Files): + icon = "material-flask-outline" + href = _resolve_path("conventions.md#experimental", page, files) + return _badge( + icon = f"[:{icon}:]({href} 'Experimental')" + ) diff --git a/docs/overrides/hooks/translations.py b/docs/overrides/hooks/translations.py new file mode 100644 index 0000000..424e877 --- /dev/null +++ b/docs/overrides/hooks/translations.py @@ -0,0 +1,195 @@ +# Copyright (c) 2016-2024 Martin Donath + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +import os +import re + +from glob import iglob +from mkdocs.config.defaults import MkDocsConfig +from mkdocs.structure.pages import Page +from urllib.parse import urlencode, urlparse + +# ----------------------------------------------------------------------------- +# Hooks +# ----------------------------------------------------------------------------- + +# Determine missing translations and render language overview in the setup +# guide, including links to provide missing translations. +def on_page_markdown(markdown: str, *, page: Page, config: MkDocsConfig, files): + issue_url = "https://github.com/squidfunk/mkdocs-material/issues/new" + if page.file.src_uri != "setup/changing-the-language.md": + return + + # Collect all existing languages + names: dict[str, str] = {} + known: dict[str, dict[str, str]] = {} + for path in iglob("src/templates/partials/languages/*.html"): + with open(path, "r", encoding = "utf-8") as f: + data = f.read() + + # Extract language code and name + name, = re.findall(r"", data) + code, _ = os.path.splitext(os.path.basename(path)) + + # Map names and available translations + names[code] = name + known[code] = dict(re.findall( + r"^ \"([^\"]+)\": \"([^\"]*)\"(?:,|$)?", data, + re.MULTILINE + )) + + # Remove technical stuff + for key in [ + "direction", + "search.config.pipeline", + "search.config.lang", + "search.config.separator" + ]: + if key in known[code]: + del known[code][key] + + # Traverse all languages and compute missing translations + languages = [] + reference = set(known["en"]) + for code, name in names.items(): + miss = reference - set(known[code]) + + # Check each translations + translations: list[str] = [] + for key, value in known["en"].items(): + if key in known[code]: + translations.append( + f" \"{key}\": \"{known[code][key]}\"" + ) + else: + translations.append( + f" \"{key}\": \"{value} ⬅️\"" + ) + + # Assemble GitHub issue URL + link = urlparse(issue_url) + link = link._replace(query = urlencode({ + "template": "04-add-translations.yml", + "title": f"Update {name} translations", + "translations": "\n".join([ + "{% macro t(key) %}{{ {", + ",\n".join(translations), + "}[key] }}{% endmacro %}" + ]), + "country-flag": f":flag_{countries[code]}:" + })) + + # Add translation + languages.append({ + "flag": countries[code], + "code": code, + "name": name, + "link": link.geturl(), + "miss": miss + }) + + # Load template and render translations + env = config.theme.get_env() + template = env.get_template( "hooks/translations.html") + translations = template.module.render( + sorted(languages, key = lambda language: language["name"]) + ) + + # Replace translation marker + return markdown.replace( + "", "\n".join( + [line.lstrip() for line in translations.split("\n") + ] + )) + +# ----------------------------------------------------------------------------- +# Data +# ----------------------------------------------------------------------------- + +# Map ISO 639-1 (languages) to ISO 3166 (countries) +countries = { + "af": "za", + "az": "az", + "ar": "ae", + "be": "by", + "bg": "bg", + "bn": "bd", + "ca": "es", + "cs": "cz", + "da": "dk", + "de": "de", + "el": "gr", + "en": "us", + "eo": "eu", + "es": "es", + "et": "ee", + "eu": "es", + "fa": "ir", + "fi": "fi", + "fr": "fr", + "gl": "es", + "he": "il", + "hi": "in", + "hr": "hr", + "hu": "hu", + "hy": "am", + "id": "id", + "is": "is", + "it": "it", + "ja": "jp", + "ka": "ge", + "kn": "in", + "ko": "kr", + "ku-IQ": "iq", + "lb": "lu", + "lt": "lt", + "lv": "lv", + "mk": "mk", + "mn": "mn", + "ms": "my", + "my": "mm", + "nb": "no", + "nl": "nl", + "nn": "no", + "pl": "pl", + "pt-BR": "br", + "pt": "pt", + "ro": "ro", + "ru": "ru", + "sa": "in", + "sh": "rs", + "si": "lk", + "sk": "sk", + "sl": "si", + "sr": "rs", + "sv": "se", + "te": "in", + "th": "th", + "ta": "in", + "tl": "ph", + "tr": "tr", + "uk": "ua", + "ur": "pk", + "uz": "uz", + "vi": "vn", + "zh": "cn", + "zh-Hant": "cn", + "zh-TW": "tw" +} diff --git a/docs/plugins/meta.py b/docs/plugins/meta.py new file mode 100644 index 0000000..11eb70e --- /dev/null +++ b/docs/plugins/meta.py @@ -0,0 +1,122 @@ +# Copyright (c) 2016-2024 Martin Donath + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +import logging +import os +import posixpath + +from mergedeep import Strategy, merge +from mkdocs.exceptions import PluginError +from mkdocs.structure.files import InclusionLevel +from mkdocs.plugins import BasePlugin, event_priority +from yaml import SafeLoader, load + +from .config import MetaConfig + +# ----------------------------------------------------------------------------- +# Classes +# ----------------------------------------------------------------------------- + +# Meta plugin +class MetaPlugin(BasePlugin[MetaConfig]): + + # Construct metadata mapping + def on_files(self, files, *, config): + if not self.config.enabled: + return + + # Initialize mapping + self.meta = {} + + # Resolve and load meta files in docs directory + docs = os.path.relpath(config.docs_dir) + for file in files: + name = posixpath.basename(file.src_uri) + if not name == self.config.meta_file: + continue + + # Exclude meta file from site directory - explicitly excluding the + # meta file allows the author to use a file name without '.' prefix + file.inclusion = InclusionLevel.EXCLUDED + + # Open file and parse as YAML + with open(file.abs_src_path, encoding = "utf-8-sig") as f: + path = file.src_path + try: + self.meta[path] = load(f, SafeLoader) + + # The meta file could not be loaded because of a syntax error, + # which we display to the author with a nice error message + except Exception as e: + raise PluginError( + f"Error reading meta file '{path}' in '{docs}':\n" + f"{e}" + ) + + # Set metadata for page, if applicable (run earlier) + @event_priority(50) + def on_page_markdown(self, markdown, *, page, config, files): + if not self.config.enabled: + return + + # Start with a clean state, as we first need to apply all meta files + # that are relevant to the current page, and then merge the page meta + # on top of that to ensure that the page meta always takes precedence + # over meta files - see https://t.ly/kvCRn + meta = {} + + # Merge matching meta files in level-order + strategy = Strategy.TYPESAFE_ADDITIVE + for path, defaults in self.meta.items(): + if not page.file.src_path.startswith(os.path.dirname(path)): + continue + + # Skip if meta file was already merged - this happens in case of + # blog posts, as they need to be merged when posts are constructed, + # which is why we need to keep track of which meta files are applied + # to what pages using the `__extends` key. + page.meta.setdefault("__extends", []) + if path in page.meta["__extends"]: + continue + + # Try to merge metadata + try: + merge(meta, defaults, strategy = strategy) + page.meta["__extends"].append(path) + + # Merging the metadata with the given strategy resulted in an error, + # which we display to the author with a nice error message + except Exception as e: + docs = os.path.relpath(config.docs_dir) + raise PluginError( + f"Error merging meta file '{path}' in '{docs}':\n" + f"{e}" + ) + + # Ensure page metadata is merged last, so the author can override any + # defaults from the meta files, or even remove them entirely + page.meta = merge(meta, page.meta, strategy = strategy) + +# ----------------------------------------------------------------------------- +# Data +# ----------------------------------------------------------------------------- + +# Set up logging +log = logging.getLogger("mkdocs.material.meta") diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..f19995d --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,214 @@ + +# Copyright (c) 2016-2024 Martin Donath + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +# Project information +site_name: Maintainerr Documentation +site_url: https://docs.maintainerr.info +site_author: ydkmlt84 +site_description: >- + Documentation for the wildly popular Maintainerr project. + +# Repository +repo_name: jorenn92/maintainerr +repo_url: https://github.com/jorenn92/maintainerr + +# Configuration +theme: + name: material + custom_dir: docs/overrides + features: + - content.code.annotate + - content.code.copy + - content.footnote.tooltips + - content.tooltips + # - header.autohide + # - navigation.expand + - navigation.footer + - navigation.indexes + - navigation.instant + # - navigation.instant.prefetch + - navigation.instant.progress + # - navigation.instant.preview + # - navigation.path + # - navigation.prune + - navigation.sections + - navigation.tabs + - navigation.tabs.sticky + - navigation.top + # - navigation.tracking + - search.highlight + - search.share + - toc.follow + # - toc.integrate + palette: + - media: "(prefers-color-scheme: light)" + scheme: default + primary: grey + accent: orange + toggle: + icon: material/weather-sunny + name: Switch to dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + primary: grey + accent: orange + toggle: + icon: material/weather-night + name: Switch to light mode + font: + text: Roboto + code: Roboto Mono + favicon: images/favicon.ico + logo: images/logo_icon.svg + +# Plugins +plugins: + - blog + #- meta + - search: + separator: '[\s\u200b\-_,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|(?!\b)(?=[A-Z][a-z])' + - social: + cards_layout: default/variant + # Continuous integration + - group: + enabled: !ENV CI + plugins: + - git-revision-date-localized: + enable_creation_date: true + type: timeago + - git-committers: + repository: squidfunk/mkdocs-material + token: !ENV GH_TOKEN + - optimize + - minify: + minify_html: true + +# Hooks +hooks: + - docs/overrides/hooks/shortcodes.py + - docs/overrides/hooks/translations.py + +# Additional configuration +extra: + annotate: + json: [.s2] + status: + new: Recently added + deprecated: Deprecated + analytics: + provider: google + property: !ENV GOOGLE_ANALYTICS_KEY + feedback: + title: Was this page helpful? + ratings: + - icon: material/emoticon-happy-outline + name: This page was helpful + data: 1 + note: Thanks for your feedback! + - icon: material/emoticon-sad-outline + name: This page could be improved + data: 0 + note: >- + Thanks for your feedback! Help us improve this page by + telling us what you're missing. + social: + - icon: fontawesome/brands/github + link: https://github.com/jorenn92/maintainerr + - icon: fontawesome/brands/docker + link: https://hub.docker.com/r/jorenn92/maintainerr/ + - icon: fontawesome/brands/discord + link: https://discord.gg/WP4ZW2QYwk + +# Extensions +markdown_extensions: + - abbr + - admonition + - attr_list + - def_list + - footnotes + - md_in_html + - toc: + permalink: true + #- material.extensions.preview: + # targets: + # include: + # - changelog/index.md + # - customization.md + # - insiders/changelog/* + # - docs/extensions/* + - pymdownx.arithmatex: + generic: true + - pymdownx.betterem: + smart_enable: all + - pymdownx.caret + - pymdownx.details + - pymdownx.emoji: + emoji_generator: !!python/name:material.extensions.emoji.to_svg + emoji_index: !!python/name:material.extensions.emoji.twemoji + - pymdownx.highlight: + anchor_linenums: true + line_spans: __span + pygments_lang_class: true + - pymdownx.inlinehilite + - pymdownx.keys + - pymdownx.magiclink: + normalize_issue_symbols: true + repo_url_shorthand: true + user: squidfunk + repo: mkdocs-material + - pymdownx.mark + - pymdownx.smartsymbols + - pymdownx.snippets: + auto_append: + - includes/mkdocs.md + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format + - pymdownx.tabbed: + alternate_style: true + combine_header_slug: true + slugify: !!python/object/apply:pymdownx.slugs.slugify + kwds: + case: lower + - pymdownx.tasklist: + custom_checkbox: true + - pymdownx.tilde + +# Page tree +nav: + - Home: index.md + - Getting started: + - Installation: Installation.md + - Configuring Maintainerr: Configuration.md + - Rules: + - Rule Explanations: Rules.md + - Rules Glossary: Glossary.md + - Collections: Collections.md + - Community: + - Contributing.md + - Guides: + - Tutorials: + - Tutorials/index.md + - S01E01: Tutorials/Tutorial_S01E01.md + - S01E02: Tutorials/Tutorial_S01E02.md + - S01E03: Tutorials/Tutorial_S01E03.md