From 97d4f5a930db6b7d46205ab3a98d4f62bde8993a Mon Sep 17 00:00:00 2001 From: Fabian Eulitz Date: Sat, 19 Apr 2025 20:25:32 +0200 Subject: [PATCH 1/7] WIP --- .gitignore | 90 +++- .idea/.gitignore | 10 + .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/misc.xml | 9 + .idea/mkdocs-color-swatch-plugin.iml | 9 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + README.md | 115 +++++- docs/index.md | 4 + mkdocs.yml | 7 + mkdocs_color_swatch_plugin/__init__.py | 0 mkdocs_color_swatch_plugin/color_swatch.py | 30 ++ mkdocs_color_swatch_plugin/plugin.py | 102 +++++ poetry.lock | 455 +++++++++++++++++++++ pyproject.toml | 28 ++ tests/__init__.py | 0 tests/test_render.py | 45 ++ 17 files changed, 911 insertions(+), 12 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/mkdocs-color-swatch-plugin.iml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 docs/index.md create mode 100644 mkdocs.yml create mode 100644 mkdocs_color_swatch_plugin/__init__.py create mode 100644 mkdocs_color_swatch_plugin/color_swatch.py create mode 100644 mkdocs_color_swatch_plugin/plugin.py create mode 100644 poetry.lock create mode 100644 pyproject.toml create mode 100644 tests/__init__.py create mode 100644 tests/test_render.py diff --git a/.gitignore b/.gitignore index 0a19790..ced224e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +### Python template # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -94,12 +95,6 @@ ipython_config.py # install all needed dependencies. #Pipfile.lock -# UV -# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -#uv.lock - # poetry # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. # This is especially recommended for binary packages to ensure reproducibility, and is more @@ -167,8 +162,81 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ -# Ruff stuff: -.ruff_cache/ - -# PyPI configuration file -.pypirc +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..7bc07ec --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Environment-dependent path to Maven home directory +/mavenHomeManager.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..b5fae63 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/mkdocs-color-swatch-plugin.iml b/.idea/mkdocs-color-swatch-plugin.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/mkdocs-color-swatch-plugin.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..d265d41 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 6126ed5..ef5893e 100644 --- a/README.md +++ b/README.md @@ -1 +1,114 @@ -# mkdocs-color-swatch-plugin \ No newline at end of file +# ๐ŸŽจ MkDocs Color Swatch Plugin + +A lightweight [MkDocs](https://www.mkdocs.org/) plugin that lets you insert inline color swatches into your Markdown docs using a simple, readable syntax. + +Supports: +- โœ… Hex colors (`#ff0000`, `#f00`) +- โœ… RGB and RGBA (`rgb(255, 0, 0)`, `rgba(255, 0, 0, 0.5)`) +- โœ… Tooltip with color value + label +- โœ… Rounded swatches with smooth hover animations +- โœ… No CSS setup required โ€” styles are embedded automatically + +--- + +## ๐Ÿš€ Installation + +Install via [PyPI](https://pypi.org/): + +```bash +pip install mkdocs-color-swatch-plugin +``` + +Then enable it in your `mkdocs.yml`: + +```yaml +plugins: + - color-swatch +``` + +Make sure you have `mkdocs` installed: + +```bash +pip install mkdocs +``` + +--- + +## โœ๏ธ Usage + +In your Markdown, use the custom swatch syntax: + +```markdown +[[color: #e74c3c | Red]] +[[color: rgb(52, 152, 219) | Blue]] +[[color: rgba(46, 204, 113, 0.6) | Transparent Green]] +``` + +Each tag will render as: + +- A **rounded swatch** showing the color +- A **tooltip** with the color value + label +- A **hover effect** that scales and highlights the swatch + +--- + +## ๐Ÿง  Why Use This Plugin? + +Instead of manually writing HTML for every color sample like: + +```html + +``` + +You can just write: + +```markdown +[[color: #e74c3c | Red]] +``` + +It's faster, cleaner, and works right out of the box. + +--- + +## ๐Ÿ›  Features + +- ๐Ÿ”น Works with any valid `hex`, `rgb()`, or `rgba()` color +- ๐Ÿ”น Tooltip automatically shows `#hex โ€“ Label` +- ๐Ÿ”น Embedded CSS โ€” no setup needed +- ๐Ÿ”น Safe to use alongside other Markdown extensions +- ๐Ÿ”น Lightweight and dependency-free + +--- + +## ๐Ÿ“ฆ Development & Contribution + +### Clone and Install: + +```bash +git clone https://github.com/yourusername/mkdocs-color-swatch-plugin.git +cd mkdocs-color-swatch-plugin +poetry install +``` + +### Editable Install (for local use): + +```bash +poetry install +pip install -e . +``` + +--- + +## ๐Ÿงช Testing + +Basic tests coming soon! + +--- + +## ๐Ÿ“„ License + +MIT ยฉ [Fabian Eulitz](https://github.com/fabieu) + +--- + +Made with โค๏ธ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..872e136 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,4 @@ +# Color Swatch Plugin Demo + +[[color: #e74c3c | Red]] +[[color: rgba(0,255,0,0.5) | Transparent Green]] diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..19444fc --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,7 @@ +site_name: Local Plugin Demo + +plugins: + - color-swatch + +watch: + - mkdocs_color_swatch_plugin diff --git a/mkdocs_color_swatch_plugin/__init__.py b/mkdocs_color_swatch_plugin/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mkdocs_color_swatch_plugin/color_swatch.py b/mkdocs_color_swatch_plugin/color_swatch.py new file mode 100644 index 0000000..ac7db7e --- /dev/null +++ b/mkdocs_color_swatch_plugin/color_swatch.py @@ -0,0 +1,30 @@ +import xml.etree.ElementTree as ElementTree + +from markdown.extensions import Extension +from markdown.inlinepatterns import InlineProcessor + +SWATCH_CLASS = 'color-swatch' + +# Support hex, rgb(), rgba() +COLOR_RE = r'\[\[color:\s*(#[0-9a-fA-F]{3,6}|rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+(?:\s*,\s*(?:\d+|\d*\.\d+))?\s*\))\s*\|\s*([^\]]+)\]\]' + + +class ColorSwatchExtension(Extension): + def extendMarkdown(self, md): + md.inlinePatterns.register(ColorSwatchInlineProcessor(COLOR_RE, md), 'color_swatch', 175) + + +class ColorSwatchInlineProcessor(InlineProcessor): + def handleMatch(self, matcher, data): + color_code = matcher.group(1) + label = matcher.group(2) + + swatch = ElementTree.Element('span') + swatch.set('class', SWATCH_CLASS) + swatch.set('style', f'background-color: {color_code};') + swatch.set('data-tooltip', f'{color_code} โ€“ {label}') + + wrapper = ElementTree.Element('div') + wrapper.append(swatch) + + return wrapper, matcher.start(0), matcher.end(0) diff --git a/mkdocs_color_swatch_plugin/plugin.py b/mkdocs_color_swatch_plugin/plugin.py new file mode 100644 index 0000000..ed82d2f --- /dev/null +++ b/mkdocs_color_swatch_plugin/plugin.py @@ -0,0 +1,102 @@ +from mkdocs.plugins import BasePlugin + +from mkdocs_color_swatch_plugin.color_swatch import ColorSwatchExtension + +EMBEDDED_CSS = """ + + +""" + + +class ColorSwatchPlugin(BasePlugin): + config_scheme = () + + def on_config(self, config, **kwargs): + config['markdown_extensions'].append(ColorSwatchExtension()) + return config + + def on_page_content(self, html, **kwargs): + if 'class="color-swatch"' in html: + html = EMBEDDED_CSS + '\n' + html + return html diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..d17f6f7 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,455 @@ +# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. + +[[package]] +name = "click" +version = "8.1.8" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "dev"] +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] +markers = {main = "platform_system == \"Windows\"", dev = "sys_platform == \"win32\""} + +[[package]] +name = "ghp-import" +version = "2.1.0" +description = "Copy your docs directly to the gh-pages branch." +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, + {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, +] + +[package.dependencies] +python-dateutil = ">=2.8.1" + +[package.extras] +dev = ["flake8", "markdown", "twine", "wheel"] + +[[package]] +name = "iniconfig" +version = "2.1.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markdown" +version = "3.8" +description = "Python implementation of John Gruber's Markdown." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "markdown-3.8-py3-none-any.whl", hash = "sha256:794a929b79c5af141ef5ab0f2f642d0f7b1872981250230e72682346f7cc90dc"}, + {file = "markdown-3.8.tar.gz", hash = "sha256:7df81e63f0df5c4b24b7d156eb81e4690595239b7d70937d0409f1b0de319c6f"}, +] + +[package.extras] +docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] +testing = ["coverage", "pyyaml"] + +[[package]] +name = "markupsafe" +version = "3.0.2" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +description = "A deep merge function for ๐Ÿ." +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, + {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +description = "Project documentation with Markdown." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e"}, + {file = "mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2"}, +] + +[package.dependencies] +click = ">=7.0" +colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} +ghp-import = ">=1.0" +jinja2 = ">=2.11.1" +markdown = ">=3.3.6" +markupsafe = ">=2.0.1" +mergedeep = ">=1.3.4" +mkdocs-get-deps = ">=0.2.0" +packaging = ">=20.5" +pathspec = ">=0.11.1" +pyyaml = ">=5.1" +pyyaml-env-tag = ">=0.1" +watchdog = ">=2.0" + +[package.extras] +i18n = ["babel (>=2.9.0)"] +min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4) ; platform_system == \"Windows\"", "ghp-import (==1.0)", "importlib-metadata (==4.4) ; python_version < \"3.10\"", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"}, + {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"}, +] + +[package.dependencies] +mergedeep = ">=1.3.4" +platformdirs = ">=2.2.0" +pyyaml = ">=5.1" + +[[package]] +name = "packaging" +version = "25.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.3.7" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"}, + {file = "platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.14.1)"] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pytest" +version = "8.3.5" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"}, + {file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.5,<2" + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pyyaml" +version = "6.0.2" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +description = "A custom YAML tag for referencing environment variables in YAML files. " +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, + {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, +] + +[package.dependencies] +pyyaml = "*" + +[[package]] +name = "six" +version = "1.17.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +files = [ + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2"}, + {file = "watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a"}, + {file = "watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"}, + {file = "watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f"}, + {file = "watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.12" +content-hash = "6dcf11d27e73eff7feac8a2edd329096ca0cf629ea8d0ad669188a642a9c9aac" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..5e54e01 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,28 @@ +[project] +name = "mkdocs-color-swatch-plugin" +version = "0.1.0" +description = "A MkDocs plugin for inline color swatches with tooltip and hover effects" +authors = [ + { name = "Fabian Eulitz", email = "dev@sustineo.de" } +] +license = { text = "MIT" } +readme = "README.md" +repository = "https://github.com/fabieu/mkdocs-color-swatch-plugin" +keywords = ["mkdocs", "plugin", "markdown", "color", "tooltip"] + +requires-python = ">=3.12" +dependencies = [ + "mkdocs (>=1.6.1,<2.0.0)", + "markdown (>=3.8,<4.0)", +] + +[project.entry-points."mkdocs.plugins"] +color-swatch = "mkdocs_color_swatch_plugin.plugin:ColorSwatchPlugin" + +[build-system] +requires = ["poetry-core>=2.0.0,<3.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry.group.dev.dependencies] +pytest = "^8.3.5" + diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_render.py b/tests/test_render.py new file mode 100644 index 0000000..512acba --- /dev/null +++ b/tests/test_render.py @@ -0,0 +1,45 @@ +from markdown import Markdown + +from mkdocs_color_swatch_plugin.color_swatch import ColorSwatchExtension +from mkdocs_color_swatch_plugin.plugin import ColorSwatchPlugin, EMBEDDED_CSS + +# Global instances to reuse across all tests +MARKDOWN_ENGINE = Markdown(extensions=[ColorSwatchExtension()]) +PLUGIN = ColorSwatchPlugin() + + +def render_markdown(text, use_plugin=False): + html = MARKDOWN_ENGINE.convert(text) + if use_plugin: + html = PLUGIN.on_page_content(html) + return html + + +def test_swatch_renders_html(): + html = render_markdown('[[color: #e74c3c | Red]]') + assert 'class="color-swatch"' in html + assert 'data-tooltip="#e74c3c โ€“ Red"' in html + + +def test_plain_text_has_no_swatch(): + html = render_markdown('This is just plain text.') + assert 'class="color-swatch"' not in html + + +def test_css_injected_when_needed(): + html = render_markdown('[[color: #3498db | Blue]]', use_plugin=True) + assert EMBEDDED_CSS.strip() in html + assert 'class="color-swatch"' in html + + +def test_css_not_injected_for_plain_text(): + html = render_markdown('Nothing to see here.', use_plugin=True) + assert EMBEDDED_CSS.strip() not in html + + +def test_rgb_and_rgba_colors_render(): + html = render_markdown('[[color: rgb(255,0,0) | Red]]') + assert 'rgb(255,0,0)' in html + + html = render_markdown('[[color: rgba(0,255,0,0.5) | Transparent Green]]') + assert 'rgba(0,255,0,0.5)' in html From 9a0e2c6346ddcc8b80ccbf159bdc3c460597cb58 Mon Sep 17 00:00:00 2001 From: Fabian Eulitz Date: Sun, 20 Apr 2025 02:16:58 +0200 Subject: [PATCH 2/7] Refactor color swatch injection and add external assets Moved CSS and JS into standalone files for better modularity and maintainability, replacing embedded styles/scripts. Enhanced Markdown inline processor to support improved syntax for color swatches. Updated tests to validate new cases and handle invalid inputs. --- docs/index.md | 11 +- .../assets/color-swatch.css | 84 +++++++++++ .../assets/color-swatch.js | 47 +++++++ mkdocs_color_swatch_plugin/color_swatch.py | 55 ++++++-- mkdocs_color_swatch_plugin/plugin.py | 130 +++++------------- poetry.lock | 49 ++++++- pyproject.toml | 1 + tests/test_render.py | 72 +++++----- 8 files changed, 304 insertions(+), 145 deletions(-) create mode 100644 mkdocs_color_swatch_plugin/assets/color-swatch.css create mode 100644 mkdocs_color_swatch_plugin/assets/color-swatch.js diff --git a/docs/index.md b/docs/index.md index 872e136..98c5436 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,4 +1,11 @@ # Color Swatch Plugin Demo -[[color: #e74c3c | Red]] -[[color: rgba(0,255,0,0.5) | Transparent Green]] +# Lorem Ipsum :color[#3498db]: + +## Lorem Ipsum :color[#e74c3c]: + +### Lorem Ipsum :color[rgba(0,255,0,0.5)]: + +#### Lorem Ipsum :color[rgba(0,255,0,0.5)]: + +Lorem Ipsum :color[rgb(0,0,255)]: diff --git a/mkdocs_color_swatch_plugin/assets/color-swatch.css b/mkdocs_color_swatch_plugin/assets/color-swatch.css new file mode 100644 index 0000000..bf979c4 --- /dev/null +++ b/mkdocs_color_swatch_plugin/assets/color-swatch.css @@ -0,0 +1,84 @@ +.color-swatch { + display: inline-block; + position: relative; + vertical-align: middle; + + width: 1em; + height: 1em; + margin: 0 0.1em; + border-radius: 0.1em; + + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.color-swatch:hover { + transform: scale(1.1); + box-shadow: 0 0 6px rgba(0, 0, 0, 0.2); +} + +.color-swatch::after { + position: absolute; + left: 50%; + bottom: 120%; + z-index: 10; + + display: block; + content: attr(data-tooltip); + + padding: 0.5em 0.8em; + border-radius: 0.1em; + white-space: nowrap; + + background: #333; + color: #fff; + font-size: 0.6em; + + opacity: 0; + pointer-events: none; + + transition: opacity 0.3s ease; + transform: translateX(-50%); +} + +.color-swatch:hover::after { + opacity: 1; +} + +/* Toast container */ +.toast-container { + position: fixed; + top: 16px; + left: 50%; + transform: translateX(-50%); + z-index: 9999; + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5em; +} + +/* Individual toast */ +.copied-toast { + background: #2ecc71; + color: white; + padding: 0.75em 1.25em 1.25em; + border-radius: 0.5em; + font-size: 1em; + min-width: 220px; + text-align: center; + position: relative; + opacity: 1; + transition: opacity 0.3s ease; +} + +.copied-toast .close-toast { + position: absolute; + top: 0.3em; + left: 50%; + transform: translateX(-50%); + font-weight: bold; + font-size: 1.2em; + line-height: 1; + cursor: pointer; + user-select: none; +} \ No newline at end of file diff --git a/mkdocs_color_swatch_plugin/assets/color-swatch.js b/mkdocs_color_swatch_plugin/assets/color-swatch.js new file mode 100644 index 0000000..7024b88 --- /dev/null +++ b/mkdocs_color_swatch_plugin/assets/color-swatch.js @@ -0,0 +1,47 @@ +document.addEventListener("DOMContentLoaded", function () { + document.querySelectorAll('.color-swatch').forEach(function (swatch) { + swatch.addEventListener('click', function () { + const tooltip = swatch.getAttribute('data-tooltip'); + if (!tooltip) return; + const colorValue = tooltip.split('โ€“')[0].trim(); + navigator.clipboard.writeText(colorValue).then(function () { + showCopiedToast(colorValue); + }); + }); + }); + + function showCopiedToast(color) { + // Create or find toast container + let container = document.querySelector('.toast-container'); + if (!container) { + container = document.createElement('div'); + container.className = 'toast-container'; + document.body.appendChild(container); + } + + // Create individual toast + const toast = document.createElement('div'); + toast.className = 'copied-toast'; + toast.style.backgroundColor = '#2ecc71'; + toast.innerHTML = ` +
+ Copied ${color} to clipboard! + ร— +
+ `; + + // Close manually + toast.querySelector('.close-toast').addEventListener('click', () => { + toast.style.opacity = '0'; + setTimeout(() => toast.remove(), 300); + }); + + // Auto-remove after 2 seconds + setTimeout(() => { + toast.style.opacity = '0'; + setTimeout(() => toast.remove(), 300); + }, 2000); + + container.appendChild(toast); + } +}); \ No newline at end of file diff --git a/mkdocs_color_swatch_plugin/color_swatch.py b/mkdocs_color_swatch_plugin/color_swatch.py index ac7db7e..ba9a140 100644 --- a/mkdocs_color_swatch_plugin/color_swatch.py +++ b/mkdocs_color_swatch_plugin/color_swatch.py @@ -1,30 +1,59 @@ -import xml.etree.ElementTree as ElementTree +import re +import xml.etree.ElementTree as etree from markdown.extensions import Extension from markdown.inlinepatterns import InlineProcessor SWATCH_CLASS = 'color-swatch' -# Support hex, rgb(), rgba() -COLOR_RE = r'\[\[color:\s*(#[0-9a-fA-F]{3,6}|rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+(?:\s*,\s*(?:\d+|\d*\.\d+))?\s*\))\s*\|\s*([^\]]+)\]\]' +# Regex pattern for :color[#hex]:, :color[rgb(...)]:, :color[rgba(...)]: with no label support +COLOR_PATTERN = ( + r":color\[\s*" + r"(#[0-9a-fA-F]{3,8}" + r"|rgb\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*\)" + r"|rgba\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*(?:\d*\.\d+|\d+)\s*\))" + r"\s*]:" +) class ColorSwatchExtension(Extension): + """ + Provides functionality to extend Markdown with custom inline color swatches. + + This class integrates with the Markdown library to add support for processing + and rendering color swatch patterns. It is intended to simplify working with + inline color definitions and incorporate them seamlessly into Markdown content. + + :ivar config: Configuration options for the extension. + :type config: dict + """ def extendMarkdown(self, md): - md.inlinePatterns.register(ColorSwatchInlineProcessor(COLOR_RE, md), 'color_swatch', 175) + """ + Extends the given Markdown instance by registering a custom inline processor for color swatch patterns. + """ + md.inlinePatterns.register(ColorSwatchInlineProcessor(COLOR_PATTERN, md), 'color_swatch', 175) class ColorSwatchInlineProcessor(InlineProcessor): - def handleMatch(self, matcher, data): - color_code = matcher.group(1) - label = matcher.group(2) + """ + Processes inline color swatch markdown elements. + + This class extends the functionality of the Markdown InlineProcessor + to identify and process inline color swatch elements. It parses color + codes within inline markdown elements and replaces them with styled + HTML elements that visually represent the color. This can be used for + rendering markdown documents where color indicators are needed. - swatch = ElementTree.Element('span') + :ivar pattern: Regex pattern used to match color swatch inline elements. + :type pattern: str + """ + + def handleMatch(self, m: re.Match[str], data: str) -> tuple[etree.Element | str | None, int | None, int | None]: + color_code = m.group(1) + + swatch = etree.Element('span') swatch.set('class', SWATCH_CLASS) swatch.set('style', f'background-color: {color_code};') - swatch.set('data-tooltip', f'{color_code} โ€“ {label}') - - wrapper = ElementTree.Element('div') - wrapper.append(swatch) + swatch.set('data-tooltip', f'{color_code}') - return wrapper, matcher.start(0), matcher.end(0) + return swatch, m.start(0), m.end(0) diff --git a/mkdocs_color_swatch_plugin/plugin.py b/mkdocs_color_swatch_plugin/plugin.py index ed82d2f..bf72f8c 100644 --- a/mkdocs_color_swatch_plugin/plugin.py +++ b/mkdocs_color_swatch_plugin/plugin.py @@ -1,102 +1,48 @@ +from pathlib import Path + +from bs4 import BeautifulSoup +from mkdocs.config.defaults import MkDocsConfig from mkdocs.plugins import BasePlugin +from mkdocs.structure.pages import Page from mkdocs_color_swatch_plugin.color_swatch import ColorSwatchExtension -EMBEDDED_CSS = """ - - -""" - class ColorSwatchPlugin(BasePlugin): - config_scheme = () + ASSET_DIR = Path(__file__).parent / "assets" + CSS_PATH = ASSET_DIR / "color-swatch.css" + JAVASCRIPT_PATH = ASSET_DIR / "color-swatch.js" + + def __init__(self) -> None: + self.css_content = self._read_content(self.CSS_PATH) + self.javascript_content = self._read_content(self.JAVASCRIPT_PATH) - def on_config(self, config, **kwargs): + def on_config(self, config: MkDocsConfig) -> MkDocsConfig | None: config['markdown_extensions'].append(ColorSwatchExtension()) return config - def on_page_content(self, html, **kwargs): - if 'class="color-swatch"' in html: - html = EMBEDDED_CSS + '\n' + html - return html + def on_post_page(self, html_output: str, /, *, page: Page, config: MkDocsConfig) -> str | None: + soup_content = BeautifulSoup(html_output, 'html.parser') + + self._inject_css(soup_content) + self._inject_js(soup_content) + + return str(soup_content) + + def _read_content(self, path: Path) -> str: + if not path.exists(): + raise FileNotFoundError(f"File not found: {path}") + + return path.read_text(encoding="utf-8") + + def _inject_css(self, soup: BeautifulSoup) -> None: + if self.css_content and soup.head: + style_tag = soup.new_tag("style") + style_tag.string = self.css_content + soup.head.append(style_tag) + + def _inject_js(self, soup_content: BeautifulSoup) -> None: + if self.javascript_content and soup_content.body: + script_tag = soup_content.new_tag("script") + script_tag.string = self.javascript_content + soup_content.body.append(script_tag) diff --git a/poetry.lock b/poetry.lock index d17f6f7..d9639e5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,28 @@ # This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. +[[package]] +name = "beautifulsoup4" +version = "4.13.4" +description = "Screen-scraping library" +optional = false +python-versions = ">=3.7.0" +groups = ["main"] +files = [ + { file = "beautifulsoup4-4.13.4-py3-none-any.whl", hash = "sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b" }, + { file = "beautifulsoup4-4.13.4.tar.gz", hash = "sha256:dbb3c4e1ceae6aefebdaf2423247260cd062430a410e38c66f2baa50a8437195" }, +] + +[package.dependencies] +soupsieve = ">1.2" +typing-extensions = ">=4.0.0" + +[package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] +html5lib = ["html5lib"] +lxml = ["lxml"] + [[package]] name = "click" version = "8.1.8" @@ -406,6 +429,30 @@ files = [ {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] +[[package]] +name = "soupsieve" +version = "2.6" +description = "A modern CSS selector implementation for Beautiful Soup." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + { file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9" }, + { file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb" }, +] + +[[package]] +name = "typing-extensions" +version = "4.13.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + { file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c" }, + { file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef" }, +] + [[package]] name = "watchdog" version = "6.0.0" @@ -452,4 +499,4 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.1" python-versions = ">=3.12" -content-hash = "6dcf11d27e73eff7feac8a2edd329096ca0cf629ea8d0ad669188a642a9c9aac" +content-hash = "032f2cdf50b0629eb000218c55adb2e004a7567043749d3bf73b940218b5d299" diff --git a/pyproject.toml b/pyproject.toml index 5e54e01..f60d152 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ requires-python = ">=3.12" dependencies = [ "mkdocs (>=1.6.1,<2.0.0)", "markdown (>=3.8,<4.0)", + "beautifulsoup4 (>=4.13.4,<5.0.0)", ] [project.entry-points."mkdocs.plugins"] diff --git a/tests/test_render.py b/tests/test_render.py index 512acba..6a80eb8 100644 --- a/tests/test_render.py +++ b/tests/test_render.py @@ -1,45 +1,43 @@ -from markdown import Markdown +import markdown +import pytest from mkdocs_color_swatch_plugin.color_swatch import ColorSwatchExtension -from mkdocs_color_swatch_plugin.plugin import ColorSwatchPlugin, EMBEDDED_CSS -# Global instances to reuse across all tests -MARKDOWN_ENGINE = Markdown(extensions=[ColorSwatchExtension()]) -PLUGIN = ColorSwatchPlugin() +# Global Markdown instance that can be reused +md = markdown.Markdown(extensions=[ColorSwatchExtension()]) -def render_markdown(text, use_plugin=False): - html = MARKDOWN_ENGINE.convert(text) - if use_plugin: - html = PLUGIN.on_page_content(html) - return html +@pytest.mark.parametrize("input_md,expected_style", [ + (":color[#3498db]:", "background-color: #3498db;"), + (":color[#fff]:", "background-color: #fff;"), + (":color[rgb(255,0,0)]:", "background-color: rgb(255,0,0);"), + (":color[rgba(10,20,30,0.5)]:", "background-color: rgba(10,20,30,0.5);"), +]) +def test_color_swatch_renders_correctly(input_md, expected_style): + # Use global Markdown instance, but reset between tests + md.reset() + html = md.convert(input_md) - -def test_swatch_renders_html(): - html = render_markdown('[[color: #e74c3c | Red]]') assert 'class="color-swatch"' in html - assert 'data-tooltip="#e74c3c โ€“ Red"' in html - - -def test_plain_text_has_no_swatch(): - html = render_markdown('This is just plain text.') + assert expected_style in html + + # Tooltip should show the color code + code_start = input_md.find('[') + 1 + code_end = input_md.find(']') + color_code = input_md[code_start:code_end].strip() + + assert f'data-tooltip="{color_code}"' in html + + +@pytest.mark.parametrize("invalid_md", [ + ":color[#12g]:", # Invalid hex + ":color[rgb(100,200)]:", # Missing channel + ":color[rgba(10,20,30)]:", # Missing alpha + ":color[rgba(10,20,30,foo)]:", # Invalid alpha + ":color[#fff|]:", # Pipe with nothing + ":color[red]:", # Named color not supported +]) +def test_color_swatch_does_not_render_on_invalid(invalid_md): + md.reset() + html = md.convert(invalid_md) assert 'class="color-swatch"' not in html - - -def test_css_injected_when_needed(): - html = render_markdown('[[color: #3498db | Blue]]', use_plugin=True) - assert EMBEDDED_CSS.strip() in html - assert 'class="color-swatch"' in html - - -def test_css_not_injected_for_plain_text(): - html = render_markdown('Nothing to see here.', use_plugin=True) - assert EMBEDDED_CSS.strip() not in html - - -def test_rgb_and_rgba_colors_render(): - html = render_markdown('[[color: rgb(255,0,0) | Red]]') - assert 'rgb(255,0,0)' in html - - html = render_markdown('[[color: rgba(0,255,0,0.5) | Transparent Green]]') - assert 'rgba(0,255,0,0.5)' in html From 66fb6f2f89a5a0686cdd49b1b7ce79276cf5de01 Mon Sep 17 00:00:00 2001 From: Fabian Eulitz Date: Sun, 20 Apr 2025 14:22:15 +0200 Subject: [PATCH 3/7] Complete rework of the plugin file initialization --- mkdocs_color_swatch_plugin/plugin.py | 78 ++++++++++++++++------------ 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/mkdocs_color_swatch_plugin/plugin.py b/mkdocs_color_swatch_plugin/plugin.py index bf72f8c..cfc9978 100644 --- a/mkdocs_color_swatch_plugin/plugin.py +++ b/mkdocs_color_swatch_plugin/plugin.py @@ -3,46 +3,58 @@ from bs4 import BeautifulSoup from mkdocs.config.defaults import MkDocsConfig from mkdocs.plugins import BasePlugin +from mkdocs.structure.files import Files, File from mkdocs.structure.pages import Page from mkdocs_color_swatch_plugin.color_swatch import ColorSwatchExtension class ColorSwatchPlugin(BasePlugin): - ASSET_DIR = Path(__file__).parent / "assets" - CSS_PATH = ASSET_DIR / "color-swatch.css" - JAVASCRIPT_PATH = ASSET_DIR / "color-swatch.js" + def __init__(self): + self.plugin_src_dir = Path(__file__).parent / "assets" + self.plugin_site_dir = None - def __init__(self) -> None: - self.css_content = self._read_content(self.CSS_PATH) - self.javascript_content = self._read_content(self.JAVASCRIPT_PATH) + def on_config(self, config: MkDocsConfig, **kwargs): + config.markdown_extensions.append(ColorSwatchExtension()) - def on_config(self, config: MkDocsConfig) -> MkDocsConfig | None: - config['markdown_extensions'].append(ColorSwatchExtension()) - return config - - def on_post_page(self, html_output: str, /, *, page: Page, config: MkDocsConfig) -> str | None: - soup_content = BeautifulSoup(html_output, 'html.parser') - - self._inject_css(soup_content) - self._inject_js(soup_content) - - return str(soup_content) + self.plugin_site_dir = Path(config.site_dir) / "plugins" / "color-swatch" + self.plugin_site_dir.mkdir(parents=True, exist_ok=True) - def _read_content(self, path: Path) -> str: - if not path.exists(): - raise FileNotFoundError(f"File not found: {path}") - - return path.read_text(encoding="utf-8") - - def _inject_css(self, soup: BeautifulSoup) -> None: - if self.css_content and soup.head: - style_tag = soup.new_tag("style") - style_tag.string = self.css_content - soup.head.append(style_tag) + return config - def _inject_js(self, soup_content: BeautifulSoup) -> None: - if self.javascript_content and soup_content.body: - script_tag = soup_content.new_tag("script") - script_tag.string = self.javascript_content - soup_content.body.append(script_tag) + def on_files(self, files: Files, config: MkDocsConfig, **kwargs) -> Files | None: + for file in self.plugin_src_dir.iterdir(): + if file.is_file(): + files.append( + File( + path=str(file.relative_to(self.plugin_src_dir)), + src_dir=str(self.plugin_src_dir), + dest_dir=str(self.plugin_site_dir), + use_directory_urls=False, + ) + ) + + return files + + def on_post_page(self, html_output: str, /, *, page: Page, config: MkDocsConfig, **kwargs) -> str | None: + soup = BeautifulSoup(html_output, 'html.parser') + + # Only inject references if there are color swatches in the page + if soup.find('span', class_='color-swatch'): + self._inject_references(soup, config) + + return str(soup) + + def _inject_references(self, soup: BeautifulSoup, config: MkDocsConfig) -> None: + for file in self.plugin_site_dir.iterdir(): + if not file.is_file(): + continue + + rel_path = file.relative_to(config.site_dir).as_posix() + + if file.suffix == '.css': + link_tag = soup.new_tag("link", rel="stylesheet", href=rel_path) + soup.head.append(link_tag) + elif file.suffix in ('.js', '.javascript'): + script_tag = soup.new_tag("script", src=rel_path) + soup.body.append(script_tag) From 1093cec32955807fcd85ca07233bc55f75446a5d Mon Sep 17 00:00:00 2001 From: Fabian Eulitz Date: Sun, 20 Apr 2025 14:32:32 +0200 Subject: [PATCH 4/7] Update documentation --- README.md | 85 ++++++++++++++++++++++++++++++-------------------- pyproject.toml | 8 ++--- 2 files changed, 56 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index ef5893e..3b377fa 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,35 @@ -# ๐ŸŽจ MkDocs Color Swatch Plugin +# ๐ŸŽจ Color Swatch Plugin for [MkDocs](https://www.mkdocs.org/) -A lightweight [MkDocs](https://www.mkdocs.org/) plugin that lets you insert inline color swatches into your Markdown docs using a simple, readable syntax. +> A lightweight plugin that lets you insert inline color swatches into your Markdown docs using a simple, readable +> syntax. -Supports: -- โœ… Hex colors (`#ff0000`, `#f00`) -- โœ… RGB and RGBA (`rgb(255, 0, 0)`, `rgba(255, 0, 0, 0.5)`) -- โœ… Tooltip with color value + label -- โœ… Rounded swatches with smooth hover animations -- โœ… No CSS setup required โ€” styles are embedded automatically +![PyPI](https://img.shields.io/pypi/v/mkdocs-color-swatch-plugin?style=for-the-badge) +![PyPI - Python Version](https://img.shields.io/pypi/pyversions/mkdocs-color-swatch-plugin?style=for-the-badge) +[![GitHub pipeline status](https://img.shields.io/github/actions/workflow/status/fabieu/mkdocs-color-swatch-plugin/build.yml?style=for-the-badge)](https://github.com/fabieu/mkdocs-color-swatch-plugin/actions) +[![GitHub issues](https://img.shields.io/github/issues-raw/fabieu/mkdocs-color-swatch-plugin?style=for-the-badge)](https://github.com/fabieu/mkdocs-color-swatch-plugin/issues) +[![GitHub merge requests](https://img.shields.io/github/issues-pr/fabieu/mkdocs-color-swatch-plugin?style=for-the-badge)](https://github.com/fabieu/mkdocs-color-swatch-plugin/pulls) +[![GitHub](https://img.shields.io/github/license/fabieu/mkdocs-color-swatch-plugin?style=for-the-badge)](https://github.com/fabieu/mkdocs-color-swatch-plugin/blob/main/LICENSE) + +## โญ Features + +- Styled swatches with smooth hover animations and tooltips +- Responsive swatches for all screen sizes +- Supports various color formats: + - Hex colors - `#ff0000`/`#f00` + - RGB colors - `rgb(255, 0, 0)` + - RGBA colors - `rgba(255, 0, 0, 0.5)` +- No CSS setup required โ€” styles are embedded automatically --- ## ๐Ÿš€ Installation -Install via [PyPI](https://pypi.org/): +### Prerequisites + +- [MkDocs](https://www.mkdocs.org/) >= 1.4.X +- [Python](https://www.python.org/) >= 3.10 + +Install the plugin from [PyPI](https://pypi.org/project/mkdocs-color-swatch-plugin/) using `pip`: ```bash pip install mkdocs-color-swatch-plugin @@ -34,21 +50,21 @@ pip install mkdocs --- -## โœ๏ธ Usage +## โœ๏ธ Syntax & Usage -In your Markdown, use the custom swatch syntax: +To add swatches to your Markdown, use the simple, custom inline format: ```markdown -[[color: #e74c3c | Red]] -[[color: rgb(52, 152, 219) | Blue]] -[[color: rgba(46, 204, 113, 0.6) | Transparent Green]] +:color[#e74c3c]: -> Red +:color[rgb(52, 152, 219)]: -> Green +:color[rgba(46, 204, 113, 0.6)]: -> Blue ``` Each tag will render as: -- A **rounded swatch** showing the color -- A **tooltip** with the color value + label -- A **hover effect** that scales and highlights the swatch +- A visual color preview +- Dynamically generated **tooltips** showing the color value and label +- A smooth **hover animation** for swatch elements --- @@ -63,26 +79,28 @@ Instead of manually writing HTML for every color sample like: You can just write: ```markdown -[[color: #e74c3c | Red]] +:color[#e74c3c]: ``` -It's faster, cleaner, and works right out of the box. +It's faster, cleaner, and scales dynamically with your content. --- -## ๐Ÿ›  Features +## ๐Ÿ’ก Features & Benefits -- ๐Ÿ”น Works with any valid `hex`, `rgb()`, or `rgba()` color -- ๐Ÿ”น Tooltip automatically shows `#hex โ€“ Label` -- ๐Ÿ”น Embedded CSS โ€” no setup needed -- ๐Ÿ”น Safe to use alongside other Markdown extensions -- ๐Ÿ”น Lightweight and dependency-free +- ๐ŸŽจ Works with all valid `hex`, `rgb()`, and `rgba()` color values +- ๐ŸŽฏ Simple syntax for embedding colors directly in your Markdown files +- ๐Ÿ›  Automatically injected CSS for responsive and visually appealing swatches +- ๐Ÿ”„ Perfectly safe to use with other Markdown extensions +- ๐Ÿ” Live color preview in rendered HTML files, complete with tooltips --- -## ๐Ÿ“ฆ Development & Contribution +## ๐Ÿ›  Development & Contribution + +### ๐Ÿ‘จโ€๐Ÿ’ป Repository Setup: -### Clone and Install: +Clone the project repository and configure the environment with Poetry: ```bash git clone https://github.com/yourusername/mkdocs-color-swatch-plugin.git @@ -97,11 +115,7 @@ poetry install pip install -e . ``` ---- - -## ๐Ÿงช Testing - -Basic tests coming soon! +This allows you to test your changes directly when running MkDocs locally. --- @@ -111,4 +125,9 @@ MIT ยฉ [Fabian Eulitz](https://github.com/fabieu) --- -Made with โค๏ธ +## ๐Ÿ“Ž Resources + +- [mkdocs-color-swatch-plugin on PyPI](https://pypi.org/project/mkdocs-color-swatch-plugin/) +- [mkdocs-color-swatch-plugin on GitHub](https://github.com/fabieu/mkdocs-color-swatch-plugin) +- [MkDocs Documentation](https://www.mkdocs.org/) + diff --git a/pyproject.toml b/pyproject.toml index f60d152..55a1f1c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,13 +10,16 @@ readme = "README.md" repository = "https://github.com/fabieu/mkdocs-color-swatch-plugin" keywords = ["mkdocs", "plugin", "markdown", "color", "tooltip"] -requires-python = ">=3.12" +requires-python = ">=3.10" dependencies = [ "mkdocs (>=1.6.1,<2.0.0)", "markdown (>=3.8,<4.0)", "beautifulsoup4 (>=4.13.4,<5.0.0)", ] +[tool.poetry.group.dev.dependencies] +pytest = "^8.3.5" + [project.entry-points."mkdocs.plugins"] color-swatch = "mkdocs_color_swatch_plugin.plugin:ColorSwatchPlugin" @@ -24,6 +27,3 @@ color-swatch = "mkdocs_color_swatch_plugin.plugin:ColorSwatchPlugin" requires = ["poetry-core>=2.0.0,<3.0.0"] build-backend = "poetry.core.masonry.api" -[tool.poetry.group.dev.dependencies] -pytest = "^8.3.5" - From fec04329e142df8d016ef52f4493908538bf8648 Mon Sep 17 00:00:00 2001 From: Fabian Eulitz Date: Sun, 20 Apr 2025 18:30:00 +0200 Subject: [PATCH 5/7] Add GitHub Actions for releases, dependencies, and builds This commit introduces workflows for automated releases, dependency updates, and package publishing. It includes a Dependabot configuration for managing Python and GitHub Actions updates, a release notes generator setup, and a build workflow to publish the package to PyPI and create GitHub releases. --- .github/dependabot.yml | 37 ++++++++++++++++++++++ .github/release.yml | 20 ++++++++++++ .github/workflows/build.yml | 63 +++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/release.yml create mode 100644 .github/workflows/build.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..81a79f2 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,37 @@ +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + day: "saturday" + time: "07:00" + labels: + - "dependencies" + assignees: + - "fabieu" + groups: + major-updates: + update-types: + - "major" + minor-updates: + update-types: + - "minor" + - "patch" + other-updates: + patterns: + - "*" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "saturday" + time: "07:00" + labels: + - "dependencies" + assignees: + - "fabieu" + groups: + gh-actions: + patterns: + - "*" \ No newline at end of file diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..6011f57 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,20 @@ +changelog: + exclude: + labels: + - ignore-for-release + categories: + - title: Breaking Changes โš ๏ธ + labels: + - "breaking change" + - title: Bug Fixes ๐Ÿ› + labels: + - "bug" + - title: Features ๐ŸŽ‰ + labels: + - "enhancement" + - title: Dependency Updates โฌ†๏ธ + labels: + - "dependencies" + - title: Other Changes + labels: + - "*" \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..ffd28fe --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,63 @@ +name: Build and publish mkdocs-color-swatch-plugin + +on: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + POETRY_VERSION: 2.1.1 + PYPI_TOKEN: "${{ secrets.PYPI_TOKEN }}" + +jobs: + variables: + name: Set environment variables + runs-on: ubuntu-latest + container: + image: python:3.13-slim + outputs: + version: ${{ env.VERSION }} + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install poetry + run: pip install poetry==$POETRY_VERSION + - name: Save version to environment + run: echo "VERSION=$(poetry version -s)" >> "$GITHUB_ENV" + - name: Display version + run: echo "Version ${{ env.VERSION }}" + publish: + name: Publish package to PYPI + runs-on: ubuntu-latest + needs: + - variables + container: + image: python:3.13-slim + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install poetry + run: pip install poetry==$POETRY_VERSION + - name: Install project dependencies + run: poetry install + - name: Public package to PYPI via Poetry + run: poetry publish --build --no-interaction --username __token__ --password $PYPI_TOKEN + create-release: + name: Create release + runs-on: ubuntu-latest + needs: + - variables + - publish + timeout-minutes: 5 + steps: + - name: Release + uses: softprops/action-gh-release@v2 + with: + name: Release v${{ needs.variables.outputs.version }} + tag_name: v${{ needs.variables.outputs.version }} + target_commitish: ${{ github.sha }} + generate_release_notes: true From 2e3604c75ac8b859ef00dbac3507d428169e98ad Mon Sep 17 00:00:00 2001 From: Fabian Eulitz Date: Sun, 20 Apr 2025 18:51:26 +0200 Subject: [PATCH 6/7] Add tests to GitHub Actions workflow --- .github/workflows/build.yml | 23 ++++++++++++++--------- .github/workflows/test.yml | 28 ++++++++++++++++++++++++++++ mkdocs.yml | 2 +- 3 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ffd28fe..7d07ea0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,45 +7,50 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -env: - POETRY_VERSION: 2.1.1 - PYPI_TOKEN: "${{ secrets.PYPI_TOKEN }}" - jobs: variables: name: Set environment variables runs-on: ubuntu-latest container: - image: python:3.13-slim + image: ${{ vars.PYTHON_IMAGE }} outputs: version: ${{ env.VERSION }} timeout-minutes: 5 steps: - name: Checkout uses: actions/checkout@v4 + - name: Install poetry - run: pip install poetry==$POETRY_VERSION + run: pip install poetry==${{ vars.POETRY_VERSION }} + - name: Save version to environment run: echo "VERSION=$(poetry version -s)" >> "$GITHUB_ENV" + - name: Display version run: echo "Version ${{ env.VERSION }}" + test: + uses: ./.github/workflows/test.yml publish: name: Publish package to PYPI runs-on: ubuntu-latest needs: + - test - variables container: - image: python:3.13-slim + image: ${{ vars.PYTHON_IMAGE }} timeout-minutes: 15 steps: - name: Checkout uses: actions/checkout@v4 + - name: Install poetry - run: pip install poetry==$POETRY_VERSION + run: pip install poetry==${{ vars.POETRY_VERSION }} + - name: Install project dependencies run: poetry install + - name: Public package to PYPI via Poetry - run: poetry publish --build --no-interaction --username __token__ --password $PYPI_TOKEN + run: poetry publish --build --no-interaction --username __token__ --password ${{ secrets.PYPI_TOKEN }} create-release: name: Create release runs-on: ubuntu-latest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..74a5f2b --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,28 @@ +name: Test Python Package + +on: + pull_request: + branches: + - main + workflow_call: + workflow_dispatch: + +jobs: + test: + name: Run tests with pytest + runs-on: ubuntu-latest + container: + image: ${{ vars.PYTHON_IMAGE }} + timeout-minutes: 5 + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Poetry + run: pip install poetry==${{ vars.POETRY_VERSION }} + + - name: Install dependencies + run: poetry install + + - name: Run pytest + run: poetry run pytest \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 19444fc..29c8da8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,4 +1,4 @@ -site_name: Local Plugin Demo +site_name: mkdocs-color-swatch-plugin demo plugins: - color-swatch From cbf711f2f0136bcf6733ae08170d8128b1e173ed Mon Sep 17 00:00:00 2001 From: Fabian Eulitz Date: Sun, 20 Apr 2025 18:54:52 +0200 Subject: [PATCH 7/7] Fix poetry.lock --- poetry.lock | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index d9639e5..ff975f5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -51,6 +51,22 @@ files = [ ] markers = {main = "platform_system == \"Windows\"", dev = "sys_platform == \"win32\""} +[[package]] +name = "exceptiongroup" +version = "1.2.2" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version < \"3.11\"" +files = [ + { file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b" }, + { file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" }, +] + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "ghp-import" version = "2.1.0" @@ -317,9 +333,11 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = { version = ">=1.0.0rc8", markers = "python_version < \"3.11\"" } iniconfig = "*" packaging = "*" pluggy = ">=1.5,<2" +tomli = { version = ">=1", markers = "python_version < \"3.11\"" } [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] @@ -441,6 +459,49 @@ files = [ { file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb" }, ] +[[package]] +name = "tomli" +version = "2.2.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version < \"3.11\"" +files = [ + { file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249" }, + { file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6" }, + { file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a" }, + { file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee" }, + { file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e" }, + { file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4" }, + { file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106" }, + { file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8" }, + { file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff" }, + { file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b" }, + { file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea" }, + { file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8" }, + { file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192" }, + { file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222" }, + { file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77" }, + { file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6" }, + { file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd" }, + { file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e" }, + { file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98" }, + { file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4" }, + { file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7" }, + { file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c" }, + { file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13" }, + { file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281" }, + { file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272" }, + { file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140" }, + { file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2" }, + { file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744" }, + { file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec" }, + { file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69" }, + { file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc" }, + { file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff" }, +] + [[package]] name = "typing-extensions" version = "4.13.2" @@ -498,5 +559,5 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.1" -python-versions = ">=3.12" -content-hash = "032f2cdf50b0629eb000218c55adb2e004a7567043749d3bf73b940218b5d299" +python-versions = ">=3.10" +content-hash = "9568daed7f8c13085196d66e75b38d58efa5299254a96bcb872304de8ababcaa"