diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 8930436..eeaf0fd 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -2,12 +2,17 @@ name: Main
on:
workflow_dispatch:
+ inputs:
+ publish_artifacts:
+ description: "Publish artifacts (Y|N)"
+ required: true
+ default: "N"
release:
types: [published]
push:
branches:
- main
- - v1
+ - dev
paths-ignore:
- README.md
pull_request:
@@ -22,7 +27,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
- python-version: ["3.11"]
+ python-version: ["3.13"]
runs-on: ${{ matrix.os }}
steps:
@@ -41,71 +46,49 @@ jobs:
pip install -U pip
pip install -r requirements.txt
- - name: Build documentation
+ - name: Build and pack docs
run: |
- mkdocs build
-
- - name: Fix links
- run: |
- chmod +x ./fixlinks.sh
- ./fixlinks.sh
-
- - name: Zip built files
- run: |
- mkdir -p .build/blacksheep
- mv site/* .build/blacksheep
- cd .build
- 7z a -r site.zip blacksheep
+ ./pack.sh
- name: Upload distribution package
- uses: actions/upload-artifact@master
+ uses: actions/upload-artifact@v4
with:
- name: dist
- path: .build/site.zip
+ name: site
+ path: site.zip
publish:
+ if: github.ref == 'refs/heads/main' || (github.event_name == 'workflow_dispatch' && github.event.inputs.publish_artifacts == 'Y')
+ needs: build
runs-on: ubuntu-latest
- needs: [build]
- if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
+
steps:
- - name: Download a distribution artifact
- uses: actions/download-artifact@v2
+ - name: Checkout repository
+ uses: actions/checkout@v4
with:
- name: dist
- path: dist
+ ref: gh-pages
+ path: neoteroi
- - name: Unzip artifacts
- run: |
- 7z x -o"site" dist/site.zip
-
- - name: Use Python 3.10
- uses: actions/setup-python@v4
+ - name: Download artifact
+ uses: actions/download-artifact@v4
with:
- python-version: "3.10"
+ name: site
+ path: site
- - name: Install tools
+ - name: Unzip artifact
run: |
- pip install pyazblob
+ unzip site/site.zip -d site
- - name: Publish distribution 📦 to DEV
+ - name: Deploy to gh-pages branch
run: |
- pyazblob upload --path site/ --account-name "$ACCOUNT_NAME" -cn "\$web" -r -f
- env:
- ACCOUNT_NAME: ${{ secrets.DEV_EUW_ACCOUNT_NAME }}
- PYAZ_ACCOUNT_KEY: ${{ secrets.DEV_EUW_ACCOUNT_KEY }}
+ find neoteroi -mindepth 1 ! -name '.git' ! -name 'CNAME' ! -name 'README.md' ! -path 'neoteroi/.git/*' -exec rm -rf {} +
+ cp -r site/site/* neoteroi/
- - name: Publish distribution 📦 to PROD EUW
- if: github.ref == 'refs/heads/main'
- run: |
- pyazblob upload --path site/ --account-name "$ACCOUNT_NAME" -cn "\$web" -r -f
- env:
- ACCOUNT_NAME: ${{ secrets.PROD_EUW_ACCOUNT_NAME }}
- PYAZ_ACCOUNT_KEY: ${{ secrets.PROD_EUW_ACCOUNT_KEY }}
+ cd neoteroi
+ git config user.name "${GITHUB_ACTOR}"
+ git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
- - name: Publish distribution 📦 to PROD USE
- if: github.ref == 'refs/heads/main'
- run: |
- pyazblob upload --path site/ --account-name "$ACCOUNT_NAME" -cn "\$web" -r -f
- env:
- ACCOUNT_NAME: ${{ secrets.PROD_USE_ACCOUNT_NAME }}
- PYAZ_ACCOUNT_KEY: ${{ secrets.PROD_USE_ACCOUNT_KEY }}
+ git add .
+ git commit -m "Deploy documentation on $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
+
+ git push origin gh-pages
+ echo "Published to gh-pages"
diff --git a/.gitignore b/.gitignore
index d3b9618..1356e3a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,13 @@
site
-
venv
-
.build
-
.env
+site.zip
+deploy
+out
+.local
+
+# temporary
+rodi
+shared-assets
+copy-shared.sh
diff --git a/LICENSE b/LICENSE
index 4576a76..8b70147 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2021 Neoteroi, Roberto Prevato (roberto.prevato@gmail.com)
+Copyright (c) 2021 Roberto Prevato (roberto.prevato@gmail.com)
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/Makefile b/Makefile
deleted file mode 100644
index 3c8ee2d..0000000
--- a/Makefile
+++ /dev/null
@@ -1,38 +0,0 @@
-.PHONY: build fixlinks
-include .env
-
-build:
- mkdocs build
- ./fixlinks.sh
- rm -rf .build
- mkdir -p .build/blacksheep
- mv site/* .build/blacksheep
- echo "Ready to publish"
-
-
-build-v1:
- mkdocs build
- VERSION="v1" ./fixlinks.sh
- rm -rf .build
- mkdir -p .build/blacksheep/v1
- mv site/* .build/blacksheep/v1
- echo "Ready to publish"
-
-
-# require env variables
-publish-dev:
- PYAZ_ACCOUNT_KEY=${DEV_ACCOUNT_KEY} pyazblob upload --path .build/ --account-name "neoteroideveuwstacc" -cn "\$$web" -r -f
-
-
-publish-prod:
- PYAZ_ACCOUNT_KEY=${PROD_EUW_ACCOUNT_KEY} pyazblob upload --path .build/ --account-name "neoteroieuwstacc" -cn "\$$web" -r -f
- PYAZ_ACCOUNT_KEY=${PROD_USE_ACCOUNT_KEY} pyazblob upload --path .build/ --account-name "neoteroieusstacc" -cn "\$$web" -r -f
-
-
-fixlinks:
- ./fixlinks.sh
-
-
-clean:
- rm -rf site/
- rm -rf .build/
diff --git a/README.md b/README.md
index d792c0c..31ae9ef 100644
--- a/README.md
+++ b/README.md
@@ -1,29 +1,35 @@
-[](https://github.com/Neoteroi/BlackSheep-Docs/actions/workflows/main.yml)
+# Neoteroi documentation 📜
-# BlackSheep documentation 📜
This repository contains the source code of the documentation that gets
-published to [https://www.neoteroi.dev/blacksheep/](https://www.neoteroi.dev/blacksheep/).
+published to [https://www.neoteroi.dev/](https://www.neoteroi.dev/).
-This code has been previously hosted in [Azure DevOps](https://dev.azure.com/robertoprevato/BlackSheep).
+---
+
+Work in progress. 🚧
+The code has been modified to unify different projects.
+
+---
## How to contribute
-The documentation uses MkDocs. For information on how to use MkDocs, refer to its
-documentation.
+The documentation uses MkDocs and Material for MkDocs. For information on how
+to use these tools, refer to their documentation.
```bash
$ mkdocs serve
```
-### Environments
+## How to build the full site
-Documentation can be deployed to a DEV environment (this happens when a release is
-created from a branch different than `main`), or a PROD environment, when a release is
-created from the `main` branch.
+- Create a Python virtual environment, activate, install the dependencies.
+- Use `pack.sh` to build the full site.
+- `cd` into the generated `site` folder.
+- Start a dev servers. Recommended: use `Python http.server` module.
-* [DEV](https://neoteroideveuwstacc.z6.web.core.windows.net/blacksheep/)
-* [PROD](https://www.neoteroi.dev/blacksheep/)
+```bash
+./pack.sh
-The documentation for `blacksheep` is published under the path `/blacksheep/`
-because the same service will be used to serve documentation for other projects,
-like `rodi`.
+cd site
+
+python3.13 -m http.server 44777
+```
diff --git a/banner.xcf b/banner.xcf
deleted file mode 100644
index 8bc94e5..0000000
Binary files a/banner.xcf and /dev/null differ
diff --git a/blacksheep/Makefile b/blacksheep/Makefile
new file mode 100644
index 0000000..467ec68
--- /dev/null
+++ b/blacksheep/Makefile
@@ -0,0 +1,24 @@
+.PHONY: build fixlinks
+include .env
+
+build:
+ mkdocs build
+ ./fixlinks.sh
+ rm -rf .build
+ mkdir -p .build/blacksheep
+ mv site/* .build/blacksheep
+ echo "Ready to publish"
+
+
+build-v1:
+ mkdocs build
+ VERSION="v1" ./fixlinks.sh
+ rm -rf .build
+ mkdir -p .build/blacksheep/v1
+ mv site/* .build/blacksheep/v1
+ echo "Ready to publish"
+
+
+clean:
+ rm -rf site/
+ rm -rf .build/
diff --git a/blacksheep/README.md b/blacksheep/README.md
new file mode 100644
index 0000000..82c2c75
--- /dev/null
+++ b/blacksheep/README.md
@@ -0,0 +1,3 @@
+# BlackSheep docs 📜
+
+[www.neoteroi.dev](https://www.neoteroi.dev/blacksheep/).
diff --git a/blacksheep/archive/README.md b/blacksheep/archive/README.md
new file mode 100644
index 0000000..c2edf2a
--- /dev/null
+++ b/blacksheep/archive/README.md
@@ -0,0 +1,4 @@
+# Archived documentation
+
+This folder contains archived documentation of the web framework, not meant
+to be updated.
diff --git a/blacksheep/archive/v1.7z b/blacksheep/archive/v1.7z
new file mode 100644
index 0000000..3ecc6eb
Binary files /dev/null and b/blacksheep/archive/v1.7z differ
diff --git a/blacksheep/copy-archive.sh b/blacksheep/copy-archive.sh
new file mode 100755
index 0000000..ff603f0
--- /dev/null
+++ b/blacksheep/copy-archive.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+# This file expects an existing ./site folder created using MkDocs build.
+# It unzips archives of older versions of the documentation into the site
+# folder.
+7z x -o"site/v1" archive/v1.7z
diff --git a/docs/about.md b/blacksheep/docs/about.md
similarity index 100%
rename from docs/about.md
rename to blacksheep/docs/about.md
diff --git a/docs/anti-request-forgery.md b/blacksheep/docs/anti-request-forgery.md
similarity index 100%
rename from docs/anti-request-forgery.md
rename to blacksheep/docs/anti-request-forgery.md
diff --git a/docs/application.md b/blacksheep/docs/application.md
similarity index 100%
rename from docs/application.md
rename to blacksheep/docs/application.md
diff --git a/docs/asgi.md b/blacksheep/docs/asgi.md
similarity index 100%
rename from docs/asgi.md
rename to blacksheep/docs/asgi.md
diff --git a/docs/authentication.md b/blacksheep/docs/authentication.md
similarity index 100%
rename from docs/authentication.md
rename to blacksheep/docs/authentication.md
diff --git a/docs/authorization.md b/blacksheep/docs/authorization.md
similarity index 100%
rename from docs/authorization.md
rename to blacksheep/docs/authorization.md
diff --git a/docs/background-tasks.md b/blacksheep/docs/background-tasks.md
similarity index 100%
rename from docs/background-tasks.md
rename to blacksheep/docs/background-tasks.md
diff --git a/blacksheep/docs/behind-proxies.md b/blacksheep/docs/behind-proxies.md
new file mode 100644
index 0000000..1ca28e2
--- /dev/null
+++ b/blacksheep/docs/behind-proxies.md
@@ -0,0 +1,159 @@
+Production web applications are commonly deployed behind HTTP proxies. While
+many modern web services use cloud platforms that abstract away the need to
+manage HTTP proxies, there are still scenarios where managing load balancing
+and proxy rules is necessary. This is especially true when deploying
+applications using platforms like [Kubernetes](https://kubernetes.io/).
+
+Deploying web applications behind proxies often requires configuring routing
+based on the properties of incoming web requests. The most common examples
+include routing based on the HTTP **host** header, the prefix of the **URL
+path**, or a combination of both.
+
+This page provides an overview of the features provided by BlackSheep to handle
+these scenarios.
+
+### Routing based on hostnames
+
+```mermaid
+graph LR
+ client1["Client 1"] -->|HTTP GET https://orders.neoteroi.xyz/order/123| proxy["Routing rules"]
+ client2["Client 2"] -->|HTTP POST https://orders.neoteroi.xyz/order| proxy["Routing rules"]
+ client3["Client 3"] -->|HTTP GET https://users.neoteroi.xyz/user/123| proxy["Routing rules"]
+
+ subgraph "HTTP Proxy"
+ direction TB
+ proxy
+ end
+
+ subgraph "Servers"
+ A["Orders Web API
orders.neoteroi.xyz"]
+ B["Users Web API
users.neoteroi.xyz"]
+ C["Consents Web API
consents.neoteroi.xyz"]
+ end
+
+ proxy -->| orders.neoteroi.xyz | A
+ proxy -->| users.neoteroi.xyz | B
+ proxy -->| consents.neoteroi.xyz | C
+
+ %% Note
+ classDef note stroke:#000,stroke-width:1px;
+ note["Example: *.neoteroi.xyz is the wildcard domain used by an HTTP Proxy.
+ Several domains are configured to point to the same proxy.
+ Requests are routed to different backend services based on subdomains."]:::note
+ proxy -.-> note
+```
+
+Routing based solely on the **host** header generally does not introduce
+complications for backend web applications. However, it does require additional
+maintenance to manage multiple domain names and TLS settings, and routing
+rules.
+
+### Routing based on paths
+
+Path-based routing allows a proxy server to forward requests to different
+backend services based on a prefix of the URL path. This is particularly useful
+when hosting multiple applications or services under the same domain.
+
+```mermaid
+graph LR
+ client1["Client 1"] -->|HTTP GET https://api.neoteroi.xyz/order/123| proxy["Routing rules"]
+ client2["Client 2"] -->|HTTP POST https://api.neoteroi.xyz/order| proxy["Routing rules"]
+ client3["Client 3"] -->|HTTP GET https://api.neoteroi.xyz/user/123| proxy["Routing rules"]
+
+ subgraph "HTTP Proxy"
+ direction TB
+ proxy
+ end
+
+ subgraph "Servers"
+ A["Orders Web API"]
+ B["Users Web API"]
+ C["Consents Web API"]
+ end
+
+ proxy -->| /orders/* | A
+ proxy -->| /users/* | B
+ proxy -->| /consents/* | C
+
+ %% Note
+ classDef note stroke:#000,stroke-width:1px;
+ note["Example: api.neoteroi.xyz is the domain of an HTTP Proxy.
+ Depending on the first portion of the URL path,
the HTTP Proxy forwards the request to the appropriate server."]:::note
+ proxy -.-> note
+```
+
+When deploying behind proxies in this manner, it is crucial to ensure that the
+application properly handles being exposed at a specific path. While this works
+well for most REST APIs, it can lead to complications with redirects and for
+applications that include user interfaces.
+
+The following diagram illustrates the problem of redirects, if the path prefix
+is not handled properly.
+
+```mermaid
+sequenceDiagram
+ autonumber
+ actor User
+ participant Proxy as HTTP Proxy
(Exposes /example/)
+ participant Backend as Backend Server
(Exposed at /)
+
+ User->>Proxy: HTTP GET https://example.com/example/dashboard
+ Proxy->>Backend: HTTP GET /dashboard
+ Backend-->>Proxy: HTTP 302 Redirect to /sign-in
+ Proxy-->>User: HTTP 302 Redirect to /sign-in
+
+ note over User: The user is redirected to
https://example.com/sign-in,
which is incorrect because
the prefix /example/ is missing.
+
+ User->>Proxy: HTTP GET https://example.com/sign-in
+ Proxy-->>User: HTTP 404 Not Found
+```
+
+/// details | The example of API Gateway
+ type: info
+
+API Gateways like [AWS API Gateway](https://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/api-routing-path.html)
+and [Azure API Management](https://learn.microsoft.com/en-us/azure/api-management/api-management-key-concepts)
+use path based routing to expose many APIs behind the same domain name.
+Path based routing generally does not cause complications for REST APIs, but
+likely causes complications for web apps serving HTML documents and
+implementing interactive sign-in.
+
+///
+
+---
+
+`BlackSheep` offers two ways to deal with this scenario:
+
+- One approach, defined by the `ASGI` specification, involves specifying a
+ `root_path` in the `ASGI` server. This information is passed in the scope of
+ web requests. This method is ideal for those who prefer not to modify the
+ path at which web servers handle requests, and to configure the proxy server
+ to strip the extra prefix when forwarding requests to backend services
+ (applying URL rewrite).
+- The second approach involves configuring a prefix in the application router
+ to globally change the prefix of all request handlers. The global prefix can
+ also be set using the environment variable `APP_ROUTE_PREFIX`. This method
+ assumes that modifying the path handled by the web server is desirable to
+ align it with the path handled by the HTTP proxy server, and it is ideal
+ when using URL rewrite is not easy.
+
+For both options, `BlackSheep` handles the information provided by `root_path`
+or the application router prefix in some specific ways.
+For example, the `get_absolute_url_to_path` defined in `blacksheep.messages`
+will handle the information and return an absolute URL to the server
+according to both scenarios.
+
+| Feature | Description |
+| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `request.base_path` | Returns the `base_path` of a web request, when the ASGI scope includes a `root_path`, or a route prefix is used. |
+| `blacksheep.messages.get_absolute_url_to_path` | Returns an absolute URL path to a given destination, including the current `root_path` or route prefix. Useful when working with redirects. |
+| OpenAPI Documentation | Since version `2.1.0`, it uses relative links to serve the OpenAPI Specification files (YAML and JSON), and relative paths to support any path prefix. |
+
+/// details | Jinja2 template helper
+ type: tip
+
+The BlackSheep MVC template includes an example of helper function to
+[render absolute paths](https://github.com/Neoteroi/BlackSheep-MVC/blob/88b0672a0696d4bef4775203fae086173fd9b0fc/%7B%7Bcookiecutter.project_name%7D%7D/app/templating.py#L26)
+in Jinja templates.
+
+///
diff --git a/docs/binders.md b/blacksheep/docs/binders.md
similarity index 100%
rename from docs/binders.md
rename to blacksheep/docs/binders.md
diff --git a/docs/cache-control.md b/blacksheep/docs/cache-control.md
similarity index 98%
rename from docs/cache-control.md
rename to blacksheep/docs/cache-control.md
index 7b0c52c..82eadab 100644
--- a/docs/cache-control.md
+++ b/blacksheep/docs/cache-control.md
@@ -115,7 +115,7 @@ For example, a middleware that disables cache-control by default can be defined
class NoCacheControlMiddleware(CacheControlMiddleware):
"""
Disable client caching globally, by default, setting a
- Cache-Contro: no-cache, no-store for all responses.
+ Cache-Control: no-cache, no-store for all responses.
"""
def __init__(self) -> None:
diff --git a/docs/cli.md b/blacksheep/docs/cli.md
similarity index 100%
rename from docs/cli.md
rename to blacksheep/docs/cli.md
diff --git a/docs/client.md b/blacksheep/docs/client.md
similarity index 100%
rename from docs/client.md
rename to blacksheep/docs/client.md
diff --git a/docs/compression.md b/blacksheep/docs/compression.md
similarity index 100%
rename from docs/compression.md
rename to blacksheep/docs/compression.md
diff --git a/docs/contributing.md b/blacksheep/docs/contributing.md
similarity index 100%
rename from docs/contributing.md
rename to blacksheep/docs/contributing.md
diff --git a/docs/controllers.md b/blacksheep/docs/controllers.md
similarity index 100%
rename from docs/controllers.md
rename to blacksheep/docs/controllers.md
diff --git a/docs/cors.md b/blacksheep/docs/cors.md
similarity index 100%
rename from docs/cors.md
rename to blacksheep/docs/cors.md
diff --git a/docs/css/extra.css b/blacksheep/docs/css/extra.css
similarity index 64%
rename from docs/css/extra.css
rename to blacksheep/docs/css/extra.css
index b6a9199..6a684fd 100644
--- a/docs/css/extra.css
+++ b/blacksheep/docs/css/extra.css
@@ -1,3 +1,51 @@
+html {
+ overflow-y: scroll;
+}
+
+/* For large screens, make better use of the horizontal space */
+@media screen and (min-width: 2000px) {
+ .md-grid {
+ max-width: 98%;
+ }
+
+ .md-sidebar {
+ width: auto;
+ min-width: 15%;
+ }
+
+ body.fullscreen #fullscreen-form label {
+ display: none !important;
+ }
+}
+
+@media screen and (min-width: 1000px) {
+ html.fullscreen {
+ .md-grid {
+ max-width: 98%;
+ }
+
+ .md-sidebar {
+ width: auto;
+ min-width: 15%;
+ }
+ }
+}
+
+#fullscreen-form label {
+ display: none;
+}
+
+html:not(.fullscreen) #full-screen {
+ display: inline-block !important;
+}
+
+html.fullscreen #full-screen-exit {
+ display: inline-block !important;
+}
+
+html.fullscreen #full-screen {
+ display: none !important;
+}
[data-md-color-scheme="default"] .md-typeset [type="checkbox"]:checked + .task-list-indicator::before {
background-color: #2d319f;
diff --git a/docs/css/neoteroi.css b/blacksheep/docs/css/neoteroi.css
similarity index 100%
rename from docs/css/neoteroi.css
rename to blacksheep/docs/css/neoteroi.css
diff --git a/docs/dataprotection.md b/blacksheep/docs/dataprotection.md
similarity index 100%
rename from docs/dataprotection.md
rename to blacksheep/docs/dataprotection.md
diff --git a/docs/dependency-injection.md b/blacksheep/docs/dependency-injection.md
similarity index 100%
rename from docs/dependency-injection.md
rename to blacksheep/docs/dependency-injection.md
diff --git a/docs/develop-with-https.md b/blacksheep/docs/develop-with-https.md
similarity index 100%
rename from docs/develop-with-https.md
rename to blacksheep/docs/develop-with-https.md
diff --git a/docs/diagrams/app-events.wsd b/blacksheep/docs/diagrams/app-events.wsd
similarity index 100%
rename from docs/diagrams/app-events.wsd
rename to blacksheep/docs/diagrams/app-events.wsd
diff --git a/docs/examples/marshmallow.md b/blacksheep/docs/examples/marshmallow.md
similarity index 100%
rename from docs/examples/marshmallow.md
rename to blacksheep/docs/examples/marshmallow.md
diff --git a/docs/extensions.md b/blacksheep/docs/extensions.md
similarity index 100%
rename from docs/extensions.md
rename to blacksheep/docs/extensions.md
diff --git a/docs/getting-started.md b/blacksheep/docs/getting-started.md
similarity index 100%
rename from docs/getting-started.md
rename to blacksheep/docs/getting-started.md
diff --git a/docs/hsts.md b/blacksheep/docs/hsts.md
similarity index 100%
rename from docs/hsts.md
rename to blacksheep/docs/hsts.md
diff --git a/docs/img/app-life-cycle.svg b/blacksheep/docs/img/app-life-cycle.svg
similarity index 100%
rename from docs/img/app-life-cycle.svg
rename to blacksheep/docs/img/app-life-cycle.svg
diff --git a/docs/img/banner.png b/blacksheep/docs/img/banner.png
similarity index 100%
rename from docs/img/banner.png
rename to blacksheep/docs/img/banner.png
diff --git a/docs/img/blacksheep.png b/blacksheep/docs/img/blacksheep.png
similarity index 100%
rename from docs/img/blacksheep.png
rename to blacksheep/docs/img/blacksheep.png
diff --git a/docs/img/cli-create-demo.gif b/blacksheep/docs/img/cli-create-demo.gif
similarity index 100%
rename from docs/img/cli-create-demo.gif
rename to blacksheep/docs/img/cli-create-demo.gif
diff --git a/docs/img/cli-group-help.png b/blacksheep/docs/img/cli-group-help.png
similarity index 100%
rename from docs/img/cli-group-help.png
rename to blacksheep/docs/img/cli-group-help.png
diff --git a/docs/img/cli-help.png b/blacksheep/docs/img/cli-help.png
similarity index 100%
rename from docs/img/cli-help.png
rename to blacksheep/docs/img/cli-help.png
diff --git a/docs/img/cli-templates-details.png b/blacksheep/docs/img/cli-templates-details.png
similarity index 100%
rename from docs/img/cli-templates-details.png
rename to blacksheep/docs/img/cli-templates-details.png
diff --git a/docs/img/di-foo.png b/blacksheep/docs/img/di-foo.png
similarity index 100%
rename from docs/img/di-foo.png
rename to blacksheep/docs/img/di-foo.png
diff --git a/docs/img/favicon.ico b/blacksheep/docs/img/favicon.ico
similarity index 100%
rename from docs/img/favicon.ico
rename to blacksheep/docs/img/favicon.ico
diff --git a/docs/img/hello-model.png b/blacksheep/docs/img/hello-model.png
similarity index 100%
rename from docs/img/hello-model.png
rename to blacksheep/docs/img/hello-model.png
diff --git a/docs/img/hello-world.png b/blacksheep/docs/img/hello-world.png
similarity index 100%
rename from docs/img/hello-world.png
rename to blacksheep/docs/img/hello-world.png
diff --git a/docs/img/internal-server-error-page.png b/blacksheep/docs/img/internal-server-error-page.png
similarity index 100%
rename from docs/img/internal-server-error-page.png
rename to blacksheep/docs/img/internal-server-error-page.png
diff --git a/docs/img/logo-square.svg b/blacksheep/docs/img/logo-square.svg
similarity index 100%
rename from docs/img/logo-square.svg
rename to blacksheep/docs/img/logo-square.svg
diff --git a/docs/img/logo.svg b/blacksheep/docs/img/logo.svg
similarity index 100%
rename from docs/img/logo.svg
rename to blacksheep/docs/img/logo.svg
diff --git a/docs/img/logow.svg b/blacksheep/docs/img/logow.svg
similarity index 100%
rename from docs/img/logow.svg
rename to blacksheep/docs/img/logow.svg
diff --git a/docs/img/minimal-openapi-setup.png b/blacksheep/docs/img/minimal-openapi-setup.png
similarity index 100%
rename from docs/img/minimal-openapi-setup.png
rename to blacksheep/docs/img/minimal-openapi-setup.png
diff --git a/docs/img/mkcert-local-https.png b/blacksheep/docs/img/mkcert-local-https.png
similarity index 100%
rename from docs/img/mkcert-local-https.png
rename to blacksheep/docs/img/mkcert-local-https.png
diff --git a/docs/img/mount-oad.png b/blacksheep/docs/img/mount-oad.png
similarity index 100%
rename from docs/img/mount-oad.png
rename to blacksheep/docs/img/mount-oad.png
diff --git a/docs/img/mvc-template-home.png b/blacksheep/docs/img/mvc-template-home.png
similarity index 100%
rename from docs/img/mvc-template-home.png
rename to blacksheep/docs/img/mvc-template-home.png
diff --git a/docs/img/mvc-template-v2.png b/blacksheep/docs/img/mvc-template-v2.png
similarity index 100%
rename from docs/img/mvc-template-v2.png
rename to blacksheep/docs/img/mvc-template-v2.png
diff --git a/docs/img/mvc-template.png b/blacksheep/docs/img/mvc-template.png
similarity index 100%
rename from docs/img/mvc-template.png
rename to blacksheep/docs/img/mvc-template.png
diff --git a/docs/img/new-view.png b/blacksheep/docs/img/new-view.png
similarity index 100%
rename from docs/img/new-view.png
rename to blacksheep/docs/img/new-view.png
diff --git a/docs/img/openapi-description-summary.png b/blacksheep/docs/img/openapi-description-summary.png
similarity index 100%
rename from docs/img/openapi-description-summary.png
rename to blacksheep/docs/img/openapi-description-summary.png
diff --git a/docs/img/openapi-docs-type-hints.png b/blacksheep/docs/img/openapi-docs-type-hints.png
similarity index 100%
rename from docs/img/openapi-docs-type-hints.png
rename to blacksheep/docs/img/openapi-docs-type-hints.png
diff --git a/docs/img/openapi-docs.png b/blacksheep/docs/img/openapi-docs.png
similarity index 100%
rename from docs/img/openapi-docs.png
rename to blacksheep/docs/img/openapi-docs.png
diff --git a/docs/img/openapi-response-examples.png b/blacksheep/docs/img/openapi-response-examples.png
similarity index 100%
rename from docs/img/openapi-response-examples.png
rename to blacksheep/docs/img/openapi-response-examples.png
diff --git a/docs/img/pytest-tests.png b/blacksheep/docs/img/pytest-tests.png
similarity index 100%
rename from docs/img/pytest-tests.png
rename to blacksheep/docs/img/pytest-tests.png
diff --git a/docs/img/start-reload.png b/blacksheep/docs/img/start-reload.png
similarity index 100%
rename from docs/img/start-reload.png
rename to blacksheep/docs/img/start-reload.png
diff --git a/docs/img/todos-api-docs-schemas.png b/blacksheep/docs/img/todos-api-docs-schemas.png
similarity index 100%
rename from docs/img/todos-api-docs-schemas.png
rename to blacksheep/docs/img/todos-api-docs-schemas.png
diff --git a/docs/img/todos-api-docs.png b/blacksheep/docs/img/todos-api-docs.png
similarity index 100%
rename from docs/img/todos-api-docs.png
rename to blacksheep/docs/img/todos-api-docs.png
diff --git a/docs/img/type-hints-functions.png b/blacksheep/docs/img/type-hints-functions.png
similarity index 100%
rename from docs/img/type-hints-functions.png
rename to blacksheep/docs/img/type-hints-functions.png
diff --git a/docs/img/type-hints.png b/blacksheep/docs/img/type-hints.png
similarity index 100%
rename from docs/img/type-hints.png
rename to blacksheep/docs/img/type-hints.png
diff --git a/docs/img/vs-code-mvc.png b/blacksheep/docs/img/vs-code-mvc.png
similarity index 100%
rename from docs/img/vs-code-mvc.png
rename to blacksheep/docs/img/vs-code-mvc.png
diff --git a/docs/img/win-py-install.png b/blacksheep/docs/img/win-py-install.png
similarity index 100%
rename from docs/img/win-py-install.png
rename to blacksheep/docs/img/win-py-install.png
diff --git a/docs/index.md b/blacksheep/docs/index.md
similarity index 92%
rename from docs/index.md
rename to blacksheep/docs/index.md
index a092307..8710a6a 100644
--- a/docs/index.md
+++ b/blacksheep/docs/index.md
@@ -16,13 +16,13 @@ pip install blacksheep
## BlackSheep offers...
- A rich code API, based on dependency injection and inspired by Flask and
- ASP.NET Core
+ ASP.NET Core.
- A typing-friendly codebase, which enables a comfortable development
- experience thanks to hints when coding with IDEs
+ experience thanks to hints when coding with IDEs.
- Built-in generation of OpenAPI Documentation, supporting version 3, YAML, and
- JSON
-- A cross-platform framework, using the most modern versions of Python
-- Good performance
+ JSON.
+- A cross-platform framework, using the most modern versions of Python.
+- Good performance.
## Getting started
diff --git a/blacksheep/docs/js/fullscreen.js b/blacksheep/docs/js/fullscreen.js
new file mode 100644
index 0000000..7d18c4d
--- /dev/null
+++ b/blacksheep/docs/js/fullscreen.js
@@ -0,0 +1,26 @@
+document.addEventListener("DOMContentLoaded", function () {
+ function setFullScreen() {
+ localStorage.setItem("FULLSCREEN", "Y")
+ document.documentElement.classList.add("fullscreen");
+ }
+ function exitFullScreen() {
+ localStorage.setItem("FULLSCREEN", "N")
+ document.documentElement.classList.remove("fullscreen");
+ }
+
+ // Select all radio inputs with the name "__fullscreen"
+ const fullscreenRadios = document.querySelectorAll('input[name="__fullscreen"]');
+
+ // Add a change event listener to each radio input
+ fullscreenRadios.forEach(function (radio) {
+ radio.addEventListener("change", function () {
+ if (radio.checked) {
+ if (radio.id === "__fullscreen") {
+ setFullScreen();
+ } else if (radio.id === "__fullscreen_no") {
+ exitFullScreen();
+ }
+ }
+ });
+ });
+});
diff --git a/docs/middlewares.md b/blacksheep/docs/middlewares.md
similarity index 100%
rename from docs/middlewares.md
rename to blacksheep/docs/middlewares.md
diff --git a/docs/mounting.md b/blacksheep/docs/mounting.md
similarity index 100%
rename from docs/mounting.md
rename to blacksheep/docs/mounting.md
diff --git a/docs/mvc-project-template.md b/blacksheep/docs/mvc-project-template.md
similarity index 100%
rename from docs/mvc-project-template.md
rename to blacksheep/docs/mvc-project-template.md
diff --git a/docs/openapi.md b/blacksheep/docs/openapi.md
similarity index 100%
rename from docs/openapi.md
rename to blacksheep/docs/openapi.md
diff --git a/docs/openid-connect.md b/blacksheep/docs/openid-connect.md
similarity index 100%
rename from docs/openid-connect.md
rename to blacksheep/docs/openid-connect.md
diff --git a/docs/remotes.md b/blacksheep/docs/remotes.md
similarity index 100%
rename from docs/remotes.md
rename to blacksheep/docs/remotes.md
diff --git a/docs/request-handlers.md b/blacksheep/docs/request-handlers.md
similarity index 100%
rename from docs/request-handlers.md
rename to blacksheep/docs/request-handlers.md
diff --git a/docs/requests.md b/blacksheep/docs/requests.md
similarity index 100%
rename from docs/requests.md
rename to blacksheep/docs/requests.md
diff --git a/docs/responses.md b/blacksheep/docs/responses.md
similarity index 100%
rename from docs/responses.md
rename to blacksheep/docs/responses.md
diff --git a/docs/routing.md b/blacksheep/docs/routing.md
similarity index 100%
rename from docs/routing.md
rename to blacksheep/docs/routing.md
diff --git a/docs/server-sent-events.md b/blacksheep/docs/server-sent-events.md
similarity index 100%
rename from docs/server-sent-events.md
rename to blacksheep/docs/server-sent-events.md
diff --git a/docs/sessions.md b/blacksheep/docs/sessions.md
similarity index 100%
rename from docs/sessions.md
rename to blacksheep/docs/sessions.md
diff --git a/docs/settings.md b/blacksheep/docs/settings.md
similarity index 96%
rename from docs/settings.md
rename to blacksheep/docs/settings.md
index e5bd8d6..d50a338 100644
--- a/docs/settings.md
+++ b/blacksheep/docs/settings.md
@@ -14,6 +14,7 @@ This page describes:
| APP_ENV | Settings | This environment variable is read to determine the environment of the application. For more information, refer to [_Defining application environment_](/blacksheep/settings/#defining-application-environment). |
| APP_SHOW_ERROR_DETAILS | Settings | If "1" or "true", configures the application to display web pages with error details in case of HTTP 500 Internal Server Error. |
| APP_MOUNT_AUTO_EVENTS | Settings | If "1" or "true", automatically binds lifecycle events of mounted apps between children and parents BlackSheep applications. |
+| APP_ROUTE_PREFIX | Settings | Allows configuring a global prefix for all routes handled by the application. For more information, refer to: [Behind proxies](/blacksheep/behind-proxies/). |
| APP_SECRET_i | Secrets | Allows configuring the secrets used by the application to protect data. |
| BLACKSHEEP_SECRET_PREFIX | Secrets | Allows specifying the prefix of environment variables used to configure application secrets, defaults to "APP_SECRET" if not specified. |
diff --git a/docs/static-files.md b/blacksheep/docs/static-files.md
similarity index 100%
rename from docs/static-files.md
rename to blacksheep/docs/static-files.md
diff --git a/docs/templating.md b/blacksheep/docs/templating.md
similarity index 100%
rename from docs/templating.md
rename to blacksheep/docs/templating.md
diff --git a/docs/testing.md b/blacksheep/docs/testing.md
similarity index 100%
rename from docs/testing.md
rename to blacksheep/docs/testing.md
diff --git a/docs/timeline.yml b/blacksheep/docs/timeline.yml
similarity index 100%
rename from docs/timeline.yml
rename to blacksheep/docs/timeline.yml
diff --git a/docs/versions/migrating-to-v2.md b/blacksheep/docs/versions/migrating-to-v2.md
similarity index 100%
rename from docs/versions/migrating-to-v2.md
rename to blacksheep/docs/versions/migrating-to-v2.md
diff --git a/docs/websocket.md b/blacksheep/docs/websocket.md
similarity index 100%
rename from docs/websocket.md
rename to blacksheep/docs/websocket.md
diff --git a/mkdocs.yml b/blacksheep/mkdocs.yml
similarity index 91%
rename from mkdocs.yml
rename to blacksheep/mkdocs.yml
index f178d2f..308a855 100644
--- a/mkdocs.yml
+++ b/blacksheep/mkdocs.yml
@@ -39,6 +39,8 @@ nav:
- Compression: compression.md
- Examples:
- Using Marshmallow: examples/marshmallow.md
+ - Production deployments:
+ - Behind proxies: behind-proxies.md
- Settings: settings.md
- Binders: binders.md
- Background tasks: background-tasks.md
@@ -83,6 +85,9 @@ extra_css:
- css/neoteroi.css
- css/extra.css?v=20221120
+extra_javascript:
+ - js/fullscreen.js
+
plugins:
- search
- neoteroi.contribs:
@@ -94,6 +99,7 @@ markdown_extensions:
- admonition
- markdown.extensions.codehilite:
guess_lang: false
+ - pymdownx.blocks.details
- pymdownx.superfences:
custom_fences:
- name: mermaid
@@ -109,5 +115,5 @@ markdown_extensions:
- neoteroi.cards
- neoteroi.projects
- pymdownx.emoji:
- emoji_index: !!python/name:materialx.emoji.twemoji
- emoji_generator: !!python/name:materialx.emoji.to_svg
+ emoji_index: !!python/name:material.extensions.emoji.twemoji
+ emoji_generator: !!python/name:material.extensions.emoji.to_svg
diff --git a/overrides/main.html b/blacksheep/overrides/main.html
similarity index 88%
rename from overrides/main.html
rename to blacksheep/overrides/main.html
index 03d9e7f..427f868 100644
--- a/overrides/main.html
+++ b/blacksheep/overrides/main.html
@@ -19,6 +19,14 @@
+
{% endblock %}
{% block content %}
{% if not config.extra.is_current_version %}
diff --git a/overrides/partials/comments.html b/blacksheep/overrides/partials/comments.html
similarity index 100%
rename from overrides/partials/comments.html
rename to blacksheep/overrides/partials/comments.html
diff --git a/overrides/partials/content.html b/blacksheep/overrides/partials/content.html
similarity index 100%
rename from overrides/partials/content.html
rename to blacksheep/overrides/partials/content.html
diff --git a/blacksheep/overrides/partials/header.html b/blacksheep/overrides/partials/header.html
new file mode 100644
index 0000000..7671fe7
--- /dev/null
+++ b/blacksheep/overrides/partials/header.html
@@ -0,0 +1,76 @@
+{#-
+ This file was automatically generated - do not edit
+-#}
+{% set class = "md-header" %}
+{% if "navigation.tabs.sticky" in features %}
+ {% set class = class ~ " md-header--shadow md-header--lifted" %}
+{% elif "navigation.tabs" not in features %}
+ {% set class = class ~ " md-header--shadow" %}
+{% endif %}
+
+
+ {% if "navigation.tabs.sticky" in features %}
+ {% if "navigation.tabs" in features %}
+ {% include "partials/tabs.html" %}
+ {% endif %}
+ {% endif %}
+
diff --git a/deploy.sh b/deploy.sh
new file mode 100755
index 0000000..941cf4d
--- /dev/null
+++ b/deploy.sh
@@ -0,0 +1,35 @@
+# For the maintainer having the necessary rights to publish from the local
+# dev environment...
+
+if [[ ! -d "site" ]]; then
+ echo -e "\033[31mError: 'site' folder does not exist. Aborting.\033[0m"
+ exit 1
+fi
+
+read -p "Are you sure you want to proceed? (y/n): " confirmation
+
+if [[ "$confirmation" =~ ^[Yy]$ ]]; then
+ echo "Deploying..."
+
+ rm -rf deploy
+ mkdir deploy
+ cd deploy
+
+ git clone -b gh-pages git@github.com:Neoteroi/neoteroi.github.io.git copy
+
+ cp copy/CNAME ../site/
+ cp copy/README.md ../site/
+
+ find copy -mindepth 1 ! -name '.git' ! -name 'CNAME' ! -name 'README.md' ! -path 'copy/.git/*' -exec rm -rf {} +
+ cp -r ../site/* copy/
+
+ cd copy/
+ git add .
+ git commit -m "Deploy documentation on $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
+ git push origin gh-pages --force
+
+ echo "Published to gh-pages"
+else
+ echo "Operation canceled."
+ exit 1
+fi
diff --git a/fixlinks.sh b/fixlinks.sh
deleted file mode 100755
index 2c26cc1..0000000
--- a/fixlinks.sh
+++ /dev/null
@@ -1,55 +0,0 @@
-echo "Fixing links..."
-
-if [ -n "$VERSION" ]; then
- VERSION="/$VERSION"
-fi
-
-for i in ./site/*.html
-do
- echo "Fixing $i"
- sed -i -E 's,href="\.\.?",href="/blacksheep'$VERSION'/",' $i
- sed -i -E 's,base: ".",base: "/blacksheep'$VERSION'/",' $i
- sed -i -E 's,worker: "assets/,worker: "/blacksheep'$VERSION'/assets/,' $i
- sed -i -E 's,src="\.\/([a-z]+),src="/blacksheep'$VERSION'/\1,' $i
- sed -i -E 's,href="\.\/([a-z]+),href="/blacksheep'$VERSION'/\1,' $i
- sed -i -E 's,src="([a-z]+),src="/blacksheep'$VERSION'/\1,' $i
- sed -i -E 's,href="([a-z]+),href="/blacksheep'$VERSION'/\1,' $i
- sed -i -E 's,src="([a-z]+),src="/blacksheep'$VERSION'/\1,' $i
- sed -i -E 's,src="img/,src="/blacksheep'$VERSION'/img/,' $i
- sed -i -E 's,src="../,src="/blacksheep'$VERSION'/,' $i
- sed -i -E 's,href="../,href="/blacksheep'$VERSION'/,' $i
- sed -i -E 's,href="css/,href="/blacksheep'$VERSION'/css/,' $i
- sed -i -E 's,href="img/,href="/blacksheep'$VERSION'/img/,' $i
- sed -i -E 's,href="assets/,href="/blacksheep'$VERSION'/assets/,' $i
- sed -i -E 's,/blacksheep'$VERSION'/https://,https://,' $i
- sed -i -E 's,src="/img,src="/blacksheep'$VERSION'/img,' $i
-done
-
-
-for i in ./site/**/*.html
-do
- echo "Fixing $i"
- sed -i -E 's,href="\.\.?",href="/blacksheep'$VERSION'/",' $i
- sed -i -E 's,base: "\.\.",base: "/blacksheep'$VERSION'/",' $i
- sed -i -E 's,worker: "\.\./assets/,worker: "/blacksheep'$VERSION'/assets/,' $i
- sed -i -E 's,src="\.\/([a-z]+),src="/blacksheep'$VERSION'/\1,' $i
- sed -i -E 's,href="\.\/([a-z]+),href="/blacksheep'$VERSION'/\1,' $i
- sed -i -E 's,src="([a-z]+),src="/blacksheep'$VERSION'/\1,' $i
- sed -i -E 's,href="([a-z]+),href="/blacksheep'$VERSION'/\1,' $i
- sed -i -E 's,src="([a-z]+),src="/blacksheep'$VERSION'/\1,' $i
- sed -i -E 's,src="img/,src="/blacksheep'$VERSION'/img/,' $i
- sed -i -E 's,src="../,src="/blacksheep'$VERSION'/,' $i
- sed -i -E 's,href="../,href="/blacksheep'$VERSION'/,' $i
- sed -i -E 's,href="css/,href="/blacksheep'$VERSION'/css/,' $i
- sed -i -E 's,href="img/,href="/blacksheep'$VERSION'/img/,' $i
- sed -i -E 's,href="assets/,href="/blacksheep'$VERSION'/assets/,' $i
- sed -i -E 's,src="/img,src="/blacksheep'$VERSION'/img,' $i
- sed -i -E 's,/blacksheep'$VERSION'/https://,https://,' $i
-done
-
-for i in ./site/**/*.html
-do
- echo "Fixing $i"
- sed -i -E 's,/blacksheep'$VERSION'/https://,https://,' $i
- sed -i -E 's,/blacksheep'$VERSION'/http://,http://,' $i
-done
diff --git a/home/README.md b/home/README.md
new file mode 100644
index 0000000..a50fbc3
--- /dev/null
+++ b/home/README.md
@@ -0,0 +1,3 @@
+# Neoteroi-docs-home
+
+Source code for the homepage of [www.neoteroi.dev](https://www.neoteroi.dev).
diff --git a/home/docs/css/extra.css b/home/docs/css/extra.css
new file mode 100644
index 0000000..e2419af
--- /dev/null
+++ b/home/docs/css/extra.css
@@ -0,0 +1,46 @@
+html {
+ overflow-y: scroll;
+}
+
+:root,
+[data-md-color-scheme=default],
+[data-md-color-scheme=slate] {
+ --md-primary-fg-color: #00435c;
+ --md-footer-bg-color: #00435c;
+}
+
+[data-md-color-scheme=slate] a {
+ --md-primary-fg-color: #76e4af;
+ --md-typeset-a-color: #76e4af;
+}
+
+[data-md-color-scheme=slate] a:hover {
+ --md-accent-fg-color: #fe5252;
+}
+
+[data-md-color-scheme=slate] a:hover {
+ --md-accent-fg-color: #5cd9b6;
+}
+
+
+.epic-timeline .nt-timeline-dot .icon {
+ color: white;
+ background: white;
+ border-radius: 50%;
+}
+
+#icons-credits>div {
+ max-width: 59rem;
+ margin: auto;
+ padding: .3rem;
+}
+
+.credits-note {
+ font-style: italic;
+ font-size: 0.7rem;
+}
+
+.nt-card-image[style*="oad.png"],
+.nt-card-image[style*="spantable.png"] {
+ background-position: top !important;
+}
diff --git a/home/docs/css/neoteroi.css b/home/docs/css/neoteroi.css
new file mode 100644
index 0000000..ea55c67
--- /dev/null
+++ b/home/docs/css/neoteroi.css
@@ -0,0 +1 @@
+:root{--nt-color-0: #CD853F;--nt-color-1: #B22222;--nt-color-2: #000080;--nt-color-3: #4B0082;--nt-color-4: #3CB371;--nt-color-5: #D2B48C;--nt-color-6: #FF00FF;--nt-color-7: #98FB98;--nt-color-8: #FFEBCD;--nt-color-9: #2E8B57;--nt-color-10: #6A5ACD;--nt-color-11: #48D1CC;--nt-color-12: #FFA500;--nt-color-13: #F4A460;--nt-color-14: #A52A2A;--nt-color-15: #FFE4C4;--nt-color-16: #FF4500;--nt-color-17: #AFEEEE;--nt-color-18: #FA8072;--nt-color-19: #2F4F4F;--nt-color-20: #FFDAB9;--nt-color-21: #BC8F8F;--nt-color-22: #FFC0CB;--nt-color-23: #00FA9A;--nt-color-24: #F0FFF0;--nt-color-25: #FFFACD;--nt-color-26: #F5F5F5;--nt-color-27: #FF6347;--nt-color-28: #FFFFF0;--nt-color-29: #7FFFD4;--nt-color-30: #E9967A;--nt-color-31: #7B68EE;--nt-color-32: #FFF8DC;--nt-color-33: #0000CD;--nt-color-34: #D2691E;--nt-color-35: #708090;--nt-color-36: #5F9EA0;--nt-color-37: #008080;--nt-color-38: #008000;--nt-color-39: #FFE4E1;--nt-color-40: #FFFF00;--nt-color-41: #FFFAF0;--nt-color-42: #DCDCDC;--nt-color-43: #ADFF2F;--nt-color-44: #ADD8E6;--nt-color-45: #8B008B;--nt-color-46: #7FFF00;--nt-color-47: #800000;--nt-color-48: #20B2AA;--nt-color-49: #556B2F;--nt-color-50: #778899;--nt-color-51: #E6E6FA;--nt-color-52: #FFFAFA;--nt-color-53: #FF7F50;--nt-color-54: #FF0000;--nt-color-55: #F5DEB3;--nt-color-56: #008B8B;--nt-color-57: #66CDAA;--nt-color-58: #808000;--nt-color-59: #FAF0E6;--nt-color-60: #00BFFF;--nt-color-61: #C71585;--nt-color-62: #00FFFF;--nt-color-63: #8B4513;--nt-color-64: #F0F8FF;--nt-color-65: #FAEBD7;--nt-color-66: #8B0000;--nt-color-67: #4682B4;--nt-color-68: #F0E68C;--nt-color-69: #BDB76B;--nt-color-70: #A0522D;--nt-color-71: #FAFAD2;--nt-color-72: #FFD700;--nt-color-73: #DEB887;--nt-color-74: #E0FFFF;--nt-color-75: #8A2BE2;--nt-color-76: #32CD32;--nt-color-77: #87CEFA;--nt-color-78: #00CED1;--nt-color-79: #696969;--nt-color-80: #DDA0DD;--nt-color-81: #EE82EE;--nt-color-82: #FFB6C1;--nt-color-83: #8FBC8F;--nt-color-84: #D8BFD8;--nt-color-85: #9400D3;--nt-color-86: #A9A9A9;--nt-color-87: #FFFFE0;--nt-color-88: #FFF5EE;--nt-color-89: #FFF0F5;--nt-color-90: #FFDEAD;--nt-color-91: #800080;--nt-color-92: #B0E0E6;--nt-color-93: #9932CC;--nt-color-94: #DAA520;--nt-color-95: #F0FFFF;--nt-color-96: #40E0D0;--nt-color-97: #00FF7F;--nt-color-98: #006400;--nt-color-99: #808080;--nt-color-100: #87CEEB;--nt-color-101: #0000FF;--nt-color-102: #6495ED;--nt-color-103: #FDF5E6;--nt-color-104: #B8860B;--nt-color-105: #BA55D3;--nt-color-106: #C0C0C0;--nt-color-107: #000000;--nt-color-108: #F08080;--nt-color-109: #B0C4DE;--nt-color-110: #00008B;--nt-color-111: #6B8E23;--nt-color-112: #FFE4B5;--nt-color-113: #FFA07A;--nt-color-114: #9ACD32;--nt-color-115: #FFFFFF;--nt-color-116: #F5F5DC;--nt-color-117: #90EE90;--nt-color-118: #1E90FF;--nt-color-119: #7CFC00;--nt-color-120: #FF69B4;--nt-color-121: #F8F8FF;--nt-color-122: #F5FFFA;--nt-color-123: #00FF00;--nt-color-124: #D3D3D3;--nt-color-125: #DB7093;--nt-color-126: #DA70D6;--nt-color-127: #FF1493;--nt-color-128: #228B22;--nt-color-129: #FFEFD5;--nt-color-130: #4169E1;--nt-color-131: #191970;--nt-color-132: #9370DB;--nt-color-133: #483D8B;--nt-color-134: #FF8C00;--nt-color-135: #EEE8AA;--nt-color-136: #CD5C5C;--nt-color-137: #DC143C}:root{--nt-group-0-main: #000000;--nt-group-0-dark: #FFFFFF;--nt-group-0-light: #000000;--nt-group-0-main-bg: #F44336;--nt-group-0-dark-bg: #BA000D;--nt-group-0-light-bg: #FF7961;--nt-group-1-main: #000000;--nt-group-1-dark: #FFFFFF;--nt-group-1-light: #000000;--nt-group-1-main-bg: #E91E63;--nt-group-1-dark-bg: #B0003A;--nt-group-1-light-bg: #FF6090;--nt-group-2-main: #FFFFFF;--nt-group-2-dark: #FFFFFF;--nt-group-2-light: #000000;--nt-group-2-main-bg: #9C27B0;--nt-group-2-dark-bg: #6A0080;--nt-group-2-light-bg: #D05CE3;--nt-group-3-main: #FFFFFF;--nt-group-3-dark: #FFFFFF;--nt-group-3-light: #000000;--nt-group-3-main-bg: #673AB7;--nt-group-3-dark-bg: #320B86;--nt-group-3-light-bg: #9A67EA;--nt-group-4-main: #FFFFFF;--nt-group-4-dark: #FFFFFF;--nt-group-4-light: #000000;--nt-group-4-main-bg: #3F51B5;--nt-group-4-dark-bg: #002984;--nt-group-4-light-bg: #757DE8;--nt-group-5-main: #000000;--nt-group-5-dark: #FFFFFF;--nt-group-5-light: #000000;--nt-group-5-main-bg: #2196F3;--nt-group-5-dark-bg: #0069C0;--nt-group-5-light-bg: #6EC6FF;--nt-group-6-main: #000000;--nt-group-6-dark: #FFFFFF;--nt-group-6-light: #000000;--nt-group-6-main-bg: #03A9F4;--nt-group-6-dark-bg: #007AC1;--nt-group-6-light-bg: #67DAFF;--nt-group-7-main: #000000;--nt-group-7-dark: #000000;--nt-group-7-light: #000000;--nt-group-7-main-bg: #00BCD4;--nt-group-7-dark-bg: #008BA3;--nt-group-7-light-bg: #62EFFF;--nt-group-8-main: #000000;--nt-group-8-dark: #FFFFFF;--nt-group-8-light: #000000;--nt-group-8-main-bg: #009688;--nt-group-8-dark-bg: #00675B;--nt-group-8-light-bg: #52C7B8;--nt-group-9-main: #000000;--nt-group-9-dark: #FFFFFF;--nt-group-9-light: #000000;--nt-group-9-main-bg: #4CAF50;--nt-group-9-dark-bg: #087F23;--nt-group-9-light-bg: #80E27E;--nt-group-10-main: #000000;--nt-group-10-dark: #000000;--nt-group-10-light: #000000;--nt-group-10-main-bg: #8BC34A;--nt-group-10-dark-bg: #5A9216;--nt-group-10-light-bg: #BEF67A;--nt-group-11-main: #000000;--nt-group-11-dark: #000000;--nt-group-11-light: #000000;--nt-group-11-main-bg: #CDDC39;--nt-group-11-dark-bg: #99AA00;--nt-group-11-light-bg: #FFFF6E;--nt-group-12-main: #000000;--nt-group-12-dark: #000000;--nt-group-12-light: #000000;--nt-group-12-main-bg: #FFEB3B;--nt-group-12-dark-bg: #C8B900;--nt-group-12-light-bg: #FFFF72;--nt-group-13-main: #000000;--nt-group-13-dark: #000000;--nt-group-13-light: #000000;--nt-group-13-main-bg: #FFC107;--nt-group-13-dark-bg: #C79100;--nt-group-13-light-bg: #FFF350;--nt-group-14-main: #000000;--nt-group-14-dark: #000000;--nt-group-14-light: #000000;--nt-group-14-main-bg: #FF9800;--nt-group-14-dark-bg: #C66900;--nt-group-14-light-bg: #FFC947;--nt-group-15-main: #000000;--nt-group-15-dark: #FFFFFF;--nt-group-15-light: #000000;--nt-group-15-main-bg: #FF5722;--nt-group-15-dark-bg: #C41C00;--nt-group-15-light-bg: #FF8A50;--nt-group-16-main: #FFFFFF;--nt-group-16-dark: #FFFFFF;--nt-group-16-light: #000000;--nt-group-16-main-bg: #795548;--nt-group-16-dark-bg: #4B2C20;--nt-group-16-light-bg: #A98274;--nt-group-17-main: #000000;--nt-group-17-dark: #FFFFFF;--nt-group-17-light: #000000;--nt-group-17-main-bg: #9E9E9E;--nt-group-17-dark-bg: #707070;--nt-group-17-light-bg: #CFCFCF;--nt-group-18-main: #000000;--nt-group-18-dark: #FFFFFF;--nt-group-18-light: #000000;--nt-group-18-main-bg: #607D8B;--nt-group-18-dark-bg: #34515E;--nt-group-18-light-bg: #8EACBB}.nt-pastello{--nt-group-0-main: #000000;--nt-group-0-dark: #000000;--nt-group-0-light: #000000;--nt-group-0-main-bg: #EF9A9A;--nt-group-0-dark-bg: #BA6B6C;--nt-group-0-light-bg: #FFCCCB;--nt-group-1-main: #000000;--nt-group-1-dark: #000000;--nt-group-1-light: #000000;--nt-group-1-main-bg: #F48FB1;--nt-group-1-dark-bg: #BF5F82;--nt-group-1-light-bg: #FFC1E3;--nt-group-2-main: #000000;--nt-group-2-dark: #000000;--nt-group-2-light: #000000;--nt-group-2-main-bg: #CE93D8;--nt-group-2-dark-bg: #9C64A6;--nt-group-2-light-bg: #FFC4FF;--nt-group-3-main: #000000;--nt-group-3-dark: #000000;--nt-group-3-light: #000000;--nt-group-3-main-bg: #B39DDB;--nt-group-3-dark-bg: #836FA9;--nt-group-3-light-bg: #E6CEFF;--nt-group-4-main: #000000;--nt-group-4-dark: #000000;--nt-group-4-light: #000000;--nt-group-4-main-bg: #9FA8DA;--nt-group-4-dark-bg: #6F79A8;--nt-group-4-light-bg: #D1D9FF;--nt-group-5-main: #000000;--nt-group-5-dark: #000000;--nt-group-5-light: #000000;--nt-group-5-main-bg: #90CAF9;--nt-group-5-dark-bg: #5D99C6;--nt-group-5-light-bg: #C3FDFF;--nt-group-6-main: #000000;--nt-group-6-dark: #000000;--nt-group-6-light: #000000;--nt-group-6-main-bg: #81D4FA;--nt-group-6-dark-bg: #4BA3C7;--nt-group-6-light-bg: #B6FFFF;--nt-group-7-main: #000000;--nt-group-7-dark: #000000;--nt-group-7-light: #000000;--nt-group-7-main-bg: #80DEEA;--nt-group-7-dark-bg: #4BACB8;--nt-group-7-light-bg: #B4FFFF;--nt-group-8-main: #000000;--nt-group-8-dark: #000000;--nt-group-8-light: #000000;--nt-group-8-main-bg: #80CBC4;--nt-group-8-dark-bg: #4F9A94;--nt-group-8-light-bg: #B2FEF7;--nt-group-9-main: #000000;--nt-group-9-dark: #000000;--nt-group-9-light: #000000;--nt-group-9-main-bg: #A5D6A7;--nt-group-9-dark-bg: #75A478;--nt-group-9-light-bg: #D7FFD9;--nt-group-10-main: #000000;--nt-group-10-dark: #000000;--nt-group-10-light: #000000;--nt-group-10-main-bg: #C5E1A5;--nt-group-10-dark-bg: #94AF76;--nt-group-10-light-bg: #F8FFD7;--nt-group-11-main: #000000;--nt-group-11-dark: #000000;--nt-group-11-light: #000000;--nt-group-11-main-bg: #E6EE9C;--nt-group-11-dark-bg: #B3BC6D;--nt-group-11-light-bg: #FFFFCE;--nt-group-12-main: #000000;--nt-group-12-dark: #000000;--nt-group-12-light: #000000;--nt-group-12-main-bg: #FFF59D;--nt-group-12-dark-bg: #CBC26D;--nt-group-12-light-bg: #FFFFCF;--nt-group-13-main: #000000;--nt-group-13-dark: #000000;--nt-group-13-light: #000000;--nt-group-13-main-bg: #FFE082;--nt-group-13-dark-bg: #CAAE53;--nt-group-13-light-bg: #FFFFB3;--nt-group-14-main: #000000;--nt-group-14-dark: #000000;--nt-group-14-light: #000000;--nt-group-14-main-bg: #FFCC80;--nt-group-14-dark-bg: #CA9B52;--nt-group-14-light-bg: #FFFFB0;--nt-group-15-main: #000000;--nt-group-15-dark: #000000;--nt-group-15-light: #000000;--nt-group-15-main-bg: #FFAB91;--nt-group-15-dark-bg: #C97B63;--nt-group-15-light-bg: #FFDDC1;--nt-group-16-main: #000000;--nt-group-16-dark: #000000;--nt-group-16-light: #000000;--nt-group-16-main-bg: #BCAAA4;--nt-group-16-dark-bg: #8C7B75;--nt-group-16-light-bg: #EFDCD5;--nt-group-17-main: #000000;--nt-group-17-dark: #000000;--nt-group-17-light: #000000;--nt-group-17-main-bg: #EEEEEE;--nt-group-17-dark-bg: #BCBCBC;--nt-group-17-light-bg: #FFFFFF;--nt-group-18-main: #000000;--nt-group-18-dark: #000000;--nt-group-18-light: #000000;--nt-group-18-main-bg: #B0BEC5;--nt-group-18-dark-bg: #808E95;--nt-group-18-light-bg: #E2F1F8}.nt-group-0 .nt-plan-group-summary,.nt-group-0 .nt-timeline-dot{color:var(--nt-group-0-dark);background-color:var(--nt-group-0-dark-bg)}.nt-group-0 .period{color:var(--nt-group-0-main);background-color:var(--nt-group-0-main-bg)}.nt-group-1 .nt-plan-group-summary,.nt-group-1 .nt-timeline-dot{color:var(--nt-group-1-dark);background-color:var(--nt-group-1-dark-bg)}.nt-group-1 .period{color:var(--nt-group-1-main);background-color:var(--nt-group-1-main-bg)}.nt-group-2 .nt-plan-group-summary,.nt-group-2 .nt-timeline-dot{color:var(--nt-group-2-dark);background-color:var(--nt-group-2-dark-bg)}.nt-group-2 .period{color:var(--nt-group-2-main);background-color:var(--nt-group-2-main-bg)}.nt-group-3 .nt-plan-group-summary,.nt-group-3 .nt-timeline-dot{color:var(--nt-group-3-dark);background-color:var(--nt-group-3-dark-bg)}.nt-group-3 .period{color:var(--nt-group-3-main);background-color:var(--nt-group-3-main-bg)}.nt-group-4 .nt-plan-group-summary,.nt-group-4 .nt-timeline-dot{color:var(--nt-group-4-dark);background-color:var(--nt-group-4-dark-bg)}.nt-group-4 .period{color:var(--nt-group-4-main);background-color:var(--nt-group-4-main-bg)}.nt-group-5 .nt-plan-group-summary,.nt-group-5 .nt-timeline-dot{color:var(--nt-group-5-dark);background-color:var(--nt-group-5-dark-bg)}.nt-group-5 .period{color:var(--nt-group-5-main);background-color:var(--nt-group-5-main-bg)}.nt-group-6 .nt-plan-group-summary,.nt-group-6 .nt-timeline-dot{color:var(--nt-group-6-dark);background-color:var(--nt-group-6-dark-bg)}.nt-group-6 .period{color:var(--nt-group-6-main);background-color:var(--nt-group-6-main-bg)}.nt-group-7 .nt-plan-group-summary,.nt-group-7 .nt-timeline-dot{color:var(--nt-group-7-dark);background-color:var(--nt-group-7-dark-bg)}.nt-group-7 .period{color:var(--nt-group-7-main);background-color:var(--nt-group-7-main-bg)}.nt-group-8 .nt-plan-group-summary,.nt-group-8 .nt-timeline-dot{color:var(--nt-group-8-dark);background-color:var(--nt-group-8-dark-bg)}.nt-group-8 .period{color:var(--nt-group-8-main);background-color:var(--nt-group-8-main-bg)}.nt-group-9 .nt-plan-group-summary,.nt-group-9 .nt-timeline-dot{color:var(--nt-group-9-dark);background-color:var(--nt-group-9-dark-bg)}.nt-group-9 .period{color:var(--nt-group-9-main);background-color:var(--nt-group-9-main-bg)}.nt-group-10 .nt-plan-group-summary,.nt-group-10 .nt-timeline-dot{color:var(--nt-group-10-dark);background-color:var(--nt-group-10-dark-bg)}.nt-group-10 .period{color:var(--nt-group-10-main);background-color:var(--nt-group-10-main-bg)}.nt-group-11 .nt-plan-group-summary,.nt-group-11 .nt-timeline-dot{color:var(--nt-group-11-dark);background-color:var(--nt-group-11-dark-bg)}.nt-group-11 .period{color:var(--nt-group-11-main);background-color:var(--nt-group-11-main-bg)}.nt-group-12 .nt-plan-group-summary,.nt-group-12 .nt-timeline-dot{color:var(--nt-group-12-dark);background-color:var(--nt-group-12-dark-bg)}.nt-group-12 .period{color:var(--nt-group-12-main);background-color:var(--nt-group-12-main-bg)}.nt-group-13 .nt-plan-group-summary,.nt-group-13 .nt-timeline-dot{color:var(--nt-group-13-dark);background-color:var(--nt-group-13-dark-bg)}.nt-group-13 .period{color:var(--nt-group-13-main);background-color:var(--nt-group-13-main-bg)}.nt-group-14 .nt-plan-group-summary,.nt-group-14 .nt-timeline-dot{color:var(--nt-group-14-dark);background-color:var(--nt-group-14-dark-bg)}.nt-group-14 .period{color:var(--nt-group-14-main);background-color:var(--nt-group-14-main-bg)}.nt-group-15 .nt-plan-group-summary,.nt-group-15 .nt-timeline-dot{color:var(--nt-group-15-dark);background-color:var(--nt-group-15-dark-bg)}.nt-group-15 .period{color:var(--nt-group-15-main);background-color:var(--nt-group-15-main-bg)}.nt-group-16 .nt-plan-group-summary,.nt-group-16 .nt-timeline-dot{color:var(--nt-group-16-dark);background-color:var(--nt-group-16-dark-bg)}.nt-group-16 .period{color:var(--nt-group-16-main);background-color:var(--nt-group-16-main-bg)}.nt-group-17 .nt-plan-group-summary,.nt-group-17 .nt-timeline-dot{color:var(--nt-group-17-dark);background-color:var(--nt-group-17-dark-bg)}.nt-group-17 .period{color:var(--nt-group-17-main);background-color:var(--nt-group-17-main-bg)}.nt-group-18 .nt-plan-group-summary,.nt-group-18 .nt-timeline-dot{color:var(--nt-group-18-dark);background-color:var(--nt-group-18-dark-bg)}.nt-group-18 .period{color:var(--nt-group-18-main);background-color:var(--nt-group-18-main-bg)}.nt-error{border:2px dashed darkred;padding:0 1rem;background:#faf9ba;color:darkred}.nt-timeline{margin-top:30px}.nt-timeline .nt-timeline-title{font-size:1.1rem;margin-top:0}.nt-timeline .nt-timeline-sub-title{margin-top:0}.nt-timeline .nt-timeline-content{font-size:.8rem;border-bottom:2px dashed #ccc;padding-bottom:1.2rem}.nt-timeline.horizontal .nt-timeline-items{flex-direction:row;overflow-x:scroll}.nt-timeline.horizontal .nt-timeline-items>div{min-width:400px;margin-right:50px}.nt-timeline.horizontal.reverse .nt-timeline-items{flex-direction:row-reverse}.nt-timeline.horizontal.center .nt-timeline-before{background-image:linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%);background-repeat:no-repeat;background-size:100% 2px;background-position:0 center}.nt-timeline.horizontal.center .nt-timeline-after{background-image:linear-gradient(180deg, rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%);background-repeat:no-repeat;background-size:100% 2px;background-position:0 center}.nt-timeline.horizontal.center .nt-timeline-items{background-image:radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%);background-repeat:no-repeat;background-size:100% 2px;background-position:0 center}.nt-timeline.horizontal .nt-timeline-dot{left:50%}.nt-timeline.horizontal .nt-timeline-dot:not(.bigger){top:calc(50% - 4px)}.nt-timeline.horizontal .nt-timeline-dot.bigger{top:calc(50% - 15px)}.nt-timeline.vertical .nt-timeline-items{flex-direction:column}.nt-timeline.vertical.reverse .nt-timeline-items{flex-direction:column-reverse}.nt-timeline.vertical.center .nt-timeline-before{background:linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%) no-repeat center/2px 100%}.nt-timeline.vertical.center .nt-timeline-after{background:linear-gradient(rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%) no-repeat center/2px 100%}.nt-timeline.vertical.center .nt-timeline-items{background:radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%) no-repeat center/2px 100%}.nt-timeline.vertical.center .nt-timeline-dot{left:calc(50% - 10px)}.nt-timeline.vertical.center .nt-timeline-dot:not(.bigger){top:10px}.nt-timeline.vertical.center .nt-timeline-dot.bigger{left:calc(50% - 20px)}.nt-timeline.vertical.left{padding-left:100px}.nt-timeline.vertical.left .nt-timeline-item{padding-left:70px}.nt-timeline.vertical.left .nt-timeline-sub-title{left:-100px;width:100px}.nt-timeline.vertical.left .nt-timeline-before{background:linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%) no-repeat 30px/2px 100%}.nt-timeline.vertical.left .nt-timeline-after{background:linear-gradient(rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%) no-repeat 30px/2px 100%}.nt-timeline.vertical.left .nt-timeline-items{background:radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%) no-repeat 30px/2px 100%}.nt-timeline.vertical.left .nt-timeline-dot{left:21px;top:8px}.nt-timeline.vertical.left .nt-timeline-dot.bigger{top:0px;left:10px}.nt-timeline.vertical.right{padding-right:100px}.nt-timeline.vertical.right .nt-timeline-sub-title{right:-100px;text-align:left;width:100px}.nt-timeline.vertical.right .nt-timeline-item{padding-right:70px}.nt-timeline.vertical.right .nt-timeline-before{background:linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%) no-repeat calc(100% - 30px)/2px 100%}.nt-timeline.vertical.right .nt-timeline-after{background:linear-gradient(rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%) no-repeat calc(100% - 30px)/2px 100%}.nt-timeline.vertical.right .nt-timeline-items{background:radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%) no-repeat calc(100% - 30px)/2px 100%}.nt-timeline.vertical.right .nt-timeline-dot{right:21px;top:8px}.nt-timeline.vertical.right .nt-timeline-dot.bigger{top:10px;right:10px}.nt-timeline-items{display:flex;position:relative}.nt-timeline-items>div{min-height:100px;padding-top:2px;padding-bottom:20px}.nt-timeline-before{content:"";height:15px}.nt-timeline-after{content:"";height:60px;margin-bottom:20px}.nt-timeline-sub-title{position:absolute;width:50%;top:4px;font-size:18px;color:var(--nt-color-50)}[data-md-color-scheme=slate] .nt-timeline-sub-title{color:var(--nt-color-51)}.nt-timeline-item{position:relative}.nt-timeline.vertical.center:not(.alternate) .nt-timeline-item{padding-left:calc(50% + 40px)}.nt-timeline.vertical.center:not(.alternate) .nt-timeline-item .nt-timeline-sub-title{left:0;padding-right:40px;text-align:right}.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(odd){padding-left:calc(50% + 40px)}.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(odd) .nt-timeline-sub-title{left:0;padding-right:40px;text-align:right}.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(even){text-align:right;padding-right:calc(50% + 40px)}.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(even) .nt-timeline-sub-title{right:0;padding-left:40px;text-align:left}.nt-timeline-dot{position:relative;width:20px;height:20px;border-radius:100%;background-color:#fc5b5b;position:absolute;top:0px;z-index:2;display:flex;justify-content:center;align-items:center;box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);border:3px solid #fff}.nt-timeline-dot:not(.bigger) .icon{font-size:10px}.nt-timeline-dot.bigger{width:40px;height:40px;padding:3px}.nt-timeline-dot .icon{color:#fff}@supports not (-moz-appearance: none){details .nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(odd) .nt-timeline-sub-title,details .nt-timeline.vertical.center:not(.alternate) .nt-timeline-item .nt-timeline-sub-title{left:-40px}details .nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(even) .nt-timeline-sub-title{right:-40px}details .nt-timeline.vertical.center .nt-timeline-dot{left:calc(50% - 12px)}details .nt-timeline-dot.bigger{font-size:1rem !important}}.nt-timeline-item:nth-child(0) .nt-timeline-dot{background-color:var(--nt-color-0)}.nt-timeline-item:nth-child(1) .nt-timeline-dot{background-color:var(--nt-color-1)}.nt-timeline-item:nth-child(2) .nt-timeline-dot{background-color:var(--nt-color-2)}.nt-timeline-item:nth-child(3) .nt-timeline-dot{background-color:var(--nt-color-3)}.nt-timeline-item:nth-child(4) .nt-timeline-dot{background-color:var(--nt-color-4)}.nt-timeline-item:nth-child(5) .nt-timeline-dot{background-color:var(--nt-color-5)}.nt-timeline-item:nth-child(6) .nt-timeline-dot{background-color:var(--nt-color-6)}.nt-timeline-item:nth-child(7) .nt-timeline-dot{background-color:var(--nt-color-7)}.nt-timeline-item:nth-child(8) .nt-timeline-dot{background-color:var(--nt-color-8)}.nt-timeline-item:nth-child(9) .nt-timeline-dot{background-color:var(--nt-color-9)}.nt-timeline-item:nth-child(10) .nt-timeline-dot{background-color:var(--nt-color-10)}.nt-timeline-item:nth-child(11) .nt-timeline-dot{background-color:var(--nt-color-11)}.nt-timeline-item:nth-child(12) .nt-timeline-dot{background-color:var(--nt-color-12)}.nt-timeline-item:nth-child(13) .nt-timeline-dot{background-color:var(--nt-color-13)}.nt-timeline-item:nth-child(14) .nt-timeline-dot{background-color:var(--nt-color-14)}.nt-timeline-item:nth-child(15) .nt-timeline-dot{background-color:var(--nt-color-15)}.nt-timeline-item:nth-child(16) .nt-timeline-dot{background-color:var(--nt-color-16)}.nt-timeline-item:nth-child(17) .nt-timeline-dot{background-color:var(--nt-color-17)}.nt-timeline-item:nth-child(18) .nt-timeline-dot{background-color:var(--nt-color-18)}.nt-timeline-item:nth-child(19) .nt-timeline-dot{background-color:var(--nt-color-19)}.nt-timeline-item:nth-child(20) .nt-timeline-dot{background-color:var(--nt-color-20)}:root{--nt-scrollbar-color: #2751b0;--nt-plan-actions-height: 24px;--nt-units-background: #ff9800;--nt-months-background: #2751b0;--nt-plan-vertical-line-color: #a3a3a3ad}.nt-pastello{--nt-scrollbar-color: #9fb8f4;--nt-units-background: #f5dc82;--nt-months-background: #5b7fd1}[data-md-color-scheme=slate]{--nt-units-background: #003773}[data-md-color-scheme=slate] .nt-pastello{--nt-units-background: #3f4997}.nt-plan-root{min-height:200px;scrollbar-width:20px;scrollbar-color:var(--nt-scrollbar-color);display:flex}.nt-plan-root ::-webkit-scrollbar{width:20px}.nt-plan-root ::-webkit-scrollbar-track{box-shadow:inset 0 0 5px gray;border-radius:10px}.nt-plan-root ::-webkit-scrollbar-thumb{background:var(--nt-scrollbar-color);border-radius:10px}.nt-plan-root .nt-plan{flex:80%}.nt-plan-root.no-groups .nt-plan-periods{padding-left:0}.nt-plan-root.no-groups .nt-plan-group-summary{display:none}.nt-plan-root .nt-timeline-dot.bigger{top:-10px}.nt-plan-root .nt-timeline-dot.bigger[title]{cursor:help}.nt-plan{white-space:nowrap;overflow-x:auto;display:flex}.nt-plan .ug-timeline-dot{left:368px;top:-8px;cursor:help}.months{display:flex}.month{flex:auto;display:inline-block;box-shadow:rgba(0,0,0,.2) 0px 3px 1px -2px,rgba(0,0,0,.14) 0px 2px 2px 0px,rgba(0,0,0,.12) 0px 1px 5px 0px inset;background-color:var(--nt-months-background);color:#fff;text-transform:uppercase;font-family:Roboto,Helvetica,Arial,sans-serif;padding:2px 5px;font-size:12px;border:1px solid #000;width:150px;border-radius:8px}.nt-plan-group-activities{flex:auto;position:relative}.nt-vline{border-left:1px dashed var(--nt-plan-vertical-line-color);height:100%;left:0;position:absolute;margin-left:-0.5px;top:0;-webkit-transition:all .5s linear !important;-moz-transition:all .5s linear !important;-ms-transition:all .5s linear !important;-o-transition:all .5s linear !important;transition:all .5s linear !important;z-index:-2}.nt-plan-activity{display:flex;margin:2px 0;background-color:rgba(187,187,187,.2509803922)}.actions{height:var(--nt-plan-actions-height)}.actions{position:relative}.period{display:inline-block;height:var(--nt-plan-actions-height);width:120px;position:absolute;left:0px;background:#1da1f2;border-radius:5px;transition:all .5s;cursor:help;-webkit-transition:width 1s ease-in-out;-moz-transition:width 1s ease-in-out;-o-transition:width 1s ease-in-out;transition:width 1s ease-in-out}.period .nt-tooltip{display:none;top:30px;position:relative;padding:1rem;text-align:center;font-size:12px}.period:hover .nt-tooltip{display:inline-block}.period-0{left:340px;visibility:visible;background-color:#456165}.period-1{left:40px;visibility:visible;background-color:green}.period-2{left:120px;visibility:visible;background-color:pink;width:80px}.period-3{left:190px;visibility:visible;background-color:darkred;width:150px}.weeks>span,.days>span{height:25px}.weeks>span{display:inline-block;margin:0;padding:0;font-weight:bold}.weeks>span .week-text{font-size:10px;position:absolute;display:inline-block;padding:3px 4px}.days{z-index:-2;position:relative}.day-text{font-size:10px;position:absolute;display:inline-block;padding:3px 4px}.period span{font-size:12px;vertical-align:top;margin-left:4px;color:#000;background:rgba(255,255,255,.6588235294);border-radius:6px;padding:0 4px}.weeks,.days{height:20px;display:flex;box-sizing:content-box}.months{display:flex}.week,.day{height:20px;position:relative;border:1;flex:auto;border:2px solid #fff;border-radius:4px;background-color:var(--nt-units-background);cursor:help}.years{display:flex}.year{text-align:center;border-right:1px solid var(--nt-plan-vertical-line-color);font-weight:bold}.year:first-child{border-left:1px solid var(--nt-plan-vertical-line-color)}.year:first-child:last-child{width:100%}.quarters{display:flex}.quarter{width:12.5%;text-align:center;border-right:1px solid var(--nt-plan-vertical-line-color);font-weight:bold}.quarter:first-child{border-left:1px solid var(--nt-plan-vertical-line-color)}.nt-plan-group{margin:20px 0;position:relative}.nt-plan-group{display:flex}.nt-plan-group-summary{background:#2751b0;width:150px;white-space:normal;padding:.1rem .5rem;border-radius:5px;color:#fff;z-index:3}.nt-plan-group-summary p{margin:0;padding:0;font-size:.6rem;color:#fff}.nt-plan-group-summary,.month,.period,.week,.day,.nt-tooltip{border:3px solid #fff;box-shadow:0 2px 3px -1px rgba(0,0,0,.2),0 3px 3px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)}.nt-plan-periods{padding-left:150px}.months{z-index:2;position:relative}.weeks{position:relative;top:-2px;z-index:0}.month,.quarter,.year,.week,.day,.nt-tooltip{font-family:Roboto,Helvetica,Arial,sans-serif;box-sizing:border-box}.nt-cards.nt-grid{display:grid;grid-auto-columns:1fr;gap:.5rem;max-width:100vw;overflow-x:auto;padding:1px}.nt-cards.nt-grid.cols-1{grid-template-columns:repeat(1, 1fr)}.nt-cards.nt-grid.cols-2{grid-template-columns:repeat(2, 1fr)}.nt-cards.nt-grid.cols-3{grid-template-columns:repeat(3, 1fr)}.nt-cards.nt-grid.cols-4{grid-template-columns:repeat(4, 1fr)}.nt-cards.nt-grid.cols-5{grid-template-columns:repeat(5, 1fr)}.nt-cards.nt-grid.cols-6{grid-template-columns:repeat(6, 1fr)}@media only screen and (max-width: 400px){.nt-cards.nt-grid{grid-template-columns:repeat(1, 1fr) !important}}.nt-card{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)}.nt-card:hover{box-shadow:0 2px 2px 0 rgba(0,0,0,.24),0 3px 1px -2px rgba(0,0,0,.3),0 1px 5px 0 rgba(0,0,0,.22)}[data-md-color-scheme=slate] .nt-card{box-shadow:0 2px 2px 0 rgba(4,40,33,.14),0 3px 1px -2px rgba(40,86,94,.47),0 1px 5px 0 rgba(139,252,255,.64)}[data-md-color-scheme=slate] .nt-card:hover{box-shadow:0 2px 2px 0 rgba(0,255,206,.14),0 3px 1px -2px rgba(33,156,177,.47),0 1px 5px 0 rgba(96,251,255,.64)}.nt-card>a{color:var(--md-default-fg-color)}.nt-card>a>div{cursor:pointer}.nt-card{padding:5px;margin-bottom:.5rem}.nt-card-title{font-size:1rem;font-weight:bold;margin:4px 0 8px 0;line-height:22px}.nt-card-content{padding:.4rem .8rem .8rem .8rem}.nt-card-text{font-size:14px;padding:0;margin:0}.nt-card .nt-card-image{text-align:center;border-radius:2px;background-position:center center;background-size:cover;background-repeat:no-repeat;min-height:120px}.nt-card .nt-card-image.tags img{margin-top:12px}.nt-card .nt-card-image img{height:105px;margin-top:5px}.nt-card a:hover,.nt-card a:focus{color:var(--md-accent-fg-color)}.nt-card h2{margin:0}.span-table-wrapper table{border-collapse:collapse;margin-bottom:2rem;border-radius:.1rem}.span-table td,.span-table th{padding:.2rem;background-color:var(--md-default-bg-color);font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto;border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.span-table tr:first-child td{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.span-table td:first-child{border-left:.05rem solid var(--md-typeset-table-color)}.span-table td:last-child{border-right:.05rem solid var(--md-typeset-table-color)}.span-table tr:last-child{border-bottom:.05rem solid var(--md-typeset-table-color)}.span-table [colspan],.span-table [rowspan]{font-weight:bold;border:.05rem solid var(--md-typeset-table-color)}.span-table tr:not(:first-child):hover td:not([colspan]):not([rowspan]),.span-table td[colspan]:hover,.span-table td[rowspan]:hover{background-color:rgba(0,0,0,.035);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset;transition:background-color 125ms}
diff --git a/home/docs/img/blacksheep.png b/home/docs/img/blacksheep.png
new file mode 100644
index 0000000..8012226
Binary files /dev/null and b/home/docs/img/blacksheep.png differ
diff --git a/home/docs/img/favicon.ico b/home/docs/img/favicon.ico
new file mode 100644
index 0000000..38ef778
Binary files /dev/null and b/home/docs/img/favicon.ico differ
diff --git a/home/docs/img/gantt.png b/home/docs/img/gantt.png
new file mode 100644
index 0000000..f0468e8
Binary files /dev/null and b/home/docs/img/gantt.png differ
diff --git a/home/docs/img/index.png b/home/docs/img/index.png
new file mode 100644
index 0000000..3e07b96
Binary files /dev/null and b/home/docs/img/index.png differ
diff --git a/home/docs/img/neoteroi-w.png b/home/docs/img/neoteroi-w.png
new file mode 100644
index 0000000..370eedd
Binary files /dev/null and b/home/docs/img/neoteroi-w.png differ
diff --git a/home/docs/img/neoteroi-w.svg b/home/docs/img/neoteroi-w.svg
new file mode 100644
index 0000000..45fd9e7
--- /dev/null
+++ b/home/docs/img/neoteroi-w.svg
@@ -0,0 +1,74 @@
+
+
diff --git a/home/docs/img/neoteroi-white.png b/home/docs/img/neoteroi-white.png
new file mode 100644
index 0000000..ed2363b
Binary files /dev/null and b/home/docs/img/neoteroi-white.png differ
diff --git a/home/docs/img/neoteroi.ico b/home/docs/img/neoteroi.ico
new file mode 100644
index 0000000..11cd814
Binary files /dev/null and b/home/docs/img/neoteroi.ico differ
diff --git a/home/docs/img/neoteroi.svg b/home/docs/img/neoteroi.svg
new file mode 100644
index 0000000..2ffdeef
--- /dev/null
+++ b/home/docs/img/neoteroi.svg
@@ -0,0 +1,75 @@
+
+
diff --git a/home/docs/index.md b/home/docs/index.md
new file mode 100644
index 0000000..8e247c6
--- /dev/null
+++ b/home/docs/index.md
@@ -0,0 +1,24 @@
+# Neoteroi documentation site
+
+Neoteroi is a collection of open source projects for Python. This site contains
+the documentation of some of the projects.
+
+::cards:: image-bg
+
+- title: BlackSheep
+ content: |
+ Fast ASGI web framework for Python.
+ image: ./img/blacksheep.png
+ url: /blacksheep/
+
+- title: MkDocs-Plugins
+ content: |
+ Plugins for Python Markdown designed for MkDocs and Material for MkDocs.
+ image: ./img/gantt.png
+ url: /mkdocs-plugins/
+
+::/cards::
+
+---
+
+[Neoteroi in GitHub :fontawesome-brands-github:](https://github.com/Neoteroi)
diff --git a/home/mkdocs.yml b/home/mkdocs.yml
new file mode 100644
index 0000000..59e178d
--- /dev/null
+++ b/home/mkdocs.yml
@@ -0,0 +1,61 @@
+site_name: Neoteroi Docs
+site_author: Roberto Prevato
+site_description: Welcome page of Neoteroi documentation site
+site_url: https://www.neoteroi.dev/
+repo_name: Neoteroi
+repo_url: https://github.com/Neoteroi
+edit_uri: ""
+
+nav:
+ - Index: index.md
+ - BlackSheep: /blacksheep/
+ - MkDocs-Plugins: /mkdocs-plugins/
+
+theme:
+ palette:
+ - scheme: slate
+ toggle:
+ icon: material/toggle-switch
+ name: Switch to light mode
+ - scheme: default
+ toggle:
+ icon: material/toggle-switch-off-outline
+ name: Switch to dark mode
+ name: "material"
+ custom_dir: overrides/
+ highlightjs: true
+ favicon: img/neoteroi.ico
+ logo: img/neoteroi-w.svg
+ font:
+ text: Roboto
+ code: Roboto Mono
+ icon:
+ repo: fontawesome/brands/github
+
+plugins: []
+
+extra_css:
+ - css/extra.css
+ - css/neoteroi.css
+
+markdown_extensions:
+ - admonition
+ - markdown.extensions.codehilite:
+ guess_lang: false
+ - pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:pymdownx.superfences.fence_code_format
+ - pymdownx.tasklist:
+ custom_checkbox: true
+ - pymdownx.tabbed:
+ alternate_style: true
+ - toc:
+ permalink: true
+ - neoteroi.timeline
+ - neoteroi.cards
+ - neoteroi.projects
+ - pymdownx.emoji:
+ emoji_index: !!python/name:material.extensions.emoji.twemoji
+ emoji_generator: !!python/name:material.extensions.emoji.to_svg
diff --git a/home/overrides/main.html b/home/overrides/main.html
new file mode 100644
index 0000000..eaf11a4
--- /dev/null
+++ b/home/overrides/main.html
@@ -0,0 +1,30 @@
+{% extends "base.html" %}
+{% block extrahead %}
+{% set title = config.site_name %}
+{% if page and page.title and not page.is_homepage %}
+{% set title = config.site_name ~ " - " ~ page.title | striptags %}
+{% endif %}
+{% set image = config.site_url ~ 'img/index.png' %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
+{% block content %}
+{{ super() }}
+{% endblock %}
+{% block analytics %}
+{% endblock %}
+{% block footer %}
+{{ super() }}
+{% endblock %}
diff --git a/mkdocs-plugins/.gitignore b/mkdocs-plugins/.gitignore
new file mode 100644
index 0000000..e03f543
--- /dev/null
+++ b/mkdocs-plugins/.gitignore
@@ -0,0 +1,7 @@
+.env
+.build
+logs
+site
+
+venv
+venv2
diff --git a/mkdocs-plugins/README.md b/mkdocs-plugins/README.md
new file mode 100644
index 0000000..4d110b2
--- /dev/null
+++ b/mkdocs-plugins/README.md
@@ -0,0 +1,3 @@
+# MkDocs Plugins docs 📜
+
+[www.neoteroi.dev](https://www.neoteroi.dev/mkdocs-plugins/).
diff --git a/mkdocs-plugins/debug.py b/mkdocs-plugins/debug.py
new file mode 100644
index 0000000..2d55742
--- /dev/null
+++ b/mkdocs-plugins/debug.py
@@ -0,0 +1,6 @@
+"""
+Run this module to debug a plugin.
+"""
+from mkdocs.commands import serve
+
+serve.serve(dev_addr="localhost:44555", livereload=True)
diff --git a/mkdocs-plugins/dev/convert.py b/mkdocs-plugins/dev/convert.py
new file mode 100644
index 0000000..3cbb07d
--- /dev/null
+++ b/mkdocs-plugins/dev/convert.py
@@ -0,0 +1,73 @@
+"""
+Utility to convert examples from one format to another.
+
+Example:
+python convert.py to-yaml ../docs/timeline/timeline-1.json ../docs/timeline/timeline-1.yaml
+"""
+import json
+import re
+import sys
+from typing import Optional
+
+import click
+import yaml
+from essentials.json import dumps as friendly_json_dumps
+
+_YAML_EXT = re.compile(r"\.ya?ml$", re.IGNORECASE)
+_JSON_EXT = re.compile(r"\.json$", re.IGNORECASE)
+
+
+def read_text_file(file_path: str) -> str:
+ with open(file_path, "rt", encoding="utf8") as source_file:
+ return source_file.read()
+
+
+def write_text_file(file_path: str, contents: str):
+ with open(file_path, "wt", encoding="utf8") as dest_file:
+ dest_file.write(contents)
+
+
+@click.group()
+def convert():
+ pass
+
+
+@click.command("to-json")
+@click.argument("source")
+@click.argument("destination", required=False)
+def yaml_to_json(source: str, destination: Optional[str]):
+ if _YAML_EXT.search(source):
+ contents = read_text_file(source)
+ data = yaml.safe_load(contents)
+ output = friendly_json_dumps(data, indent=4, ensure_ascii=False)
+ if destination:
+ write_text_file(destination, output)
+ else:
+ print(output)
+ else:
+ click.echo(f'Unsupported source: "{source}"')
+ sys.exit(1)
+
+
+@click.command("to-yaml")
+@click.argument("source")
+@click.argument("destination", required=False)
+def json_to_yaml(source: str, destination: Optional[str]):
+ if _JSON_EXT.search(source):
+ contents = read_text_file(source)
+ data = json.loads(contents)
+ if destination:
+ write_text_file(destination, yaml.dump(data))
+ else:
+ print(yaml.dump(data))
+ else:
+ click.echo(f'Unsupported source: "{source}"')
+ sys.exit(1)
+
+
+convert.add_command(yaml_to_json)
+convert.add_command(json_to_yaml)
+
+
+if __name__ == "__main__":
+ convert()
diff --git a/mkdocs-plugins/docs/about.md b/mkdocs-plugins/docs/about.md
new file mode 100644
index 0000000..091ea9a
--- /dev/null
+++ b/mkdocs-plugins/docs/about.md
@@ -0,0 +1,8 @@
+# About Neoteroi
+
+[Neoteroi](https://github.com/Neoteroi/) is a collection of projects for Python.
+
+## The project's home
+The project source code is in [GitHub](https://github.com/Neoteroi/mkdocs-plugins).
+
+The documentation source code is in [GitHub](https://github.com/Neoteroi/mkdocs-plugins-docs).
diff --git a/mkdocs-plugins/docs/cards.md b/mkdocs-plugins/docs/cards.md
new file mode 100644
index 0000000..cfba291
--- /dev/null
+++ b/mkdocs-plugins/docs/cards.md
@@ -0,0 +1,404 @@
+The cards extension provides eye-catching card-like controls, to display information that
+usually includes images.
+
+::cards::
+
+- title: Zeus
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/001-zeus.png
+
+- title: Athena
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/003-athena.png
+
+- title: Poseidon
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/007-poseidon.png
+
+- title: Artemis
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/021-artemis.png
+
+- title: Ares
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/006-ares.png
+
+- title: Nike
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/027-nike.png
+
+::/cards::
+
+
+
+## How to use
+
+Edit your `mkdocs.yml` file to include the extra CSS file from Neoteroi
+mkdocs-plugins and the `neoteroi.cards` extension:
+
+```yaml
+
+extra_css:
+ - css/neoteroi-mkdocs.css
+ ...
+
+markdown_extensions:
+ - neoteroi.cards
+ ...
+
+```
+
+## Input object
+
+### Examples
+
+=== "JSON"
+
+ ```json
+ ::cards::
+
+ [
+ {
+ "title": "Zeus",
+ "content": "Lorem ipsum dolor sit amet.",
+ "image": "./img/icons/001-zeus.png"
+ },
+ {
+ "title": "Athena",
+ "content": "Lorem ipsum dolor sit amet.",
+ "image": "./img/icons/003-athena.png"
+ },
+ {
+ "title": "Poseidon",
+ "content": "Lorem ipsum dolor sit amet.",
+ "image": "./img/icons/007-poseidon.png"
+ },
+ {
+ "title": "Artemis",
+ "content": "Lorem ipsum dolor sit amet.",
+ "image": "./img/icons/021-artemis.png"
+ },
+ {
+ "title": "Ares",
+ "content": "Lorem ipsum dolor sit amet.",
+ "image": "./img/icons/006-ares.png"
+ },
+ {
+ "title": "Nike",
+ "content": "Lorem ipsum dolor sit amet.",
+ "image": "./img/icons/027-nike.png"
+ }
+ ]
+
+ ::/cards::
+ ```
+
+=== "YAML"
+
+ ```yaml
+ ::cards::
+
+ - title: Zeus
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/001-zeus.png
+
+ - title: Athena
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/003-athena.png
+
+ - title: Poseidon
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/007-poseidon.png
+
+ - title: Artemis
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/021-artemis.png
+
+ - title: Ares
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/006-ares.png
+
+ - title: Nike
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/027-nike.png
+
+ ::/cards::
+ ```
+
+=== "File source"
+
+ ```
+ [cards(./settings.yaml)]
+
+ [cards(./settings.json)]
+
+ # with view options:
+
+ [cards image-bg(./settings.yaml)]
+ ```
+
+=== "URL source"
+
+ ```
+ [cards(https://www.neoteroi.dev/examples/cards.yaml)]
+
+ [cards(https://www.neoteroi.dev/examples/cards.json)]
+
+ # with view options:
+
+ [cards image-bg(https://www.neoteroi.dev/examples/cards.yaml)]
+ ```
+
+### Schema
+
+```mermaid
+classDiagram
+direction LR
+
+class CardItem {
+ title: str
+ url: str | None = None
+ content: str | None = None
+ icon: str | None = None
+ key: str | None = None
+ image: str | Image | None = None
+}
+
+class Cards {
+ items: Array of CardItem
+}
+
+Cards --> CardItem
+
+```
+
+```python
+
+@dataclass
+class Image:
+ url: str
+ height: int | None = None
+ width: int | None = None
+ alt: str | None = None
+
+
+@dataclass
+class CardItem:
+ title: str
+ url: str | None = None
+ content: str | None = None
+ icon: str | None = None
+ key: str | None = None
+ image: str | Image | None = None
+
+
+@dataclass
+class Cards:
+ items: List[CardItem]
+
+```
+
+## Options
+
+### Image properties
+
+To control some image properties, specify images as objects:
+
+```
+::cards::
+
+- title: Zeus
+ content: Lorem ipsum dolor sit amet.
+ image:
+ url: ./img/icons/001-zeus.png
+ alt: Some alt text
+
+- title: Athena
+ content: Lorem ipsum dolor sit amet.
+ image:
+ url: ./img/icons/003-athena.png
+ alt: Some other alt text
+
+::/cards::
+```
+
+It is possible to define `alt`, `height`, and `width` properties for the image.
+
+If not specified, `alt` is set using the card's title.
+
+### Cards with links
+
+Specify a `url` property in the items to have links in cards.
+
+```yaml
+- title: Zeus
+ content: |
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua.
+ image: ./img/icons/001-zeus.png
+ url: https://en.wikipedia.org/wiki/Zeus
+```
+
+::cards:: image-tags
+
+- title: Zeus
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/001-zeus.png
+ url: https://en.wikipedia.org/wiki/Zeus
+
+- title: Athena
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/003-athena.png
+ url: https://en.wikipedia.org/wiki/Athena
+
+- title: Poseidon
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/007-poseidon.png
+ url: https://en.wikipedia.org/wiki/Poseidon
+
+- title: Artemis
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/021-artemis.png
+ url: https://en.wikipedia.org/wiki/Artemis
+
+- title: Ares
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/006-ares.png
+ url: https://en.wikipedia.org/wiki/Ares
+
+- title: Nike
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/027-nike.png
+ url: https://en.wikipedia.org/wiki/Nike_(mythology)
+
+::/cards::
+
+### Controlling the number of columns
+
+To control the number of columns in the grid, use the `cols` view option.
+
+```diff
+cols=4
+```
+
+[cards cols="4"(./docs/cards/example-1.yaml)]
+
+```diff
+cols=2
+```
+
+[cards cols="2"(./docs/cards/example-1.yaml)]
+
+```diff
+cols=1
+```
+
+[cards cols="1"(./docs/cards/example-1.yaml)]
+
+!!! tip "Columns and CSS rules"
+ Only values between 1 and 6 are supported out of the box. To handle
+ greater values, also specify a custom CSS rule in your MkDocs settings like
+ the following:
+
+ ```css
+ .nt-cards.nt-grid.cols-10 {
+ grid-template-columns: repeat(10, 1fr);
+ }
+ ```
+
+### Using background images
+
+To display images using background images instead of image elements, use the
+`image-bg` view option.
+
+```diff
+::cards:: image-bg
+```
+
+::cards:: image-bg
+
+- title: Zeus
+ content: |
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua.
+ image: ../img/icons/001-zeus.png
+
+- title: Athena
+ content: Lorem ipsum dolor sit amet.
+ image: ../img/icons/003-athena.png
+
+- title: Poseidon
+ content: Lorem ipsum dolor sit amet.
+ image: ../img/icons/007-poseidon.png
+
+::/cards::
+
+## Bigger
+
+::cards:: cols=3 class_name="bigger"
+
+- title: Zeus
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/001-zeus.png
+
+- title: Athena
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/003-athena.png
+
+- title: Poseidon
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/007-poseidon.png
+
+- title: Artemis
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/021-artemis.png
+
+- title: Ares
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/006-ares.png
+
+- title: Nike
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/027-nike.png
+
+::/cards::
+
+## Smaller
+
+
+
+::cards:: cols=6 class_name="smaller"
+
+- title: Zeus
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/001-zeus.png
+
+- title: Athena
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/003-athena.png
+
+- title: Poseidon
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/007-poseidon.png
+
+- title: Artemis
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/021-artemis.png
+
+- title: Ares
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/006-ares.png
+
+- title: Nike
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/027-nike.png
+
+::/cards::
diff --git a/mkdocs-plugins/docs/cards/example-1.yaml b/mkdocs-plugins/docs/cards/example-1.yaml
new file mode 100644
index 0000000..e2f425a
--- /dev/null
+++ b/mkdocs-plugins/docs/cards/example-1.yaml
@@ -0,0 +1,24 @@
+- title: Zeus
+ content: |
+ Lorem ipsum dolor sit amet.
+ image: ./img/icons/001-zeus.png
+
+- title: Athena
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/003-athena.png
+
+- title: Poseidon
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/007-poseidon.png
+
+- title: Artemis
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/021-artemis.png
+
+- title: Ares
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/006-ares.png
+
+- title: Nike
+ content: Lorem ipsum dolor sit amet.
+ image: ./img/icons/027-nike.png
diff --git a/mkdocs-plugins/docs/contribs.md b/mkdocs-plugins/docs/contribs.md
new file mode 100644
index 0000000..10be1d8
--- /dev/null
+++ b/mkdocs-plugins/docs/contribs.md
@@ -0,0 +1,107 @@
+The contribs extension provides a plugin to display information about contributors and
+last commit time for each page. It works using the `git` CLI to obtain information from
+the same repository where the MkDocs site is built. It doesn't require any communication
+with third party services, but it requires running in a Git repository.
+
+!!! danger "Git support only"
+ This plugin works only with Git repositories, and since it obtains
+ information from the git repository that contains the MkDocs site, it is
+ designed for scenarios in which the documentation is built in CI/CD jobs.
+
+This plugin doesn't require any markup code: it modifies each page to include
+contributors' list and last commit time affecting the file, and it doesn't
+require integration with any external API.
+
+## How to use
+
+Install using `pip install neoteroi-mkdocs`.
+Edit your `mkdocs.yml` file to include the extra CSS file from Neoteroi
+mkdocs-plugins and the `neoteroi.contribs` plugin for MkDocs:
+
+
+```yaml
+extra_css:
+ - css/neoteroi-mkdocs.css
+ ...
+
+plugins:
+ - search
+ - neoteroi.contribs
+```
+
+## Information
+
+The plugin displays the last modified time for each file (the last time a file
+was modified in the Git repository), and the list of contributors, sorted by
+commits count.
+
+
+
+## Options
+
+| Name | Description | Type | Default |
+| --------------------- | ------------------------------------------------------------------------- | ------------------------------- | ------------------- |
+| `contributors_label` | The label text for contributors list. | `str` | "Contributors" |
+| `last_modified_label` | The label text for last modified time. | `str` | "Last modified on" |
+| `last_modified_time` | Whether to display the last modified time for each page. | `bool` | `True` |
+| `time_format` | Format to be used for dates. | `str` | "%Y-%m-%d %H:%M:%S" |
+| `contributors` | Information about contributors, use to configure images for contributors. | `list` of `contributor` objects | `[]` |
+
+The plugin by default displays dots with the first two initials of each committer's name,
+displaying pictures requires explicit configuration, described below.
+
+### Contributor object
+
+The following table describes the objects that can be used to provide more
+information about contributors.
+
+| Property | Description | Type | Default |
+| -------- | -------------------------------------------- | ----- | ------- |
+| `email` | Email address used to match a contributor. | `str` | `n/a` |
+| `image` | URL to be used as image for the contributor. | `str` | "" |
+
+### Including contributors' pictures
+
+To configure images for contributors, use the `contributors` option like in the
+following example:
+
+```yaml
+ - neoteroi.contribs:
+ contributors:
+ - email: roberto.prevato@gmail.com
+ image: https://avatars.githubusercontent.com/u/2576032?s=400&u=d8d880e8ed05bb170877dd3d561d8301c4beeeed&v=4
+
+```
+
+Contributors are matched by email address, and the image is used if configured.
+
+## Adding information with txt files
+
+In some cases contributors information cannot be obtained from Git history:
+for example following a history rewrite, or because contributors for a page
+are not competent in Git, and contributed in ways that are not visible in the
+commit history. For these situations, the contribs plugin supports adding more
+information using `*.contribs.txt` files, with a structure like the following:
+
+```
+# Comment
+Charlie Brown (3)
+Sally Brown (1)
+Roberto Prevato (10)
+```
+
+The name of the .txt files must match the name of the page:
+
+- `example.md`
+- `example.contribs.txt`
+
+## Under the hood
+
+This plugin works by using the following `git` commands, to obtain contributors
+and the last modified time of a file:
+
+```
+git shortlog --summary --numbered --email "README.md"
+
+git log -1 --pretty="format:%ci" "README.md"
+```
diff --git a/mkdocs-plugins/docs/credits.md b/mkdocs-plugins/docs/credits.md
new file mode 100644
index 0000000..6334e30
--- /dev/null
+++ b/mkdocs-plugins/docs/credits.md
@@ -0,0 +1,37 @@
+The pictures used in the examples are made by by max.icons from www.flaticon.com.
+
+::cards:: cols=4
+
+- title: Zeus
+ image: ./img/icons/001-zeus.png
+ url: https://www.flaticon.com/authors/maxicons
+
+- title: Athena
+ image: ./img/icons/003-athena.png
+ url: https://www.flaticon.com/authors/maxicons
+
+- title: Poseidon
+ image: ./img/icons/007-poseidon.png
+ url: https://www.flaticon.com/authors/maxicons
+
+- title: Artemis
+ image: ./img/icons/021-artemis.png
+ url: https://www.flaticon.com/authors/maxicons
+
+- title: Ares
+ image: ./img/icons/006-ares.png
+ url: https://www.flaticon.com/authors/maxicons
+
+- title: Nike
+ image: ./img/icons/027-nike.png
+ url: https://www.flaticon.com/authors/maxicons
+
+- title: Prometheus
+ image: ./img/icons/019-prometheus.png
+ url: https://www.flaticon.com/authors/maxicons
+
+- title: Medusa
+ image: ./img/icons/018-medusa.png
+ url: https://www.flaticon.com/authors/maxicons
+
+::/cards::
diff --git a/mkdocs-plugins/docs/css/extra.css b/mkdocs-plugins/docs/css/extra.css
new file mode 100644
index 0000000..e2419af
--- /dev/null
+++ b/mkdocs-plugins/docs/css/extra.css
@@ -0,0 +1,46 @@
+html {
+ overflow-y: scroll;
+}
+
+:root,
+[data-md-color-scheme=default],
+[data-md-color-scheme=slate] {
+ --md-primary-fg-color: #00435c;
+ --md-footer-bg-color: #00435c;
+}
+
+[data-md-color-scheme=slate] a {
+ --md-primary-fg-color: #76e4af;
+ --md-typeset-a-color: #76e4af;
+}
+
+[data-md-color-scheme=slate] a:hover {
+ --md-accent-fg-color: #fe5252;
+}
+
+[data-md-color-scheme=slate] a:hover {
+ --md-accent-fg-color: #5cd9b6;
+}
+
+
+.epic-timeline .nt-timeline-dot .icon {
+ color: white;
+ background: white;
+ border-radius: 50%;
+}
+
+#icons-credits>div {
+ max-width: 59rem;
+ margin: auto;
+ padding: .3rem;
+}
+
+.credits-note {
+ font-style: italic;
+ font-size: 0.7rem;
+}
+
+.nt-card-image[style*="oad.png"],
+.nt-card-image[style*="spantable.png"] {
+ background-position: top !important;
+}
diff --git a/mkdocs-plugins/docs/css/neoteroi.css b/mkdocs-plugins/docs/css/neoteroi.css
new file mode 100644
index 0000000..6aebfb7
--- /dev/null
+++ b/mkdocs-plugins/docs/css/neoteroi.css
@@ -0,0 +1 @@
+:root{--nt-color-0: #CD853F;--nt-color-1: #B22222;--nt-color-2: #000080;--nt-color-3: #4B0082;--nt-color-4: #3CB371;--nt-color-5: #D2B48C;--nt-color-6: #FF00FF;--nt-color-7: #98FB98;--nt-color-8: #FFEBCD;--nt-color-9: #2E8B57;--nt-color-10: #6A5ACD;--nt-color-11: #48D1CC;--nt-color-12: #FFA500;--nt-color-13: #F4A460;--nt-color-14: #A52A2A;--nt-color-15: #FFE4C4;--nt-color-16: #FF4500;--nt-color-17: #AFEEEE;--nt-color-18: #FA8072;--nt-color-19: #2F4F4F;--nt-color-20: #FFDAB9;--nt-color-21: #BC8F8F;--nt-color-22: #FFC0CB;--nt-color-23: #00FA9A;--nt-color-24: #F0FFF0;--nt-color-25: #FFFACD;--nt-color-26: #F5F5F5;--nt-color-27: #FF6347;--nt-color-28: #FFFFF0;--nt-color-29: #7FFFD4;--nt-color-30: #E9967A;--nt-color-31: #7B68EE;--nt-color-32: #FFF8DC;--nt-color-33: #0000CD;--nt-color-34: #D2691E;--nt-color-35: #708090;--nt-color-36: #5F9EA0;--nt-color-37: #008080;--nt-color-38: #008000;--nt-color-39: #FFE4E1;--nt-color-40: #FFFF00;--nt-color-41: #FFFAF0;--nt-color-42: #DCDCDC;--nt-color-43: #ADFF2F;--nt-color-44: #ADD8E6;--nt-color-45: #8B008B;--nt-color-46: #7FFF00;--nt-color-47: #800000;--nt-color-48: #20B2AA;--nt-color-49: #556B2F;--nt-color-50: #778899;--nt-color-51: #E6E6FA;--nt-color-52: #FFFAFA;--nt-color-53: #FF7F50;--nt-color-54: #FF0000;--nt-color-55: #F5DEB3;--nt-color-56: #008B8B;--nt-color-57: #66CDAA;--nt-color-58: #808000;--nt-color-59: #FAF0E6;--nt-color-60: #00BFFF;--nt-color-61: #C71585;--nt-color-62: #00FFFF;--nt-color-63: #8B4513;--nt-color-64: #F0F8FF;--nt-color-65: #FAEBD7;--nt-color-66: #8B0000;--nt-color-67: #4682B4;--nt-color-68: #F0E68C;--nt-color-69: #BDB76B;--nt-color-70: #A0522D;--nt-color-71: #FAFAD2;--nt-color-72: #FFD700;--nt-color-73: #DEB887;--nt-color-74: #E0FFFF;--nt-color-75: #8A2BE2;--nt-color-76: #32CD32;--nt-color-77: #87CEFA;--nt-color-78: #00CED1;--nt-color-79: #696969;--nt-color-80: #DDA0DD;--nt-color-81: #EE82EE;--nt-color-82: #FFB6C1;--nt-color-83: #8FBC8F;--nt-color-84: #D8BFD8;--nt-color-85: #9400D3;--nt-color-86: #A9A9A9;--nt-color-87: #FFFFE0;--nt-color-88: #FFF5EE;--nt-color-89: #FFF0F5;--nt-color-90: #FFDEAD;--nt-color-91: #800080;--nt-color-92: #B0E0E6;--nt-color-93: #9932CC;--nt-color-94: #DAA520;--nt-color-95: #F0FFFF;--nt-color-96: #40E0D0;--nt-color-97: #00FF7F;--nt-color-98: #006400;--nt-color-99: #808080;--nt-color-100: #87CEEB;--nt-color-101: #0000FF;--nt-color-102: #6495ED;--nt-color-103: #FDF5E6;--nt-color-104: #B8860B;--nt-color-105: #BA55D3;--nt-color-106: #C0C0C0;--nt-color-107: #000000;--nt-color-108: #F08080;--nt-color-109: #B0C4DE;--nt-color-110: #00008B;--nt-color-111: #6B8E23;--nt-color-112: #FFE4B5;--nt-color-113: #FFA07A;--nt-color-114: #9ACD32;--nt-color-115: #FFFFFF;--nt-color-116: #F5F5DC;--nt-color-117: #90EE90;--nt-color-118: #1E90FF;--nt-color-119: #7CFC00;--nt-color-120: #FF69B4;--nt-color-121: #F8F8FF;--nt-color-122: #F5FFFA;--nt-color-123: #00FF00;--nt-color-124: #D3D3D3;--nt-color-125: #DB7093;--nt-color-126: #DA70D6;--nt-color-127: #FF1493;--nt-color-128: #228B22;--nt-color-129: #FFEFD5;--nt-color-130: #4169E1;--nt-color-131: #191970;--nt-color-132: #9370DB;--nt-color-133: #483D8B;--nt-color-134: #FF8C00;--nt-color-135: #EEE8AA;--nt-color-136: #CD5C5C;--nt-color-137: #DC143C}:root{--nt-group-0-main: #000000;--nt-group-0-dark: #FFFFFF;--nt-group-0-light: #000000;--nt-group-0-main-bg: #F44336;--nt-group-0-dark-bg: #BA000D;--nt-group-0-light-bg: #FF7961;--nt-group-1-main: #000000;--nt-group-1-dark: #FFFFFF;--nt-group-1-light: #000000;--nt-group-1-main-bg: #E91E63;--nt-group-1-dark-bg: #B0003A;--nt-group-1-light-bg: #FF6090;--nt-group-2-main: #FFFFFF;--nt-group-2-dark: #FFFFFF;--nt-group-2-light: #000000;--nt-group-2-main-bg: #9C27B0;--nt-group-2-dark-bg: #6A0080;--nt-group-2-light-bg: #D05CE3;--nt-group-3-main: #FFFFFF;--nt-group-3-dark: #FFFFFF;--nt-group-3-light: #000000;--nt-group-3-main-bg: #673AB7;--nt-group-3-dark-bg: #320B86;--nt-group-3-light-bg: #9A67EA;--nt-group-4-main: #FFFFFF;--nt-group-4-dark: #FFFFFF;--nt-group-4-light: #000000;--nt-group-4-main-bg: #3F51B5;--nt-group-4-dark-bg: #002984;--nt-group-4-light-bg: #757DE8;--nt-group-5-main: #000000;--nt-group-5-dark: #FFFFFF;--nt-group-5-light: #000000;--nt-group-5-main-bg: #2196F3;--nt-group-5-dark-bg: #0069C0;--nt-group-5-light-bg: #6EC6FF;--nt-group-6-main: #000000;--nt-group-6-dark: #FFFFFF;--nt-group-6-light: #000000;--nt-group-6-main-bg: #03A9F4;--nt-group-6-dark-bg: #007AC1;--nt-group-6-light-bg: #67DAFF;--nt-group-7-main: #000000;--nt-group-7-dark: #000000;--nt-group-7-light: #000000;--nt-group-7-main-bg: #00BCD4;--nt-group-7-dark-bg: #008BA3;--nt-group-7-light-bg: #62EFFF;--nt-group-8-main: #000000;--nt-group-8-dark: #FFFFFF;--nt-group-8-light: #000000;--nt-group-8-main-bg: #009688;--nt-group-8-dark-bg: #00675B;--nt-group-8-light-bg: #52C7B8;--nt-group-9-main: #000000;--nt-group-9-dark: #FFFFFF;--nt-group-9-light: #000000;--nt-group-9-main-bg: #4CAF50;--nt-group-9-dark-bg: #087F23;--nt-group-9-light-bg: #80E27E;--nt-group-10-main: #000000;--nt-group-10-dark: #000000;--nt-group-10-light: #000000;--nt-group-10-main-bg: #8BC34A;--nt-group-10-dark-bg: #5A9216;--nt-group-10-light-bg: #BEF67A;--nt-group-11-main: #000000;--nt-group-11-dark: #000000;--nt-group-11-light: #000000;--nt-group-11-main-bg: #CDDC39;--nt-group-11-dark-bg: #99AA00;--nt-group-11-light-bg: #FFFF6E;--nt-group-12-main: #000000;--nt-group-12-dark: #000000;--nt-group-12-light: #000000;--nt-group-12-main-bg: #FFEB3B;--nt-group-12-dark-bg: #C8B900;--nt-group-12-light-bg: #FFFF72;--nt-group-13-main: #000000;--nt-group-13-dark: #000000;--nt-group-13-light: #000000;--nt-group-13-main-bg: #FFC107;--nt-group-13-dark-bg: #C79100;--nt-group-13-light-bg: #FFF350;--nt-group-14-main: #000000;--nt-group-14-dark: #000000;--nt-group-14-light: #000000;--nt-group-14-main-bg: #FF9800;--nt-group-14-dark-bg: #C66900;--nt-group-14-light-bg: #FFC947;--nt-group-15-main: #000000;--nt-group-15-dark: #FFFFFF;--nt-group-15-light: #000000;--nt-group-15-main-bg: #FF5722;--nt-group-15-dark-bg: #C41C00;--nt-group-15-light-bg: #FF8A50;--nt-group-16-main: #FFFFFF;--nt-group-16-dark: #FFFFFF;--nt-group-16-light: #000000;--nt-group-16-main-bg: #795548;--nt-group-16-dark-bg: #4B2C20;--nt-group-16-light-bg: #A98274;--nt-group-17-main: #000000;--nt-group-17-dark: #FFFFFF;--nt-group-17-light: #000000;--nt-group-17-main-bg: #9E9E9E;--nt-group-17-dark-bg: #707070;--nt-group-17-light-bg: #CFCFCF;--nt-group-18-main: #000000;--nt-group-18-dark: #FFFFFF;--nt-group-18-light: #000000;--nt-group-18-main-bg: #607D8B;--nt-group-18-dark-bg: #34515E;--nt-group-18-light-bg: #8EACBB}.nt-pastello{--nt-group-0-main: #000000;--nt-group-0-dark: #000000;--nt-group-0-light: #000000;--nt-group-0-main-bg: #EF9A9A;--nt-group-0-dark-bg: #BA6B6C;--nt-group-0-light-bg: #FFCCCB;--nt-group-1-main: #000000;--nt-group-1-dark: #000000;--nt-group-1-light: #000000;--nt-group-1-main-bg: #F48FB1;--nt-group-1-dark-bg: #BF5F82;--nt-group-1-light-bg: #FFC1E3;--nt-group-2-main: #000000;--nt-group-2-dark: #000000;--nt-group-2-light: #000000;--nt-group-2-main-bg: #CE93D8;--nt-group-2-dark-bg: #9C64A6;--nt-group-2-light-bg: #FFC4FF;--nt-group-3-main: #000000;--nt-group-3-dark: #000000;--nt-group-3-light: #000000;--nt-group-3-main-bg: #B39DDB;--nt-group-3-dark-bg: #836FA9;--nt-group-3-light-bg: #E6CEFF;--nt-group-4-main: #000000;--nt-group-4-dark: #000000;--nt-group-4-light: #000000;--nt-group-4-main-bg: #9FA8DA;--nt-group-4-dark-bg: #6F79A8;--nt-group-4-light-bg: #D1D9FF;--nt-group-5-main: #000000;--nt-group-5-dark: #000000;--nt-group-5-light: #000000;--nt-group-5-main-bg: #90CAF9;--nt-group-5-dark-bg: #5D99C6;--nt-group-5-light-bg: #C3FDFF;--nt-group-6-main: #000000;--nt-group-6-dark: #000000;--nt-group-6-light: #000000;--nt-group-6-main-bg: #81D4FA;--nt-group-6-dark-bg: #4BA3C7;--nt-group-6-light-bg: #B6FFFF;--nt-group-7-main: #000000;--nt-group-7-dark: #000000;--nt-group-7-light: #000000;--nt-group-7-main-bg: #80DEEA;--nt-group-7-dark-bg: #4BACB8;--nt-group-7-light-bg: #B4FFFF;--nt-group-8-main: #000000;--nt-group-8-dark: #000000;--nt-group-8-light: #000000;--nt-group-8-main-bg: #80CBC4;--nt-group-8-dark-bg: #4F9A94;--nt-group-8-light-bg: #B2FEF7;--nt-group-9-main: #000000;--nt-group-9-dark: #000000;--nt-group-9-light: #000000;--nt-group-9-main-bg: #A5D6A7;--nt-group-9-dark-bg: #75A478;--nt-group-9-light-bg: #D7FFD9;--nt-group-10-main: #000000;--nt-group-10-dark: #000000;--nt-group-10-light: #000000;--nt-group-10-main-bg: #C5E1A5;--nt-group-10-dark-bg: #94AF76;--nt-group-10-light-bg: #F8FFD7;--nt-group-11-main: #000000;--nt-group-11-dark: #000000;--nt-group-11-light: #000000;--nt-group-11-main-bg: #E6EE9C;--nt-group-11-dark-bg: #B3BC6D;--nt-group-11-light-bg: #FFFFCE;--nt-group-12-main: #000000;--nt-group-12-dark: #000000;--nt-group-12-light: #000000;--nt-group-12-main-bg: #FFF59D;--nt-group-12-dark-bg: #CBC26D;--nt-group-12-light-bg: #FFFFCF;--nt-group-13-main: #000000;--nt-group-13-dark: #000000;--nt-group-13-light: #000000;--nt-group-13-main-bg: #FFE082;--nt-group-13-dark-bg: #CAAE53;--nt-group-13-light-bg: #FFFFB3;--nt-group-14-main: #000000;--nt-group-14-dark: #000000;--nt-group-14-light: #000000;--nt-group-14-main-bg: #FFCC80;--nt-group-14-dark-bg: #CA9B52;--nt-group-14-light-bg: #FFFFB0;--nt-group-15-main: #000000;--nt-group-15-dark: #000000;--nt-group-15-light: #000000;--nt-group-15-main-bg: #FFAB91;--nt-group-15-dark-bg: #C97B63;--nt-group-15-light-bg: #FFDDC1;--nt-group-16-main: #000000;--nt-group-16-dark: #000000;--nt-group-16-light: #000000;--nt-group-16-main-bg: #BCAAA4;--nt-group-16-dark-bg: #8C7B75;--nt-group-16-light-bg: #EFDCD5;--nt-group-17-main: #000000;--nt-group-17-dark: #000000;--nt-group-17-light: #000000;--nt-group-17-main-bg: #EEEEEE;--nt-group-17-dark-bg: #BCBCBC;--nt-group-17-light-bg: #FFFFFF;--nt-group-18-main: #000000;--nt-group-18-dark: #000000;--nt-group-18-light: #000000;--nt-group-18-main-bg: #B0BEC5;--nt-group-18-dark-bg: #808E95;--nt-group-18-light-bg: #E2F1F8}.nt-group-0 .nt-plan-group-summary,.nt-group-0 .nt-timeline-dot{color:var(--nt-group-0-dark);background-color:var(--nt-group-0-dark-bg)}.nt-group-0 .period{color:var(--nt-group-0-main);background-color:var(--nt-group-0-main-bg)}.nt-group-1 .nt-plan-group-summary,.nt-group-1 .nt-timeline-dot{color:var(--nt-group-1-dark);background-color:var(--nt-group-1-dark-bg)}.nt-group-1 .period{color:var(--nt-group-1-main);background-color:var(--nt-group-1-main-bg)}.nt-group-2 .nt-plan-group-summary,.nt-group-2 .nt-timeline-dot{color:var(--nt-group-2-dark);background-color:var(--nt-group-2-dark-bg)}.nt-group-2 .period{color:var(--nt-group-2-main);background-color:var(--nt-group-2-main-bg)}.nt-group-3 .nt-plan-group-summary,.nt-group-3 .nt-timeline-dot{color:var(--nt-group-3-dark);background-color:var(--nt-group-3-dark-bg)}.nt-group-3 .period{color:var(--nt-group-3-main);background-color:var(--nt-group-3-main-bg)}.nt-group-4 .nt-plan-group-summary,.nt-group-4 .nt-timeline-dot{color:var(--nt-group-4-dark);background-color:var(--nt-group-4-dark-bg)}.nt-group-4 .period{color:var(--nt-group-4-main);background-color:var(--nt-group-4-main-bg)}.nt-group-5 .nt-plan-group-summary,.nt-group-5 .nt-timeline-dot{color:var(--nt-group-5-dark);background-color:var(--nt-group-5-dark-bg)}.nt-group-5 .period{color:var(--nt-group-5-main);background-color:var(--nt-group-5-main-bg)}.nt-group-6 .nt-plan-group-summary,.nt-group-6 .nt-timeline-dot{color:var(--nt-group-6-dark);background-color:var(--nt-group-6-dark-bg)}.nt-group-6 .period{color:var(--nt-group-6-main);background-color:var(--nt-group-6-main-bg)}.nt-group-7 .nt-plan-group-summary,.nt-group-7 .nt-timeline-dot{color:var(--nt-group-7-dark);background-color:var(--nt-group-7-dark-bg)}.nt-group-7 .period{color:var(--nt-group-7-main);background-color:var(--nt-group-7-main-bg)}.nt-group-8 .nt-plan-group-summary,.nt-group-8 .nt-timeline-dot{color:var(--nt-group-8-dark);background-color:var(--nt-group-8-dark-bg)}.nt-group-8 .period{color:var(--nt-group-8-main);background-color:var(--nt-group-8-main-bg)}.nt-group-9 .nt-plan-group-summary,.nt-group-9 .nt-timeline-dot{color:var(--nt-group-9-dark);background-color:var(--nt-group-9-dark-bg)}.nt-group-9 .period{color:var(--nt-group-9-main);background-color:var(--nt-group-9-main-bg)}.nt-group-10 .nt-plan-group-summary,.nt-group-10 .nt-timeline-dot{color:var(--nt-group-10-dark);background-color:var(--nt-group-10-dark-bg)}.nt-group-10 .period{color:var(--nt-group-10-main);background-color:var(--nt-group-10-main-bg)}.nt-group-11 .nt-plan-group-summary,.nt-group-11 .nt-timeline-dot{color:var(--nt-group-11-dark);background-color:var(--nt-group-11-dark-bg)}.nt-group-11 .period{color:var(--nt-group-11-main);background-color:var(--nt-group-11-main-bg)}.nt-group-12 .nt-plan-group-summary,.nt-group-12 .nt-timeline-dot{color:var(--nt-group-12-dark);background-color:var(--nt-group-12-dark-bg)}.nt-group-12 .period{color:var(--nt-group-12-main);background-color:var(--nt-group-12-main-bg)}.nt-group-13 .nt-plan-group-summary,.nt-group-13 .nt-timeline-dot{color:var(--nt-group-13-dark);background-color:var(--nt-group-13-dark-bg)}.nt-group-13 .period{color:var(--nt-group-13-main);background-color:var(--nt-group-13-main-bg)}.nt-group-14 .nt-plan-group-summary,.nt-group-14 .nt-timeline-dot{color:var(--nt-group-14-dark);background-color:var(--nt-group-14-dark-bg)}.nt-group-14 .period{color:var(--nt-group-14-main);background-color:var(--nt-group-14-main-bg)}.nt-group-15 .nt-plan-group-summary,.nt-group-15 .nt-timeline-dot{color:var(--nt-group-15-dark);background-color:var(--nt-group-15-dark-bg)}.nt-group-15 .period{color:var(--nt-group-15-main);background-color:var(--nt-group-15-main-bg)}.nt-group-16 .nt-plan-group-summary,.nt-group-16 .nt-timeline-dot{color:var(--nt-group-16-dark);background-color:var(--nt-group-16-dark-bg)}.nt-group-16 .period{color:var(--nt-group-16-main);background-color:var(--nt-group-16-main-bg)}.nt-group-17 .nt-plan-group-summary,.nt-group-17 .nt-timeline-dot{color:var(--nt-group-17-dark);background-color:var(--nt-group-17-dark-bg)}.nt-group-17 .period{color:var(--nt-group-17-main);background-color:var(--nt-group-17-main-bg)}.nt-group-18 .nt-plan-group-summary,.nt-group-18 .nt-timeline-dot{color:var(--nt-group-18-dark);background-color:var(--nt-group-18-dark-bg)}.nt-group-18 .period{color:var(--nt-group-18-main);background-color:var(--nt-group-18-main-bg)}.nt-error{border:2px dashed darkred;padding:0 1rem;background:#faf9ba;color:darkred}.nt-timeline{margin-top:30px}.nt-timeline .nt-timeline-title{font-size:1.1rem;margin-top:0}.nt-timeline .nt-timeline-sub-title{margin-top:0}.nt-timeline .nt-timeline-content{font-size:.8rem;border-bottom:2px dashed #ccc;padding-bottom:1.2rem}.nt-timeline.horizontal .nt-timeline-items{flex-direction:row;overflow-x:scroll}.nt-timeline.horizontal .nt-timeline-items>div{min-width:400px;margin-right:50px}.nt-timeline.horizontal.reverse .nt-timeline-items{flex-direction:row-reverse}.nt-timeline.horizontal.center .nt-timeline-before{background-image:linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%);background-repeat:no-repeat;background-size:100% 2px;background-position:0 center}.nt-timeline.horizontal.center .nt-timeline-after{background-image:linear-gradient(180deg, rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%);background-repeat:no-repeat;background-size:100% 2px;background-position:0 center}.nt-timeline.horizontal.center .nt-timeline-items{background-image:radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%);background-repeat:no-repeat;background-size:100% 2px;background-position:0 center}.nt-timeline.horizontal .nt-timeline-dot{left:50%}.nt-timeline.horizontal .nt-timeline-dot:not(.bigger){top:calc(50% - 4px)}.nt-timeline.horizontal .nt-timeline-dot.bigger{top:calc(50% - 15px)}.nt-timeline.vertical .nt-timeline-items{flex-direction:column}.nt-timeline.vertical.reverse .nt-timeline-items{flex-direction:column-reverse}.nt-timeline.vertical.center .nt-timeline-before{background:linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%) no-repeat center/2px 100%}.nt-timeline.vertical.center .nt-timeline-after{background:linear-gradient(rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%) no-repeat center/2px 100%}.nt-timeline.vertical.center .nt-timeline-items{background:radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%) no-repeat center/2px 100%}.nt-timeline.vertical.center .nt-timeline-dot{left:calc(50% - 10px)}.nt-timeline.vertical.center .nt-timeline-dot:not(.bigger){top:10px}.nt-timeline.vertical.center .nt-timeline-dot.bigger{left:calc(50% - 20px)}.nt-timeline.vertical.left{padding-left:100px}.nt-timeline.vertical.left .nt-timeline-item{padding-left:70px}.nt-timeline.vertical.left .nt-timeline-sub-title{left:-100px;width:100px}.nt-timeline.vertical.left .nt-timeline-before{background:linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%) no-repeat 30px/2px 100%}.nt-timeline.vertical.left .nt-timeline-after{background:linear-gradient(rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%) no-repeat 30px/2px 100%}.nt-timeline.vertical.left .nt-timeline-items{background:radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%) no-repeat 30px/2px 100%}.nt-timeline.vertical.left .nt-timeline-dot{left:21px;top:8px}.nt-timeline.vertical.left .nt-timeline-dot.bigger{top:0px;left:10px}.nt-timeline.vertical.right{padding-right:100px}.nt-timeline.vertical.right .nt-timeline-sub-title{right:-100px;text-align:left;width:100px}.nt-timeline.vertical.right .nt-timeline-item{padding-right:70px}.nt-timeline.vertical.right .nt-timeline-before{background:linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%) no-repeat calc(100% - 30px)/2px 100%}.nt-timeline.vertical.right .nt-timeline-after{background:linear-gradient(rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%) no-repeat calc(100% - 30px)/2px 100%}.nt-timeline.vertical.right .nt-timeline-items{background:radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%) no-repeat calc(100% - 30px)/2px 100%}.nt-timeline.vertical.right .nt-timeline-dot{right:21px;top:8px}.nt-timeline.vertical.right .nt-timeline-dot.bigger{top:10px;right:10px}.nt-timeline-items{display:flex;position:relative}.nt-timeline-items>div{min-height:100px;padding-top:2px;padding-bottom:20px}.nt-timeline-before{content:"";height:15px}.nt-timeline-after{content:"";height:60px;margin-bottom:20px}.nt-timeline-sub-title{position:absolute;width:50%;top:4px;font-size:18px;color:var(--nt-color-50)}[data-md-color-scheme=slate] .nt-timeline-sub-title{color:var(--nt-color-51)}.nt-timeline-item{position:relative}.nt-timeline.vertical.center:not(.alternate) .nt-timeline-item{padding-left:calc(50% + 40px)}.nt-timeline.vertical.center:not(.alternate) .nt-timeline-item .nt-timeline-sub-title{left:0;padding-right:40px;text-align:right}.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(odd){padding-left:calc(50% + 40px)}.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(odd) .nt-timeline-sub-title{left:0;padding-right:40px;text-align:right}.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(even){text-align:right;padding-right:calc(50% + 40px)}.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(even) .nt-timeline-sub-title{right:0;padding-left:40px;text-align:left}.nt-timeline-dot{position:relative;width:20px;height:20px;border-radius:100%;background-color:#fc5b5b;position:absolute;top:0px;z-index:2;display:flex;justify-content:center;align-items:center;box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);border:3px solid #fff}.nt-timeline-dot:not(.bigger) .icon{font-size:10px}.nt-timeline-dot.bigger{width:40px;height:40px;padding:3px}.nt-timeline-dot .icon{color:#fff}@supports not (-moz-appearance: none){details .nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(odd) .nt-timeline-sub-title,details .nt-timeline.vertical.center:not(.alternate) .nt-timeline-item .nt-timeline-sub-title{left:-40px}details .nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(even) .nt-timeline-sub-title{right:-40px}details .nt-timeline.vertical.center .nt-timeline-dot{left:calc(50% - 12px)}details .nt-timeline-dot.bigger{font-size:1rem !important}}.nt-timeline-item:nth-child(0) .nt-timeline-dot{background-color:var(--nt-color-0)}.nt-timeline-item:nth-child(1) .nt-timeline-dot{background-color:var(--nt-color-1)}.nt-timeline-item:nth-child(2) .nt-timeline-dot{background-color:var(--nt-color-2)}.nt-timeline-item:nth-child(3) .nt-timeline-dot{background-color:var(--nt-color-3)}.nt-timeline-item:nth-child(4) .nt-timeline-dot{background-color:var(--nt-color-4)}.nt-timeline-item:nth-child(5) .nt-timeline-dot{background-color:var(--nt-color-5)}.nt-timeline-item:nth-child(6) .nt-timeline-dot{background-color:var(--nt-color-6)}.nt-timeline-item:nth-child(7) .nt-timeline-dot{background-color:var(--nt-color-7)}.nt-timeline-item:nth-child(8) .nt-timeline-dot{background-color:var(--nt-color-8)}.nt-timeline-item:nth-child(9) .nt-timeline-dot{background-color:var(--nt-color-9)}.nt-timeline-item:nth-child(10) .nt-timeline-dot{background-color:var(--nt-color-10)}.nt-timeline-item:nth-child(11) .nt-timeline-dot{background-color:var(--nt-color-11)}.nt-timeline-item:nth-child(12) .nt-timeline-dot{background-color:var(--nt-color-12)}.nt-timeline-item:nth-child(13) .nt-timeline-dot{background-color:var(--nt-color-13)}.nt-timeline-item:nth-child(14) .nt-timeline-dot{background-color:var(--nt-color-14)}.nt-timeline-item:nth-child(15) .nt-timeline-dot{background-color:var(--nt-color-15)}.nt-timeline-item:nth-child(16) .nt-timeline-dot{background-color:var(--nt-color-16)}.nt-timeline-item:nth-child(17) .nt-timeline-dot{background-color:var(--nt-color-17)}.nt-timeline-item:nth-child(18) .nt-timeline-dot{background-color:var(--nt-color-18)}.nt-timeline-item:nth-child(19) .nt-timeline-dot{background-color:var(--nt-color-19)}.nt-timeline-item:nth-child(20) .nt-timeline-dot{background-color:var(--nt-color-20)}:root{--nt-scrollbar-color: #2751b0;--nt-plan-actions-height: 24px;--nt-units-background: #ff9800;--nt-months-background: #2751b0;--nt-plan-vertical-line-color: #a3a3a3ad}.nt-pastello{--nt-scrollbar-color: #9fb8f4;--nt-units-background: #f5dc82;--nt-months-background: #5b7fd1}[data-md-color-scheme=slate]{--nt-units-background: #003773}[data-md-color-scheme=slate] .nt-pastello{--nt-units-background: #3f4997}.nt-plan-root{min-height:200px;scrollbar-width:20px;scrollbar-color:var(--nt-scrollbar-color);display:flex}.nt-plan-root ::-webkit-scrollbar{width:20px}.nt-plan-root ::-webkit-scrollbar-track{box-shadow:inset 0 0 5px gray;border-radius:10px}.nt-plan-root ::-webkit-scrollbar-thumb{background:var(--nt-scrollbar-color);border-radius:10px}.nt-plan-root .nt-plan{flex:80%}.nt-plan-root.no-groups .nt-plan-periods{padding-left:0}.nt-plan-root.no-groups .nt-plan-group-summary{display:none}.nt-plan-root .nt-timeline-dot.bigger{top:-10px}.nt-plan-root .nt-timeline-dot.bigger[title]{cursor:help}.nt-plan{white-space:nowrap;overflow-x:auto;display:flex}.nt-plan .ug-timeline-dot{left:368px;top:-8px;cursor:help}.months{display:flex}.month{flex:auto;display:inline-block;box-shadow:rgba(0,0,0,.2) 0px 3px 1px -2px,rgba(0,0,0,.14) 0px 2px 2px 0px,rgba(0,0,0,.12) 0px 1px 5px 0px inset;background-color:var(--nt-months-background);color:#fff;text-transform:uppercase;font-family:Roboto,Helvetica,Arial,sans-serif;padding:2px 5px;font-size:12px;border:1px solid #000;width:150px;border-radius:8px}.nt-plan-group-activities{flex:auto;position:relative}.nt-vline{border-left:1px dashed var(--nt-plan-vertical-line-color);height:100%;left:0;position:absolute;margin-left:-0.5px;top:0;-webkit-transition:all .5s linear !important;-moz-transition:all .5s linear !important;-ms-transition:all .5s linear !important;-o-transition:all .5s linear !important;transition:all .5s linear !important;z-index:-2}.nt-plan-activity{display:flex;margin:2px 0;background-color:rgba(187,187,187,.2509803922)}.actions{height:var(--nt-plan-actions-height)}.actions{position:relative}.period{display:inline-block;height:var(--nt-plan-actions-height);width:120px;position:absolute;left:0px;background:#1da1f2;border-radius:5px;transition:all .5s;cursor:help;-webkit-transition:width 1s ease-in-out;-moz-transition:width 1s ease-in-out;-o-transition:width 1s ease-in-out;transition:width 1s ease-in-out}.period .nt-tooltip{display:none;top:30px;position:relative;padding:1rem;text-align:center;font-size:12px}.period:hover .nt-tooltip{display:inline-block}.period-0{left:340px;visibility:visible;background-color:#456165}.period-1{left:40px;visibility:visible;background-color:green}.period-2{left:120px;visibility:visible;background-color:pink;width:80px}.period-3{left:190px;visibility:visible;background-color:darkred;width:150px}.weeks>span,.days>span{height:25px}.weeks>span{display:inline-block;margin:0;padding:0;font-weight:bold}.weeks>span .week-text{font-size:10px;position:absolute;display:inline-block;padding:3px 4px}.days{z-index:-2;position:relative}.day-text{font-size:10px;position:absolute;display:inline-block;padding:3px 4px}.period span{font-size:12px;vertical-align:top;margin-left:4px;color:#000;background:rgba(255,255,255,.6588235294);border-radius:6px;padding:0 4px}.weeks,.days{height:20px;display:flex;box-sizing:content-box}.months{display:flex}.week,.day{height:20px;position:relative;border:1;flex:auto;border:2px solid #fff;border-radius:4px;background-color:var(--nt-units-background);cursor:help}.years{display:flex}.year{text-align:center;border-right:1px solid var(--nt-plan-vertical-line-color);font-weight:bold}.year:first-child{border-left:1px solid var(--nt-plan-vertical-line-color)}.year:first-child:last-child{width:100%}.quarters{display:flex}.quarter{width:12.5%;text-align:center;border-right:1px solid var(--nt-plan-vertical-line-color);font-weight:bold}.quarter:first-child{border-left:1px solid var(--nt-plan-vertical-line-color)}.nt-plan-group{margin:20px 0;position:relative}.nt-plan-group{display:flex}.nt-plan-group-summary{background:#2751b0;width:150px;white-space:normal;padding:.1rem .5rem;border-radius:5px;color:#fff;z-index:3}.nt-plan-group-summary p{margin:0;padding:0;font-size:.6rem;color:#fff}.nt-plan-group-summary,.month,.period,.week,.day,.nt-tooltip{border:3px solid #fff;box-shadow:0 2px 3px -1px rgba(0,0,0,.2),0 3px 3px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)}.nt-plan-periods{padding-left:150px}.months{z-index:2;position:relative}.weeks{position:relative;top:-2px;z-index:0}.month,.quarter,.year,.week,.day,.nt-tooltip{font-family:Roboto,Helvetica,Arial,sans-serif;box-sizing:border-box}.nt-cards.nt-grid{display:grid;grid-auto-columns:1fr;gap:.5rem;max-width:100vw;overflow-x:auto;padding:1px}.nt-cards.nt-grid.cols-1{grid-template-columns:repeat(1, 1fr)}.nt-cards.nt-grid.cols-2{grid-template-columns:repeat(2, 1fr)}.nt-cards.nt-grid.cols-3{grid-template-columns:repeat(3, 1fr)}.nt-cards.nt-grid.cols-4{grid-template-columns:repeat(4, 1fr)}.nt-cards.nt-grid.cols-5{grid-template-columns:repeat(5, 1fr)}.nt-cards.nt-grid.cols-6{grid-template-columns:repeat(6, 1fr)}@media only screen and (max-width: 400px){.nt-cards.nt-grid{grid-template-columns:repeat(1, 1fr) !important}}.nt-card{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)}.nt-card:hover{box-shadow:0 2px 2px 0 rgba(0,0,0,.24),0 3px 1px -2px rgba(0,0,0,.3),0 1px 5px 0 rgba(0,0,0,.22)}[data-md-color-scheme=slate] .nt-card{box-shadow:0 2px 2px 0 rgba(4,40,33,.14),0 3px 1px -2px rgba(40,86,94,.47),0 1px 5px 0 rgba(139,252,255,.64)}[data-md-color-scheme=slate] .nt-card:hover{box-shadow:0 2px 2px 0 rgba(0,255,206,.14),0 3px 1px -2px rgba(33,156,177,.47),0 1px 5px 0 rgba(96,251,255,.64)}.nt-card>a{color:var(--md-default-fg-color)}.nt-card>a>div{cursor:pointer}.nt-card{padding:5px;margin-bottom:.5rem}.nt-card-title{font-size:1rem;font-weight:bold;margin:4px 0 8px 0;line-height:22px}.nt-card-content{padding:.4rem .8rem .8rem .8rem}.nt-card-text{font-size:14px;padding:0;margin:0}.nt-card .nt-card-image{text-align:center;border-radius:2px;background-position:center center;background-size:cover;background-repeat:no-repeat;min-height:120px}.nt-card .nt-card-image.tags img{margin-top:12px}.nt-card .nt-card-image img{height:105px;margin-top:5px}.nt-card a:hover,.nt-card a:focus{color:var(--md-accent-fg-color)}.nt-card h2{margin:0}.span-table-wrapper table{border-collapse:collapse;margin-bottom:2rem;border-radius:.1rem}.span-table td,.span-table th{padding:.2rem;background-color:var(--md-default-bg-color);font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto;border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.span-table tr:first-child td{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.span-table td:first-child{border-left:.05rem solid var(--md-typeset-table-color)}.span-table td:last-child{border-right:.05rem solid var(--md-typeset-table-color)}.span-table tr:last-child{border-bottom:.05rem solid var(--md-typeset-table-color)}.span-table [colspan],.span-table [rowspan]{font-weight:bold;border:.05rem solid var(--md-typeset-table-color)}.span-table tr:not(:first-child):hover td:not([colspan]):not([rowspan]),.span-table td[colspan]:hover,.span-table td[rowspan]:hover{background-color:rgba(0,0,0,.035);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset;transition:background-color 125ms}.nt-contribs{margin-top:2rem;font-size:small;border-top:1px dotted #d3d3d3;padding-top:.5rem}.nt-contribs .nt-contributors{padding-top:.5rem;display:flex;flex-wrap:wrap}.nt-contribs .nt-contributor{background:#d3d3d3;background-size:cover;width:40px;height:40px;border-radius:100%;margin:0 6px 6px 0;cursor:help;opacity:.7}.nt-contribs .nt-contributor:hover{opacity:1}.nt-contribs .nt-initials{text-transform:uppercase;font-size:24px;text-align:center;width:40px;height:40px;display:inline-block;vertical-align:middle;position:relative;top:2px;color:inherit;font-weight:bold}.nt-contribs .nt-group-0{background-color:var(--nt-color-0)}.nt-contribs .nt-group-1{background-color:var(--nt-color-1)}.nt-contribs .nt-group-2{background-color:var(--nt-color-2)}.nt-contribs .nt-group-3{background-color:var(--nt-color-3)}.nt-contribs .nt-group-4{background-color:var(--nt-color-4)}.nt-contribs .nt-group-5{background-color:var(--nt-color-5)}.nt-contribs .nt-group-6{background-color:var(--nt-color-6)}.nt-contribs .nt-group-7{color:#000;background-color:var(--nt-color-7)}.nt-contribs .nt-group-8{color:#000;background-color:var(--nt-color-8)}.nt-contribs .nt-group-9{background-color:var(--nt-color-9)}.nt-contribs .nt-group-10{background-color:var(--nt-color-10)}.nt-contribs .nt-group-11{background-color:var(--nt-color-11)}.nt-contribs .nt-group-12{background-color:var(--nt-color-12)}.nt-contribs .nt-group-13{background-color:var(--nt-color-13)}.nt-contribs .nt-group-14{background-color:var(--nt-color-14)}.nt-contribs .nt-group-15{color:#000;background-color:var(--nt-color-15)}.nt-contribs .nt-group-16{background-color:var(--nt-color-16)}.nt-contribs .nt-group-17{color:#000;background-color:var(--nt-color-17)}.nt-contribs .nt-group-18{background-color:var(--nt-color-18)}.nt-contribs .nt-group-19{background-color:var(--nt-color-19)}.nt-contribs .nt-group-20{color:#000;background-color:var(--nt-color-20)}.nt-contribs .nt-group-21{color:#000;background-color:var(--nt-color-21)}.nt-contribs .nt-group-22{color:#000;background-color:var(--nt-color-22)}.nt-contribs .nt-group-23{color:#000;background-color:var(--nt-color-23)}.nt-contribs .nt-group-24{color:#000;background-color:var(--nt-color-24)}.nt-contribs .nt-group-25{color:#000;background-color:var(--nt-color-25)}.nt-contribs .nt-group-26{color:#000;background-color:var(--nt-color-26)}.nt-contribs .nt-group-27{background-color:var(--nt-color-27)}.nt-contribs .nt-group-28{color:#000;background-color:var(--nt-color-28)}.nt-contribs .nt-group-29{color:#000;background-color:var(--nt-color-29)}.nt-contribs .nt-group-30{background-color:var(--nt-color-30)}.nt-contribs .nt-group-31{background-color:var(--nt-color-31)}.nt-contribs .nt-group-32{color:#000;background-color:var(--nt-color-32)}.nt-contribs .nt-group-33{background-color:var(--nt-color-33)}.nt-contribs .nt-group-34{background-color:var(--nt-color-34)}.nt-contribs .nt-group-35{background-color:var(--nt-color-35)}.nt-contribs .nt-group-36{background-color:var(--nt-color-36)}.nt-contribs .nt-group-37{background-color:var(--nt-color-37)}.nt-contribs .nt-group-38{background-color:var(--nt-color-38)}.nt-contribs .nt-group-39{color:#000;background-color:var(--nt-color-39)}.nt-contribs .nt-group-40{color:#000;background-color:var(--nt-color-40)}.nt-contribs .nt-group-41{color:#000;background-color:var(--nt-color-41)}.nt-contribs .nt-group-42{color:#000;background-color:var(--nt-color-42)}.nt-contribs .nt-group-43{color:#000;background-color:var(--nt-color-43)}.nt-contribs .nt-group-44{color:#000;background-color:var(--nt-color-44)}.nt-contribs .nt-group-45{background-color:var(--nt-color-45)}.nt-contribs .nt-group-46{color:#000;background-color:var(--nt-color-46)}.nt-contribs .nt-group-47{background-color:var(--nt-color-47)}.nt-contribs .nt-group-48{background-color:var(--nt-color-48)}.nt-contribs .nt-group-49{background-color:var(--nt-color-49)}
diff --git a/mkdocs-plugins/docs/gantt.md b/mkdocs-plugins/docs/gantt.md
new file mode 100644
index 0000000..b20a55f
--- /dev/null
+++ b/mkdocs-plugins/docs/gantt.md
@@ -0,0 +1,698 @@
+The Gantt extension provides a beautiful implementation of Gantt diagrams for MkDocs. A
+Gantt diagram is great to provide detailed information of chronological events, like a
+project roadmap.
+
+[gantt(./docs/gantt/gantt-1.yaml)]
+
+## How to use
+
+Edit your `mkdocs.yml` file to include the extra CSS file from Neoteroi
+mkdocs-plugins and the `neoteroi.projects` extension:
+
+```yaml
+
+extra_css:
+ - css/neoteroi-mkdocs.css
+ ...
+
+markdown_extensions:
+ - neoteroi.projects
+ ...
+
+```
+
+## Input object
+
+### Examples
+
+=== "JSON"
+
+ ```json
+ ::gantt::
+ [
+ {
+ "title": "Definition Phase",
+ "activities": [
+ {
+ "title": "Creative Brief",
+ "start": "2022-03-03",
+ "lasts": "1 day"
+ },
+ {
+ "title": "Graphic Design Research",
+ "start": "2022-03-02",
+ "lasts": "2 weeks"
+ },
+ {
+ "title": "Brainstorming / Mood Boarding",
+ "start": "2022-03-11",
+ "lasts": "2 weeks"
+ }
+ ]
+ },
+ {
+ "title": "Creation Phase",
+ "activities": [
+ {
+ "title": "Sketching",
+ "start": "2022-03-21",
+ "lasts": "2 weeks"
+ },
+ {
+ "title": "Design Building",
+ "start": "2022-04-02",
+ "lasts": "4 weeks"
+ },
+ {
+ "title": "Refining",
+ "start": "2022-05-01",
+ "lasts": "2 weeks"
+ }
+ ]
+ },
+ {
+ "title": "Feedback Phase",
+ "activities": [
+ {
+ "title": "Presenting",
+ "start": "2022-05-01",
+ "lasts": "3 days"
+ },
+ {
+ "title": "Revisions",
+ "start": "2022-05-02",
+ "end": "2022-05-31"
+ }
+ ]
+ },
+ {
+ "title": "Delivery Phase",
+ "activities": [
+ {
+ "title": "Final delivery",
+ "start": "2022-06-05",
+ "end": "2022-06-06"
+ }
+ ]
+ }
+ ]
+ ::/gantt::
+ ```
+
+=== "YAML"
+
+ ```yaml
+ ::gantt::
+
+ - title: Definition Phase
+ activities:
+ - title: Creative Brief
+ start: 2022-03-03
+ lasts: 1 day
+ - title: Graphic Design Research
+ start: 2022-03-02
+ end: 2022-03-10
+ lasts: 2 weeks
+ - title: Brainstorming / Mood Boarding
+ start: 2022-03-11
+ end: 2022-03-20
+
+ - title: Creation Phase
+ activities:
+ - title: Sketching
+ start: 2022-03-21
+ end: 2022-04-01
+ - title: Design Building
+ start: 2022-04-02
+ end: 2022-04-20
+ - title: Refining
+ start: 2022-04-21
+ end: 2022-04-30
+
+ - title: Feedback Phase
+ activities:
+ - title: Presenting
+ start: 2022-04-22
+ end: 2022-05-01
+ - title: Revisions
+ start: 2022-05-02
+ end: 2022-05-10
+
+ - title: Delivery Phase
+ activities:
+ - title: Final delivery
+ start: 2022-05-11
+ end: 2022-05-12
+
+ ::/gantt::
+ ```
+
+=== "File source"
+
+ ```
+ [gantt(./settings.yaml)]
+
+ [gantt(./settings.json)]
+ ```
+
+=== "URL source"
+
+ ```
+ [gantt(https://www.neoteroi.dev/examples/gantt.yaml)]
+
+ [gantt(https://www.neoteroi.dev/examples/gantt.json)]
+ ```
+
+### Schema
+
+The input for a Gantt diagram is a list of activities having a shape described
+by the following scheme:
+
+```mermaid
+classDiagram
+direction LR
+
+class Event {
+ title: str
+ description: str | None = None
+ time: datetime | None = None
+ icon: str | None = None
+}
+
+class Activity {
+ title: str
+ start: date | None = None
+ end: date | None = None
+ lasts: str | None = None
+ description: str | None = None
+ events: Array of Event | None
+ activities: Array of Activity | None
+}
+
+Activity --> Event
+Activity --> Activity
+
+```
+
+```python
+
+@dataclass(frozen=True)
+class Event:
+ title: str
+ description: str | None = None
+ time: datetime | None = None
+ icon: str | None = None
+
+@dataclass(frozen=True)
+class Activity:
+ title: str
+ start: date | None = None
+ end: date | None = None
+ lasts: str | None = None
+ description: str | None = None
+ activities: List["Activity"] | None = None
+ events: List[Event] | None = None
+
+```
+
+### Dates and times
+
+The duration of activities can be described in two ways:
+
+1. specifying `start` and `end` as dates or datetimes
+2. specifying `start` and `lasts` properties
+
+When using `lasts`, it is possible to use the following syntax:
+
+| Days | Example | Alternative |
+| ---------------- | ---------------- | ------------------------------ |
+| lasts _n_ days | _lasts 10 days_ | _days | day | d_ |
+| lasts _n_ weeks | _lasts 2 weeks_ | _weeks | week | w_ |
+| lasts _n_ months | _lasts 3 months_ | _months | month | m_ |
+| lasts _n_ years | _lasts 3 years_ | _years | year | y_ |
+
+This feature is inspired by gantt diagrams in [PlantUML](https://plantuml.com/gantt-diagram).
+
+!!! danger "Currently unsupported"
+ - Time information is currently ignored, the extension only handles dates.
+ Anyway, the input objects can still have detailed date and time information.
+ - The extension currently requires dates (year, month, day information): it
+ cannot handle information having only number of days without month and year
+ information (unlike PlantUML).
+
+### Using events
+It is possible to define events for each activity in the plan. Events require a single
+date and are represented with circles.
+
+[gantt(./docs/gantt/gantt-2.yaml)]
+
+Examples:
+
+=== "JSON"
+
+ ```json
+ ::gantt::
+ [
+ {
+ "title": "Milestones",
+ "events": [
+ {
+ "title": "Kick-off meeting",
+ "time": "2022-03-03",
+ "icon": ":octicons-rocket-16:"
+ },
+ {
+ "title": "Final delivery",
+ "time": "2022-06-05",
+ "icon": ":octicons-sun-16:"
+ }
+ ]
+ },
+ {
+ "title": "Definition Phase",
+ "activities": [
+ {
+ "title": "Graphic Design Research",
+ "start": "2022-03-02",
+ "lasts": "2 weeks"
+ },
+ {
+ "title": "Brainstorming / Mood Boarding",
+ "start": "2022-03-11",
+ "lasts": "2 weeks"
+ }
+ ]
+ },
+ {
+ "title": "Creation Phase",
+ "activities": [
+ {
+ "title": "Sketching",
+ "start": "2022-03-21",
+ "lasts": "2 weeks"
+ },
+ {
+ "title": "Design Building",
+ "start": "2022-04-02",
+ "lasts": "4 weeks"
+ },
+ {
+ "title": "Refining",
+ "start": "2022-05-01",
+ "lasts": "2 weeks"
+ }
+ ]
+ },
+ {
+ "title": "Feedback Phase",
+ "activities": [
+ {
+ "title": "Presenting",
+ "start": "2022-05-01",
+ "lasts": "3 days"
+ },
+ {
+ "title": "Revisions",
+ "start": "2022-05-02",
+ "end": "2022-05-31"
+ }
+ ]
+ }
+ ]
+ ::/gantt::
+ ```
+
+=== "YAML"
+
+ ```yaml
+ ::gantt::
+
+ - title: Milestones
+ events:
+ - title: Kick-off meeting
+ time: 2022-03-03
+ icon: ":octicons-rocket-16:"
+ - title: Final delivery
+ time: 2022-06-05
+ icon: ":octicons-sun-16:"
+
+ - title: Definition Phase
+ activities:
+ - title: Graphic Design Research
+ start: 2022-03-02
+ lasts: 2 weeks
+ - title: Brainstorming / Mood Boarding
+ start: 2022-03-11
+ lasts: 2 weeks
+
+ - title: Creation Phase
+ activities:
+ - title: Sketching
+ start: 2022-03-21
+ lasts: 2 weeks
+ - title: Design Building
+ start: 2022-04-02
+ lasts: 4 weeks
+ - title: Refining
+ start: 2022-05-01
+ lasts: 2 weeks
+
+ - title: Feedback Phase
+ activities:
+ - title: Presenting
+ start: 2022-05-01
+ lasts: 3 days
+ - title: Revisions
+ start: 2022-05-02
+ end: 2022-05-31
+
+ ::/gantt::
+ ```
+
+!!! tip "Any activity can have events"
+ The examples here show events in a single activity, but they can be added
+ to any activity of a plan.
+
+### Subactivities
+
+It is possible to define more than one item per row, using subactivities. Subactivities
+are always displayed inside the row of their root activity.
+
+When defining activities, it is also possible to define the start date for the first item
+in a tree of activities, and only specify how long following activities last. To add
+breaks, add items having a `skip` property with a value describing a duration.
+
+The following examples illustrate both features:
+
+[gantt(./docs/gantt/gantt-3.yaml)]
+
+=== "JSON"
+
+ ```json
+ ::gantt::
+ {
+ "start": "2022-03-01",
+ "activities": [
+ {
+ "title": "Developer",
+ "activities": [
+ {
+ "activities": [
+ {
+ "title": "Custom sign-up",
+ "lasts": "2 weeks"
+ },
+ {
+ "skip": "1 week"
+ },
+ {
+ "title": "Custom password reset",
+ "lasts": "2 weeks"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Tester",
+ "activities": [
+ {
+ "activities": [
+ {
+ "skip": "5 days"
+ },
+ {
+ "title": "Tests custom sign-up",
+ "lasts": "2 weeks"
+ },
+ {
+ "skip": "1 week"
+ },
+ {
+ "title": "Tests custom password reset",
+ "lasts": "2 weeks"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Technical writer",
+ "activities": [
+ {
+ "activities": [
+ {
+ "skip": "4 weeks"
+ },
+ {
+ "title": "Documents custom sign-up",
+ "lasts": "2 weeks"
+ },
+ {
+ "title": "Documents custom password reset",
+ "lasts": "2 weeks"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ::/gantt::
+ ```
+
+=== "YAML"
+
+ ```yaml
+ ::gantt::
+ start: 2022-03-01
+ activities:
+ - title: Developer
+ activities:
+ - activities:
+ - title: Custom sign-up
+ lasts: 2 weeks
+ - skip: 1 week
+ - title: Custom password reset
+ lasts: 2 weeks
+
+ - title: Tester
+ activities:
+ - activities:
+ - skip: 5 days
+ - title: Tests custom sign-up
+ lasts: 2 weeks
+ - skip: 1 week
+ - title: Tests custom password reset
+ lasts: 2 weeks
+
+ - title: Technical writer
+ activities:
+ - activities:
+ - skip: 4 weeks
+ - title: Documents custom sign-up
+ lasts: 2 weeks
+ - title: Documents custom password reset
+ lasts: 2 weeks
+ ::/gantt::
+ ```
+
+[gantt(./docs/gantt/gantt-4.yaml)]
+
+=== "JSON"
+
+ ```json
+ ::gantt::
+ [
+ {
+ "title": "Example",
+ "start": "2022-01-01",
+ "activities": [
+ {
+ "title": "Feature 1",
+ "lasts": "10 day",
+ "activities": [
+ {
+ "skip": "10 days"
+ },
+ {
+ "title": "Activity 1.1",
+ "lasts": "30 days",
+ "activities": [
+ {
+ "skip": "5 days"
+ },
+ {
+ "title": "Activity 1.12",
+ "lasts": "30 days"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Activity 2",
+ "lasts": "10 days"
+ },
+ {
+ "title": "Activity 3",
+ "lasts": "20 days"
+ },
+ {
+ "title": "Activity 2",
+ "lasts": "10 weeks"
+ },
+ {
+ "title": "Activity 2",
+ "lasts": "10 weeks"
+ }
+ ]
+ }
+ ]
+ ::/gantt::
+ ```
+
+=== "YAML"
+
+ ```yaml
+ ::gantt::
+
+ - title: Beginning
+ start: 2022-01-01
+ activities:
+ - title: Feature 1
+ lasts: 10 day
+ activities:
+ - skip: 10 days
+ - title: Activity 1.1
+ lasts: 30 days
+ activities:
+ - skip: 5 days
+ - title: Activity 1.12
+ lasts: 30 days
+ - title: Activity 2
+ lasts: 10 week
+ - title: Activity 3
+ lasts: 20 days
+ - title: Activity 2
+ lasts: 10 week
+ - title: Activity 2
+ lasts: 10 week
+
+ - title: Beginning
+ start: 2022-01-01
+ activities:
+ - title: Activity 1
+ lasts: 10 day
+ activities:
+ - title: Activity 1.1
+ lasts: 30 days
+ - title: Activity 2
+ lasts: 40 week
+ - title: Activity 3
+ lasts: 20 days
+
+ ::/gantt::
+ ```
+
+## Options
+
+| Name | Description | Default |
+| ------------ | ------------------------------------------------------------------------------------ | --------------------- |
+| id | Configures an `id` property on the root HTML element | "" |
+| month-width | Controls the size of the scale - represents the pixels width of a month with 30 days | 150 |
+| month-format | Controls date formatting for months | "%B %Y" |
+| no-groups | Disables groups (flag) | False |
+| no-years | Disables years (flag) | False |
+| no-weeks | Disables weeks (flag) | False |
+| no-quarters | Disables quarters (flag) | False |
+| no-days | Disables days (flag) | False |
+| whole-years | Displays whole years from January to December (flag) | False |
+| pastello | Applies a CSS class to use a color palette with milder saturation | False |
+| vlines-pace | Controls how separator vertical lines are generated (each week or each month) | "monthly" or "weekly" |
+
+### Controlling the scale size
+
+This extension produces diagrams displaying years, quarters, months, weeks, and days in
+scale. To control the size of the scale, use the `month-width` option, which affects the
+size of months having 30 days.
+
+```
+[gantt month-width=800(./docs/gantt/gantt-1.yaml)]
+```
+
+[gantt month-width=800(./docs/gantt/gantt-1.yaml)]
+
+!!! tip "Displaying days"
+ Days are not displayed when the default month size is used.
+ When `month-width` is sufficiently big, days are displayed automatically.
+
+### Gentler colors
+
+It's possible to use a a different color palette with less saturated colors,
+using the `pastello` flag.
+
+```
+[gantt pastello(./docs/gantt/gantt-1.yaml)]
+```
+
+[gantt pastello(./docs/gantt/gantt-1.yaml)]
+
+### Disabling groups
+
+To disable groups on the left side, use the `no-groups` flag.
+
+```
+[gantt no-groups(./docs/gantt/gantt-1.yaml)]
+```
+
+[gantt no-groups(./docs/gantt/gantt-1.yaml)]
+
+### Disabling parts of the periods
+
+Use the `no-years`, `no-weeks`, `no-quarters`, or `no-days` to disable certain
+periods displayed on the top. For example, to disable years and quarters:
+
+```
+[gantt no-years no-quarters(./docs/gantt/gantt-2.yaml)]
+```
+
+[gantt no-years no-quarters(./docs/gantt/gantt-2.yaml)]
+
+!!! warning "Days default"
+ Days are displayed by default, but only if their elements width would be
+ at least of 20px.
+
+### Displaying full years
+
+Gantt diagrams display by default the months between the smallest date and the biggest
+date in the input data, from the beginning of the earliest month to the end of the latest
+month. To display full years, from January to December, use the `whole-years` option.
+
+```
+[gantt whole-years(./docs/gantt/gantt-1.yaml)]
+```
+
+[gantt whole-years(./docs/gantt/gantt-1.yaml)]
+
+### Icons support
+
+The gantt extension integrates with [Material for MkDocs icons](https://squidfunk.github.io/mkdocs-material/reference/icons-emojis/),
+like shown in the examples above. The extension also supports links to images,
+like in the following example:
+
+::gantt:: no-years no-quarters
+
+- title: Parties
+ events:
+ - title: Zeus' birthday party
+ time: 2022-03-03
+ icon: ./img/icons/001-zeus.png
+ - title: Poseidon's birthday party
+ time: 2022-06-05
+ icon: ./img/icons/007-poseidon.png
+ - title: Hera's birthday party
+ time: 2022-04-05
+ icon: ./img/icons/024-hera.png
+
+::/gantt::
diff --git a/mkdocs-plugins/docs/gantt/gantt-1.json b/mkdocs-plugins/docs/gantt/gantt-1.json
new file mode 100644
index 0000000..9210690
--- /dev/null
+++ b/mkdocs-plugins/docs/gantt/gantt-1.json
@@ -0,0 +1,67 @@
+[
+ {
+ "title": "Definition Phase",
+ "activities": [
+ {
+ "title": "Creative Brief",
+ "start": "2022-03-03",
+ "lasts": "1 day"
+ },
+ {
+ "title": "Graphic Design Research",
+ "start": "2022-03-02",
+ "lasts": "2 weeks"
+ },
+ {
+ "title": "Brainstorming / Mood Boarding",
+ "start": "2022-03-11",
+ "lasts": "2 weeks"
+ }
+ ]
+ },
+ {
+ "title": "Creation Phase",
+ "activities": [
+ {
+ "title": "Sketching",
+ "start": "2022-03-21",
+ "lasts": "2 weeks"
+ },
+ {
+ "title": "Design Building",
+ "start": "2022-04-02",
+ "lasts": "4 weeks"
+ },
+ {
+ "title": "Refining",
+ "start": "2022-05-01",
+ "lasts": "2 weeks"
+ }
+ ]
+ },
+ {
+ "title": "Feedback Phase",
+ "activities": [
+ {
+ "title": "Presenting",
+ "start": "2022-05-01",
+ "lasts": "3 days"
+ },
+ {
+ "title": "Revisions",
+ "start": "2022-05-02",
+ "end": "2022-05-31"
+ }
+ ]
+ },
+ {
+ "title": "Delivery Phase",
+ "activities": [
+ {
+ "title": "Final delivery",
+ "start": "2022-06-05",
+ "end": "2022-06-06"
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/mkdocs-plugins/docs/gantt/gantt-1.yaml b/mkdocs-plugins/docs/gantt/gantt-1.yaml
new file mode 100644
index 0000000..70147a6
--- /dev/null
+++ b/mkdocs-plugins/docs/gantt/gantt-1.yaml
@@ -0,0 +1,38 @@
+- title: Definition Phase
+ activities:
+ - title: Creative Brief
+ start: 2022-03-03
+ lasts: 1 day
+ - title: Graphic Design Research
+ start: 2022-03-02
+ lasts: 2 weeks
+ - title: Brainstorming / Mood Boarding
+ start: 2022-03-11
+ lasts: 2 weeks
+
+- title: Creation Phase
+ activities:
+ - title: Sketching
+ start: 2022-03-21
+ lasts: 2 weeks
+ - title: Design Building
+ start: 2022-04-02
+ lasts: 4 weeks
+ - title: Refining
+ start: 2022-05-01
+ lasts: 2 weeks
+
+- title: Feedback Phase
+ activities:
+ - title: Presenting
+ start: 2022-05-01
+ lasts: 3 days
+ - title: Revisions
+ start: 2022-05-02
+ end: 2022-05-31
+
+- title: Delivery Phase
+ activities:
+ - title: Final delivery
+ start: 2022-06-05
+ end: 2022-06-06
diff --git a/mkdocs-plugins/docs/gantt/gantt-2.json b/mkdocs-plugins/docs/gantt/gantt-2.json
new file mode 100644
index 0000000..dbb556e
--- /dev/null
+++ b/mkdocs-plugins/docs/gantt/gantt-2.json
@@ -0,0 +1,67 @@
+[
+ {
+ "title": "Milestones",
+ "events": [
+ {
+ "title": "Kick-off meeting",
+ "time": "2022-03-03",
+ "icon": ":octicons-rocket-16:"
+ },
+ {
+ "title": "Final delivery",
+ "time": "2022-06-05",
+ "icon": ":octicons-sun-16:"
+ }
+ ]
+ },
+ {
+ "title": "Definition Phase",
+ "activities": [
+ {
+ "title": "Graphic Design Research",
+ "start": "2022-03-02",
+ "lasts": "2 weeks"
+ },
+ {
+ "title": "Brainstorming / Mood Boarding",
+ "start": "2022-03-11",
+ "lasts": "2 weeks"
+ }
+ ]
+ },
+ {
+ "title": "Creation Phase",
+ "activities": [
+ {
+ "title": "Sketching",
+ "start": "2022-03-21",
+ "lasts": "2 weeks"
+ },
+ {
+ "title": "Design Building",
+ "start": "2022-04-02",
+ "lasts": "4 weeks"
+ },
+ {
+ "title": "Refining",
+ "start": "2022-05-01",
+ "lasts": "2 weeks"
+ }
+ ]
+ },
+ {
+ "title": "Feedback Phase",
+ "activities": [
+ {
+ "title": "Presenting",
+ "start": "2022-05-01",
+ "lasts": "3 days"
+ },
+ {
+ "title": "Revisions",
+ "start": "2022-05-02",
+ "end": "2022-05-31"
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/mkdocs-plugins/docs/gantt/gantt-2.yaml b/mkdocs-plugins/docs/gantt/gantt-2.yaml
new file mode 100644
index 0000000..e7d1f8d
--- /dev/null
+++ b/mkdocs-plugins/docs/gantt/gantt-2.yaml
@@ -0,0 +1,38 @@
+- title: Milestones
+ events:
+ - title: Kick-off meeting
+ time: 2022-03-03
+ icon: ":octicons-rocket-16:"
+ - title: Final delivery
+ time: 2022-06-05
+ icon: ":octicons-sun-16:"
+
+- title: Definition Phase
+ activities:
+ - title: Graphic Design Research
+ start: 2022-03-02
+ lasts: 2 weeks
+ - title: Brainstorming / Mood Boarding
+ start: 2022-03-11
+ lasts: 2 weeks
+
+- title: Creation Phase
+ activities:
+ - title: Sketching
+ start: 2022-03-21
+ lasts: 2 weeks
+ - title: Design Building
+ start: 2022-04-02
+ lasts: 4 weeks
+ - title: Refining
+ start: 2022-05-01
+ lasts: 2 weeks
+
+- title: Feedback Phase
+ activities:
+ - title: Presenting
+ start: 2022-05-01
+ lasts: 3 days
+ - title: Revisions
+ start: 2022-05-02
+ end: 2022-05-31
diff --git a/mkdocs-plugins/docs/gantt/gantt-3.json b/mkdocs-plugins/docs/gantt/gantt-3.json
new file mode 100644
index 0000000..dfa273f
--- /dev/null
+++ b/mkdocs-plugins/docs/gantt/gantt-3.json
@@ -0,0 +1,68 @@
+{
+ "start": "2022-03-01",
+ "activities": [
+ {
+ "title": "Developer",
+ "activities": [
+ {
+ "activities": [
+ {
+ "title": "Custom sign-up",
+ "lasts": "2 weeks"
+ },
+ {
+ "skip": "1 week"
+ },
+ {
+ "title": "Custom password reset",
+ "lasts": "2 weeks"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Tester",
+ "activities": [
+ {
+ "activities": [
+ {
+ "skip": "5 days"
+ },
+ {
+ "title": "Tests custom sign-up",
+ "lasts": "2 weeks"
+ },
+ {
+ "skip": "1 week"
+ },
+ {
+ "title": "Tests custom password reset",
+ "lasts": "2 weeks"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Technical writer",
+ "activities": [
+ {
+ "activities": [
+ {
+ "skip": "4 weeks"
+ },
+ {
+ "title": "Documents custom sign-up",
+ "lasts": "2 weeks"
+ },
+ {
+ "title": "Documents custom password reset",
+ "lasts": "2 weeks"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/mkdocs-plugins/docs/gantt/gantt-3.yaml b/mkdocs-plugins/docs/gantt/gantt-3.yaml
new file mode 100644
index 0000000..0d1e5f6
--- /dev/null
+++ b/mkdocs-plugins/docs/gantt/gantt-3.yaml
@@ -0,0 +1,29 @@
+start: 2022-03-15
+activities:
+ - title: Developer
+ activities:
+ - activities:
+ - title: Custom sign-up
+ lasts: 2 weeks
+ - skip: 1 week
+ - title: Custom password reset
+ lasts: 2 weeks
+
+ - title: Tester
+ activities:
+ - activities:
+ - skip: 5 days
+ - title: Tests custom sign-up
+ lasts: 2 weeks
+ - skip: 1 week
+ - title: Tests custom password reset
+ lasts: 2 weeks
+
+ - title: Technical writer
+ activities:
+ - activities:
+ - skip: 4 weeks
+ - title: Documents custom sign-up
+ lasts: 2 weeks
+ - title: Documents custom password reset
+ lasts: 2 weeks
diff --git a/mkdocs-plugins/docs/gantt/gantt-4.json b/mkdocs-plugins/docs/gantt/gantt-4.json
new file mode 100644
index 0000000..da2e128
--- /dev/null
+++ b/mkdocs-plugins/docs/gantt/gantt-4.json
@@ -0,0 +1,46 @@
+[
+ {
+ "title": "Example",
+ "start": "2022-01-01",
+ "activities": [
+ {
+ "title": "Feature 1",
+ "lasts": "10 day",
+ "activities": [
+ {
+ "skip": "10 days"
+ },
+ {
+ "title": "Activity 1.1",
+ "lasts": "30 days",
+ "activities": [
+ {
+ "skip": "5 days"
+ },
+ {
+ "title": "Activity 1.12",
+ "lasts": "30 days"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Activity 2",
+ "lasts": "10 days"
+ },
+ {
+ "title": "Activity 3",
+ "lasts": "20 days"
+ },
+ {
+ "title": "Activity 2",
+ "lasts": "10 weeks"
+ },
+ {
+ "title": "Activity 2",
+ "lasts": "10 weeks"
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/mkdocs-plugins/docs/gantt/gantt-4.yaml b/mkdocs-plugins/docs/gantt/gantt-4.yaml
new file mode 100644
index 0000000..60aad14
--- /dev/null
+++ b/mkdocs-plugins/docs/gantt/gantt-4.yaml
@@ -0,0 +1,21 @@
+- title: Example
+ start: 2022-01-01
+ activities:
+ - title: Feature 1
+ lasts: 10 day
+ activities:
+ - skip: 10 days
+ - title: Activity 1.1
+ lasts: 30 days
+ activities:
+ - skip: 5 days
+ - title: Activity 1.12
+ lasts: 30 days
+ - title: Activity 2
+ lasts: 10 days
+ - title: Activity 3
+ lasts: 20 days
+ - title: Activity 2
+ lasts: 10 weeks
+ - title: Activity 2
+ lasts: 10 weeks
diff --git a/mkdocs-plugins/docs/img/cards.png b/mkdocs-plugins/docs/img/cards.png
new file mode 100644
index 0000000..6430ca3
Binary files /dev/null and b/mkdocs-plugins/docs/img/cards.png differ
diff --git a/mkdocs-plugins/docs/img/contribs-01.png b/mkdocs-plugins/docs/img/contribs-01.png
new file mode 100644
index 0000000..da671e4
Binary files /dev/null and b/mkdocs-plugins/docs/img/contribs-01.png differ
diff --git a/mkdocs-plugins/docs/img/contribs-02.png b/mkdocs-plugins/docs/img/contribs-02.png
new file mode 100644
index 0000000..e87aa94
Binary files /dev/null and b/mkdocs-plugins/docs/img/contribs-02.png differ
diff --git a/mkdocs-plugins/docs/img/favicon.ico b/mkdocs-plugins/docs/img/favicon.ico
new file mode 100644
index 0000000..38ef778
Binary files /dev/null and b/mkdocs-plugins/docs/img/favicon.ico differ
diff --git a/mkdocs-plugins/docs/img/gantt.png b/mkdocs-plugins/docs/img/gantt.png
new file mode 100644
index 0000000..f0468e8
Binary files /dev/null and b/mkdocs-plugins/docs/img/gantt.png differ
diff --git a/mkdocs-plugins/docs/img/icons/001-zeus.png b/mkdocs-plugins/docs/img/icons/001-zeus.png
new file mode 100644
index 0000000..5d26bfb
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/001-zeus.png differ
diff --git a/mkdocs-plugins/docs/img/icons/002-statue.png b/mkdocs-plugins/docs/img/icons/002-statue.png
new file mode 100644
index 0000000..fb66744
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/002-statue.png differ
diff --git a/mkdocs-plugins/docs/img/icons/003-athena.png b/mkdocs-plugins/docs/img/icons/003-athena.png
new file mode 100644
index 0000000..7dfac6e
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/003-athena.png differ
diff --git a/mkdocs-plugins/docs/img/icons/004-helmet.png b/mkdocs-plugins/docs/img/icons/004-helmet.png
new file mode 100644
index 0000000..5a612c6
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/004-helmet.png differ
diff --git a/mkdocs-plugins/docs/img/icons/005-demeter.png b/mkdocs-plugins/docs/img/icons/005-demeter.png
new file mode 100644
index 0000000..8525e87
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/005-demeter.png differ
diff --git a/mkdocs-plugins/docs/img/icons/006-ares.png b/mkdocs-plugins/docs/img/icons/006-ares.png
new file mode 100644
index 0000000..1932801
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/006-ares.png differ
diff --git a/mkdocs-plugins/docs/img/icons/007-poseidon.png b/mkdocs-plugins/docs/img/icons/007-poseidon.png
new file mode 100644
index 0000000..1ace811
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/007-poseidon.png differ
diff --git a/mkdocs-plugins/docs/img/icons/008-hephaestus.png b/mkdocs-plugins/docs/img/icons/008-hephaestus.png
new file mode 100644
index 0000000..5572c51
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/008-hephaestus.png differ
diff --git a/mkdocs-plugins/docs/img/icons/009-themis.png b/mkdocs-plugins/docs/img/icons/009-themis.png
new file mode 100644
index 0000000..9e723d7
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/009-themis.png differ
diff --git a/mkdocs-plugins/docs/img/icons/010-ancient-pillar.png b/mkdocs-plugins/docs/img/icons/010-ancient-pillar.png
new file mode 100644
index 0000000..d795d01
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/010-ancient-pillar.png differ
diff --git a/mkdocs-plugins/docs/img/icons/011-atlas.png b/mkdocs-plugins/docs/img/icons/011-atlas.png
new file mode 100644
index 0000000..9a7d9c8
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/011-atlas.png differ
diff --git a/mkdocs-plugins/docs/img/icons/012-hades.png b/mkdocs-plugins/docs/img/icons/012-hades.png
new file mode 100644
index 0000000..469a54b
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/012-hades.png differ
diff --git a/mkdocs-plugins/docs/img/icons/013-aphrodite.png b/mkdocs-plugins/docs/img/icons/013-aphrodite.png
new file mode 100644
index 0000000..68ce546
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/013-aphrodite.png differ
diff --git a/mkdocs-plugins/docs/img/icons/014-vase.png b/mkdocs-plugins/docs/img/icons/014-vase.png
new file mode 100644
index 0000000..1075b86
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/014-vase.png differ
diff --git a/mkdocs-plugins/docs/img/icons/015-trident.png b/mkdocs-plugins/docs/img/icons/015-trident.png
new file mode 100644
index 0000000..313f264
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/015-trident.png differ
diff --git a/mkdocs-plugins/docs/img/icons/016-hydra.png b/mkdocs-plugins/docs/img/icons/016-hydra.png
new file mode 100644
index 0000000..ffcd307
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/016-hydra.png differ
diff --git a/mkdocs-plugins/docs/img/icons/017-cerberus.png b/mkdocs-plugins/docs/img/icons/017-cerberus.png
new file mode 100644
index 0000000..f8a815c
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/017-cerberus.png differ
diff --git a/mkdocs-plugins/docs/img/icons/018-medusa.png b/mkdocs-plugins/docs/img/icons/018-medusa.png
new file mode 100644
index 0000000..fa103b4
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/018-medusa.png differ
diff --git a/mkdocs-plugins/docs/img/icons/019-prometheus.png b/mkdocs-plugins/docs/img/icons/019-prometheus.png
new file mode 100644
index 0000000..d16e921
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/019-prometheus.png differ
diff --git a/mkdocs-plugins/docs/img/icons/020-persephone.png b/mkdocs-plugins/docs/img/icons/020-persephone.png
new file mode 100644
index 0000000..8600ec3
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/020-persephone.png differ
diff --git a/mkdocs-plugins/docs/img/icons/021-artemis.png b/mkdocs-plugins/docs/img/icons/021-artemis.png
new file mode 100644
index 0000000..477c4d8
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/021-artemis.png differ
diff --git a/mkdocs-plugins/docs/img/icons/022-apollo.png b/mkdocs-plugins/docs/img/icons/022-apollo.png
new file mode 100644
index 0000000..a1835a3
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/022-apollo.png differ
diff --git a/mkdocs-plugins/docs/img/icons/023-hermes.png b/mkdocs-plugins/docs/img/icons/023-hermes.png
new file mode 100644
index 0000000..a0f609b
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/023-hermes.png differ
diff --git a/mkdocs-plugins/docs/img/icons/024-hera.png b/mkdocs-plugins/docs/img/icons/024-hera.png
new file mode 100644
index 0000000..ceeac57
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/024-hera.png differ
diff --git a/mkdocs-plugins/docs/img/icons/025-perseus.png b/mkdocs-plugins/docs/img/icons/025-perseus.png
new file mode 100644
index 0000000..b974ced
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/025-perseus.png differ
diff --git a/mkdocs-plugins/docs/img/icons/026-dionysus.png b/mkdocs-plugins/docs/img/icons/026-dionysus.png
new file mode 100644
index 0000000..c3ce726
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/026-dionysus.png differ
diff --git a/mkdocs-plugins/docs/img/icons/027-nike.png b/mkdocs-plugins/docs/img/icons/027-nike.png
new file mode 100644
index 0000000..7f3fa9b
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/027-nike.png differ
diff --git a/mkdocs-plugins/docs/img/icons/028-minotaur.png b/mkdocs-plugins/docs/img/icons/028-minotaur.png
new file mode 100644
index 0000000..0023399
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/028-minotaur.png differ
diff --git a/mkdocs-plugins/docs/img/icons/029-pandora.png b/mkdocs-plugins/docs/img/icons/029-pandora.png
new file mode 100644
index 0000000..36e5c87
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/029-pandora.png differ
diff --git a/mkdocs-plugins/docs/img/icons/030-eros.png b/mkdocs-plugins/docs/img/icons/030-eros.png
new file mode 100644
index 0000000..d12118d
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/030-eros.png differ
diff --git a/mkdocs-plugins/docs/img/icons/031-olympus.png b/mkdocs-plugins/docs/img/icons/031-olympus.png
new file mode 100644
index 0000000..551cf77
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/031-olympus.png differ
diff --git a/mkdocs-plugins/docs/img/icons/032-lightning.png b/mkdocs-plugins/docs/img/icons/032-lightning.png
new file mode 100644
index 0000000..6d2271b
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/032-lightning.png differ
diff --git a/mkdocs-plugins/docs/img/icons/033-titan.png b/mkdocs-plugins/docs/img/icons/033-titan.png
new file mode 100644
index 0000000..7fde128
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/033-titan.png differ
diff --git a/mkdocs-plugins/docs/img/icons/034-chimera.png b/mkdocs-plugins/docs/img/icons/034-chimera.png
new file mode 100644
index 0000000..c5aa3d5
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/034-chimera.png differ
diff --git a/mkdocs-plugins/docs/img/icons/035-sphinx.png b/mkdocs-plugins/docs/img/icons/035-sphinx.png
new file mode 100644
index 0000000..947f7e2
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/035-sphinx.png differ
diff --git a/mkdocs-plugins/docs/img/icons/036-pan.png b/mkdocs-plugins/docs/img/icons/036-pan.png
new file mode 100644
index 0000000..3fcfee5
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/036-pan.png differ
diff --git a/mkdocs-plugins/docs/img/icons/037-cyclops.png b/mkdocs-plugins/docs/img/icons/037-cyclops.png
new file mode 100644
index 0000000..9be4f63
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/037-cyclops.png differ
diff --git a/mkdocs-plugins/docs/img/icons/038-pegasus.png b/mkdocs-plugins/docs/img/icons/038-pegasus.png
new file mode 100644
index 0000000..a245bd1
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/038-pegasus.png differ
diff --git a/mkdocs-plugins/docs/img/icons/039-hermes-1.png b/mkdocs-plugins/docs/img/icons/039-hermes-1.png
new file mode 100644
index 0000000..f4f32de
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/039-hermes-1.png differ
diff --git a/mkdocs-plugins/docs/img/icons/040-centaur.png b/mkdocs-plugins/docs/img/icons/040-centaur.png
new file mode 100644
index 0000000..58bdb45
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/040-centaur.png differ
diff --git a/mkdocs-plugins/docs/img/icons/041-pyre.png b/mkdocs-plugins/docs/img/icons/041-pyre.png
new file mode 100644
index 0000000..02714d6
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/041-pyre.png differ
diff --git a/mkdocs-plugins/docs/img/icons/042-hercules.png b/mkdocs-plugins/docs/img/icons/042-hercules.png
new file mode 100644
index 0000000..4fe0fab
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/042-hercules.png differ
diff --git a/mkdocs-plugins/docs/img/icons/043-pegasus-1.png b/mkdocs-plugins/docs/img/icons/043-pegasus-1.png
new file mode 100644
index 0000000..f166d94
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/043-pegasus-1.png differ
diff --git a/mkdocs-plugins/docs/img/icons/044-horn.png b/mkdocs-plugins/docs/img/icons/044-horn.png
new file mode 100644
index 0000000..3b580da
Binary files /dev/null and b/mkdocs-plugins/docs/img/icons/044-horn.png differ
diff --git a/mkdocs-plugins/docs/img/index.png b/mkdocs-plugins/docs/img/index.png
new file mode 100644
index 0000000..afd322b
Binary files /dev/null and b/mkdocs-plugins/docs/img/index.png differ
diff --git a/mkdocs-plugins/docs/img/neoteroi-w.png b/mkdocs-plugins/docs/img/neoteroi-w.png
new file mode 100644
index 0000000..370eedd
Binary files /dev/null and b/mkdocs-plugins/docs/img/neoteroi-w.png differ
diff --git a/mkdocs-plugins/docs/img/neoteroi-w.svg b/mkdocs-plugins/docs/img/neoteroi-w.svg
new file mode 100644
index 0000000..45fd9e7
--- /dev/null
+++ b/mkdocs-plugins/docs/img/neoteroi-w.svg
@@ -0,0 +1,74 @@
+
+
diff --git a/mkdocs-plugins/docs/img/neoteroi-white.png b/mkdocs-plugins/docs/img/neoteroi-white.png
new file mode 100644
index 0000000..ed2363b
Binary files /dev/null and b/mkdocs-plugins/docs/img/neoteroi-white.png differ
diff --git a/mkdocs-plugins/docs/img/neoteroi.ico b/mkdocs-plugins/docs/img/neoteroi.ico
new file mode 100644
index 0000000..11cd814
Binary files /dev/null and b/mkdocs-plugins/docs/img/neoteroi.ico differ
diff --git a/mkdocs-plugins/docs/img/neoteroi.svg b/mkdocs-plugins/docs/img/neoteroi.svg
new file mode 100644
index 0000000..2ffdeef
--- /dev/null
+++ b/mkdocs-plugins/docs/img/neoteroi.svg
@@ -0,0 +1,75 @@
+
+
diff --git a/mkdocs-plugins/docs/img/oad-example-1.png b/mkdocs-plugins/docs/img/oad-example-1.png
new file mode 100644
index 0000000..2f338b4
Binary files /dev/null and b/mkdocs-plugins/docs/img/oad-example-1.png differ
diff --git a/mkdocs-plugins/docs/img/oad-example-2.png b/mkdocs-plugins/docs/img/oad-example-2.png
new file mode 100644
index 0000000..9914554
Binary files /dev/null and b/mkdocs-plugins/docs/img/oad-example-2.png differ
diff --git a/mkdocs-plugins/docs/img/oad.png b/mkdocs-plugins/docs/img/oad.png
new file mode 100644
index 0000000..392e921
Binary files /dev/null and b/mkdocs-plugins/docs/img/oad.png differ
diff --git a/mkdocs-plugins/docs/img/spantable.png b/mkdocs-plugins/docs/img/spantable.png
new file mode 100644
index 0000000..39f5a84
Binary files /dev/null and b/mkdocs-plugins/docs/img/spantable.png differ
diff --git a/mkdocs-plugins/docs/img/timeline.png b/mkdocs-plugins/docs/img/timeline.png
new file mode 100644
index 0000000..26e2934
Binary files /dev/null and b/mkdocs-plugins/docs/img/timeline.png differ
diff --git a/mkdocs-plugins/docs/index.md b/mkdocs-plugins/docs/index.md
new file mode 100644
index 0000000..38918d8
--- /dev/null
+++ b/mkdocs-plugins/docs/index.md
@@ -0,0 +1,53 @@
+# Plugins for MkDocs
+
+Plugins for [MkDocs](https://www.mkdocs.org) and [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/)
+by [Roberto Prevato](https://twitter.com/RobertoPrevato).
+
+```shell
+pip install neoteroi-mkdocs
+```
+
+::cards:: image-bg
+
+- title: Cards
+ content: |
+ Extension to provide cards-like HTML controls, to display information
+ with text and pictures.
+ image: ./img/cards.png
+ url: ./cards/
+
+- title: Timeline
+ content: |
+ Extension to display chronological information with style.
+ image: ./img/timeline.png
+ url: ./timeline/
+
+- title: Gantt
+ content: |
+ Markdown extension to generate beautiful gantt diagrams.
+ image: ./img/gantt.png
+ url: ./gantt/
+
+- title: OAD
+ content: |
+ MkDocs plugin to generate human readable documentation
+ from OpenAPI Documentation specification files (also known as
+ _swagger_ files).
+ image: ./img/oad.png
+ url: ./web/oad/
+
+- title: Spantable
+ content: |
+ Markdown extension to generate HTML tables supporting `colspan`
+ and `rowspan`.
+ image: ./img/spantable.png
+ url: ./spantable/
+
+- title: Contribs
+ content: |
+ MkDocs plugin to generate contributions information for each page, obtained
+ automatically from the project's `git` repository.
+ image: ./img/contribs-02.png
+ url: ./contribs/
+
+::/cards::
diff --git a/mkdocs-plugins/docs/intro.md b/mkdocs-plugins/docs/intro.md
new file mode 100644
index 0000000..1d4d712
--- /dev/null
+++ b/mkdocs-plugins/docs/intro.md
@@ -0,0 +1,14 @@
+These plugins are designed to be used with [MkDocs](https://www.mkdocs.org) and
+are tested for [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/).
+They should work also without Material for MkDocs, but they aren't tested for
+different kinds of themes.
+
+## How to obtain CSS files
+
+The plugins in this library use specific CSS rules to work. The source code is
+written in SASS, CSS files are built during the CI build of the project.
+
+The recommended way to obtain the CSS files is to download a copy from one of these sources:
+
+- the `dist-package-css` artifact generated by a build ([example](https://github.com/Neoteroi/mkdocs-plugins/actions/runs/2843393852))
+- downloads or assets of the latest successful release ([example](https://github.com/Neoteroi/mkdocs-plugins/releases/tag/v0.0.6))
diff --git a/mkdocs-plugins/docs/spantable.md b/mkdocs-plugins/docs/spantable.md
new file mode 100644
index 0000000..a3a4111
--- /dev/null
+++ b/mkdocs-plugins/docs/spantable.md
@@ -0,0 +1,106 @@
+Extension to support tables with `colspan` and `rowspan`, including automatic handling of
+span value, support for captions, and table classes.
+
+## How to use
+
+Edit your `mkdocs.yml` file to include the extra CSS file from Neoteroi
+mkdocs-plugins and the `neoteroi.spantable` extension:
+
+```yaml
+
+extra_css:
+ - css/neoteroi-mkdocs.css
+ ...
+
+markdown_extensions:
+ - neoteroi.spantable
+ ...
+
+```
+
+Write a Markdown table like in the following example, use `@span` placeholders for
+automatic handling of colspan and rowspan depending on adjacent empty cells (separator
+lines are ignored):
+
+```
+::spantable::
+
+| Country | Address |
+| ------------ | -------------------------------------------------------- |
+| France @span | 8 Rue St Ferréol - 92190 City: Meudon (Île-de-France) |
+| | 50 boulevard Amiral Courbet - 94310 Orly (Île-de-France) |
+| | ... |
+| | ... |
+| Italy @span | Str. S. Maurizio, 12, 10072 Caselle torinese TO |
+| | S.S. Torino-Asti - 10026 Santena (TO) |
+| | ... |
+| Poland @span | al. Jana Pawła II 22, 00-133 Warszawa |
+| | plac Trzech Krzyży 4/6, 00-535 Warszawa |
+| | ... |
+| | ... |
+
+::end-spantable::
+```
+
+Produces an output like the following:
+
+::spantable::
+
+| Country | Address |
+| ------------ | -------------------------------------------------------- |
+| France @span | 8 Rue St Ferréol - 92190 City: Meudon (Île-de-France) |
+| | 50 boulevard Amiral Courbet - 94310 Orly (Île-de-France) |
+| | ... |
+| | ... |
+| Italy @span | Str. S. Maurizio, 12, 10072 Caselle torinese TO |
+| | S.S. Torino-Asti - 10026 Santena (TO) |
+| | ... |
+| Poland @span | al. Jana Pawła II 22, 00-133 Warszawa |
+| | plac Trzech Krzyży 4/6, 00-535 Warszawa |
+| | ... |
+| | ... |
+
+::end-spantable::
+
+## Options
+
+| Option | Description |
+| :-------------- | :------------------------------------------------------------------------------------------------------------------------ |
+| @span | Applies colspan and rowspan automatically to expand the cell to all adjacent cells (colspan has precedence over rowspan). |
+| @span=x | colspan=x |
+| @span=x:y | colspan=x; rowspan=y; |
+| @class="value" | Adds an HTML _class_ to any cell, to simplify styling (optional). |
+| caption="value" | Adds a _caption_ element with the given value to the table (optional). |
+| class="value" | Adds a _class_ to the _table_ element with the given value (optional). |
+
+In the following example, the cells with `Italy` and `France` both get
+`colspan="2" rowspan="3"` because they have empty adjacent cells growing one
+column and two rows:
+
+```
+::spantable:: caption="Life Expectancy By Current Age" class="foo"
+
+| Italy @span | | 40 @span | | 20 @span | |
+| ------------- | ----- | ------------- | ----- | ------------- | ----- |
+| | | Men | Women | Men | Women |
+| | | 78 | 82 | 77 | 81 |
+| Poland @span | | 40 @span | | 20 @span | |
+| ------------- | ----- | ------------- | ----- | ------------- | ----- |
+| | | Men | Women | Men | Women |
+| | | 78 | 82 | 77 | 81 |
+
+::end-spantable::
+```
+
+::spantable:: caption="Life Expectancy By Current Age" class="foo"
+
+| Italy @span | | 40 @span | | 20 @span | |
+| ------------- | ----- | ------------- | ----- | ------------- | ----- |
+| | | Men | Women | Men | Women |
+| | | 78 | 82 | 77 | 81 |
+| Poland @span | | 40 @span | | 20 @span | |
+| ------------- | ----- | ------------- | ----- | ------------- | ----- |
+| | | Men | Women | Men | Women |
+| | | 78 | 82 | 77 | 81 |
+
+::end-spantable::
diff --git a/mkdocs-plugins/docs/timeline.md b/mkdocs-plugins/docs/timeline.md
new file mode 100644
index 0000000..391592b
--- /dev/null
+++ b/mkdocs-plugins/docs/timeline.md
@@ -0,0 +1,278 @@
+The timeline extension provides a way to display chronological events with style.
+A timeline is great to present a high level overview of information happening
+at different stages or times.
+
+[timeline(./docs/timeline/timeline-1.json)]
+
+## How to use
+
+Edit your `mkdocs.yml` file to include the extra CSS file from Neoteroi
+mkdocs-plugins and the `neoteroi.timeline` extension:
+
+```yaml
+
+extra_css:
+ - css/neoteroi-mkdocs.css
+ ...
+
+markdown_extensions:
+ - neoteroi.timeline
+ ...
+
+```
+
+## Input object
+
+### Examples
+
+=== "JSON"
+
+ ```json
+ ::timeline::
+
+ [
+ {
+ "title": "Launch",
+ "content": "First implementation.",
+ "icon": ":fontawesome-rocket:",
+ "sub_title": "2022-Q1"
+ },
+ {
+ "title": "One",
+ "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ "icon": ":octicons-sun-16:",
+ "key": "cyan",
+ "sub_title": "2022-Q2"
+ },
+ {
+ "title": "Two",
+ "content": "Lorem ipsum dolor sit amet.",
+ "icon": ":material-github:",
+ "sub_title": "2022-Q3"
+ },
+ {
+ "title": "Three",
+ "content": "Lorem ipsum dolor sit amet.",
+ "key": "pink",
+ "sub_title": "2022-Q4"
+ }
+ ]
+
+ ::/timeline::
+ ```
+
+=== "YAML"
+
+ ```yaml
+ ::timeline::
+
+ - content: First implementation.
+ icon: ':material-rocket-launch-outline:'
+ sub_title: 2022-Q1
+ title: Launch
+ - content: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ icon: ':fontawesome-solid-gem:'
+ sub_title: 2022-Q2
+ title: New features
+ - content: Lorem ipsum dolor sit amet.
+ icon: ':material-gauge-empty:'
+ sub_title: 2022-Q3
+ title: More features!
+ - content: Lorem ipsum dolor sit amet.
+ icon: ':material-bug:'
+ sub_title: 2022-Q4
+ title: Bugs!
+
+ ::/timeline::
+ ```
+
+=== "File source"
+
+ ```
+ [timeline(./settings.yaml)]
+
+ [timeline(./settings.json)]
+ ```
+
+=== "URL source"
+
+ ```
+ [timeline(https://www.neoteroi.dev/examples/timeline.yaml)]
+
+ [timeline(https://www.neoteroi.dev/examples/timeline.json)]
+ ```
+
+### Schema
+
+```mermaid
+classDiagram
+direction LR
+
+class TimelineItem {
+ title: str
+ content: str | null = null
+ sub_title: str | null = null
+ icon: str | null = null
+ key: str | null = null
+}
+
+class Timeline {
+ items: Array of TimelineItem
+}
+
+Timeline --> TimelineItem
+
+```
+
+```python
+
+@dataclass
+class TimelineItem:
+ title: str
+ content: str | None = None
+ sub_title: str | None = None
+ icon: str | None = None
+ key: str | None = None
+
+
+@dataclass
+class Timeline:
+ items: List[TimelineItem]
+
+```
+
+## Options
+
+The line of a timeline can be aligned on the left, center, or right.
+The default alignment for timelines is `left`.
+
+### Center alignment
+
+To have the line of the timeline on the center, add the `center` option:
+
+```
+[timeline center(./docs/timeline/timeline-1.json)]
+```
+
+[timeline center(./docs/timeline/timeline-1.json)]
+
+#### Center alternate
+
+When using `center` alignment, it is also possible to alternate the position of items,
+using the `alternate` option.
+
+```
+[timeline center alternate(./docs/timeline/timeline-1.json)]
+```
+
+[timeline center alternate(./docs/timeline/timeline-1.json)]
+
+### Right alignment
+
+To have the line of the timeline on the right, add the `right` option:
+
+```
+[timeline right(./docs/timeline/timeline-1.json)]
+```
+
+[timeline right(./docs/timeline/timeline-1.json)]
+
+### Rendering headings
+
+To render headings (`h3` elements), resulting in links for the table of contents, use the
+`headings` option.
+
+```
+[timeline center headings(./docs/timeline/timeline-1.json)]
+```
+
+### Icons support
+
+The timeline extension integrates with [Material for MkDocs icons](https://squidfunk.github.io/mkdocs-material/reference/icons-emojis/),
+like shown in the examples above. However, the extension also supports links to images,
+like in the following example:
+
+```
+::timeline:: class="epic-timeline"
+- title: Zeus does something
+ content: ...
+ icon: ./img/icons/001-zeus.png
+ sub_title: Turn 1
+- title: Athena does something
+ content: ...
+ icon: ./img/icons/003-athena.png
+ sub_title: Turn 2
+- title: Poseidon does something
+ content: ...
+ icon: ./img/icons/007-poseidon.png
+ sub_title: Turn 3
+::/timeline::
+```
+
+::timeline:: class="epic-timeline"
+- title: Zeus does something
+ content: ...
+ icon: ./img/icons/001-zeus.png
+ sub_title: Turn 1
+- title: Athena does something
+ content: ...
+ icon: ./img/icons/003-athena.png
+ sub_title: Turn 2
+- title: Poseidon does something
+ content: ...
+ icon: ./img/icons/007-poseidon.png
+ sub_title: Turn 3
+::/timeline::
+
+### Styling
+
+To apply custom styles to a timeline, assign a custom `id` or `class` to it, and apply
+custom CSS rules to the mkdocs configuration:
+
+```
+::timeline:: class="epic-timeline"
+
+...
+
+::timeline:: id="epic-timeline"
+```
+
+_mkdocs.yml_
+
+```yaml
+extra_css:
+ - css/example.css
+```
+
+_css/example.css_
+
+```css
+.epic-timeline .nt-timeline-dot .icon {
+ color: white;
+ background: white;
+ border-radius: 50%;
+}
+```
+
+To apply a class to a particular item of the timeline, assign a `key` property
+to it.
+
+```
+::timeline:: class="epic-timeline"
+- title: Zeus does something
+ key: zeus
+ content: ...
+ icon: ./img/icons/001-zeus.png
+ sub_title: Turn 1
+- title: Athena does something
+ key: athena
+ content: ...
+ icon: ./img/icons/003-athena.png
+ sub_title: Turn 2
+- title: Poseidon does something
+ key: poseidon
+ content: ...
+ icon: ./img/icons/007-poseidon.png
+ sub_title: Turn 3
+::/timeline::
+```
diff --git a/mkdocs-plugins/docs/timeline/timeline-1.json b/mkdocs-plugins/docs/timeline/timeline-1.json
new file mode 100644
index 0000000..8d00e24
--- /dev/null
+++ b/mkdocs-plugins/docs/timeline/timeline-1.json
@@ -0,0 +1,26 @@
+[
+ {
+ "title": "Launch",
+ "content": "First implementation.",
+ "icon": ":material-rocket-launch-outline:",
+ "sub_title": "2022-Q1"
+ },
+ {
+ "title": "New features",
+ "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ "icon": ":fontawesome-solid-gem:",
+ "sub_title": "2022-Q2"
+ },
+ {
+ "title": "More features!",
+ "content": "Lorem ipsum dolor sit amet.",
+ "icon": ":material-gauge-empty:",
+ "sub_title": "2022-Q3"
+ },
+ {
+ "title": "Bugs!",
+ "content": "Lorem ipsum dolor sit amet.",
+ "icon": ":material-bug:",
+ "sub_title": "2022-Q4"
+ }
+]
diff --git a/mkdocs-plugins/docs/timeline/timeline-1.yaml b/mkdocs-plugins/docs/timeline/timeline-1.yaml
new file mode 100644
index 0000000..52c5884
--- /dev/null
+++ b/mkdocs-plugins/docs/timeline/timeline-1.yaml
@@ -0,0 +1,16 @@
+- content: First implementation.
+ icon: ':material-rocket-launch-outline:'
+ sub_title: 2022-Q1
+ title: Launch
+- content: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ icon: ':fontawesome-solid-gem:'
+ sub_title: 2022-Q2
+ title: New features
+- content: Lorem ipsum dolor sit amet.
+ icon: ':material-gauge-empty:'
+ sub_title: 2022-Q3
+ title: More features!
+- content: Lorem ipsum dolor sit amet.
+ icon: ':material-bug:'
+ sub_title: 2022-Q4
+ title: Bugs!
diff --git a/mkdocs-plugins/docs/web/oad.md b/mkdocs-plugins/docs/web/oad.md
new file mode 100644
index 0000000..49c101a
--- /dev/null
+++ b/mkdocs-plugins/docs/web/oad.md
@@ -0,0 +1,86 @@
+Plugin for MkDocs to generate human readable documentation from [OpenAPI
+Documentation](https://swagger.io/specification/) **Version 3** (also known as
+Swagger documentation).
+
+## How to use
+
+Install using `pip install neoteroi-mkdocs`.
+Configure this plugin in the MkDocs configuration file:
+
+```yaml
+plugins:
+ - search
+ - neoteroi.mkdocsoad
+```
+
+Configure a source in your Markdown file, for example having a `swagger.json`
+file in your `docs` folder:
+
+```markdown
+[OAD(./docs/swagger.json)]
+```
+
+The plugin fetches the contents from the OpenAPI Specification source,
+generates Markdown using [essentials-openapi](https://github.com/Neoteroi/essentials-openapi),
+then writes them in the markdown file.
+
+This configuration is sufficient to generate HTML documentation from OpenAPI
+specification files. To have a better looking result, it is recommended to apply the
+extra configuration steps described in the next paragraph.
+
+### Recommended: enable PyMDown and extra CSS
+
+This plugin was designed to generate Markdown for sites that use [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/)
+and three extensions from [PyMdown extensions](https://facelessuser.github.io/pymdown-extensions/).
+To achieve the best results, it is recommended to enable PyMdown extensions.
+
+- Install [PyMdown extensions](https://facelessuser.github.io/pymdown-extensions/)
+ using `pip install pymdown-extensions`
+- Configure the following PyMdown markdown extensions in the MkDocs
+ configuration file:
+
+```yaml
+markdown_extensions:
+ - pymdownx.details
+ - pymdownx.superfences
+ - pymdownx.tabbed:
+ alternate_style: true
+```
+
+- Enable PyMdown integration this way:
+
+```yaml
+plugins:
+ - search
+ - neoteroi.mkdocsoad:
+ use_pymdownx: true
+```
+
+- Download a copy of [`neoteroi.mkdocsoad.css` file](/mkdocs-plugins/intro/) and
+ configure it as extra file in your MkDocs configuration:
+
+```yaml
+extra_css:
+ - css/mkdocsoad.css
+```
+
+Example result:
+
+
+
+!!! danger "Soon changing..."
+ This feature is currently shipped as plugin for MkDocs, it will be modified
+ to be an extension for Python Markdown.
+
+## Supported sources for OpenAPI Documentation
+
+| Source | Example |
+| :----------------------------- | :---------------------------------------------------------- |
+| YAML file | `[OAD(./docs/swagger.yaml)]` |
+| JSON file | `[OAD(./docs/swagger.json)]` |
+| URL returning YAML on HTTP GET | `[OAD(https://example-domain.net/swagger/v1/swagger.yaml)]` |
+| URL returning JSON on HTTP GET | `[OAD(https://example-domain.net/swagger/v1/swagger.json)]` |
+
+---
+
+
diff --git a/mkdocs-plugins/mkdocs.yml b/mkdocs-plugins/mkdocs.yml
new file mode 100644
index 0000000..daf2d7c
--- /dev/null
+++ b/mkdocs-plugins/mkdocs.yml
@@ -0,0 +1,88 @@
+site_name: MkDocs Plugins
+site_author: Roberto Prevato
+site_description: The documentation of Neoteroi MkDocs Plugins.
+site_url: https://www.neoteroi.dev/mkdocs-plugins/
+repo_name: Neoteroi/mkdocs-plugins
+repo_url: https://github.com/Neoteroi/mkdocs-plugins
+edit_uri: ""
+
+nav:
+ - Overview: index.md
+ - Introduction: intro.md
+ - Plugins:
+ - Cards: cards.md
+ - Timeline: timeline.md
+ - Gantt: gantt.md
+ - OpenAPI Docs: ./web/oad.md
+ - Spantable: spantable.md
+ - Contribs: contribs.md
+ - Info:
+ - Credits: credits.md
+ - About: about.md
+ - Neoteroi docs home: "/"
+
+theme:
+ palette:
+ - scheme: slate
+ toggle:
+ icon: material/toggle-switch
+ name: Switch to light mode
+ - scheme: default
+ toggle:
+ icon: material/toggle-switch-off-outline
+ name: Switch to dark mode
+ name: "material"
+ custom_dir: overrides/
+ highlightjs: true
+ favicon: img/neoteroi.ico
+ logo: img/neoteroi-w.svg
+ font:
+ text: Roboto
+ code: Roboto Mono
+ icon:
+ repo: fontawesome/brands/github
+
+extra_css:
+ - css/extra.css
+ - css/neoteroi.css
+
+plugins:
+ - search
+ - neoteroi.contribs:
+ contributors:
+ - email: roberto.prevato@gmail.com
+ image: https://avatars.githubusercontent.com/u/2576032?s=400&u=d8d880e8ed05bb170877dd3d561d8301c4beeeed&v=4
+
+markdown_extensions:
+ - admonition
+ - neoteroi.spantable
+ - neoteroi.timeline
+ - neoteroi.cards
+ - neoteroi.projects
+ - markdown.extensions.codehilite:
+ guess_lang: false
+ - toc:
+ permalink: true
+ - pymdownx.arithmatex
+ - pymdownx.betterem:
+ smart_enable: all
+ - pymdownx.caret
+ - pymdownx.critic
+ - pymdownx.details
+ - pymdownx.emoji:
+ emoji_index: !!python/name:material.extensions.emoji.twemoji
+ emoji_generator: !!python/name:material.extensions.emoji.to_svg
+ - pymdownx.inlinehilite
+ - pymdownx.magiclink
+ - pymdownx.mark
+ - pymdownx.smartsymbols
+ - pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:pymdownx.superfences.fence_code_format
+ - pymdownx.tasklist:
+ custom_checkbox: true
+ - pymdownx.tabbed:
+ alternate_style: true
+ - footnotes
diff --git a/mkdocs-plugins/overrides/main.html b/mkdocs-plugins/overrides/main.html
new file mode 100644
index 0000000..7a6985e
--- /dev/null
+++ b/mkdocs-plugins/overrides/main.html
@@ -0,0 +1,41 @@
+{% extends "base.html" %}
+{% block extrahead %}
+{% set title = config.site_name %}
+{% if page and page.title and not page.is_homepage %}
+{% set title = config.site_name ~ " - " ~ page.title | striptags %}
+{% endif %}
+{% set image = config.site_url ~ 'img/index.png' %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
+{% block content %}
+{{ super() }}
+{% endblock %}
+{% block analytics %}
+
+
+{% endblock %}
+{% block footer %}
+
+{{ super() }}
+{% endblock %}
diff --git a/pack.sh b/pack.sh
new file mode 100755
index 0000000..32d4337
--- /dev/null
+++ b/pack.sh
@@ -0,0 +1,42 @@
+#! /bin/bash
+folders=(
+ blacksheep
+ mkdocs-plugins
+)
+
+rm -rf site
+rm -rf ./site.zip
+mkdir -p site
+
+for folder in "${folders[@]}" ; do
+ echo "$folder 🏗️"
+ mkdir site/$folder
+
+ cd $folder
+
+ mkdocs build
+
+ # check if there is a copy-archive.sh file, to support including docs
+ # of older versions of the library
+ if [ -f "copy-archive.sh" ]; then
+ echo "File $FILE exists."
+ ./copy-archive.sh
+ fi
+
+ mv site/* ../site/$folder
+ rm -rf site
+ cd ../
+done
+
+# The home is special...
+echo "home"
+cd home
+mkdocs build
+mv site/* ../site/
+rm -rf site
+cd ../
+
+echo "Zipping..."
+7z a -r site.zip site
+
+echo "All done! ✨ 🍰 ✨"
diff --git a/requirements.txt b/requirements.txt
index dc20436..fa93dc7 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,55 +1,2 @@
-anyio==3.6.2
-azure-common==1.1.28
-azure-core==1.25.0
-azure-storage-blob==12.13.1
-certifi==2022.9.24
-cffi==1.15.1
-charset-normalizer==2.1.1
-click
-commonmark==0.9.1
-cryptography==38.0.3
-essentials==1.1.5
-essentials-openapi==1.0.4
-future==0.18.2
-ghp-import==2.0.2
-h11==0.12.0
-httpcore==0.15.0
-httpx==0.23.0
-idna==3.4
-importlib-metadata==4.10.1
-isodate==0.6.1
-Jinja2==3.0.3
-joblib==0.17.0
-livereload==2.6.3
-lunr==0.5.8
-Markdown==3.3
-MarkupSafe==2.1.1
-mergedeep==1.3.4
-mkdocs==1.4.2
-mkdocs-material==7.3.1
-mkdocs-material-extensions==1.0.1
-msrest==0.7.1
-neoteroi-mkdocs==0.1.2
-nltk==3.5
-oauthlib==3.2.2
-packaging==21.3
-pycparser==2.21
-Pygments==2.7.1
-pymdown-extensions==9.1
-pyparsing==3.0.7
-python-dateutil==2.8.2
-PyYAML==6.0
-pyyaml_env_tag==0.1
-regex==2020.9.27
-requests==2.28.1
-requests-oauthlib==1.3.1
-rfc3986==1.5.0
-rich==12.2.0
-six==1.15.0
-sniffio==1.3.0
-tornado==6.0.4
-tqdm==4.50.0
-typing_extensions==4.4.0
-urllib3==1.26.12
-watchdog==2.1.6
-zipp==3.7.0
+mkdocs-material==9.6.9
+neoteroi-mkdocs==1.1.0