feat: Make the examples interactive in the documentation site.
Ctrl/Cmd + Enter and a run button is added. The feature was first implemented in https://github.com/mermaid-js/mermaid/pull/5330. This is a simplified version without introducing additional dependencies. Co-authored-by: Anton <m@antonz.org>
This commit is contained in:
parent
244b161032
commit
32ca0b97fc
|
@ -18,20 +18,7 @@ const MermaidExample = async (md: MarkdownRenderer) => {
|
|||
'Missing MarkdownIt highlight function (should be automatically created by vitepress'
|
||||
);
|
||||
}
|
||||
|
||||
// doing ```mermaid-example {line-numbers=5 highlight=14-17} is not supported
|
||||
const langAttrs = '';
|
||||
return `
|
||||
<h5>Code:</h5>
|
||||
<div class="language-mermaid">
|
||||
<button class="copy"></button>
|
||||
<span class="lang">mermaid</span>
|
||||
${
|
||||
// html is pre-escaped by the highlight function
|
||||
// (it also adds `v-pre` to ignore Vue template syntax)
|
||||
md.options.highlight(token.content, 'mermaid', langAttrs)
|
||||
}
|
||||
</div>`;
|
||||
return '';
|
||||
} else if (token.info.trim() === 'mermaid') {
|
||||
const key = index;
|
||||
return `
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
<template>
|
||||
<h5>Code:</h5>
|
||||
<div class="language-mermaid">
|
||||
<button class="copy"></button>
|
||||
<span class="lang">mermaid</span>
|
||||
<pre><code contenteditable="true" @input="updateCode" @keydown.meta.enter="renderChart" ref="editableContent" class="editable-code"></code></pre>
|
||||
<div class="buttons-container">
|
||||
<span>{{ ctrlSymbol }} + Enter</span><span>|</span>
|
||||
<button @click="renderChart">Run ►</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-html="svg"></div>
|
||||
</template>
|
||||
|
||||
|
@ -18,15 +28,29 @@ const props = defineProps({
|
|||
});
|
||||
|
||||
const svg = ref('');
|
||||
const code = ref(decodeURIComponent(props.graph));
|
||||
const ctrlSymbol = ref(navigator.platform.includes('Mac') ? '⌘' : 'Ctrl');
|
||||
const editableContent = ref(null);
|
||||
|
||||
let mut = null;
|
||||
|
||||
const updateCode = (event) => {
|
||||
code.value = event.target.innerText;
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
mut = new MutationObserver(() => renderChart());
|
||||
mut.observe(document.documentElement, { attributes: true });
|
||||
|
||||
// Set the initial value of the contenteditable element
|
||||
// We cannot bind using `{{ code }}` because it will rerender the whole component
|
||||
// when the value changes, shifting the cursor when enter is used
|
||||
editableContent.value.textContent = code.value;
|
||||
|
||||
await renderChart();
|
||||
|
||||
//refresh images on first render
|
||||
const hasImages = /<img([\w\W]+?)>/.exec(decodeURIComponent(props.graph))?.length > 0;
|
||||
const hasImages = /<img([\w\W]+?)>/.exec(code.value)?.length > 0;
|
||||
if (hasImages)
|
||||
setTimeout(() => {
|
||||
let imgElements = document.getElementsByTagName('img');
|
||||
|
@ -51,16 +75,14 @@ onMounted(async () => {
|
|||
onUnmounted(() => mut.disconnect());
|
||||
|
||||
const renderChart = async () => {
|
||||
console.log('rendering chart' + props.id + props.graph);
|
||||
console.log('rendering chart' + props.id + code.value);
|
||||
const hasDarkClass = document.documentElement.classList.contains('dark');
|
||||
const mermaidConfig = {
|
||||
securityLevel: 'loose',
|
||||
startOnLoad: false,
|
||||
theme: hasDarkClass ? 'dark' : 'default',
|
||||
};
|
||||
|
||||
console.log({ mermaidConfig });
|
||||
let svgCode = await render(props.id, decodeURIComponent(props.graph), mermaidConfig);
|
||||
let svgCode = await render(props.id, code.value, mermaidConfig);
|
||||
// This is a hack to force v-html to re-render, otherwise the diagram disappears
|
||||
// when **switching themes** or **reloading the page**.
|
||||
// The cause is that the diagram is deleted during rendering (out of Vue's knowledge).
|
||||
|
@ -70,3 +92,35 @@ const renderChart = async () => {
|
|||
svg.value = `${svgCode} <span style="display: none">${salt}</span>`;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.editable-code:focus {
|
||||
outline: none; /* Removes the default focus indicator */
|
||||
}
|
||||
|
||||
.buttons-container {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
padding: 0.5rem;
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.buttons-container > span {
|
||||
cursor: default;
|
||||
opacity: 0.5;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.buttons-container > button {
|
||||
color: #007bffbf;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.buttons-container > button:hover {
|
||||
color: #007bff;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue