Compare commits

...

3 Commits

Author SHA1 Message Date
yu.kuai 3999621981 feat: markdown 编辑模式支持拖拽/粘贴文件资源 2025-11-12 15:46:12 +08:00
yu.kuai da17b21387 fix: ts 报错问题修复 2025-11-12 11:43:07 +08:00
yu.kuai e361644f01 feat: 编辑页添加快捷键 ctrl+B 控制展开和收起目录 2025-11-12 11:23:56 +08:00
8 changed files with 29 additions and 62 deletions

View File

@ -25,12 +25,6 @@ import DocDelete from '../../component/DocDelete';
interface HeaderProps {
edit: boolean;
collaborativeUsers?: Array<{
id: string;
name: string;
color: string;
}>;
isSyncing?: boolean;
detail: V1NodeDetailResp;
updateDetail: (detail: V1NodeDetailResp) => void;
handleSave: () => void;
@ -39,8 +33,6 @@ interface HeaderProps {
const Header = ({
edit,
collaborativeUsers = [],
isSyncing = false,
detail,
updateDetail,
handleSave,
@ -54,10 +46,6 @@ const Header = ({
const { catalogOpen, nodeDetail, setCatalogOpen } =
useOutletContext<WrapContext>();
// const docWidth = useMemo(() => {
// return nodeDetail?.meta?.doc_width || 'full';
// }, [nodeDetail]);
const [renameOpen, setRenameOpen] = useState(false);
const [delOpen, setDelOpen] = useState(false);
const [publishOpen, setPublishOpen] = useState(false);
@ -68,22 +56,6 @@ const Header = ({
return license.edition === 2;
}, [license]);
// const updateDocWidth = (doc_width: string) => {
// if (!nodeDetail) return;
// putApiV1NodeDetail({
// id: nodeDetail.id!,
// kb_id,
// doc_width,
// }).then(() => {
// updateDetail({
// meta: {
// ...nodeDetail.meta,
// doc_width,
// },
// });
// });
// };
const handlePublish = useCallback(() => {
if (nodeDetail?.status === 2 && !edit) {
message.info('当前已是最新版本!');

View File

@ -39,8 +39,6 @@ const LoadingEditorWrap = () => {
>
<Header
edit={false}
isSyncing={isSyncing}
collaborativeUsers={collaborativeUsers}
detail={{}}
updateDetail={() => {}}
handleSave={() => {}}

View File

@ -40,7 +40,7 @@ const Wrap = ({ detail: defaultDetail }: WrapProps) => {
const { license } = useAppSelector(state => state.config);
const state = useLocation().state as { node?: V1NodeDetailResp };
const { catalogOpen, nodeDetail, setNodeDetail, onSave, docWidth } =
const { catalogOpen, setCatalogOpen, nodeDetail, setNodeDetail, onSave } =
useOutletContext<WrapContext>();
const storageTocOpen = localStorage.getItem('toc-open');
@ -280,14 +280,18 @@ const Wrap = ({ detail: defaultDetail }: WrapProps) => {
isMarkdown,
]);
const handleGlobalSave = useCallback(
const handleGlobalKeydown = useCallback(
(event: KeyboardEvent) => {
if ((event.ctrlKey || event.metaKey) && event.key === 's') {
event.preventDefault();
changeCatalogItem();
}
if ((event.ctrlKey || event.metaKey) && event.key === 'b') {
event.preventDefault();
setCatalogOpen(!catalogOpen);
}
},
[changeCatalogItem],
[changeCatalogItem, catalogOpen, setCatalogOpen],
);
const renderEditorTitleEmojiSummary = () => {
@ -525,11 +529,11 @@ const Wrap = ({ detail: defaultDetail }: WrapProps) => {
}, [defaultDetail]);
useEffect(() => {
document.addEventListener('keydown', handleGlobalSave);
document.addEventListener('keydown', handleGlobalKeydown);
return () => {
document.removeEventListener('keydown', handleGlobalSave);
document.removeEventListener('keydown', handleGlobalKeydown);
};
}, [handleGlobalSave]);
}, [handleGlobalKeydown]);
useEffect(() => {
if (state && state.node && editorRef.editor) {
@ -659,7 +663,10 @@ const Wrap = ({ detail: defaultDetail }: WrapProps) => {
<Toolbar editorRef={editorRef} handleAiGenerate={handleAiGenerate} />
)}
</Box>
<Box sx={{ ...(fixedToc && { display: 'flex' }) }}>
<Box
sx={{ ...(fixedToc && { display: 'flex' }) }}
onKeyDown={event => event.stopPropagation()}
>
{isMarkdown ? (
<Box
sx={{

View File

@ -8,19 +8,11 @@ import { useEffect, useRef } from 'react';
import { useWrapContext } from '..';
interface HeaderProps {
edit: boolean;
collaborativeUsers?: Array<{
id: string;
name: string;
color: string;
}>;
isSyncing?: boolean;
detail: V1NodeDetailResp;
updateDetail: (detail: V1NodeDetailResp) => void;
handleSave: () => void;
}
const Header = ({ edit, detail, handleSave }: HeaderProps) => {
const Header = ({ detail, handleSave }: HeaderProps) => {
const firstLoad = useRef(true);
const { catalogOpen, nodeDetail, setCatalogOpen, saveLoading } =

View File

@ -1,4 +1,5 @@
'use client';
import { V1NodeDetailResp } from '@/request/types';
import { useTiptap } from '@ctzhian/tiptap';
import { Icon } from '@ctzhian/ui';
import { Box, Skeleton, Stack } from '@mui/material';
@ -35,14 +36,7 @@ const LoadingEditorWrap = () => {
transition: 'left 0.3s ease-in-out',
}}
>
<Header
edit={false}
isSyncing={isSyncing}
collaborativeUsers={collaborativeUsers}
detail={{}}
updateDetail={() => {}}
handleSave={() => {}}
/>
<Header detail={{} as V1NodeDetailResp} handleSave={() => {}} />
{editorRef.editor && <Toolbar editorRef={editorRef} />}
</Box>
<Box>

View File

@ -179,10 +179,14 @@ const Wrap = ({ detail: defaultDetail = {} }: WrapProps) => {
}}
>
<Header
edit={isEditing}
detail={nodeDetail!}
updateDetail={updateDetail}
handleSave={async () => {
if (!isMarkdown) {
const value = editorRef.getContent();
updateDetail({
content: value,
});
}
if (checkRequiredFields()) {
setConfirmModalOpen(true);
}

View File

@ -18,7 +18,7 @@
"license": "ISC",
"packageManager": "pnpm@10.12.1",
"dependencies": {
"@ctzhian/tiptap": "^1.12.20",
"@ctzhian/tiptap": "^1.12.21",
"@ctzhian/ui": "^7.0.5",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",

View File

@ -9,8 +9,8 @@ importers:
.:
dependencies:
'@ctzhian/tiptap':
specifier: ^1.12.20
version: 1.12.20(3f8aa6e4b731b59772b9acd58d22fc94)
specifier: ^1.12.21
version: 1.12.21(3f8aa6e4b731b59772b9acd58d22fc94)
'@ctzhian/ui':
specifier: ^7.0.5
version: 7.0.5(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@mui/icons-material@7.3.4(@mui/material@7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@mui/material@7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@mui/utils@7.3.3(@types/react@19.2.2)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@ -514,8 +514,8 @@ packages:
react: '>=16.9.0'
react-dom: '>=16.9.0'
'@ctzhian/tiptap@1.12.20':
resolution: {integrity: sha512-FLGgzZcvNpf1ncgPdagFaHEfqnzkWjiRw3s9tT1loyhaX+KrxQRjY86MW3qPh7qB6WIhZsfb8T1sgWLwRNN0/Q==}
'@ctzhian/tiptap@1.12.21':
resolution: {integrity: sha512-BU6ZfMbt1UzX6XeTpGvbdp2fAF/wnBz3HcjcXm8Tf4HODPrO7alIF6fPaTPOrWVnWmSCYqBEE4msYiDpAS6TXA==}
peerDependencies:
'@emotion/react': ^11
'@emotion/styled': ^11
@ -5995,7 +5995,7 @@ snapshots:
- react-native
- typescript
'@ctzhian/tiptap@1.12.20(3f8aa6e4b731b59772b9acd58d22fc94)':
'@ctzhian/tiptap@1.12.21(3f8aa6e4b731b59772b9acd58d22fc94)':
dependencies:
'@emotion/react': 11.14.0(@types/react@19.2.2)(react@19.2.0)
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0)