重构编辑器,进度50%
This commit is contained in:
1335
package-lock.json
generated
1335
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,8 @@
|
||||
"url": "https://blog.liuyuyang.net"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bytemd/plugin-highlight": "^1.21.0",
|
||||
"@bytemd/react": "^1.21.0",
|
||||
"antd": "^5.19.3",
|
||||
"apexcharts": "^3.41.0",
|
||||
"axios": "^1.7.2",
|
||||
@@ -32,7 +34,6 @@
|
||||
"react-toastify": "^9.1.3",
|
||||
"sass": "^1.77.8",
|
||||
"sort-by": "^0.0.2",
|
||||
"vditor": "^3.10.4",
|
||||
"vite-plugin-sass-dts": "^1.3.25",
|
||||
"zustand": "^4.5.4"
|
||||
},
|
||||
|
||||
@@ -1,13 +1,25 @@
|
||||
"use client"
|
||||
|
||||
import { Card } from "antd"
|
||||
import Breadcrumb from "../Breadcrumbs"
|
||||
import { titleSty } from '@/styles/sty'
|
||||
import { ReactNode } from "react"
|
||||
|
||||
export default ({ value, className }: { value: string, className?: string }) => {
|
||||
interface Props {
|
||||
value: string,
|
||||
children?: ReactNode,
|
||||
className?: string
|
||||
}
|
||||
|
||||
export default ({ value, children, className }: Props) => {
|
||||
return (
|
||||
<>
|
||||
<Card title={<Breadcrumb pageName={value} />} className={`${titleSty} ${className}`} />
|
||||
<Card className={`${titleSty} p-4 mb-2 ${className}`}>
|
||||
<div className="flex justify-between items-center">
|
||||
<h2 className="font-semibold text-black dark:text-white text-xl">{value}</h2>
|
||||
|
||||
{children}
|
||||
</div>
|
||||
</Card>
|
||||
</>
|
||||
)
|
||||
}
|
||||
207
src/pages/Create/components/Editor/index.scss
Normal file
207
src/pages/Create/components/Editor/index.scss
Normal file
@@ -0,0 +1,207 @@
|
||||
.markdown-body {
|
||||
color: #595959;
|
||||
font-size: 15px;
|
||||
font-family: -apple-system, system-ui, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
|
||||
background-image: linear-gradient(90deg, rgba(60, 10, 30, 0.04) 3%, rgba(0, 0, 0, 0) 3%), linear-gradient(360deg, rgba(60, 10, 30, 0.04) 3%, rgba(0, 0, 0, 0) 3%);
|
||||
background-size: 20px 20px;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
/* 段落 */
|
||||
.markdown-body p {
|
||||
color: #595959;
|
||||
font-size: 15px;
|
||||
line-height: 2;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* 段落间距控制 */
|
||||
.markdown-body p+p {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
/* 标题的通用设置 */
|
||||
.markdown-body h1,
|
||||
.markdown-body h2,
|
||||
.markdown-body h3,
|
||||
.markdown-body h4,
|
||||
.markdown-body h5,
|
||||
.markdown-body h6 {
|
||||
padding: 30px 0;
|
||||
margin: 0;
|
||||
color: #135ce0;
|
||||
}
|
||||
|
||||
/* 一级标题 */
|
||||
.markdown-body h1 {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
font-size: 22px;
|
||||
margin: 50px 0;
|
||||
}
|
||||
|
||||
/* 一级标题前缀,用来放背景图,支持透明度控制 */
|
||||
.markdown-body h1:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
top: -10px;
|
||||
left: 50%;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
transform: translateX(-50%);
|
||||
background-size: 100% 100%;
|
||||
opacity: .36;
|
||||
background-repeat: no-repeat;
|
||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABfVBMVEX///8Ad/8AgP8AgP8AgP8Aff8AgP8Af/8AgP8AVf8Af/8Af/8AgP8AgP8Af/8Afv8AAP8Afv8Afv8Aef8AgP8AdP8Afv8AgP8AgP8Acf8Ae/8AgP8Af/8AgP8Af/8Af/8AfP8Afv8AgP8Af/8Af/8Afv8Afv8AgP8Afv8AgP8Af/8Af/8AgP8AgP8Afv8AgP8Af/8AgP8AgP8AgP8Ae/8Afv8Af/8AgP8Af/8AgP8Af/8Af/8Aff8Af/8Abf8AgP8Af/8AgP8Af/8Af/8Afv8AgP8AgP8Afv8Afv8AgP8Af/8Aff8AgP8Afv8AgP8Aff8AgP8AfP8AgP8Ae/8AgP8Af/8AgP8AgP8AgP8Afv8AgP8AgP8AgP8Afv8AgP8AgP8AgP8AgP8AgP8Af/8AgP8Af/8Af/8Aev8Af/8AgP8Aff8Afv8AgP8AgP8AgP8Af/8AgP8Af/8Af/8AgP8Afv8AgP8AgP8AgP8AgP8Af/8AeP8Af/8Af/8Af//////rzEHnAAAAfXRSTlMAD7CCAivatxIDx5EMrP19AXdLEwgLR+6iCR/M0yLRzyFF7JupSXn8cw6v60Q0QeqzKtgeG237HMne850/6Qeq7QaZ+WdydHtj+OM3qENCMRYl1B3K2U7wnlWE/mhlirjkODa9FN/BF7/iNV/2kASNZpX1Wlf03C4stRGxgUPclqoAAAABYktHRACIBR1IAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gEaBzgZ4yeM3AAAAT9JREFUOMvNUldbwkAQvCAqsSBoABE7asSOBRUVVBQNNuy9996789+9cMFAMHnVebmdm+/bmdtbQv4dOFOW2UjPzgFyLfo6nweKfIMOBYWwFtmMPGz2Yj2pJI0JDq3udJW6VVbmKa9I192VQFV1ktXUAl5NB0cd4KpnORqsEO2ZIRpF9gJfE9Dckqq0KuZt7UAH5+8EPF3spjsRpCeQNO/tA/qDwIDA+OCQbBoKA8NOdjMySgcZGVM6jwcgRuUiSs0nlPFNSrEpJfU0jTLD6llqbvKxei7OzvkFNQohi0vAsj81+MoqsCaoPOQFgus/1LyxichW+hS2JWCHZ7VlF9jb187pIAYcHiViHAMnp5mTjJ8B5xeEXF4B1ze/fTh/C0h398DDI9HB07O8ci+vRBdvdGnfP4gBuM8vw7X/G3wDmFhFZEdxzjMAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTgtMDEtMjZUMDc6NTY6MjUrMDE6MDA67pVWAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE4LTAxLTI2VDA3OjU2OjI1KzAxOjAwS7Mt6gAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAWdEVYdFRpdGxlAGp1ZWppbl9sb2dvIGNvcHlxapmKAAAAV3pUWHRSYXcgcHJvZmlsZSB0eXBlIGlwdGMAAHic4/IMCHFWKCjKT8vMSeVSAAMjCy5jCxMjE0uTFAMTIESANMNkAyOzVCDL2NTIxMzEHMQHy4BIoEouAOoXEXTyQjWVAAAAAElFTkSuQmCC);
|
||||
}
|
||||
|
||||
/* 二级标题 */
|
||||
.markdown-body h2 {
|
||||
position: relative;
|
||||
font-size: 20px;
|
||||
border-left: 4px solid;
|
||||
padding: 0 0 0 10px;
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
/* 三级标题 */
|
||||
.markdown-body h3 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* 无序列表 */
|
||||
.markdown-body ul {
|
||||
list-style: disc outside;
|
||||
margin-left: 2em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
/* 无序列表内容 */
|
||||
.markdown-body li {
|
||||
line-height: 2;
|
||||
color: #595959;
|
||||
margin-bottom: 0;
|
||||
list-style: inherit;
|
||||
}
|
||||
|
||||
.markdown-body img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* 已加载图片 */
|
||||
.markdown-body img.loaded {
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 引用 */
|
||||
.markdown-body blockquote {
|
||||
background: #fff9f9;
|
||||
margin: 2em 0;
|
||||
padding: 2px 20px;
|
||||
border-left: 4px solid #b2aec5;
|
||||
}
|
||||
|
||||
/* 引用文字 */
|
||||
.markdown-body blockquote p {
|
||||
color: #666;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
/* 链接 */
|
||||
.markdown-body a {
|
||||
color: #036aca;
|
||||
border-bottom: 1px solid rgba(3, 106, 202, .8);
|
||||
font-weight: 400;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* 加粗 */
|
||||
.markdown-body strong {
|
||||
color: #036aca;
|
||||
}
|
||||
|
||||
/* 加粗斜体 */
|
||||
.markdown-body em strong {
|
||||
color: #036aca;
|
||||
}
|
||||
|
||||
/* 分隔线 */
|
||||
.markdown-body hr {
|
||||
border-top: 1px solid #135ce0;
|
||||
}
|
||||
|
||||
/* 代码 */
|
||||
.markdown-body pre {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.markdown-body pre,
|
||||
.markdown-body code {
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
line-height: 1.75;
|
||||
font-family: Menlo, Monaco, Consolas, Courier New, monospace;
|
||||
}
|
||||
|
||||
.markdown-body pre>code {
|
||||
font-size: 12px;
|
||||
padding: 15px 12px;
|
||||
margin: 0;
|
||||
word-break: normal;
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
color: #DCDCDC;
|
||||
background: #1E1E1E;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.markdown-body code {
|
||||
word-break: break-word;
|
||||
border-radius: 2px;
|
||||
overflow-x: auto;
|
||||
background-color: #fff5f5;
|
||||
color: #ff502c;
|
||||
font-size: .87em;
|
||||
padding: .065em .4em;
|
||||
}
|
||||
|
||||
/* 表格 */
|
||||
.markdown-body table {
|
||||
border-collapse: collapse;
|
||||
margin: 1rem 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.markdown-body table th,
|
||||
.markdown-body table td {
|
||||
border: 1px solid #dfe2e5;
|
||||
padding: .6em 1em;
|
||||
}
|
||||
|
||||
.markdown-body table tr {
|
||||
border-top: 1px solid #dfe2e5;
|
||||
}
|
||||
|
||||
.markdown-body table tr:nth-child(2n) {
|
||||
background-color: #f6f8fa;
|
||||
}
|
||||
|
||||
/*
|
||||
From: icewolf-sec (御坂19008号)
|
||||
Description: 新增HTML5 键盘文字标签样式
|
||||
*/
|
||||
.markdown-body kbd {
|
||||
color: white;
|
||||
background-color: #135ce0;
|
||||
border: 1px solid #135ce0;
|
||||
border-radius: 5px;
|
||||
padding: 2px;
|
||||
font-weight: bold;
|
||||
margin: auto 5px auto;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.bytemd {
|
||||
height: 600px;
|
||||
}
|
||||
47
src/pages/Create/components/Editor/index.tsx
Normal file
47
src/pages/Create/components/Editor/index.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Editor, Viewer } from '@bytemd/react'
|
||||
import 'bytemd/dist/index.css'
|
||||
import highlight from '@bytemd/plugin-highlight'
|
||||
import 'highlight.js/styles/vs2015.css';
|
||||
import "./index.scss"
|
||||
|
||||
const plugins = [
|
||||
highlight()
|
||||
]
|
||||
|
||||
// import FileUpload from "@/components/FileUpload";
|
||||
|
||||
interface Props {
|
||||
value?: string,
|
||||
getValue: (value: string) => void
|
||||
}
|
||||
|
||||
const EditorMD = ({ value, getValue }: Props) => {
|
||||
const [content, setContent] = useState('')
|
||||
|
||||
return (
|
||||
<>
|
||||
<Editor
|
||||
value={content}
|
||||
plugins={plugins}
|
||||
onChange={(v) => {
|
||||
setContent(v)
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 文件上传 */}
|
||||
{/* <FileUpload
|
||||
dir="article"
|
||||
open={openUploadModalOpen}
|
||||
onSuccess={(urls: string[]) => {
|
||||
urls.forEach((path: string) => {
|
||||
vd?.insertValue(``);
|
||||
});
|
||||
}}
|
||||
onCancel={() => setOpenUploadModalOpen(false)}
|
||||
/> */}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditorMD;
|
||||
@@ -1,33 +0,0 @@
|
||||
#vditor {
|
||||
border: none;
|
||||
|
||||
.vditor-toolbar {
|
||||
padding-left: 0 !important;
|
||||
background-color: transparent;
|
||||
border-bottom: none;
|
||||
|
||||
.vditor-tooltipped__ai {
|
||||
padding: 0;
|
||||
|
||||
svg {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vditor-reset {
|
||||
background-color: transparent !important;
|
||||
|
||||
.vditor-ir__marker--heading {
|
||||
color: #727cf5;
|
||||
}
|
||||
}
|
||||
|
||||
// 针对表单元素的光标样式
|
||||
pre {
|
||||
// 设置光标样式
|
||||
caret-color: #727cf5; // 光标颜色
|
||||
}
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import Vditor from "vditor";
|
||||
import "vditor/dist/index.css";
|
||||
import "./index.scss"
|
||||
import FileUpload from "@/components/FileUpload";
|
||||
|
||||
const toolbar = [
|
||||
{
|
||||
hotkey: "⌘H",
|
||||
icon:
|
||||
'<svg><use xlink:href="#vditor-icon-headings"></use></svg>',
|
||||
name: "headings",
|
||||
tipPosition: "ne",
|
||||
},
|
||||
{
|
||||
hotkey: "⌘B",
|
||||
icon: '<svg><use xlink:href="#vditor-icon-bold"></use></svg>',
|
||||
name: "bold",
|
||||
prefix: "**",
|
||||
suffix: "**",
|
||||
tipPosition: "ne",
|
||||
},
|
||||
{
|
||||
hotkey: "⌘I",
|
||||
icon: '<svg><use xlink:href="#vditor-icon-italic"></use></svg>',
|
||||
name: "italic",
|
||||
prefix: "*",
|
||||
suffix: "*",
|
||||
tipPosition: "ne",
|
||||
},
|
||||
{
|
||||
hotkey: "⌘D",
|
||||
icon: '<svg><use xlink:href="#vditor-icon-strike"></use></svg>',
|
||||
name: "strike",
|
||||
prefix: "~~",
|
||||
suffix: "~~",
|
||||
tipPosition: "ne",
|
||||
},
|
||||
{
|
||||
hotkey: "⌘K",
|
||||
icon: '<svg><use xlink:href="#vditor-icon-link"></use></svg>',
|
||||
name: "link",
|
||||
prefix: "[",
|
||||
suffix: "](https://)",
|
||||
tipPosition: "n",
|
||||
},
|
||||
{
|
||||
name: "|",
|
||||
},
|
||||
{
|
||||
hotkey: "⌘L",
|
||||
icon: '<svg><use xlink:href="#vditor-icon-list"></use></svg>',
|
||||
name: "list",
|
||||
prefix: "* ",
|
||||
tipPosition: "n",
|
||||
},
|
||||
{
|
||||
hotkey: "⌘O",
|
||||
icon:
|
||||
'<svg><use xlink:href="#vditor-icon-ordered-list"></use></svg>',
|
||||
name: "ordered-list",
|
||||
prefix: "1. ",
|
||||
tipPosition: "n",
|
||||
},
|
||||
{
|
||||
hotkey: "⌘J",
|
||||
icon: '<svg><use xlink:href="#vditor-icon-check"></use></svg>',
|
||||
name: "check",
|
||||
prefix: "* [ ] ",
|
||||
tipPosition: "n",
|
||||
},
|
||||
{
|
||||
hotkey: "⇧⌘I",
|
||||
icon:
|
||||
'<svg><use xlink:href="#vditor-icon-outdent"></use></svg>',
|
||||
name: "outdent",
|
||||
tipPosition: "n",
|
||||
},
|
||||
{
|
||||
hotkey: "⇧⌘O",
|
||||
icon: '<svg><use xlink:href="#vditor-icon-indent"></use></svg>',
|
||||
name: "indent",
|
||||
tipPosition: "n",
|
||||
},
|
||||
{
|
||||
name: "|",
|
||||
},
|
||||
{
|
||||
hotkey: "⌘;",
|
||||
icon: '<svg><use xlink:href="#vditor-icon-quote"></use></svg>',
|
||||
name: "quote",
|
||||
prefix: "> ",
|
||||
tipPosition: "n",
|
||||
},
|
||||
{
|
||||
hotkey: "⇧⌘H",
|
||||
icon: '<svg><use xlink:href="#vditor-icon-line"></use></svg>',
|
||||
name: "line",
|
||||
prefix: "---",
|
||||
tipPosition: "n",
|
||||
},
|
||||
{
|
||||
hotkey: "⌘U",
|
||||
icon: '<svg><use xlink:href="#vditor-icon-code"></use></svg>',
|
||||
name: "code",
|
||||
prefix: "```",
|
||||
suffix: "\n```",
|
||||
tipPosition: "n",
|
||||
},
|
||||
{
|
||||
hotkey: "⌘G",
|
||||
icon:
|
||||
'<svg><use xlink:href="#vditor-icon-inline-code"></use></svg>',
|
||||
name: "inline-code",
|
||||
prefix: "`",
|
||||
suffix: "`",
|
||||
tipPosition: "n",
|
||||
},
|
||||
{
|
||||
name: "|",
|
||||
},
|
||||
{
|
||||
icon: '<svg><use xlink:href="#vditor-icon-upload"></use></svg>',
|
||||
name: "upload",
|
||||
tipPosition: "n",
|
||||
},
|
||||
{
|
||||
hotkey: "⌘M",
|
||||
icon: '<svg><use xlink:href="#vditor-icon-table"></use></svg>',
|
||||
name: "table",
|
||||
prefix: "| col1",
|
||||
suffix:
|
||||
" | col2 | col3 |\n| --- | --- | --- |\n| | | |\n| | | |",
|
||||
tipPosition: "n",
|
||||
},
|
||||
{
|
||||
name: "|",
|
||||
},
|
||||
{
|
||||
hotkey: "⌘Z",
|
||||
icon: '<svg><use xlink:href="#vditor-icon-undo"></use></svg>',
|
||||
name: "undo",
|
||||
tipPosition: "nw",
|
||||
},
|
||||
{
|
||||
hotkey: "⌘Y",
|
||||
icon: '<svg><use xlink:href="#vditor-icon-redo"></use></svg>',
|
||||
name: "redo",
|
||||
tipPosition: "nw",
|
||||
},
|
||||
{
|
||||
name: "|",
|
||||
},
|
||||
{
|
||||
icon:
|
||||
'<svg><use xlink:href="#vditor-icon-align-center"></use></svg>',
|
||||
name: "outline",
|
||||
tipPosition: "nw",
|
||||
},
|
||||
{
|
||||
icon: '<svg><use xlink:href="#vditor-icon-theme"></use></svg>',
|
||||
name: "content-theme",
|
||||
tipPosition: "nw",
|
||||
},
|
||||
{
|
||||
icon: '<svg><use xlink:href="#vditor-icon-code-theme"></use></svg>',
|
||||
name: "code-theme",
|
||||
tipPosition: "nw",
|
||||
},
|
||||
{
|
||||
name: "br",
|
||||
}
|
||||
]
|
||||
|
||||
interface VditorProps {
|
||||
value?: string,
|
||||
getValue: (value: string) => void
|
||||
}
|
||||
|
||||
const VditorEditor = ({ value, getValue }: VditorProps) => {
|
||||
const [openUploadModalOpen, setOpenUploadModalOpen] = useState(false);
|
||||
const [vd, setVd] = useState<Vditor>();
|
||||
|
||||
useEffect(() => {
|
||||
const vditor = new Vditor("vditor", {
|
||||
minHeight: 550,
|
||||
// 禁止缓存数据
|
||||
cache: {
|
||||
enable: false
|
||||
},
|
||||
preview: {
|
||||
// 限制防抖时间
|
||||
delay: 500
|
||||
},
|
||||
toolbar,
|
||||
// upload: {
|
||||
// handler: async (files) => {
|
||||
// console.log(files, 333);
|
||||
|
||||
// const formData = new FormData();
|
||||
// files.forEach(file => {
|
||||
// formData.append('files', file);
|
||||
// });
|
||||
|
||||
// // 添加额外参数
|
||||
// formData.append('dir', 'article');
|
||||
|
||||
// const res = await fetch(`${baseURL}/file`, {
|
||||
// method: "POST",
|
||||
// body: formData,
|
||||
// headers: {
|
||||
// "Authorization": `Bearer ${store.token}`
|
||||
// }
|
||||
// });
|
||||
|
||||
// const { code, message, data } = await res.json();
|
||||
// if (code !== 200) return message.error("文件上传失败:" + message);
|
||||
|
||||
// // 插入到编辑器中
|
||||
// data.forEach((path: string) => {
|
||||
// vditor.insertValue(``);
|
||||
// });
|
||||
// },
|
||||
// },
|
||||
input: (value) => {
|
||||
// 把数据传给父组件
|
||||
getValue(value)
|
||||
},
|
||||
after: () => {
|
||||
// 获取文件上传按钮
|
||||
const uploadButton = document.querySelector('.vditor-toolbar [data-type="upload"]')!;
|
||||
|
||||
// 添加点击事件监听器
|
||||
uploadButton.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
console.log('文件上传图标被点击');
|
||||
// 在这里添加你的自定义逻辑
|
||||
|
||||
setOpenUploadModalOpen(true)
|
||||
});
|
||||
|
||||
setVd(vditor);
|
||||
}
|
||||
})
|
||||
|
||||
return () => {
|
||||
vd?.destroy();
|
||||
setVd(undefined);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 监听 value 变化并更新编辑器内容
|
||||
useEffect(() => {
|
||||
if (vd && value !== undefined && value !== vd.getValue()) {
|
||||
vd.setValue(value);
|
||||
}
|
||||
}, [value, vd]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id="vditor" className="vditor" />
|
||||
|
||||
{/* 文件上传 */}
|
||||
<FileUpload
|
||||
dir="article"
|
||||
open={openUploadModalOpen}
|
||||
onSuccess={(urls: string[]) => {
|
||||
urls.forEach((path: string) => {
|
||||
vd?.insertValue(``);
|
||||
});
|
||||
}}
|
||||
onCancel={() => setOpenUploadModalOpen(false)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default VditorEditor;
|
||||
@@ -3,7 +3,7 @@ import { useSearchParams } from 'react-router-dom';
|
||||
import { Button, Card, Drawer, Dropdown, MenuProps, message } from 'antd';
|
||||
|
||||
import Title from '@/components/Title';
|
||||
import VditorEditor from './components/VditorMD';
|
||||
import Editor from './components/Editor';
|
||||
import PublishForm from './components/PublishForm';
|
||||
|
||||
import { Article } from '@/types/app/article';
|
||||
@@ -151,26 +151,22 @@ const CreatePage = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title value="创作" />
|
||||
<Title value="创作">
|
||||
<div className='flex space-x-4'>
|
||||
<Dropdown.Button menu={{ items }}>创作神器</Dropdown.Button>
|
||||
|
||||
<Card className='relative mt-2'>
|
||||
<div className='flex justify-end w-full'>
|
||||
<div className='relative z-50 flex w-[24%] space-x-4'>
|
||||
<Dropdown.Button menu={{ items }}>创作神器</Dropdown.Button>
|
||||
<Button className='w-full flex justify-between' onClick={saveBtn} >
|
||||
<BiSave className='text-base' /> 保存
|
||||
</Button>
|
||||
|
||||
<Button className='w-full flex justify-between' onClick={saveBtn} >
|
||||
<BiSave className='text-base' /> 保存
|
||||
</Button>
|
||||
|
||||
<Button type="primary" className='w-full flex justify-between' onClick={nextBtn} >
|
||||
<GrFormNext className='text-2xl' /> 下一步
|
||||
</Button>
|
||||
</div>
|
||||
<Button type="primary" className='w-full flex justify-between' onClick={nextBtn} >
|
||||
<GrFormNext className='text-2xl' /> 下一步
|
||||
</Button>
|
||||
</div>
|
||||
</Title>
|
||||
|
||||
<div className='relative -top-[40px]'>
|
||||
<VditorEditor value={content} getValue={getVditorData} />
|
||||
</div>
|
||||
<Card className='[&>.ant-card-body]:!p-0 overflow-hidden rounded-xl'>
|
||||
<Editor value={content} getValue={getVditorData} />
|
||||
|
||||
<Drawer
|
||||
title={id ? "编辑文章" : "发布文章"}
|
||||
|
||||
Reference in New Issue
Block a user