From bb829cfcaab1ec663dc50e4a5fe3f79954bbfcf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Krzy=C5=9Bk=C3=B3w?= Date: Sun, 9 Jun 2024 07:48:47 +0200 Subject: [PATCH 01/10] init blog --- docs/.pages | 3 +- docs/blog/.authors.yml | 8 +++ docs/blog/index.md | 5 ++ docs/blog/posts/welcome.md | 45 ++++++++++++ mkdocs.yml | 7 ++ overrides/.hooks/all_plugin_patch.py | 98 +++++++++++++++++++++++++- overrides/assets/javascripts/extra.js | 5 ++ overrides/assets/stylesheets/extra.css | 14 +++- overrides/main.html | 13 ++-- 9 files changed, 189 insertions(+), 9 deletions(-) create mode 100644 docs/blog/.authors.yml create mode 100644 docs/blog/index.md create mode 100644 docs/blog/posts/welcome.md diff --git a/docs/.pages b/docs/.pages index 935044d41e..890ec3c1f8 100644 --- a/docs/.pages +++ b/docs/.pages @@ -4,4 +4,5 @@ nav: - ... | preferences*.md - zengin - genome - - contribute \ No newline at end of file + - contribute + - blog \ No newline at end of file diff --git a/docs/blog/.authors.yml b/docs/blog/.authors.yml new file mode 100644 index 0000000000..fcd08b7acf --- /dev/null +++ b/docs/blog/.authors.yml @@ -0,0 +1,8 @@ +authors: + kamilkrzyskow: + name: HRY + description: > + Enthusiast of hacky solutions. Python generalist, without AI or math + avatar: https://avatars.githubusercontent.com/u/34622465 + slug: hry + url: https://github.com/Made-by-HRY \ No newline at end of file diff --git a/docs/blog/index.md b/docs/blog/index.md new file mode 100644 index 0000000000..0ea3385cd9 --- /dev/null +++ b/docs/blog/index.md @@ -0,0 +1,5 @@ +--- +title: Community Posts +--- + + diff --git a/docs/blog/posts/welcome.md b/docs/blog/posts/welcome.md new file mode 100644 index 0000000000..46fe1c9403 --- /dev/null +++ b/docs/blog/posts/welcome.md @@ -0,0 +1,45 @@ +--- +date: 2024-06-09 +authors: + - kamilkrzyskow +categories: + - GMC +--- +# Introducing Community Posts + +> Made possible thanks to the built-in Blog plugin of Material for MkDocs. + +This is a blog-like section of GMC, where users can post their tutorials, guides, analytical +articles, useful snippets, promote their modding tools etc. + +Basically this should allow for more flexibility when it comes to content creation on the website. + + + +## Why a blog? + +Many times over the span of running Gothic Modding Community one issue has resurfaced over and over +again. The issue concerns the fact that some pages don't fit the "docs" idea. Therefore, a new +section was required. At first, we wanted to just put everything into a plain new area, but the Blog +plugin was supposed to be released to the Community version of the Material theme, so we pushed back +the idea and waited for that to happen, but while waiting for it, we started supporting i18n +localization, in hopes of getting new users for both translation and content creation, but after +a year has passed no new members have become regular contributors. Also the GitHub/PayPal fiasco +took place which pushed back the release of the Blog plugin to the public to use. + +Finally, the Blog plugin arrived in the Community version, but then it turned out that the +mkdocs-static-i18n plugin unfortunately can't handle the internally generated blog pages of the Blog +plugin. So we waited a bit longer, in hopes of the situation resolving itself via some nifty fix. +Unfortunately, nothing did change, and the initial issue kept resurfacing. + +## i18n support + +!!! failure "Not supported" + As of the day of writing this post (2024-06-09) the i18n plugin doesn't support blog pages. + +Given the skill of the developer maintaining the i18n plugin ([@ultrabug]()) I don't think this is an +easy issue to solve, as it would get solved already. The solution probably requires overriding +internal code of the Blog plugin, and as it updates together with the theme, people using it with +localization could end up blocked from updating and this would create a rather bad situation where +@ultrabug has to constantly make fixes. Add to it different versions of the Blog plugin for the +Community and Insiders version \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 06712e2f67..6d0d726e54 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -127,6 +127,11 @@ plugins: order: asc sort_type: natural order_by: title + - blog: + archive: false + post_url_format: "{categories}/{slug}" + categories_allowed: # Case-sensitive + - GMC # Posts about internal topics concerning the site or the Discord server. - mkdocs-video: css_style: width: "100%" @@ -153,6 +158,7 @@ plugins: nav_translations: Afsp: AFSP Anims: Animations + Blog: Community Posts Contribute: How To Contribute Daedalus tools: Daedalus General info: General information @@ -169,6 +175,7 @@ plugins: nav_translations: Anims: Animacje Applications: Zastosowania + Blog: Posty Społeczności Classes: Klasy Contribute: Jak Się Udzielić Examples: Przykłady diff --git a/overrides/.hooks/all_plugin_patch.py b/overrides/.hooks/all_plugin_patch.py index c6a64451e2..d1d7d2c42a 100644 --- a/overrides/.hooks/all_plugin_patch.py +++ b/overrides/.hooks/all_plugin_patch.py @@ -20,6 +20,7 @@ MIT Licence 2023 Kamil Krzyśków (HRY) """ + import logging from copy import deepcopy from pathlib import Path @@ -28,7 +29,9 @@ from mkdocs import plugins from mkdocs.config import Config from mkdocs.config.defaults import MkDocsConfig +from mkdocs.exceptions import PluginError from mkdocs.plugins import PrefixedLogger +from mkdocs.structure.files import File, Files from mkdocs.utils import get_markdown_title from pygments import lexers from pymdownx import highlight @@ -36,9 +39,13 @@ @plugins.event_priority(100) def on_config(config: MkDocsConfig) -> Optional[Config]: + global BLOG_URL_COLLISIONS + BLOG_URL_COLLISIONS = set() + social_plugin = config.plugins.get("material/social") or config.plugins.get("social") i18n_plugin = config.plugins.get("i18n") redirects_plugin = config.plugins.get("redirects") + mkdocs_video_plugin = config.plugins.get("mkdocs-video") has_been_patched = hasattr(config.extra, "all_plugin_patch") @@ -47,6 +54,9 @@ def on_config(config: MkDocsConfig) -> Optional[Config]: if i18n_plugin and redirects_plugin: process_i18n_redirects(has_been_patched, i18n_plugin, redirects_plugin) + if mkdocs_video_plugin: + allow_for_empty_html_mkdocs_video(mkdocs_video_plugin, config) + # the rest of the patches only need to be applied once # as they aren't aware of multiple executions if has_been_patched: @@ -68,6 +78,44 @@ def on_config(config: MkDocsConfig) -> Optional[Config]: return None +@plugins.event_priority(-95) +def _on_files_disconnect_blog_files(files: Files, config, *_, **__): + """Disconnect blog files before on_files from the i18n plugin runs (-100) after blog (-50)""" + global BLOG_FILES + BLOG_FILES = [] + non_blog_files: list[File] = [] + blog_prefixes = [] + + for name, instance in config.plugins.items(): + if name.startswith("material/blog"): + blog_prefixes.append(instance.config.blog_dir) + + blog_prefixes = tuple(map(lambda x: x.rstrip("/") + "/", blog_prefixes)) + + # i18n blog prefix awareness + config.extra.i18n_blog_prefixes = blog_prefixes + + for file in files: + if file.src_uri.startswith(blog_prefixes): + BLOG_FILES.append(file) + else: + non_blog_files.append(file) + + return non_blog_files + + +@plugins.event_priority(-105) +def _on_files_connect_blog_files(files, *_, **__): + """Breaking the convention of a maximal -100. Restore blog files after i18n on_files""" + for file in BLOG_FILES: + files.append(file) + + return files + + +on_files = plugins.CombinedEvent(_on_files_disconnect_blog_files, _on_files_connect_blog_files) + + @plugins.event_priority(100) def on_pre_build(config): search_plugin = config.plugins.get("material/search") or config.plugins.get("search") @@ -91,6 +139,15 @@ def on_env(env, config, **_): return env +@plugins.event_priority(100) +def on_post_page(output: str, page, config): + + # The blog plugin doesn't do that + if page.url in BLOG_URL_COLLISIONS: + raise PluginError(f"{HOOK_NAME}: URL collision: {page.url}") + + BLOG_URL_COLLISIONS.add(page.url) + @plugins.event_priority(100) def on_post_build(config) -> None: has_been_patched = hasattr(config.extra, "all_plugin_patch") @@ -108,7 +165,7 @@ def on_post_build(config) -> None: class Mock: - ... + pass def patch_social_font_crash(func): @@ -154,6 +211,34 @@ def wrap_get_lexer_by_name(alias, **options): return wrap_get_lexer_by_name +def allow_for_empty_html_mkdocs_video(plugin, config): + """ + To keep the blog page clean the index file needs to be empty. This causes an error, + therefore we need to make sure it is handled properly. + """ + + def on_page_content_wrapper(func): + + if func.__name__ == "wrapper": + return func + + LOG.info("Fixing mkdocs-video empty html crash") + + def wrapper(html, page, config, files): + if not html.strip(): + return html + return func(html, page, config, files) + + return wrapper + + for i, event in enumerate(config.plugins.events["page_content"]): + if not hasattr(event, "__self__"): + continue + if event.__self__.__class__ is plugin.__class__: + config.plugins.events["page_content"][i] = on_page_content_wrapper(event) + break + + def process_i18n_redirects(has_been_patched, i18n_plugin, redirects_plugin): import mkdocs_redirects.plugin as module @@ -270,7 +355,16 @@ def wrap_create_entry_for_section(section, toc, url, page): return wrap_create_entry_for_section -CUSTOM_DIR_PATH = "overrides" +BLOG_FILES: Optional[list[File]] = None +""" +List of files that belong to a blog they will be temporarily removed and added back to hide them +from the i18n plugin. +""" + +BLOG_URL_COLLISIONS: Optional[set[str]] = None +"""The blog plugin doesn't check for url collisions, so we do it in the patch""" + +CUSTOM_DIR_PATH: str = "overrides" """A relative path to the custom directory based from the `docs_dir` parent directory.""" HOOK_NAME: str = "all_plugin_patch" diff --git a/overrides/assets/javascripts/extra.js b/overrides/assets/javascripts/extra.js index 9b8512935c..3ea94b8b5c 100644 --- a/overrides/assets/javascripts/extra.js +++ b/overrides/assets/javascripts/extra.js @@ -358,6 +358,11 @@ const gmcLinksForVersion = () => { }; const gmcTranslateButton = () => { + // Hack: detect blog pages via .md-post and ignore them + const postElement = document.querySelector(".md-post"); + if (postElement) { + return; + } const anchor = document.querySelectorAll("a.md-content__button")[0]; const hrefParts = anchor.href.split("/"); const oldFileName = hrefParts.pop(); diff --git a/overrides/assets/stylesheets/extra.css b/overrides/assets/stylesheets/extra.css index cf2a7831b2..001c9fc37a 100644 --- a/overrides/assets/stylesheets/extra.css +++ b/overrides/assets/stylesheets/extra.css @@ -75,12 +75,19 @@ } /* center the images */ -.md-content img { +.md-content__inner img { display: block; margin: 1em auto; min-width: 75%; } +/* enforce icon height for emojis in blog author profiles */ +/* fix margin that is incorrectly applied here */ +.md-post img { + height: 100%; + margin: unset; +} + /* Code in a list */ .md-content li > code:first-of-type, .md-content li > code + code { @@ -136,6 +143,11 @@ div.md-nav__link--index { text-shadow: 0 0 0 var(--md-default-fg-color--light); } +/* fix headings for posts excerpts */ +.md-post :is(h1, h2, h3, h4, h5, h6) { + text-shadow: unset; +} + .md-typeset :is(h3, h4, h5, h6) { padding-top: 0.5em; margin-top: 0.5em; diff --git a/overrides/main.html b/overrides/main.html index 31b35c35d5..22023eb2de 100644 --- a/overrides/main.html +++ b/overrides/main.html @@ -64,11 +64,14 @@ "cs": "Podpoř nás a pomoz nám s překladem!", } %} - {% if i18n_page_locale != "en" and i18n_file_locale != i18n_page_locale %} -
- {{ announcement[i18n_page_locale] }} - {{ call_to_action[i18n_page_locale] }} -
+ {# Wrapper for non-i18n blog files #} + {% if page and not page.file.src_uri.startswith(config.extra.i18n_blog_prefixes) %} + {% if i18n_page_locale != "en" and i18n_file_locale != i18n_page_locale -%} +
+ {{ announcement[i18n_page_locale] }} + {{ call_to_action[i18n_page_locale] }} +
+ {%- endif %} {% endif %} {# Add script with additional localization for use in extra.js #} + + + +{% endif %} \ No newline at end of file From 7cd14e079ece3f0b94ec3e6fce62a55cec786a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Krzy=C5=9Bk=C3=B3w?= Date: Fri, 28 Jun 2024 23:10:30 +0200 Subject: [PATCH 03/10] gg go next --- docs/blog/index.md | 1 + .../posts/{ => community-news}/welcome.md | 11 ++++--- mkdocs.yml | 31 ++++++++++--------- overrides/assets/stylesheets/extra.css | 4 +-- 4 files changed, 26 insertions(+), 21 deletions(-) rename docs/blog/posts/{ => community-news}/welcome.md (92%) diff --git a/docs/blog/index.md b/docs/blog/index.md index 0ea3385cd9..fe4fa79211 100644 --- a/docs/blog/index.md +++ b/docs/blog/index.md @@ -1,5 +1,6 @@ --- title: Community Posts +icon: material/alert-decagram --- diff --git a/docs/blog/posts/welcome.md b/docs/blog/posts/community-news/welcome.md similarity index 92% rename from docs/blog/posts/welcome.md rename to docs/blog/posts/community-news/welcome.md index 12471ae647..718341cf04 100644 --- a/docs/blog/posts/welcome.md +++ b/docs/blog/posts/community-news/welcome.md @@ -1,18 +1,18 @@ --- -date: 2024-06-09 authors: - - kamilkrzyskow - kamilkrzyskow +date: 2024-07-02 categories: - - GMC + - Community News tags: + - Documentation + - i18n - MkDocs - - Meta --- # Introducing Community Posts > Made possible thanks to the built-in Blog plugin of Material for MkDocs. -> [![Material for MkDocs][badge]{: .normalImgStyling}](#usage) +> [![Material for MkDocs][badge]{: .gmc-default-img}][mkdocs-material] This is a blog-like section of GMC, where users can post their tutorials, guides, analytical articles, useful snippets, promote their modding tools etc. @@ -22,6 +22,7 @@ Basically this should allow for more flexibility when it comes to content creati [badge]: https://img.shields.io/badge/Material_for_MkDocs-526CFE?style=for-the-badge&logo=MaterialForMkDocs&logoColor=white +[mkdocs-material]: https://squidfunk.github.io/mkdocs-material/ ## Why a blog? diff --git a/mkdocs.yml b/mkdocs.yml index 76d5144ed3..6e76b521c3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -129,21 +129,24 @@ plugins: order_by: title - blog: archive: false - post_url_format: "{categories}/{slug}" - post_excerpt_max_categories: 4 # Default 5 categories_allowed: # Case-sensitive - - Animation # Posts about creating animations. - - Analysis # Posts about deep dives into certain topics. - - 3D # Posts about 3d modeling etc. - - General # Posts about topics that don't fit other categories. - - Genome # Posts about the Genome engine. - - GMC # Posts about internal topics concerning the site or the Discord server. - - Programming # Posts about scripting in any language. - - Sound # Posts about sound related topics. - - Tutorial # Posts with the intention to teach others. - - Tool # Post with the intention to show a tool. - - Union # Posts about Union SDK or Plugins. - - ZenGin # Posts about the ZenGin engine. + # Primary level categories for the URLs + - Analysis # Posts about deep dives into certain topics. + - Community News # Posts about updates in the Gothic Modding Community. + - Devlogs # Posts about stories from mod development. + - Off-Topic # Posts about topics that don't fit other categories, e.g., WebDev. + - Showcase # Posts about tools, workflows etc. + - Tutorials # Posts including guides or follow-along tutorials. + # Secondary level categories for better granularity. + - Assets # Posts about 2D, 3D, Sound or other non-code file assets. + - Genome # Posts about Genome engine. + - Scripts # Posts about internal built-in scripting like Daedalus. + - SDK # Posts about external development kits like Union. + - Tools # Posts about tools. + - Workflows # Posts about workflows. + - ZenGin # Posts about ZenGin engine. + post_excerpt_max_categories: 3 # Default 5 + post_url_format: "{categories}/{slug}" # Default {date}/{slug} - mkdocs-video: css_style: width: "100%" diff --git a/overrides/assets/stylesheets/extra.css b/overrides/assets/stylesheets/extra.css index 05dd44a071..eafaca8646 100644 --- a/overrides/assets/stylesheets/extra.css +++ b/overrides/assets/stylesheets/extra.css @@ -75,7 +75,7 @@ } /* center the images */ -.md-content__inner img:not(.normalImgStyling) { +.md-content__inner img:not(.gmc-default-img) { display: block; margin: 1em auto; min-width: 75%; @@ -83,7 +83,7 @@ /* enforce icon height for emojis in blog author profiles */ /* fix margin that is incorrectly applied here */ -.md-post img { +.md-post__authors .md-author img { height: 100%; margin: unset; } From 15bb79f5b1768b7089ae15cca216e6573187f1c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Krzy=C5=9Bk=C3=B3w?= Date: Sun, 30 Jun 2024 16:59:47 +0200 Subject: [PATCH 04/10] rss --- .../tutorials/how_to_write_blog_posts.md | 105 ++++++++++++++++++ mkdocs.yml | 16 ++- overrides/partials/comments.html | 12 +- requirements.txt | 3 +- 4 files changed, 128 insertions(+), 8 deletions(-) create mode 100644 docs/blog/posts/tutorials/how_to_write_blog_posts.md diff --git a/docs/blog/posts/tutorials/how_to_write_blog_posts.md b/docs/blog/posts/tutorials/how_to_write_blog_posts.md new file mode 100644 index 0000000000..e029898409 --- /dev/null +++ b/docs/blog/posts/tutorials/how_to_write_blog_posts.md @@ -0,0 +1,105 @@ +--- +authors: + - kamilkrzyskow +categories: + - Tutorials +date: 2024-07-01 +tags: + - Best Practices + - Documentation + - How To + - MkDocs +--- +# Guidelines For Community Posts + +Question: What are the requirements for my blog post to be added here? +Answer: There are almost no requirements, other than managing files... + + + +## Technical requirements + +### Creation date + +Each post needs to have a date of creation that is used for sorting and ordering of the posts. The +`date` key can be a simple string only with the creation date, or a object structure with sub-keys +`created` and `updated`. + +```yaml +date: 2024-07-01 +``` + +[Reference](https://squidfunk.github.io/mkdocs-material/plugins/blog/#meta.date) + +### At least one category + +Instead of the default time-based post URLs, this blog uses category-based URLs, and the first +category is included in the URL of the post. The `categories` key is a list of strings. + +```yaml +categories: + - Tutorials +``` + +[Reference](https://squidfunk.github.io/mkdocs-material/plugins/blog/#meta.categories) + +## Mandatory opinionated requirements + +### Keep the posts and assets organized + +Put posts under the `blog/posts` directory into a subdirectory matching the category `slug`, so +lowercase and with `-` in place of spaces: + +> The filenames should use `_` for spaces, and should be lowercase. + +``` +blog/posts/community-news/welcome.md +blog/posts/tutorials/how_to_write_blog_posts.md +``` + +In case of assets specific to the blog section it would be something like this: + +> Notice the lack of `posts`. + +``` +assets/blog/images/tutorials/image.png +``` + +### Assets like images need to be put under the `overrides` path + +Due to the rest of the site using multiple languages (i18n), assets are kept in the overrides +directory, which reduces duplication of files after the build. The overrides directory is put on top +of the built directory so all relative paths are the same as if the files would be in the `docs` +directory. So use a couple of `../` to get to the root of the built site and access the asset: + +![](../../../assets/images/gmc_logo.png){: .gmc-default-img style="width: 2rem" } + +``` +../../../assets/images/gmc_logo.png +``` + +So in case of the example before: + +``` +../../../assets/blog/images/tutorials/image.png +``` + +## Optional opinionated recommendations + +### Keep keys and values in the front-matter in alphabetical order + +Will make it easier to spot mistakes. + +### Keep a strict line width limit + +It will make it easier to read and spot mistakes in Markdown. `mkdocs-material` uses a 80-character +limit, which is a bit narrow. As of the time of writing this post the CSS settings for the width of +the content is roughly ~140 characters, which is a bit wide. This Markdown file uses a 100-character +limit. Keep things reasonable and use the same width throughout the file. + +### Don't be lazy when a name conflict occurs + +If there isn't any better alternative you can add a lazy `-2` at the end of the name, but for better +search-ability your name should be distinct in some way. For example an image with a success message +`result.png` can be quite common, so prepend a slug `blender_modifier_result.png` or the slug of the +blog post you're writing. diff --git a/mkdocs.yml b/mkdocs.yml index 6e76b521c3..5c964020b9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -69,6 +69,9 @@ extra: - icon: fontawesome/brands/github link: https://github.com/Gothic-Modding-Community/gmc name: Gothic Modding Community GitHub repository + - icon: material/rss + link: /feed_rss_updated.xml + name: Subscribe to our RSS Feed validation: nav: @@ -238,4 +241,15 @@ plugins: - social: enabled: !ENV [GMC_ENABLE_ON_PUBLISH, False] - tags: - tags_file: blog/tags.md \ No newline at end of file + tags_file: blog/tags.md + - rss: + enabled: !ENV [GMC_ENABLE_ON_PUBLISH, True] + categories: + - tags + - categories + comments_path: "#__comments" + json_feed_enabled: false + match_path: "blog.posts..*" # regex, dots as dir separators to support Linux and Windows + date_from_meta: + as_creation: date.created + as_update: date.updated \ No newline at end of file diff --git a/overrides/partials/comments.html b/overrides/partials/comments.html index 0bbe4edb55..f265c0f861 100644 --- a/overrides/partials/comments.html +++ b/overrides/partials/comments.html @@ -1,4 +1,4 @@ -{% if page.meta.template == "blog-post.html" %} +{% if page.meta.template and page.meta.template.startswith("blog-post.html") %} {# Add it in TOC

{{ lang.t("meta.comments") }}

#} @@ -21,17 +21,17 @@