2023-03-30 17:58:48 +02:00
import { RuleOptions } from '../../MdToHtml' ;
2020-10-21 01:23:55 +02:00
export default {
2020-03-23 02:47:25 +02:00
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2023-03-30 17:58:48 +02:00
assets : function ( theme : any ) {
2020-10-21 01:23:55 +02:00
return [
2024-06-04 00:49:09 +02:00
{
name : 'mermaid.min.js' ,
} ,
{
name : 'mermaid_render.js' ,
} ,
2020-10-21 01:23:55 +02:00
{
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
2024-01-04 15:45:06 +02:00
text : '.mermaid { width: 640px; }' ,
2020-10-21 01:23:55 +02:00
mime : 'text/css' ,
} ,
2024-05-27 09:53:57 +02:00
{
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.
2024-08-03 17:42:16 +02:00
text : 'pre.mermaid[data-processed=true] { white-space: unset; }' ,
2024-05-27 09:53:57 +02:00
mime : 'text/css' ,
} ,
2023-03-30 17:58:48 +02:00
{
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 : `
2024-02-03 00:57:57 +02:00
. mermaid - export - graph {
opacity : 0 ;
height : 0 ;
2024-02-08 20:41:19 +02:00
z - index : 1 ;
position : relative ;
2024-02-03 00:57:57 +02:00
}
. 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 ;
}
2023-03-30 17:58:48 +02:00
` .trim(),
mime : 'text/css' ,
} ,
2024-06-04 00:49:09 +02:00
] . map ( e = > {
return {
source : 'mermaid' ,
. . . e ,
} ;
} ) ;
2020-10-21 01:23:55 +02:00
} ,
2020-02-12 00:27:34 +02:00
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2023-03-30 17:58:48 +02:00
plugin : function ( markdownIt : any , ruleOptions : RuleOptions ) {
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any -- Old code before rule was applied, Old code before rule was applied
2020-11-12 21:13:28 +02:00
const defaultRender : Function = markdownIt . renderer . rules . fence || function ( tokens : any [ ] , idx : number , options : any , env : any , self : any ) {
2020-10-21 01:23:55 +02:00
return self . renderToken ( tokens , idx , options , env , self ) ;
} ;
2020-02-12 00:27:34 +02:00
2023-03-30 17:58:48 +02:00
const exportButtonMarkup = isDesktop ( ruleOptions . platformName ) ? exportGraphButton ( ruleOptions ) : '' ;
2024-04-05 13:16:49 +02:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
2023-06-30 11:30:29 +02:00
markdownIt . renderer . rules . fence = function ( tokens : any [ ] , idx : number , options : any , env : any , self : any ) {
2020-10-21 01:23:55 +02:00
const token = tokens [ idx ] ;
if ( token . info !== 'mermaid' ) return defaultRender ( tokens , idx , options , env , self ) ;
2024-06-04 00:49:09 +02:00
ruleOptions . context . pluginWasUsed . mermaid = true ;
2020-10-21 01:23:55 +02:00
const contentHtml = markdownIt . utils . escapeHtml ( token . content ) ;
2024-01-04 15:45:06 +02:00
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' ) ;
}
2021-03-15 18:31:11 +02:00
// 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
2020-10-21 01:23:55 +02:00
return `
< div class = "joplin-editable" >
< pre class = "joplin-source" data - joplin - language = "mermaid" data - joplin - source - open = "\`\`\`mermaid " data - joplin - source - close = " \`\`\` " > $ { contentHtml } < / pre >
2023-03-30 17:58:48 +02:00
$ { exportButtonMarkup }
2024-01-04 15:45:06 +02:00
< pre class = "${cssClasses.join(' ')}" > $ { contentHtml } < / pre >
2020-10-21 01:23:55 +02:00
< / div >
` ;
2020-03-23 02:47:25 +02:00
} ;
} ,
} ;
2023-03-30 17:58:48 +02:00
const exportGraphButton = ( ruleOptions : RuleOptions ) = > {
const theme = ruleOptions . theme ;
// Clicking on export button manually triggers a right click context menu event
const onClickHandler = `
const target = arguments [ 0 ] . target ;
2024-02-03 00:57:57 +02:00
const button = target . closest ( "div.mermaid-export-graph" ) ;
2023-03-30 17:58:48 +02:00
if ( ! button ) return false ;
const $mermaid_elem = button . nextElementSibling ;
const rightClickEvent = new PointerEvent ( "contextmenu" , { bubbles : true } ) ;
rightClickEvent . target = $mermaid_elem ;
$mermaid_elem . dispatchEvent ( rightClickEvent ) ;
return false ;
` .trim();
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();
2024-02-03 00:57:57 +02:00
return `
< div class = "mermaid-export-graph" >
< button onclick = '${onClickHandler}' style = "${style}" alt = "Export mermaid graph" > $ { downloadIcon ( ) } < / button >
< / div >
` ;
2023-03-30 17:58:48 +02:00
} ;
const downloadIcon = ( ) = > {
// https://www.svgrepo.com/svg/505363/download
return '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <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 ) ;
} ;