Skip to content

Commit

Permalink
Add mermaid support to listing
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminleonard committed Dec 13, 2024
1 parent fdd8ab6 commit 87d60df
Show file tree
Hide file tree
Showing 5 changed files with 1,552 additions and 53 deletions.
59 changes: 59 additions & 0 deletions components/src/asciidoc/Listing.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { LiteralBlock, Title, useConverterContext } from '@oxide/react-asciidoc'
import cn from 'classnames'

import Mermaid from './Mermaid'

const Listing = ({ node }: { node: LiteralBlock }) => {
const { document } = useConverterContext()

const docAttrs = document.attributes || {}
const nowrap = node.attributes.nowrap || docAttrs['prewrap'] === undefined

if (node.style === 'source') {
const lang = node.language

return (
<div
className="listingblock"
{...(node.lineNumber ? { 'data-lineno': node.lineNumber } : {})}
>
<Title text={node.title} />
<div className="content">
<pre className={cn('highlight', nowrap ? ' nowrap' : '')}>
{lang && lang === 'mermaid' ? (
<Mermaid content={node.content || ''} />
) : (
<code
className={lang && `language-${lang}`}
data-lang={lang || undefined}
dangerouslySetInnerHTML={{
__html: node.content || '',
}}
/>
)}
</pre>
</div>
</div>
)
} else {
// Regular listing blocks are wrapped only in a `pre` tag
return (
<div
className="listingblock"
{...(node.lineNumber ? { 'data-lineno': node.lineNumber } : {})}
>
<Title text={node.title} />
<div className="content">
<pre
className={cn('highlight !block', nowrap ? 'nowrap' : '')}
dangerouslySetInnerHTML={{
__html: node.content || '',
}}
/>
</div>
</div>
)
}
}

export default Listing
41 changes: 41 additions & 0 deletions components/src/asciidoc/Mermaid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* Copyright Oxide Computer Company
*/
import mermaid from 'mermaid'
import { memo, useId, useState } from 'react'

mermaid.initialize({
startOnLoad: false,
theme: 'dark',
})

const Mermaid = memo(function Mermaid({ content }: { content: string }) {
const [showSource, setShowSource] = useState(false)
const id = `mermaid-diagram-${useId().replace(/:/g, '_')}`

const mermaidRef = async (node: HTMLElement | null) => {
if (node) {
const { svg } = await mermaid.render(id, content)
node.innerHTML = svg
}
}

return (
<>
<button
className="absolute right-2 top-2 text-mono-xs text-tertiary"
onClick={() => setShowSource(!showSource)}
>
{showSource ? 'Hide' : 'Show'} Source <span className="text-quinary">|</span>{' '}
Mermaid
</button>
{!showSource ? <code ref={mermaidRef} className="w-full" /> : <code>{content}</code>}
</>
)
})

export default Mermaid
2 changes: 2 additions & 0 deletions components/src/asciidoc/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import asciidoctor, { Block, Html5Converter, Inline } from '@asciidoctor/core'
import { Content, type DocumentBlock } from '@oxide/react-asciidoc'

import Admonition from './Admonition'
import Mermaid from './Mermaid'
import Section from './Section'
import Table from './Table'
import {
Expand All @@ -29,6 +30,7 @@ const AsciiDocBlocks = {
Admonition,
Table,
Section,
Mermaid,
MinimalDocument,
}

Expand Down
Loading

0 comments on commit 87d60df

Please sign in to comment.