LukeCarrier / mkdocs-drawio-exporter

Exports your Draw.io diagrams at build time for easier embedding into your documentation
https://pypi.org/project/mkdocs-drawio-exporter/
MIT License
81 stars 9 forks source link

Add link_css option #70

Open yves-chevallier opened 4 months ago

yves-chevallier commented 4 months ago

I was disappointed to find that the colors in Draw.io do not match the MkDocs theme. Unfortunately, Draw.io does not support applying CSS styles directly; instead, it uses a set of predefined colors. These colors are applied to SVG elements using the stroke= or fill= attributes.

The idea is to leverage the embed_format: '{content}' option to replace fill and stroke attributes with CSS variables.

image

image

In this example, I used the following mkdocs.yml:

site_name: Draw Exporter with CSS
plugins:
  - drawio-exporter:
      embed_format: '{content}'
      link_css: true
theme:
  name: material
  palette:
    - scheme: default
      toggle:
        icon: material/toggle-switch-off-outline
        name: Switch to dark mode
    - scheme: slate
      toggle:
        icon: material/toggle-switch
        name: Switch to light mode

extra_css:
  - style.css

The style.css is the following, where the colours are those from the first set in draw.io:

:root {
    --drawio-color-ffffff: #000000;
    --drawio-color-f5f5f5: #e9b3b3;
    --drawio-color-dae8fc: #9bbbe7;
    --drawio-color-d5e8d4: #75c770;
    --drawio-color-ffe6cc: #cc9e6d;
    --drawio-color-fff2cc: #dabd66;
    --drawio-color-f8cecc: #b95c57;
    --drawio-color-e1d5e7: #8c49ad;
}

[data-md-color-scheme="slate"] {
    --drawio-color-ffffff: #ffffff;
    --drawio-color-f5f5f5: #f5f5f5;
    --drawio-color-dae8fc: #dae8fc;
    --drawio-color-d5e8d4: #d5e8d4;
    --drawio-color-ffe6cc: #ffe6cc;
    --drawio-color-fff2cc: #fff2cc;
    --drawio-color-f8cecc: #f8cecc;
    --drawio-color-e1d5e7: #e1d5e7;
}

And the index.md:

# Test

![](test.drawio)

Another option to add is to let the user choose which drawing requires local CSS. We could imagine later using attr_list

![](test.drawio)
![](test.drawio){ link_css=true }
yves-chevallier commented 3 months ago

I realize one could simplify the parsing if using bs4 and lxml:

def set_css_classes(self, svg_content, prefix="--drawio-color"):
    def color2hex(string):
        if m := re.match(r'^#([0-9a-fA-F]{6})$', string):
            return m.group(1)
        if m := re.match('^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$'):
            return ''.join([f"{int(x):02x}" for x in m.groups()])
        return None
    tags = ['fill', 'stroke']
    soup = BeautifulSoup(svg_content, 'xml')
    elements = soup.select(','.join([f'[{tag}]' for tag in tags]))
    for element in elements:
        for attr in tags:
            hexcolor = color2hex(element.get(attr))
            if not hexcolor:
                self.log.error(f'Failed to parse color: {element.get(attr)}')
            element[attr] = f'var({prefix}-{hexcolor})'
    return str(soup)

It would certainly be more robust than complex regex, but it adds dependencies. I think bs4 is used by all mkdocs themes anyway.

What do you think?

LukeCarrier commented 3 months ago

I realize one could simplify the parsing if using bs4 and lxml:

What do you think?

I think the robustness gain is worth the additional dependencies, and I can see value in depending on an XML parser for other issues too (e.g. #9, #48). Less for us to test 🙌

yves-chevallier commented 3 months ago

I am changing my mind. I found a more elegant way to render drawio figures in browser. I am rendering figures directly in the browser using GraphViewer min.js.

I don't need any plugin on MkDocs, but just a js file. You can see it in action here. You may enable editable to edit, copy the figure in place. The script is pretty small docs/js/drawio.js.

LukeCarrier commented 3 months ago

That’s okay, glad you find a workable solution. Thanks for the work on this though; I’ll leave the PR open as I’d like to get this feature integrated when I next work on this. 🙂