一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
131 行
4.8 KiB
TypeScript
131 行
4.8 KiB
TypeScript
import { RuleOptions } from '../../MdToHtml';
|
|
import { RendererTheme } from '../../types';
|
|
import type * as MarkdownIt from 'markdown-it';
|
|
import type Token = require('markdown-it/lib/token');
|
|
import type Renderer = require('markdown-it/lib/renderer');
|
|
|
|
export default {
|
|
|
|
assets: function(theme: RendererTheme) {
|
|
return [
|
|
{
|
|
name: 'mermaid.min.js',
|
|
},
|
|
{
|
|
name: 'mermaid_render.js',
|
|
},
|
|
{
|
|
inline: true,
|
|
// Note: Mermaid is buggy when rendering below a certain width (500px?)
|
|
// so set an arbitrarily high width here for the container. Once the
|
|
// diagram is rendered it will be reset to 100% in mermaid_render.js
|
|
text: '.mermaid { width: 640px; }',
|
|
mime: 'text/css',
|
|
},
|
|
{
|
|
inline: true,
|
|
// Override the default pre styles. Using the default `white-space: pre`
|
|
// can cause math expressions to be too tall and break some diagrams.
|
|
text: 'pre.mermaid[data-processed=true] { white-space: unset; }',
|
|
mime: 'text/css',
|
|
},
|
|
{
|
|
inline: true,
|
|
// Export button in mermaid graph should be shown only on hovering the mermaid graph
|
|
// ref: https://github.com/laurent22/joplin/issues/6101
|
|
text: `
|
|
.mermaid-export-graph {
|
|
opacity: 0;
|
|
height: 0;
|
|
z-index: 1;
|
|
position: relative;
|
|
}
|
|
.joplin-editable:hover .mermaid-export-graph,
|
|
.joplin-editable .mermaid-export-graph:has(:focus-visible) {
|
|
opacity: 1;
|
|
}
|
|
.mermaid-export-graph > button:hover {
|
|
background-color: ${theme.backgroundColorHover3} !important;
|
|
}
|
|
`.trim(),
|
|
mime: 'text/css',
|
|
},
|
|
].map(e => {
|
|
return {
|
|
source: 'mermaid',
|
|
...e,
|
|
};
|
|
});
|
|
},
|
|
|
|
plugin: function(markdownIt: MarkdownIt, ruleOptions: RuleOptions) {
|
|
const defaultRender: Renderer.RenderRule = markdownIt.renderer.rules.fence || function(tokens, idx, options, env, self): string {
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- this fallback passes extra `env, self` args to renderToken which the type signature does not declare; preserved for parity with other rule fallbacks
|
|
return (self.renderToken as any)(tokens, idx, options, env, self);
|
|
};
|
|
const exportButtonMarkup = isDesktop(ruleOptions.platformName) ? exportGraphButton(ruleOptions) : '';
|
|
|
|
markdownIt.renderer.rules.fence = function(tokens: Token[], idx: number, options: MarkdownIt.Options, env: unknown, self: Renderer) {
|
|
const token = tokens[idx];
|
|
if (token.info !== 'mermaid') return defaultRender(tokens, idx, options, env, self);
|
|
|
|
ruleOptions.context.pluginWasUsed.mermaid = true;
|
|
|
|
const contentHtml = markdownIt.utils.escapeHtml((token.content as string).trimEnd());
|
|
|
|
const cssClasses = ['mermaid'];
|
|
if (ruleOptions.theme.appearance === 'dark') {
|
|
// This class applies globally -- if any elements have this class, all mermaid
|
|
// elements will be rendered in dark mode.
|
|
// (See mermaid_render.js for details).
|
|
cssClasses.push('joplin--mermaid-use-dark-theme');
|
|
}
|
|
|
|
// Note: The mermaid script (`contentHtml`) needs to be wrapped
|
|
// in a `pre` tag, otherwise in WYSIWYG mode TinyMCE removes
|
|
// all the white space from it, which causes mermaid to fail.
|
|
// See PR #4670 https://github.com/laurent22/joplin/pull/4670
|
|
return `
|
|
<div class="joplin-editable">
|
|
<pre class="joplin-source" hidden data-joplin-language="mermaid" data-joplin-source-open="\`\`\`mermaid " data-joplin-source-close=" \`\`\` ">${contentHtml}</pre>
|
|
${exportButtonMarkup}
|
|
<pre class="${cssClasses.join(' ')}">${contentHtml}</pre>
|
|
</div>
|
|
`;
|
|
};
|
|
},
|
|
};
|
|
|
|
const exportGraphButton = (ruleOptions: RuleOptions) => {
|
|
const theme = ruleOptions.theme;
|
|
const style = `
|
|
display: block;
|
|
margin-left: auto;
|
|
border-radius: ${theme.buttonStyle.borderRadius}px;
|
|
font-size: ${theme.fontSize}px;
|
|
color: ${theme.color};
|
|
background: ${theme.buttonStyle.backgroundColor};
|
|
border: ${theme.buttonStyle.border};
|
|
`.trim();
|
|
|
|
// OnClick is handled in the renderer script
|
|
return `
|
|
<div class="mermaid-export-graph">
|
|
<button type="button" style="${style}" aria-label="Download Mermaid chart" title="Download Mermaid chart">${downloadIcon()}</button>
|
|
</div>
|
|
`;
|
|
};
|
|
|
|
const downloadIcon = () => {
|
|
// https://www.svgrepo.com/svg/505363/download
|
|
return '<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" xmlns="http://www.w3.org/2000/svg"><g stroke-width="0"></g><g stroke-linecap="round" stroke-linejoin="round"></g><g> <path d="M20 15V18C20 19.1046 19.1046 20 18 20H6C4.89543 20 4 19.1046 4 18L4 15M8 11L12 15M12 15L16 11M12 15V3" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>';
|
|
};
|
|
|
|
const isDesktop = (platformName?: string) => {
|
|
if (!platformName) {
|
|
return false;
|
|
}
|
|
|
|
return ['darwin', 'linux', 'freebsd', 'win32'].includes(platformName);
|
|
};
|