Skip to content

Commit

Permalink
feat: Add support for Mermaid diagrams in Writing component
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <i@innei.in>
  • Loading branch information
Innei committed Feb 2, 2024
1 parent 32f076c commit 488ca57
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 5 deletions.
18 changes: 18 additions & 0 deletions src/components/icons/mermaid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { SVGProps } from 'react'

export function SimpleIconsMermaid(props: SVGProps<SVGSVGElement>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 24 24"
{...props}
>
<path
fill="currentColor"
d="M23.99 2.115A12.223 12.223 0 0 0 12 10.149A12.223 12.223 0 0 0 .01 2.115a12.23 12.23 0 0 0 5.32 10.604a6.562 6.562 0 0 1 2.845 5.423v3.754h7.65v-3.754a6.561 6.561 0 0 1 2.844-5.423a12.223 12.223 0 0 0 5.32-10.604Z"
/>
</svg>
)
}
26 changes: 24 additions & 2 deletions src/components/modules/dashboard/writing/Writing.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useRef } from 'react'
import React, { isValidElement, useEffect, useRef } from 'react'
import { produce } from 'immer'
import { atom, useAtomValue, useSetAtom, useStore } from 'jotai'
import type { FC } from 'react'
Expand All @@ -15,6 +15,7 @@ import {
} from '@milkdown/preset-commonmark'
import { callCommand } from '@milkdown/utils'

import { SimpleIconsMermaid } from '~/components/icons/mermaid'
import { useEventCallback } from '~/hooks/common/use-event-callback'
import { clsxm } from '~/lib/helper'
import { jotaiStore } from '~/lib/store'
Expand Down Expand Up @@ -112,6 +113,23 @@ const MenuBar = () => {
language: 'excalidraw',
})

view.dispatch(state.tr.insert(currentCursorPosition, nextNode))
},
},
{
icon: <SimpleIconsMermaid />,
action: () => {
const ctx = editorRef?.editor.ctx
if (!ctx) return
const view = ctx.get(editorViewCtx)
if (!view) return
const state = view.state

const currentCursorPosition = state.selection.from
const nextNode = ctx.get(schemaCtx).node('diagram', {
value: '<auto_open>',
})

view.dispatch(state.tr.insert(currentCursorPosition, nextNode))
},
},
Expand All @@ -131,7 +149,11 @@ const MenuBar = () => {
})
}}
>
<i className={menu.icon} />
{isValidElement(menu.icon) ? (
menu.icon
) : typeof menu.icon === 'string' ? (
<i className={menu.icon} />
) : null}
</button>
))}
</div>
Expand Down
33 changes: 30 additions & 3 deletions src/components/ui/editor/Milkdown/plugins/Mermaid.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useNodeViewContext } from '@prosemirror-adapter/react'
import { useEffect, useRef } from 'react'
import type { MilkdownPlugin } from '@milkdown/ctx'
import type { ModalContentPropsInternal } from '~/components/ui/modal'
import type { FC } from 'react'
Expand All @@ -13,10 +14,13 @@ import { TextArea } from '~/components/ui/input'
import { useModalStack } from '~/components/ui/modal'
import { useUncontrolledInput } from '~/hooks/common/use-uncontrolled-input'

const autoOpenValue = '<auto_open>'

const MermaidRender = () => {
const { contentRef, node, setAttrs, view, getPos } = useNodeViewContext()

const value = node.attrs.value
const autoOpen = value === autoOpenValue

const modalStack = useModalStack()

Expand All @@ -28,10 +32,16 @@ const MermaidRender = () => {
view.dispatch(view.state.tr.delete(pos, pos + node.nodeSize))
dismiss()
}
const [, getValue, ref] = useUncontrolledInput<HTMLTextAreaElement>(value)
const defaultValue = value === autoOpenValue ? '' : value
const [, getValue, ref] =
useUncontrolledInput<HTMLTextAreaElement>(defaultValue)
return (
<div className="flex h-[450px] max-h-[80vh] w-[60ch] max-w-full flex-col">
<TextArea defaultValue={value} className="flex-grow" ref={ref} />
<TextArea
defaultValue={defaultValue}
className="flex-grow"
ref={ref}
/>
<div className="mt-4 flex justify-end space-x-2">
<StyledButton variant="secondary" onClick={deleteNode}>
删除
Expand All @@ -56,7 +66,24 @@ const MermaidRender = () => {
})
}

if (!value) {
const openOnceRef = useRef(false)

useEffect(() => {
if (!autoOpen) return

if (openOnceRef.current) return

openOnceRef.current = true
setAttrs({
value: '',
})
requestAnimationFrame(() => {
requestAnimationFrame(() => {
handleEdit()
})
})
}, [])
if (!value || autoOpen) {
return (
<div
ref={contentRef}
Expand Down

0 comments on commit 488ca57

Please sign in to comment.