Skip to content

Commit

Permalink
feat: copy excalidraw data
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <i@innei.in>
  • Loading branch information
Innei committed Feb 3, 2024
1 parent 73285fb commit 6897840
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 63 deletions.
158 changes: 98 additions & 60 deletions src/components/ui/editor/Milkdown/plugins/Excalidraw.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from '@milkdown/utils'

import { BlockLoading } from '~/components/modules/shared/BlockLoading'
import { StyledButton } from '~/components/ui/button'
import { CheckBoxLabel } from '~/components/ui/checkbox'
import { useModalStack } from '~/components/ui/modal'
import { safeJsonParse } from '~/lib/helper'
Expand Down Expand Up @@ -82,6 +83,29 @@ export const excalidrawSchema = $nodeSchema(id, () => {
},
},

parseDOM: [
{
tag: `div[data-type="${id}"]`,
preserveWhitespace: 'full',
getAttrs: (dom) => {
return {
value: (dom as any)?.dataset?.value || '',
}
},
},
],
toDOM: (node) => {
const code = node.attrs.value as string

const dom = document.createElement('div')
dom.dataset.type = id

dom.dataset.value = code
dom.textContent = code

return dom
},

parseMarkdown: {
match: ({ type }) => type === id,
runner: (state, node, type) => {
Expand Down Expand Up @@ -178,6 +202,61 @@ const ExcalidrawBoard: FC = () => {

const [editorOption, setEditorOption] = useAtom(excalidrawOptionAtom)
const excalidrawRef = useRef<ExcalidrawRefObject>(null)

const getFinalSaveValue = async (): Promise<string | undefined> => {
if (editorOption.delta) {
const currentData = valueRef.current
if (!currentData) {
toast.error('无法获取当前数据,更新失败')
return
}

// 如果是增量存储

if (!initialContent) {
// 没有初始数据的话,直接刷新文件 Link
return fullFileUpdateAsLink()
}

// 初始数据是嵌入式数据
const isEmbeddedData = safeJsonParse(initialContent)
if (isEmbeddedData) {
// 如果是嵌入式数据,直接更新为 link
return fullFileUpdateAsLink()
}

// 初始数据是文件链接
const dataRefData = excalidrawRef.current?.getRefData()

if (!dataRefData) {
toast.error('无法获取原始数据增量更新失败')
return
}

const delta = diff(dataRefData, JSON.parse(currentData))
const firstLine = initialContent.split('\n')[0]
return [firstLine, JSON.stringify(delta, null, 0)].join('\n')
} else if (editorOption.embed) {
return valueRef.current
}

if (!editorOption.delta && !editorOption.embed) {
return fullFileUpdateAsLink()
}

async function fullFileUpdateAsLink() {
// 更新为链接类型
const currentData = valueRef.current
if (!currentData) return

const file = new File([currentData], 'file.excalidraw', {})
toast.info('正在上传文件')
const result = await uploadFileToServer(FileTypeEnum.File, file)

toast.success('上传成功')
return `ref:file/${result.name}`
}
}
return (
<div className="flex h-full w-full flex-col">
<Suspense>
Expand Down Expand Up @@ -224,69 +303,28 @@ const ExcalidrawBoard: FC = () => {
getValue={valueGetterRef.current}
nodeCtx={nodeCtx}
save={async () => {
if (editorOption.delta) {
const currentData = valueRef.current
if (!currentData) {
toast.error('无法获取当前数据,更新失败')
return
}

// 如果是增量存储

if (!initialContent) {
// 没有初始数据的话,直接刷新文件 Link
return fullFileUpdateAsLink()
}

// 初始数据是嵌入式数据
const isEmbeddedData = safeJsonParse(initialContent)
if (isEmbeddedData) {
// 如果是嵌入式数据,直接更新为 link
return fullFileUpdateAsLink()
}

// 初始数据是文件链接
const dataRefData = excalidrawRef.current?.getRefData()

if (!dataRefData) {
toast.error('无法获取原始数据增量更新失败')
const value = await getFinalSaveValue()
if (!value) return
nodeCtx.setAttrs({ value })
}}
>
<StyledButton
variant="secondary"
onClick={async () => {
const value = await getFinalSaveValue()
if (!value) {
toast.error('无法获取当前数据')
return
}

const delta = diff(dataRefData, JSON.parse(currentData))
const firstLine = initialContent.split('\n')[0]
nodeCtx.setAttrs({
value: [firstLine, JSON.stringify(delta, null, 0)].join(
'\n',
),
})
} else if (editorOption.embed) {
nodeCtx.setAttrs({ value: valueRef.current })
}

if (!editorOption.delta && !editorOption.embed) {
return fullFileUpdateAsLink()
}

async function fullFileUpdateAsLink() {
// 更新为链接类型
const currentData = valueRef.current
if (!currentData) return

const file = new File([currentData], 'file.excalidraw', {})
toast.info('正在上传文件')
const result = await uploadFileToServer(
FileTypeEnum.File,
file,
await navigator.clipboard.writeText(
`\`\`\`excalidraw\n${value}\n\`\`\``,
)

toast.success('上传成功')
nodeCtx.setAttrs({
value: `ref:file/${result.name}`,
})
}
}}
/>
toast.success('已复制')
}}
>
复制
</StyledButton>
</SharedModalAction>
</div>
</Suspense>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useState } from 'react'
import type { NodeViewContext } from '@prosemirror-adapter/react'
import type { FC } from 'react'

import { schemaCtx } from '@milkdown/core'

Expand All @@ -9,12 +8,12 @@ import { useCurrentModal } from '~/components/ui/modal'

import { useEditorCtx } from '../../ctx'

export const SharedModalAction: FC<{
export const SharedModalAction: Component<{
nodeCtx: NodeViewContext
getValue(): string | undefined

save?: (value: string) => Promise<void> | void
}> = ({ nodeCtx, getValue, save }) => {
}> = ({ nodeCtx, getValue, save, children }) => {
const { getPos, view, node } = nodeCtx
const { dismiss } = useCurrentModal()
const ctx = useEditorCtx()
Expand All @@ -29,6 +28,7 @@ export const SharedModalAction: FC<{
const [waiting, setWaiting] = useState(false)
return (
<div className="mt-4 flex justify-end space-x-2 p-2">
{children}
<StyledButton variant="secondary" onClick={deleteNode}>
删除
</StyledButton>
Expand Down

0 comments on commit 6897840

Please sign in to comment.