Skip to content

Add support for mermaid.js diagrams. #1338

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 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 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
1 change: 1 addition & 0 deletions docs/_docset.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ toc:
- file: conditionals.md
- file: dropdowns.md
- file: definition-lists.md
- file: diagrams.md
- file: example_blocks.md
- file: file_inclusion.md
- file: frontmatter.md
Expand Down
164 changes: 164 additions & 0 deletions docs/syntax/diagrams.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# Diagrams

You can embedd diagrams using [mermaid.js](https://mermaid.js.org)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also add here which diagrams are not supported? (and maybe why)

Copy link
Contributor

@theletterf theletterf Jun 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edited the docs right now


## Flowcharts

:::::{tab-set}

::::{tab-item} Output

```mermaid
flowchart LR
A[Jupyter Notebook] --> C
B[MyST Markdown] --> C
C(mystmd) --> D{AST}
D <--> E[LaTeX]
E --> F[PDF]
D --> G[Word]
D --> H[React]
D --> I[HTML]
D <--> J[JATS]
```

::::

::::{tab-item} Markdown
````markdown
```mermaid
flowchart LR
A[Jupyter Notebook] --> C
B[MyST Markdown] --> C
C(mystmd) --> D{AST}
D <--> E[LaTeX]
E --> F[PDF]
D --> G[Word]
D --> H[React]
D --> I[HTML]
D <--> J[JATS]
```
````
::::

:::::


## Sequence Diagram


```mermaid
sequenceDiagram
participant Alice
participant Bob
Alice->>John: Hello John, how are you?
loop HealthCheck
John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts <br/>prevail!
John-->>Alice: Great!
John->>Bob: How about you?
Bob-->>John: Jolly good!
```

## Gant charts

```mermaid
gantt
dateFormat YYYY-MM-DD
title Adding GANTT diagram to mermaid
excludes weekdays 2014-01-10

section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
```

## Class Diagram

```mermaid
classDiagram
Class01 <|-- AveryLongClass : Cool
Class03 *-- Class04
Class05 o-- Class06
Class07 .. Class08
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
```

## Git Graph

```mermaid
gitGraph
commit
commit
branch develop
commit
commit
commit
checkout main
commit
commit
```


## Entity Relation Diagram

```mermaid
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
```

## User Journey

```mermaid
journey
title My working day
section Go to work
Make tea: 5: Me
Go upstairs: 3: Me
Do work: 1: Me, Cat
section Go home
Go downstairs: 5: Me
Sit down: 5: Me
```

## Quadrant Chart

```mermaid
quadrantChart
title Reach and engagement of campaigns
x-axis Low Reach --> High Reach
y-axis Low Engagement --> High Engagement
quadrant-1 We should expand
quadrant-2 Need to promote
quadrant-3 Re-evaluate
quadrant-4 May be improved
Campaign A: [0.3, 0.6]
Campaign B: [0.45, 0.23]
Campaign C: [0.57, 0.69]
Campaign D: [0.78, 0.34]
Campaign E: [0.40, 0.34]
Campaign F: [0.35, 0.78]
```

## XY Chart

```mermaid
xychart-beta
title "Sales Revenue"
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
```
2 changes: 2 additions & 0 deletions src/Elastic.Markdown/.prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Ignore artifacts:
build
coverage
mermaid.js
mermaid.tiny.js
2 changes: 1 addition & 1 deletion src/Elastic.Markdown/Assets/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ document.addEventListener('htmx:beforeRequest', function (event) {
}
}
})

