Skip to content

feat: add ability to control mermaid icon packs #7929

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions docs/reference/diagrams.md
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ popular and flexible solution for drawing diagrams.
<!-- md:version 8.2.0 -->

This configuration enables native support for [Mermaid.js] diagrams. Material
for MkDocs will automatically initialize the JavaScript runtime when a page
for MkDocs will automatically initialize the JavaScript runtime when a page
includes a `mermaid` code block:

``` yaml
@@ -38,14 +38,40 @@ No further configuration is necessary. Advantages over a custom integration:
[^1]:
While all [Mermaid.js] features should work out-of-the-box, Material for
MkDocs will currently only adjust the fonts and colors for flowcharts,
sequence diagrams, class diagrams, state diagrams and entity relationship
sequence diagrams, class diagrams, state diagrams and entity relationship
diagrams. See the section on [other diagrams] for more information why this
is currently not implemented for all diagrams.

[instant loading]: ../setup/setting-up-navigation.md#instant-loading
[additional style sheets]: ../customization.md#additional-css
[other diagrams]: #other-diagram-types

### Loading additional icon packs

You can define additional [icon packs](https://mermaid.js.org/config/icons.html) you want be loaded by specifying list in `theme.mermaid.iconPacks`

Options:
- `url:<prefix>:<url>` for loading from Icon Packs from URL
- `iconify:<package>@<version>` for loading icons from iconify

``` yaml
theme:
mermaid:
iconPacks:
- iconify:logos@1
- url:aws:https://raw.githubusercontent.com/awslabs/aws-icons-for-plantuml/v19.0/dist/aws-icons-mermaid.json
```

### Overriding Mermaid JS version

Mermaid JS version can be overrided by providing `theme.mermaid.version` value. Use this carefully.

``` yaml
theme:
mermaid:
version: "11"
```

## Usage

### Using flowcharts
@@ -82,7 +108,7 @@ graph LR

### Using sequence diagrams

[Sequence diagrams] describe a specific scenario as sequential interactions
[Sequence diagrams] describe a specific scenario as sequential interactions
between multiple objects or actors, including the messages that are exchanged
between those actors:

@@ -194,7 +220,7 @@ classDiagram
+int postalCode
+String country
-validate()
+outputAsLabel()
+outputAsLabel()
}
```
````
@@ -226,7 +252,7 @@ classDiagram
+int postalCode
+String country
-validate()
+outputAsLabel()
+outputAsLabel()
}
```

33 changes: 33 additions & 0 deletions docs/schema/theme.json
Original file line number Diff line number Diff line change
@@ -800,6 +800,39 @@
}
}
]
},
"mermaid": {
"title": "Mermaid JS configuration",
"type": "object",
"properties": {
"version": {
"title": "Mermaid JS version",
"description": "ID of version to be substituted in https://unpkg.com/mermaid@(VERSION)/dist/mermaid.min.js",
"examples": [
"11"
]
},
"iconPacks": {
"title": "Icon packs",
"type": "array",
"items": {
"title": "Name of icon pack",
"description": "url:https://raw.githubusercontent.com/awslabs/aws-icons-for-plantuml/v19.0/dist/aws-icons-mermaid.json or iconify:logos@1",
"type": "string",
"examples": [
"url:aws:https://raw.githubusercontent.com/awslabs/aws-icons-for-plantuml/v19.0/dist/aws-icons-mermaid.json",
"iconify:logos@1"
]
},
"examples": [
[
"url:aws:https://raw.githubusercontent.com/awslabs/aws-icons-for-plantuml/v19.0/dist/aws-icons-mermaid.json",
"iconify:logos@1"
]
]
}
},
"additionalProperties": false
}
},
"additionalProperties": false,
2 changes: 1 addition & 1 deletion material/overrides/main.html
Original file line number Diff line number Diff line change
@@ -23,5 +23,5 @@
{% endblock %}
{% block scripts %}
{{ super() }}
<script src="{{ 'assets/javascripts/custom.00e08f28.min.js' | url }}"></script>
<script src="{{ 'assets/javascripts/custom.4e16f5b8.min.js' | url }}"></script>
{% endblock %}
5 changes: 4 additions & 1 deletion material/templates/base.html
Original file line number Diff line number Diff line change
@@ -244,12 +244,15 @@
] -%}
{%- set _ = translations.update({ key: lang.t(key) }) -%}
{%- endfor -%}
{%- if config.theme.mermaid -%}
{%- set _ = app.update({ "mermaid": config.theme.mermaid }) -%}
{%- endif -%}
<script id="__config" type="application/json">
{{- app | tojson -}}
</script>
{% endblock %}
{% block scripts %}
<script src="{{ 'assets/javascripts/bundle.5090c770.min.js' | url }}"></script>
<script src="{{ 'assets/javascripts/bundle.b64615fe.min.js' | url }}"></script>
{% for script in config.extra_javascript %}
{{ script | script_tag }}
{% endfor %}
9 changes: 9 additions & 0 deletions src/templates/assets/javascripts/_/index.ts
Original file line number Diff line number Diff line change
@@ -86,6 +86,14 @@ export interface Versioning {
alias?: boolean /* Show alias */
}

/**
* Mermaid JS Configuration
*/
export interface MermaidConfig {
version?: string
iconPacks?: string[]
}

/**
* Configuration
*/
@@ -96,6 +104,7 @@ export interface Config {
search: string /* Search worker URL */
tags?: Record<string, string> /* Tags mapping */
version?: Versioning /* Versioning */
mermaid?: MermaidConfig /* Mermaid JS configuration */
}

/* ----------------------------------------------------------------------------
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@

import { Observable, merge } from "rxjs"

import { feature } from "~/_"
import { configuration, feature } from "~/_"
import { Viewport, getElements } from "~/browser"

import { Component } from "../../_"
@@ -114,7 +114,7 @@ export function mountContent(

/* Mermaid diagrams */
...getElements("pre.mermaid", el)
.map(child => mountMermaid(child)),
.map(child => mountMermaid(child, configuration().mermaid)),

/* Data tables */
...getElements("table:not([class])", el)
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@ import {

import { watchScript } from "~/browser"
import { h } from "~/utilities"
import { MermaidConfig } from "~/_"

import { Component } from "../../_"

@@ -67,16 +68,70 @@ let sequence = 0
*
* @returns Mermaid scripts observable
*/
function fetchScripts(): Observable<void> {
function fetchScripts(config?: MermaidConfig): Observable<void> {
let version = "11";
if (config && config.version) {
version = config.version;
}

return typeof mermaid === "undefined" || mermaid instanceof Element
? watchScript("https://unpkg.com/mermaid@11/dist/mermaid.min.js")
? watchScript(`https://unpkg.com/mermaid@${version}/dist/mermaid.min.js`)
: of(undefined)
}

