diff --git a/docs/assets/stylesheets/extra.css b/docs/assets/stylesheets/extra.css new file mode 100644 index 0000000..c010654 --- /dev/null +++ b/docs/assets/stylesheets/extra.css @@ -0,0 +1,118 @@ +/** + * Example information + */ + +.md-typeset .author { + text-align: right; +} + +/** + * Tag filters + */ +.md-typeset .filters { + background-color: lightgray; +} + +.md-typeset .tagcheck { + display: none; +} + +.md-typeset .taglabel { + background: var(--md-primary-fg-color); + border-radius: 10px; + padding-left: 5px; + padding-right: 5px; + color: white; + font-size: .64rem; +} + +.md-typeset .taglist { + float:right; + padding-left:1em; +} + +.md-typeset input:not(:checked) + .taglabel { + background: #909090; +} + +/** First row: Materials version and integration **/ + +#public:not(:checked) ~ .example[data-tags~="public"]{ + display:none; +} + +#insiders:not(:checked) ~ .example[data-tags~="insiders"]{ + display:none; +} + +#integration:not(:checked) ~ .example[data-tags~="integration"]{ + display:none; +} + +/** Second row: functionality */ + +#colors:not(:checked) ~ .example[data-tags~="colors"]{ + display:none; +} + +#fonts:not(:checked) ~ .example[data-tags~="fonts"]{ + display:none; +} + +#icons:not(:checked) ~ .example[data-tags~="icons"]{ + display:none; +} + +#page_status:not(:checked) ~ .example[data-tags~="page_status"]{ + display:none; +} + +/** Third row: plugin */ + +#blog:not(:checked) ~ .example[data-tags~="blog"]{ + display:none; +} + +#group:not(:checked) ~ .example[data-tags~="group"]{ + display:none; +} + +#info:not(:checked) ~ .example[data-tags~="info"]{ + display:none; +} + +#meta:not(:checked) ~ .example[data-tags~="meta"]{ + display:none; +} + +#offline:not(:checked) ~ .example[data-tags~="offline"]{ + display:none; +} + +#optimize:not(:checked) ~ .example[data-tags~="optimize"]{ + display:none; +} + +#privacy:not(:checked) ~ .example[data-tags~="privacy"]{ + display:none; +} + +#projects:not(:checked) ~ .example[data-tags~="projects"]{ + display:none; +} + +#search:not(:checked) ~ .example[data-tags~="search"]{ + display:none; +} + +#social:not(:checked) ~ .example[data-tags~="social"]{ + display:none; +} + +#tags:not(:checked) ~ .example[data-tags~="tags"] { + display: none; +} + +#typeset:not(:checked) ~ .example[data-tags~="typeset"] { + display: none; +} diff --git a/docs/index.md b/docs/index.md index 4f5b689..a0abec2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,10 +1,25 @@ +--- +template: exampleindex.html +--- # Examples -This project lists all options that are supported by Material for MkDocs and -can be used as a basis for new projects or reproductions. Note that some options -might currently be reserved for [sponsors]. Check the list of [available features] -to be sure. +The examples in this repository augment the documentation of Material for +MkDocs by providing worked examples of the functionality it provides. There +are also extended examples showing common integrations with third-party plugins +or that demonstrate specific use cases. + +Our aim is to cover all the options that are supported by Material for MkDocs +so that the examples can be used as a basis for new projects or [reproductions]. + +Note that some options might currently be reserved for [sponsors]. We aim to +indicate this in the tags that are displayed with each examples but please +check the list of [available features] to be sure. [sponsors]: https://squidfunk.github.io/mkdocs-material/insiders/ [available features]: https://squidfunk.github.io/mkdocs-material/insiders/#whats-in-for-me + [reproductions]: https://squidfunk.github.io/mkdocs-material/guides/creating-a-reproduction/ +Use the filters below to choose which examples should be shown. For an example +to show, the filters matching *all* of its tags need to be selected. Note that +some examples have addtional tags that do not show in the filters - these are +not used in filtering. diff --git a/examples/blog-basic/.example.yml b/examples/blog-basic/.example.yml deleted file mode 100644 index 5186201..0000000 --- a/examples/blog-basic/.example.yml +++ /dev/null @@ -1,10 +0,0 @@ -example: - tags: - - public # works without Insiders - - blog # functionality demonstrated - - simple # requires no extra plugins or other magic - authors: - alexvoss: - name: Alex Voss - description: Collaborator - avatar: https://github.com/alexvoss.png diff --git a/examples/blog-basic/docs/README.md b/examples/blog-basic/docs/README.md index 18167eb..6daada6 100644 --- a/examples/blog-basic/docs/README.md +++ b/examples/blog-basic/docs/README.md @@ -1,8 +1,17 @@ -# Adding a blog to your site +--- +tags: + - public + - blog +authors: + alexvoss: + name: Alex Voss + description: Collaborator + ghuser: alexvoss +--- -This example shows how to add a [blog] to your site. +# Adding a blog to your site -It shows how to: +This example shows how to add a [blog] to your site. It shows how to: - configure the `mkdocs.yml` to activate and configure the plugin - set up a directory structure in your `docs/` folder diff --git a/examples/blog-rss/.example.yaml b/examples/blog-rss/.example.yaml deleted file mode 100644 index 1d5a3c5..0000000 --- a/examples/blog-rss/.example.yaml +++ /dev/null @@ -1,10 +0,0 @@ -example: - tags: - - public # works without Insiders - - blog # functionality demonstrated - - integration # demonstrates integration, use of other plugins - authors: - alexvoss: - name: Alex Voss - description: Collaborator - avatar: https://github.com/alexvoss.png diff --git a/examples/blog-rss/docs/README.md b/examples/blog-rss/docs/README.md index 629c575..615bdb3 100644 --- a/examples/blog-rss/docs/README.md +++ b/examples/blog-rss/docs/README.md @@ -1,3 +1,14 @@ +--- +tags: + - public + - blog + - integration +authors: + alexvoss: + name: Alex Voss + description: Collaborator + ghuser: alexvoss +--- # Adding an RSS feed to a blog This example shows how to [add an RSS feed to a blog]. You should be diff --git a/examples/blog-update/.example.yml b/examples/blog-update/.example.yml deleted file mode 100644 index 737b14a..0000000 --- a/examples/blog-update/.example.yml +++ /dev/null @@ -1,11 +0,0 @@ -example: - tags: - - public # works without Insiders - - blog # functionality demonstrated - - simple # requires no extra plugins or other magic - - customization # shows how to customize the theme - authors: - alexvoss: - name: Alex Voss - description: Collaborator - avatar: https://github.com/alexvoss.png diff --git a/examples/blog-update/docs/README.md b/examples/blog-update/docs/README.md index a845fc4..6d92359 100644 --- a/examples/blog-update/docs/README.md +++ b/examples/blog-update/docs/README.md @@ -1,3 +1,15 @@ +--- +name: Blog that shows post updates +tags: + - public + - blog + - customization +authors: + alexvoss: + name: Alex Voss + description: Collaborator + ghuser: alexvoss +--- # A blog with update dates shown This example shows how to add a small customization that will show diff --git a/examples/color-palette-system-preference/docs/README.md b/examples/color-palette-system-preference/docs/README.md index 1f7e1f2..53453dd 100644 --- a/examples/color-palette-system-preference/docs/README.md +++ b/examples/color-palette-system-preference/docs/README.md @@ -1,3 +1,8 @@ +--- +tags: + - colors + - public +--- # Using the color palette system preference This example shows how to implement the [color palette toggle] so that it diff --git a/examples/color-palette-toggle/docs/README.md b/examples/color-palette-toggle/docs/README.md index fae9b34..c619488 100644 --- a/examples/color-palette-toggle/docs/README.md +++ b/examples/color-palette-toggle/docs/README.md @@ -1,3 +1,9 @@ +--- +tags: + - colors + - public +--- + # Using the color palette toggle This example shows how to implement the [color palette toggle] to let users switch diff --git a/examples/cookie-consent/docs/README.md b/examples/cookie-consent/docs/README.md index ac8f67c..840eca4 100644 --- a/examples/cookie-consent/docs/README.md +++ b/examples/cookie-consent/docs/README.md @@ -1,3 +1,8 @@ +--- +tags: + - privacy + - insiders +--- # Adding a cookie consent This example shows how to add a [cookie consent]. [Click here] to bring diff --git a/examples/custom-colors/docs/README.md b/examples/custom-colors/docs/README.md index b8142a9..99df2d9 100644 --- a/examples/custom-colors/docs/README.md +++ b/examples/custom-colors/docs/README.md @@ -1,3 +1,8 @@ +--- +tags: + - colors + - public +--- # Using custom colors This example shows how to set [custom colors] with [additional CSS]. diff --git a/examples/custom-cookies/docs/README.md b/examples/custom-cookies/docs/README.md index 70753bc..9d10b89 100644 --- a/examples/custom-cookies/docs/README.md +++ b/examples/custom-cookies/docs/README.md @@ -1,3 +1,8 @@ +--- +tags: + - insiders + - privacy +--- # Adding a custom cookie This example shows how to add a [custom cookie] to the [cookie consent] and diff --git a/examples/fonts-builtin/docs/README.md b/examples/fonts-builtin/docs/README.md index 6e067d9..8891ddf 100644 --- a/examples/fonts-builtin/docs/README.md +++ b/examples/fonts-builtin/docs/README.md @@ -1,3 +1,14 @@ +--- +tags: + - public + - fonts +authors: + alexvoss: + name: Alex Voss + description: Collaborator + ghuser: alexvoss +--- + # Using built-in browser fonts This example shows what happens when auto-loading of fonts from Google diff --git a/examples/fonts-custom/.example.yml b/examples/fonts-custom/.example.yml new file mode 100644 index 0000000..92ec824 --- /dev/null +++ b/examples/fonts-custom/.example.yml @@ -0,0 +1,11 @@ +example: + name: Using a custom font + tags: + - public # works without Insiders + - fonts # functionality demonstrated + - simple # uses only Material functionality + authors: + alexvoss: + name: Alex Voss + description: Collaborator + ghuser: alexvoss diff --git a/examples/fonts-custom/docs/README.md b/examples/fonts-custom/docs/README.md index f5ecfb6..dea3387 100644 --- a/examples/fonts-custom/docs/README.md +++ b/examples/fonts-custom/docs/README.md @@ -1,3 +1,13 @@ +--- +tags: + - public + - fonts +authors: + alexvoss: + name: Alex Voss + description: Collaborator + ghuser: alexvoss +--- # Using a custom font This example uses the Noto Serif and Noto Mono font families to show diff --git a/examples/page-status/docs/README.md b/examples/page-status/docs/README.md index 965965b..e2b2358 100644 --- a/examples/page-status/docs/README.md +++ b/examples/page-status/docs/README.md @@ -1,3 +1,8 @@ +--- +tags: + - public + - "page_status" +--- # Using page status This example shows how to add a [page status] to a page. This works for section diff --git a/examples/tags-with-icons/docs/README.md b/examples/tags-with-icons/docs/README.md index 6ab3284..38977db 100644 --- a/examples/tags-with-icons/docs/README.md +++ b/examples/tags-with-icons/docs/README.md @@ -1,3 +1,8 @@ +--- +tags: + - public + - tags +--- # Using tags with icons This example shows how to use [tags with icons] and includes the following pages: diff --git a/examples/tags/docs/README.md b/examples/tags/docs/README.md index 74bb118..195cb79 100644 --- a/examples/tags/docs/README.md +++ b/examples/tags/docs/README.md @@ -1,3 +1,8 @@ +--- +tags: + - public + - tags +--- # Using tags This example shows how to use [tags] and includes the following pages: diff --git a/hooks/index_pages.py b/hooks/index_pages.py new file mode 100644 index 0000000..319071f --- /dev/null +++ b/hooks/index_pages.py @@ -0,0 +1,124 @@ +# Copyright (c) 2016-2023 Martin Donath +# Alex Voss +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +""" +Hook for building an index of examples in `examples/` by parsing the +`README.md` files for metadata, both from the Markdown header and the +Markdown itself. +""" + +import logging +import os +from glob import iglob + +import yaml +from mkdocs.config.defaults import MkDocsConfig + +# ----------------------------------------------------------------------------- +# State +# ----------------------------------------------------------------------------- + +# pre-defined structure for the tag filters. +tags = [ + ["public", "insiders", "integration"], + ["colors", "fonts", "icons", "page_status"], + ["blog", "group", "info", "meta", "offline", "optimize", \ + "privacy", "projects", "search", "social", "tags", "typeset"] +] + +# The list of examples. +examples = [] + +def on_pre_build(config: MkDocsConfig): + """ + Populate the module variables examples and tags with the data from all + the `.example.y(a)ml` files we can find in `examples/`. + """ + + if len(examples) > 0: + examples.clear() + + readmes = iglob("examples/*/docs/README.md", recursive = True) + for file in readmes: + example = read_header(file) + example['path'] = os.path.dirname(file) + examples.append(example) + log.info("Found %d examples with metadata.", len(examples)) + +def read_header(file) -> dict: + """ + Read the YAML header from a Markdown file (or the first document from + a multi-document yaml file) by scanning for the separator lines ('---'). + If the metadata do not specify a name for the example, the markdown is + scanned for a top-level heading. + + Limitation: currently assumes there *is* a markdown header, so files + without one will fail to parse, resulting in a message on the log and + an example object that contains an error message. + """ + header = [] + with open(file, 'r', encoding='utf-8') as fd: + line = fd.readline() + if line == '---\n': # found a markdown yaml header + example = read_yaml_header(file, header, fd) + else: # found plain Markdown file + example = {} + if not 'name' in example: + example['name'] = read_first_markdown_heading(line, fd) + return example + +def read_yaml_header(file, header, fd): + """ + Read the YAML header from `fd`, scanning up to the second separating + line and using `yaml.safe_load()` to do the parsing. + """ + line = fd.readline() + while line not in ("---\n", ""): + header.append(line) + line = fd.readline() + try: + example = yaml.safe_load("".join(header)) + except yaml.error.YAMLError as err: + log.warning("could not read Markdown header in: %s - error: %s", file, str(err)) + example = {"name": "failed to parse"} + return example + +def read_first_markdown_heading(line, fd) -> str: + """ + After reading the YAML header, scan the Markdown for a first-level + heading, indicated by '# ' as the first non-whitespace characters. + """ + while not line.startswith('# '): + if line == '': + return 'no name' + line = fd.readline() + return line.removeprefix('# ') + +def on_page_context(context, *, page, config, nav): + """ + Put the data collected into the rendering context so the data are + available to the template. + """ + context["exampletags"] = tags + context["examples"] = examples + +# Set up logging +log = logging.getLogger("mkdocs.material.examples") diff --git a/mkdocs.yml b/mkdocs.yml index bed6f4e..5bbc214 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -43,6 +43,7 @@ theme: - navigation.sections icon: logo: logo + custom_dir: overrides # Plugins plugins: @@ -54,13 +55,16 @@ plugins: # Hooks hooks: - hooks/archive.py + - hooks/index_pages.py # Customization extra: analytics: provider: google property: !ENV GOOGLE_ANALYTICS_KEY - +extra_css: + - assets/stylesheets/extra.css + # Extensions markdown_extensions: - admonition diff --git a/overrides/exampleindex.html b/overrides/exampleindex.html new file mode 100644 index 0000000..5562c8f --- /dev/null +++ b/overrides/exampleindex.html @@ -0,0 +1,47 @@ +{% extends "base.html" %} + +{% block content %} + {% include "partials/content.html" %} +
+ {% for group in exampletags %} + {% for tag in group %} + + + {% endfor %} +
+ {% endfor %} + {% for example in examples %} +
+
+
+ {{ ', '.join(example['tags']) }} +
+ {{ example['name']}} +
+

+ {% if 'description' in example %} + {{ example['description'] }} + {% else %} + Missing description. + {% endif %} +

+ {% if 'authors' in example %} + {% for author in example['authors'] %} + {% set author = example['authors'][author] %} +
+ {% if 'name' in author %} + {% if 'ghuser' in author %} + by {{ author['name'] }} + {% else %} + by {{ author['name'] }} + {% endif %} + {% endif %} +
+ {% endfor %} + {% endif %} +
+ {% endfor %} +
+{% endblock %} \ No newline at end of file