document.body.addEventListener('htmx:oobBeforeSwap', function (event) {
// This is needed to scroll to the top of the page when the content is swapped

if (
event.target.id === 'main-container' ||
event.target.id === 'markdown-content' ||
Expand Down
91 changes: 91 additions & 0 deletions src/Elastic.Markdown/Assets/markdown/mermaid.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
.mermaid {
@apply border-grey-10 mt-4 rounded-md border-2 font-sans;

font-size: 0.875em !important;

.nodeLabel {
@apply font-mono;
font-size: 0.875em !important;
}
.labelText {
@apply font-mono;
font-size: 0.875em !important;
}
.loopText {
@apply font-mono;
font-size: 0.875em !important;
}
.noteText {
@apply font-mono;
font-size: 0.875em !important;
}
.messageText {
@apply font-mono;
font-size: 0.875em !important;
}
text.actor {
@apply font-mono;
font-size: 0.875em !important;
}
.actor {
stroke: var(--color-blue-elastic-50);
fill: var(--color-blue-elastic-10);
}
text.actor {
fill: var(--color-ink-dark);
stroke: none;
@apply font-mono;
font-size: 0.875em !important;
}

.actor-line {
stroke: var(--color-grey-70);
}

.messageLine0 {
stroke-width: 1.5;
stroke: black;
}

.messageLine1 {
stroke-width: 1.5;
stroke: var(--color-ink-dark);
}

#arrowhead {
fill: var(--color-ink-dark);
}

.messageText {
fill: var(--color-ink-dark);
stroke: none;
@apply font-mono;
font-size: 1em;
}

.labelBox {
stroke: #ccccff;
fill: #ececff;
}

.labelText {
fill: var(--color-ink-dark);
stroke: none;
@apply font-mono;
}

.loopText {
fill: var(--color-ink-dark);
stroke: none;
font-size: 1em;
}
.note {
fill: var(--color-yellow-10) !important;
stroke: var(--color-yellow-50) !important;
font-size: 1em !important;
}

rect.background {
display: none;
}
}
26 changes: 26 additions & 0 deletions src/Elastic.Markdown/Assets/mermaid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
var mermaidInitialize = function () {
mermaid.initialize({
startOnLoad: false, theme: 'base',
themeVariables: {
fontFamily: 'inherit',
altFontFamily: 'inherit',
fontSize: '0.875em',
},
fontFamily: 'inherit', altFontFamily: 'inherit',
"sequence": {
"actorFontFamily": "inherit",
"noteFontFamily": "inherit",
"messageFontFamily": "inherit"
},
"journey": {
"taskFontFamily": "inherit"
}
});
mermaid.run({
nodes: document.querySelectorAll('.mermaid'),
});
}

document.addEventListener('htmx:load', function () {
mermaidInitialize()
})
1 change: 1 addition & 0 deletions src/Elastic.Markdown/Assets/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
@import './markdown/list.css';
@import './markdown/tabs.css';
@import './markdown/code.css';
@import './markdown/mermaid.css';
@import './copybutton.css';
@import './markdown/admonition.css';
@import './markdown/dropdown.css';
Expand Down
10 changes: 8 additions & 2 deletions src/Elastic.Markdown/IO/MarkdownFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Elastic.Markdown.IO.Navigation;
using Elastic.Markdown.Links.CrossLinks;
using Elastic.Markdown.Myst;
using Elastic.Markdown.Myst.CodeBlocks;
using Elastic.Markdown.Myst.Directives;
using Elastic.Markdown.Myst.FrontMatter;
using Elastic.Markdown.Myst.InlineParsers;
Expand Down Expand Up @@ -152,6 +153,8 @@ public string Url
/// because we need to minimally parse to see the anchors anchor validation is deferred.
public IReadOnlyDictionary<string, string?>? AnchorRemapping { get; set; }

public bool HasMermaidBlock { get; private set; }

private void ValidateAnchorRemapping()
{
if (AnchorRemapping is null)
Expand Down Expand Up @@ -187,6 +190,9 @@ public async Task<MarkdownDocument> ParseFullAsync(Cancel ctx)
_ = await MinimalParseAsync(ctx);

var document = await GetParseDocumentAsync(ctx);

HasMermaidBlock = document.Descendants<EnhancedCodeBlock>().Any(b => b.Language == "mermaid");

return document;
}

Expand Down Expand Up @@ -333,7 +339,7 @@ private YamlFrontMatter ProcessYamlFrontMatter(MarkdownDocument document)
Title = deprecatedTitle;
}

// set title on yaml front matter manually.
// set title on YAML front matter manually.
// frontmatter gets passed around as page information throughout
fm.Title = Title;
return fm;
Expand All @@ -359,7 +365,7 @@ private YamlFrontMatter ReadYamlFrontMatter(string raw)

public static string CreateHtml(MarkdownDocument document)
{
//we manually render title and optionally append an applies block embedded in yaml front matter.
//we manually render the title and optionally append an `applies block` embedded in YAML front matter.
var h1 = document.Descendants<HeadingBlock>().FirstOrDefault(h => h.Level == 1);
if (h1 is not null)
_ = document.Remove(h1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using Elastic.Markdown.Myst.CodeBlocks;
using Elastic.Markdown.Myst.FrontMatter;
using Markdig.Parsers;

namespace Elastic.Markdown.Myst.Directives;
namespace Elastic.Markdown.Myst.CodeBlocks;


public class AppliesToDirective(BlockParser parser, ParserContext context)
public class AppliesToCodeBlock(BlockParser parser, ParserContext context)
: EnhancedCodeBlock(parser, context), IApplicableToElement
{
public ApplicableTo? AppliesTo { get; set; }
Expand Down
Loading
Loading