/* ----------------------------------------------------------------------------
* Functions
* ------------------------------------------------------------------------- */


/**
* Icon descriptor for Mermaid JS icon Packs
*/
interface IconPackDescriptor {
name: string,
loader: () => Promise<any>
}

/**
* Prepare details about icon packs for Mermaid JS
*
* @param iconName - Icon name. url:https://raw.githubusercontent.com/awslabs/aws-icons-for-plantuml/v19.0/dist/aws-icons-mermaid.json or iconify:logos@1
* @returns icon pack descriptor for Mermaid JS
*/
export function prepareIconDescriptor(iconName: string): IconPackDescriptor | undefined {
// First - we need to strip type from full icon name
const parts = iconName.split(':');
if (parts.length < 2) {
return undefined;
}

switch (parts[0]){
case 'url':
if (parts.length < 3) {
return undefined;
}

const url = parts.slice(2).join(':');
return {
name: parts[1],
loader: () => fetch(url).then((res) => res.json()),
}
case 'iconify':
const iconifyParts = parts[1].split('@', 2);
if (iconifyParts.length !== 2) {
return undefined;
}

return {
name: iconifyParts[0],
loader: () => fetch(`https://unpkg.com/@iconify-json/${parts[1]}/icons.json`).then((res) => res.json()),
}

default:
return undefined;
}
}

/**
* Mount Mermaid diagram
*
@@ -85,20 +140,29 @@ function fetchScripts(): Observable<void> {
* @returns Mermaid diagram component observable
*/
export function mountMermaid(
el: HTMLElement
el: HTMLElement, config?: MermaidConfig
): Observable<Component<Mermaid>> {
el.classList.remove("mermaid") // Hack: mitigate https://bit.ly/3CiN6Du
mermaid$ ||= fetchScripts()
mermaid$ ||= fetchScripts(config)
.pipe(
tap(() => mermaid.initialize({
startOnLoad: false,
themeCSS,
sequence: {
actorFontSize: "16px", // Hack: mitigate https://bit.ly/3y0NEi3
messageFontSize: "16px",
noteFontSize: "16px"
tap(() => {
mermaid.initialize({
startOnLoad: false,
themeCSS,
sequence: {
actorFontSize: "16px", // Hack: mitigate https://bit.ly/3y0NEi3
messageFontSize: "16px",
noteFontSize: "16px"
}
});

/* Load icon packs */
if (config && config.iconPacks) {
mermaid.registerIconPacks(
config.iconPacks.map(name => prepareIconDescriptor(name)).filter(descriptor => descriptor !== undefined)
);
}
})),
}),
map(() => undefined),
shareReplay(1)
)
5 changes: 5 additions & 0 deletions src/templates/base.html
Original file line number Diff line number Diff line change
@@ -424,6 +424,11 @@
{%- set _ = translations.update({ key: lang.t(key) }) -%}
{%- endfor -%}

<!-- Mermaid -->
{%- if config.theme.mermaid -%}
{%- set _ = app.update({ "mermaid": config.theme.mermaid }) -%}
{%- endif -%}

<!-- Configuration -->
<script id="__config" type="application/json">
{{- app | tojson -}}