From c445e80a7f4c3831299b70eba7ebe50dc12292e0 Mon Sep 17 00:00:00 2001 From: Alex Voss Date: Tue, 7 Nov 2023 20:32:53 +0000 Subject: [PATCH 1/6] added mechanism to create index pages with information based on `.example.yml` files that describe each example --- docs/index.md | 1 + examples/blog-basic/.example.yml | 1 + examples/blog-rss/.example.yaml | 1 + hooks/index_pages.py | 100 +++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+) create mode 100644 hooks/index_pages.py diff --git a/docs/index.md b/docs/index.md index 4f5b689..b3c86ac 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,3 +8,4 @@ to be sure. [sponsors]: https://squidfunk.github.io/mkdocs-material/insiders/ [available features]: https://squidfunk.github.io/mkdocs-material/insiders/#whats-in-for-me + diff --git a/examples/blog-basic/.example.yml b/examples/blog-basic/.example.yml index 5186201..372ee35 100644 --- a/examples/blog-basic/.example.yml +++ b/examples/blog-basic/.example.yml @@ -1,4 +1,5 @@ example: + name: Adding a blog to your site tags: - public # works without Insiders - blog # functionality demonstrated diff --git a/examples/blog-rss/.example.yaml b/examples/blog-rss/.example.yaml index 1d5a3c5..d9d879d 100644 --- a/examples/blog-rss/.example.yaml +++ b/examples/blog-rss/.example.yaml @@ -1,4 +1,5 @@ example: + name: Adding an RSS-feed to your blog tags: - public # works without Insiders - blog # functionality demonstrated diff --git a/hooks/index_pages.py b/hooks/index_pages.py new file mode 100644 index 0000000..d7630fa --- /dev/null +++ b/hooks/index_pages.py @@ -0,0 +1,100 @@ +# 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. + +import inspect +import logging +import os +import re +import yaml + +from glob import iglob +from mkdocs.config.defaults import MkDocsConfig +from mkdocs.structure.files import File, Files +from mkdocs.structure.pages import Page +from re import Match + +# ----------------------------------------------------------------------------- +# State +# ----------------------------------------------------------------------------- + +# Initialize incremental builds +examples = [] + +# ----------------------------------------------------------------------------- +# Hooks +# ----------------------------------------------------------------------------- + +def on_pre_build(config: MkDocsConfig): + """ + Populate the module variable examples with the data from all the + `.example.y(a)ml` files we can find in `examples/`. + """ + global examples + examples = [] + + # Create archives for each example + ymlfiles = iglob("examples/*/.example.y*ml", recursive = True) + for file in ymlfiles: + with open(file, 'r') as f: + example = yaml.safe_load(f)['example'] + example['path'] = os.path.dirname(file) + examples.append(example) + log.info(f"Found {len(examples)} examples with metadata.") + +def on_page_markdown(markdown: str, page, config, files): + """ + For each markdown page, look for a marker `` and + replace it with the list of examples. + """ + + def replace(match: Match): + rendered = [] + type, args = match.groups() + args = args.strip() + if type == "all": + for example in examples: + rendered.append(render(example)) + return '\n'.join(rendered) + + log.info(f"looking for index definitions") + return re.sub( + r"", + replace, markdown, flags = re.I | re.M + ) + +def render(example: dict) -> str: + result = f"""
+
{render_tags(example['tags'])}
+ + {example['name']} + +
""".strip() + return result + +def render_tags(tags: list) -> str: + return ', '.join(tags) + +# ----------------------------------------------------------------------------- +# Data +# ----------------------------------------------------------------------------- + +# Set up logging +log = logging.getLogger("mkdocs.material.examples") From 06cd1dbdd83574e78e2d3d529b80800984c39070 Mon Sep 17 00:00:00 2001 From: Alex Voss Date: Sun, 26 Nov 2023 16:46:15 -0500 Subject: [PATCH 2/6] fix: exception on incomplete .example.yml, added to mkdocs.yml code maintenance: - added missing encoding to open (PyLint W1514) - removed f-strings from log statements (PyLint W1309) - reorganized imports (PyLint misc) - removed use of global variable (PyLint W0603) - avoiding use of 'type' as a variable name --- hooks/index_pages.py | 34 ++++++++++++++++++++-------------- mkdocs.yml | 1 + 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/hooks/index_pages.py b/hooks/index_pages.py index d7630fa..1974a43 100644 --- a/hooks/index_pages.py +++ b/hooks/index_pages.py @@ -19,17 +19,13 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. -import inspect import logging import os import re -import yaml - from glob import iglob + +import yaml from mkdocs.config.defaults import MkDocsConfig -from mkdocs.structure.files import File, Files -from mkdocs.structure.pages import Page -from re import Match # ----------------------------------------------------------------------------- # State @@ -47,17 +43,15 @@ def on_pre_build(config: MkDocsConfig): Populate the module variable examples with the data from all the `.example.y(a)ml` files we can find in `examples/`. """ - global examples - examples = [] # Create archives for each example ymlfiles = iglob("examples/*/.example.y*ml", recursive = True) for file in ymlfiles: - with open(file, 'r') as f: + with open(file, 'r', encoding='utf-8') as f: example = yaml.safe_load(f)['example'] example['path'] = os.path.dirname(file) examples.append(example) - log.info(f"Found {len(examples)} examples with metadata.") + log.info("Found %d examples with metadata.", len(examples)) def on_page_markdown(markdown: str, page, config, files): """ @@ -65,22 +59,31 @@ def on_page_markdown(markdown: str, page, config, files): replace it with the list of examples. """ - def replace(match: Match): + def replace(match: re.Match): rendered = [] - type, args = match.groups() + indextype, args = match.groups() args = args.strip() - if type == "all": + if indextype == "all": for example in examples: rendered.append(render(example)) return '\n'.join(rendered) + else: + log.error("At the moment, we do not support filtering, so use 'all'.") + return "Invalid index placeholder." - log.info(f"looking for index definitions") + log.info("looking for index definitions") return re.sub( r"", replace, markdown, flags = re.I | re.M ) def render(example: dict) -> str: + """ + Render an individual example and return the HTML as a string. + """ + if not 'name' in example and 'path' in example: + log.info("ignored example %s as it was missing a name", example['path']) + return "" result = f"""
{render_tags(example['tags'])}
@@ -90,6 +93,9 @@ def render(example: dict) -> str: return result def render_tags(tags: list) -> str: + """ + Render a list of tags. TODO: discuss how tags can be selected? + """ return ', '.join(tags) # ----------------------------------------------------------------------------- diff --git a/mkdocs.yml b/mkdocs.yml index bed6f4e..95d77a9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -54,6 +54,7 @@ plugins: # Hooks hooks: - hooks/archive.py + - hooks/index_pages.py # Customization extra: From bbd92b72ef7c094ec9484a4137a2b9a4dd2cd1ec Mon Sep 17 00:00:00 2001 From: Alex Voss Date: Mon, 27 Nov 2023 16:36:56 -0500 Subject: [PATCH 3/6] added missing name attribute --- examples/blog-update/.example.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/blog-update/.example.yml b/examples/blog-update/.example.yml index 737b14a..eb3fb21 100644 --- a/examples/blog-update/.example.yml +++ b/examples/blog-update/.example.yml @@ -1,4 +1,5 @@ example: + name: Blog that shows post updates tags: - public # works without Insiders - blog # functionality demonstrated From 6041d51afeeb63ecdba2e1cdf78d96420d467f2f Mon Sep 17 00:00:00 2001 From: Alex Voss Date: Mon, 27 Nov 2023 21:27:17 -0500 Subject: [PATCH 4/6] New implementation of examples index page using a custom template instead of generating HTML code in the hook, looking much tidier as a result. --- docs/assets/stylesheets/extra.css | 44 ++++++++++++++++++ hooks/index_pages.py | 76 +++++++++---------------------- mkdocs.yml | 5 +- overrides/exampleindex.html | 25 ++++++++++ 4 files changed, 94 insertions(+), 56 deletions(-) create mode 100644 docs/assets/stylesheets/extra.css create mode 100644 overrides/exampleindex.html diff --git a/docs/assets/stylesheets/extra.css b/docs/assets/stylesheets/extra.css new file mode 100644 index 0000000..0dcf259 --- /dev/null +++ b/docs/assets/stylesheets/extra.css @@ -0,0 +1,44 @@ +.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 input:not(:checked) + .taglabel { + background: #909090; +} + +#public:not(:checked) ~ .example[data-tags~="public"]{ + display:none; +} + +#insiders:not(:checked) ~ .example[data-tags~="insiders"]{ + display:none; +} + +#simple:not(:checked) ~ .example[data-tags~="simple"]{ + display:none; +} + +#integration:not(:checked) ~ .example[data-tags~="integration"]{ + display:none; +} + +#blog:not(:checked) ~ .example[data-tags~="blog"]{ + display:none; +} + +#fonts:not(:checked) ~ .example[data-tags~="fonts"] { + display: none; +} diff --git a/hooks/index_pages.py b/hooks/index_pages.py index 1974a43..de4ea3d 100644 --- a/hooks/index_pages.py +++ b/hooks/index_pages.py @@ -21,7 +21,6 @@ import logging import os -import re from glob import iglob import yaml @@ -31,20 +30,27 @@ # State # ----------------------------------------------------------------------------- -# Initialize incremental builds -examples = [] +# pre-defined structure for the tag filters. +# TODO: perhaps use tags plugin or tag definition in mkdocs.yml??? +tags = [ + ["public", "insiders", "simple", "integration"], + ["colors", "fonts"], + ["blog", "group", "info", "meta", "offline", "optimize", \ + "privacy", "projects", "search", "social", "tags", "typeset"] +] -# ----------------------------------------------------------------------------- -# Hooks -# ----------------------------------------------------------------------------- +# The list of examples. +examples = [] -def on_pre_build(config: MkDocsConfig): +def on_pre_build(_: MkDocsConfig): """ - Populate the module variable examples with the data from all the - `.example.y(a)ml` files we can find in `examples/`. + Populate the module variables examples and tags with the data from all + the `.example.y(a)ml` files we can find in `examples/`. """ - # Create archives for each example + if len(examples) > 0: + examples.clear() + ymlfiles = iglob("examples/*/.example.y*ml", recursive = True) for file in ymlfiles: with open(file, 'r', encoding='utf-8') as f: @@ -53,54 +59,14 @@ def on_pre_build(config: MkDocsConfig): examples.append(example) log.info("Found %d examples with metadata.", len(examples)) -def on_page_markdown(markdown: str, page, config, files): - """ - For each markdown page, look for a marker `` and - replace it with the list of examples. - """ - - def replace(match: re.Match): - rendered = [] - indextype, args = match.groups() - args = args.strip() - if indextype == "all": - for example in examples: - rendered.append(render(example)) - return '\n'.join(rendered) - else: - log.error("At the moment, we do not support filtering, so use 'all'.") - return "Invalid index placeholder." - log.info("looking for index definitions") - return re.sub( - r"", - replace, markdown, flags = re.I | re.M - ) - -def render(example: dict) -> str: - """ - Render an individual example and return the HTML as a string. - """ - if not 'name' in example and 'path' in example: - log.info("ignored example %s as it was missing a name", example['path']) - return "" - result = f""" """.strip() - return result - -def render_tags(tags: list) -> str: +def on_page_context(context, *, page, config, nav): """ - Render a list of tags. TODO: discuss how tags can be selected? + Put the data collected into the rendering context so the data are + available to the template. """ - return ', '.join(tags) - -# ----------------------------------------------------------------------------- -# Data -# ----------------------------------------------------------------------------- + context["exampletags"] = tags + context["examples"] = examples # Set up logging log = logging.getLogger("mkdocs.material.examples") diff --git a/mkdocs.yml b/mkdocs.yml index 95d77a9..5bbc214 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -43,6 +43,7 @@ theme: - navigation.sections icon: logo: logo + custom_dir: overrides # Plugins plugins: @@ -61,7 +62,9 @@ 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..16342d2 --- /dev/null +++ b/overrides/exampleindex.html @@ -0,0 +1,25 @@ +{% 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']}} +
+
+
+ {% endfor %} +
+{% endblock %} \ No newline at end of file From 3b75786a3f36278aa70caf9204a2c95d443357f7 Mon Sep 17 00:00:00 2001 From: Alex Voss Date: Mon, 27 Nov 2023 22:09:55 -0500 Subject: [PATCH 5/6] changed presentation of examples in list, added author(s) --- docs/assets/stylesheets/extra.css | 8 ++++++ examples/blog-basic/.example.yml | 2 +- examples/blog-rss/.example.yaml | 2 +- examples/blog-update/.example.yml | 2 +- examples/fonts-builtin/.example.yml | 11 +++++++++ examples/fonts-custom/.example.yml | 11 +++++++++ hooks/index_pages.py | 2 +- overrides/exampleindex.html | 38 +++++++++++++++++++++++------ 8 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 examples/fonts-builtin/.example.yml create mode 100644 examples/fonts-custom/.example.yml diff --git a/docs/assets/stylesheets/extra.css b/docs/assets/stylesheets/extra.css index 0dcf259..9a77c2f 100644 --- a/docs/assets/stylesheets/extra.css +++ b/docs/assets/stylesheets/extra.css @@ -1,3 +1,6 @@ +.md-typeset .author { + text-align: right; +} .md-typeset .filters { background-color: lightgray; } @@ -15,6 +18,11 @@ font-size: .64rem; } +.md-typeset .taglist { + float:right; + padding-left:1em; +} + .md-typeset input:not(:checked) + .taglabel { background: #909090; } diff --git a/examples/blog-basic/.example.yml b/examples/blog-basic/.example.yml index 372ee35..ab46de5 100644 --- a/examples/blog-basic/.example.yml +++ b/examples/blog-basic/.example.yml @@ -8,4 +8,4 @@ example: alexvoss: name: Alex Voss description: Collaborator - avatar: https://github.com/alexvoss.png + ghuser: alexvoss diff --git a/examples/blog-rss/.example.yaml b/examples/blog-rss/.example.yaml index d9d879d..6d791a3 100644 --- a/examples/blog-rss/.example.yaml +++ b/examples/blog-rss/.example.yaml @@ -8,4 +8,4 @@ example: alexvoss: name: Alex Voss description: Collaborator - avatar: https://github.com/alexvoss.png + ghuser: alexvoss diff --git a/examples/blog-update/.example.yml b/examples/blog-update/.example.yml index eb3fb21..44d456b 100644 --- a/examples/blog-update/.example.yml +++ b/examples/blog-update/.example.yml @@ -9,4 +9,4 @@ example: alexvoss: name: Alex Voss description: Collaborator - avatar: https://github.com/alexvoss.png + ghuser: alexvoss diff --git a/examples/fonts-builtin/.example.yml b/examples/fonts-builtin/.example.yml new file mode 100644 index 0000000..958b57c --- /dev/null +++ b/examples/fonts-builtin/.example.yml @@ -0,0 +1,11 @@ +example: + name: Using built-in browser fonts + 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/.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/hooks/index_pages.py b/hooks/index_pages.py index de4ea3d..cf1bb66 100644 --- a/hooks/index_pages.py +++ b/hooks/index_pages.py @@ -42,7 +42,7 @@ # The list of examples. examples = [] -def on_pre_build(_: MkDocsConfig): +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/`. diff --git a/overrides/exampleindex.html b/overrides/exampleindex.html index 16342d2..c81f223 100644 --- a/overrides/exampleindex.html +++ b/overrides/exampleindex.html @@ -11,14 +11,36 @@
{% endfor %} {% for example in examples %} -
-
- {{ ', '.join(example['tags']) }} -
- {{ example['name']}} -
-
+
+
+
+ {{ ', '.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 %}
From cd25525d67ad4ca8cce69b3c5b24d7367935f0ef Mon Sep 17 00:00:00 2001 From: Alex Voss Date: Tue, 28 Nov 2023 10:55:00 -0500 Subject: [PATCH 6/6] moved example metadata into the Markdown header --- docs/assets/stylesheets/extra.css | 72 ++++++++++++++++++- docs/index.md | 24 +++++-- examples/blog-basic/.example.yml | 11 --- examples/blog-basic/docs/README.md | 15 +++- examples/blog-rss/.example.yaml | 11 --- examples/blog-rss/docs/README.md | 11 +++ examples/blog-update/.example.yml | 12 ---- examples/blog-update/docs/README.md | 12 ++++ .../docs/README.md | 5 ++ examples/color-palette-toggle/docs/README.md | 6 ++ examples/cookie-consent/docs/README.md | 5 ++ examples/custom-colors/docs/README.md | 5 ++ examples/custom-cookies/docs/README.md | 5 ++ examples/fonts-builtin/.example.yml | 11 --- examples/fonts-builtin/docs/README.md | 11 +++ examples/fonts-custom/docs/README.md | 10 +++ examples/page-status/docs/README.md | 5 ++ examples/tags-with-icons/docs/README.md | 5 ++ examples/tags/docs/README.md | 5 ++ hooks/index_pages.py | 70 +++++++++++++++--- overrides/exampleindex.html | 2 +- 21 files changed, 247 insertions(+), 66 deletions(-) delete mode 100644 examples/blog-basic/.example.yml delete mode 100644 examples/blog-rss/.example.yaml delete mode 100644 examples/blog-update/.example.yml delete mode 100644 examples/fonts-builtin/.example.yml diff --git a/docs/assets/stylesheets/extra.css b/docs/assets/stylesheets/extra.css index 9a77c2f..c010654 100644 --- a/docs/assets/stylesheets/extra.css +++ b/docs/assets/stylesheets/extra.css @@ -1,6 +1,14 @@ +/** + * Example information + */ + .md-typeset .author { text-align: right; } + +/** + * Tag filters + */ .md-typeset .filters { background-color: lightgray; } @@ -27,6 +35,8 @@ background: #909090; } +/** First row: Materials version and integration **/ + #public:not(:checked) ~ .example[data-tags~="public"]{ display:none; } @@ -35,18 +45,74 @@ display:none; } -#simple:not(:checked) ~ .example[data-tags~="simple"]{ +#integration:not(:checked) ~ .example[data-tags~="integration"]{ display:none; } -#integration:not(:checked) ~ .example[data-tags~="integration"]{ +/** 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; } -#fonts:not(:checked) ~ .example[data-tags~="fonts"] { +#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 b3c86ac..a0abec2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,11 +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 ab46de5..0000000 --- a/examples/blog-basic/.example.yml +++ /dev/null @@ -1,11 +0,0 @@ -example: - name: Adding a blog to your site - tags: - - public # works without Insiders - - blog # functionality demonstrated - - simple # requires no extra plugins or other magic - authors: - alexvoss: - name: Alex Voss - description: Collaborator - ghuser: alexvoss 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 6d791a3..0000000 --- a/examples/blog-rss/.example.yaml +++ /dev/null @@ -1,11 +0,0 @@ -example: - name: Adding an RSS-feed to your blog - tags: - - public # works without Insiders - - blog # functionality demonstrated - - integration # demonstrates integration, use of other plugins - authors: - alexvoss: - name: Alex Voss - description: Collaborator - ghuser: alexvoss 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 44d456b..0000000 --- a/examples/blog-update/.example.yml +++ /dev/null @@ -1,12 +0,0 @@ -example: - name: Blog that shows post updates - 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 - ghuser: alexvoss 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/.example.yml b/examples/fonts-builtin/.example.yml deleted file mode 100644 index 958b57c..0000000 --- a/examples/fonts-builtin/.example.yml +++ /dev/null @@ -1,11 +0,0 @@ -example: - name: Using built-in browser fonts - 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-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/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 index cf1bb66..319071f 100644 --- a/hooks/index_pages.py +++ b/hooks/index_pages.py @@ -19,6 +19,12 @@ # 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 @@ -31,10 +37,9 @@ # ----------------------------------------------------------------------------- # pre-defined structure for the tag filters. -# TODO: perhaps use tags plugin or tag definition in mkdocs.yml??? tags = [ - ["public", "insiders", "simple", "integration"], - ["colors", "fonts"], + ["public", "insiders", "integration"], + ["colors", "fonts", "icons", "page_status"], ["blog", "group", "info", "meta", "offline", "optimize", \ "privacy", "projects", "search", "social", "tags", "typeset"] ] @@ -51,14 +56,61 @@ def on_pre_build(config: MkDocsConfig): if len(examples) > 0: examples.clear() - ymlfiles = iglob("examples/*/.example.y*ml", recursive = True) - for file in ymlfiles: - with open(file, 'r', encoding='utf-8') as f: - example = yaml.safe_load(f)['example'] - example['path'] = os.path.dirname(file) - examples.append(example) + 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): """ diff --git a/overrides/exampleindex.html b/overrides/exampleindex.html index c81f223..5562c8f 100644 --- a/overrides/exampleindex.html +++ b/overrides/exampleindex.html @@ -5,7 +5,7 @@
{% for group in exampletags %} {% for tag in group %} - + {% endfor %}