优化了链接
parent
2af47195c1
commit
a6e2e95cc3
|
|
@ -17,6 +17,7 @@ import {
|
||||||
FileImageOutlined,
|
FileImageOutlined,
|
||||||
FilePdfOutlined,
|
FilePdfOutlined,
|
||||||
FileTextOutlined,
|
FileTextOutlined,
|
||||||
|
UndoOutlined,
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import { Editor } from '@bytemd/react'
|
import { Editor } from '@bytemd/react'
|
||||||
import gfm from '@bytemd/plugin-gfm'
|
import gfm from '@bytemd/plugin-gfm'
|
||||||
|
|
@ -78,13 +79,19 @@ function DocumentEditor() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 简单的从路径获取文件名
|
|
||||||
const fileName = linkTarget.split('/').pop()
|
|
||||||
const linkText = `[${fileName}](${linkTarget})`
|
|
||||||
|
|
||||||
if (editorCtxRef.current && editorCtxRef.current.editor) {
|
if (editorCtxRef.current && editorCtxRef.current.editor) {
|
||||||
editorCtxRef.current.editor.replaceSelection(linkText)
|
const editor = editorCtxRef.current.editor
|
||||||
editorCtxRef.current.editor.focus()
|
// 获取当前选中的文字
|
||||||
|
const selection = editor.getSelection()
|
||||||
|
|
||||||
|
// 简单的从路径获取文件名作为备选
|
||||||
|
const fileName = linkTarget.split('/').pop()
|
||||||
|
// 如果没有选中文字,则使用文件名作为链接文字;否则保留原文字
|
||||||
|
const linkTitle = selection || fileName
|
||||||
|
const linkText = `[${linkTitle}](${linkTarget})`
|
||||||
|
|
||||||
|
editor.replaceSelection(linkText)
|
||||||
|
editor.focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
setLinkModalVisible(false)
|
setLinkModalVisible(false)
|
||||||
|
|
@ -197,6 +204,28 @@ function DocumentEditor() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重置当前编辑内容(重新从服务器加载)
|
||||||
|
const handleReset = () => {
|
||||||
|
if (!selectedFile) return
|
||||||
|
|
||||||
|
Modal.confirm({
|
||||||
|
title: '确认重置',
|
||||||
|
content: '确定要重置当前修改吗?所有未保存的更改都将丢失。',
|
||||||
|
onOk: async () => {
|
||||||
|
setLoading(true)
|
||||||
|
try {
|
||||||
|
const res = await getFileContent(projectId, selectedFile)
|
||||||
|
setFileContent(res.data.content)
|
||||||
|
Toast.success('重置成功', '已恢复至最后保存的版本')
|
||||||
|
} catch (error) {
|
||||||
|
Toast.error('重置失败', '无法重新加载文件内容')
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const handleSaveFile = async () => {
|
const handleSaveFile = async () => {
|
||||||
if (!selectedFile) {
|
if (!selectedFile) {
|
||||||
Toast.warning('提示', '请先选择文件')
|
Toast.warning('提示', '请先选择文件')
|
||||||
|
|
@ -915,12 +944,11 @@ function DocumentEditor() {
|
||||||
保存
|
保存
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
danger
|
icon={<UndoOutlined />}
|
||||||
icon={<DeleteOutlined />}
|
onClick={handleReset}
|
||||||
onClick={handleDelete}
|
disabled={!selectedFile || loading}
|
||||||
disabled={!selectedFile}
|
|
||||||
>
|
>
|
||||||
删除
|
重置
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -249,11 +249,20 @@ function DocumentPage() {
|
||||||
// 解码失败,使用原始值
|
// 解码失败,使用原始值
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析相对路径
|
// 解析路径
|
||||||
const targetPath = resolveRelativePath(selectedFile, decodedHref)
|
let targetPath
|
||||||
|
if (decodedHref.startsWith('.') || decodedHref.startsWith('..')) {
|
||||||
|
// 真正的相对路径,相对于当前文件
|
||||||
|
targetPath = resolveRelativePath(selectedFile, decodedHref)
|
||||||
|
} else {
|
||||||
|
// 项目内绝对路径(由编辑器生成),相对于项目根目录
|
||||||
|
targetPath = decodedHref.startsWith('/') ? decodedHref.substring(1) : decodedHref
|
||||||
|
}
|
||||||
|
|
||||||
// 自动展开父目录
|
// 自动展开父目录
|
||||||
const parentPath = targetPath.substring(0, targetPath.lastIndexOf('/'))
|
const lastSlashIndex = targetPath.lastIndexOf('/')
|
||||||
|
if (lastSlashIndex !== -1) {
|
||||||
|
const parentPath = targetPath.substring(0, lastSlashIndex)
|
||||||
if (parentPath && !openKeys.includes(parentPath)) {
|
if (parentPath && !openKeys.includes(parentPath)) {
|
||||||
// 收集所有父路径
|
// 收集所有父路径
|
||||||
const pathParts = parentPath.split('/')
|
const pathParts = parentPath.split('/')
|
||||||
|
|
@ -265,6 +274,7 @@ function DocumentPage() {
|
||||||
}
|
}
|
||||||
setOpenKeys([...new Set([...openKeys, ...allParentPaths])])
|
setOpenKeys([...new Set([...openKeys, ...allParentPaths])])
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 选中文件并加载
|
// 选中文件并加载
|
||||||
setSelectedFile(targetPath)
|
setSelectedFile(targetPath)
|
||||||
|
|
@ -590,15 +600,20 @@ function DocumentPage() {
|
||||||
remarkPlugins={[remarkGfm]}
|
remarkPlugins={[remarkGfm]}
|
||||||
rehypePlugins={[rehypeRaw, rehypeSlug, rehypeHighlight]}
|
rehypePlugins={[rehypeRaw, rehypeSlug, rehypeHighlight]}
|
||||||
components={{
|
components={{
|
||||||
a: ({ node, href, children, ...props }) => (
|
a: ({ node, href, children, ...props }) => {
|
||||||
|
const isExternal = href && (href.startsWith('http') || href.startsWith('//'));
|
||||||
|
return (
|
||||||
<a
|
<a
|
||||||
href={href}
|
href={href}
|
||||||
onClick={(e) => handleMarkdownLink(e, href)}
|
onClick={(e) => handleMarkdownLink(e, href)}
|
||||||
|
target={isExternal ? '_blank' : undefined}
|
||||||
|
rel={isExternal ? 'noopener noreferrer' : undefined}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</a>
|
</a>
|
||||||
),
|
);
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{markdownContent}
|
{markdownContent}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue