import { useEffect, useState, useRef } from 'react' import Viz from 'viz.js' import { Module, render } from 'viz.js/full.render.js' import coarse from './dot-rough.js' import Popout from 'shared/components/popout' import oc from 'open-color' import { useTranslation } from 'next-i18next' // Some regex voodoo to allow people to use open-color // colors like oc-orange-5 and make it 'just work' const regexA = /(oc-((gray)|(red)|(pink)|(grape)|(violet)|(indigo)|(blue)|(cyan)|(teal)|(green)|(lime)|(yellow)|(orange))-([0-9]))/g const regexB = /(oc-((gray)|(red)|(pink)|(grape)|(violet)|(indigo)|(blue)|(cyan)|(teal)|(green)|(lime)|(yellow)|(orange)))/g const getColorTint = (a,b,color) => oc[color][a.slice(-1)] const getColor = (a,b,color,tint=false) => oc[color][5] const colorDot = dot => dot .replace(regexA, getColorTint) .replace(regexB, getColor) // More regex voodoo to handle translation // Looking for prefix i18n: and terminated by ther space of " const regexC = /i18n:([^ "]+)/g const i18nDot = (dot, t) => dot.replace(regexC, (a,b) => t(b)) const Dot = props => { const { t } = useTranslation(['app']) const { plain=false } = props const wrapDot = dot => { if (dot.slice(0,7) === 'digraph') return dot return plain ? `digraph G { bgcolor=transparent; ${i18nDot(colorDot(dot), t)} }` : `digraph G { graph [fontname = "Indie Flower"]; node [fontname = "Indie Flower"]; edge [fontname = "Indie Flower"]; bgcolor=transparent; ${i18nDot(colorDot(dot), t)} }` } // Extract code/caption from props const [code, caption] = props.children // Extract dot code from mdx const dot = wrapDot(code.props.children.props.children) // Initialize viz library const viz = new Viz({ Module, render }) // State and effect are needed to run async code as this // library always returns a promise const svgRef = useRef(null) const [svg, setSvg] = useState('') const [reveal, setReveal] = useState(false) const [zoom, setZoom] = useState(false) useEffect(() => { viz.renderString(dot).then(res => { setSvg(res) if (!plain) coarse(svgRef.current) // Strip width/height so it's responsive svgRef.current.children[0].attributes.width.value = "" svgRef.current.children[0].attributes.height.value = "" // Add class for specific styling svgRef.current.children[0].setAttribute('class', "no-fs") }) }, [dot]) return (
zoom ? setZoom(false) : null}>
setZoom(!zoom)} className={zoom ? 'svg-zoom non-fs-svg text-base-content' : "dot shadow p-2 rounded -mt-8 hover:cursor-zoom-in text-base-content non-fs-svg" } dangerouslySetInnerHTML={{__html: svg}} /> {reveal && !zoom && ( <>

You can edit this online

Use a site like SketchViz or another online Graphviz editor to edit this diagram. You can use its source code below as a starting point.

{dot}
)}
{caption || ''}
) } export default Dot