mirror of https://github.com/fantasticit/think.git
feat: add global event center
This commit is contained in:
parent
a8d9f41734
commit
11ce42dbe3
|
@ -17,11 +17,11 @@ import {
|
||||||
} from '@douyinfe/semi-ui';
|
} from '@douyinfe/semi-ui';
|
||||||
import { IconUserAdd, IconDelete } from '@douyinfe/semi-icons';
|
import { IconUserAdd, IconDelete } from '@douyinfe/semi-icons';
|
||||||
import { useUser } from 'data/user';
|
import { useUser } from 'data/user';
|
||||||
import { EventEmitter } from 'helpers/event-emitter';
|
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
import { useCollaborationDocument } from 'data/document';
|
import { useCollaborationDocument } from 'data/document';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { DocumentLinkCopyer } from 'components/document/link';
|
import { DocumentLinkCopyer } from 'components/document/link';
|
||||||
|
import { event, JOIN_USER } from 'event';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
wikiId: string;
|
wikiId: string;
|
||||||
|
@ -31,13 +31,6 @@ interface IProps {
|
||||||
const { Paragraph } = Typography;
|
const { Paragraph } = Typography;
|
||||||
const { Column } = Table;
|
const { Column } = Table;
|
||||||
|
|
||||||
const CollaborationEventEmitter = new EventEmitter();
|
|
||||||
const KEY = 'JOIN_USER';
|
|
||||||
|
|
||||||
export const joinUser = (users) => {
|
|
||||||
CollaborationEventEmitter.emit(KEY, users);
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderChecked = (onChange, authKey: 'readable' | 'editable') => (checked, docAuth) => {
|
const renderChecked = (onChange, authKey: 'readable' | 'editable') => (checked, docAuth) => {
|
||||||
const handle = (evt) => {
|
const handle = (evt) => {
|
||||||
const data = {
|
const data = {
|
||||||
|
@ -56,7 +49,6 @@ export const DocumentCollaboration: React.FC<IProps> = ({ wikiId, documentId })
|
||||||
const [visible, toggleVisible] = useToggle(false);
|
const [visible, toggleVisible] = useToggle(false);
|
||||||
const { users, loading, error, addUser, updateUser, deleteUser } = useCollaborationDocument(documentId);
|
const { users, loading, error, addUser, updateUser, deleteUser } = useCollaborationDocument(documentId);
|
||||||
const [inviteUser, setInviteUser] = useState('');
|
const [inviteUser, setInviteUser] = useState('');
|
||||||
|
|
||||||
const [collaborationUsers, setCollaborationUsers] = useState([]);
|
const [collaborationUsers, setCollaborationUsers] = useState([]);
|
||||||
|
|
||||||
const handleOk = () => {
|
const handleOk = () => {
|
||||||
|
@ -75,7 +67,7 @@ export const DocumentCollaboration: React.FC<IProps> = ({ wikiId, documentId })
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
CollaborationEventEmitter.on(KEY, ({ states: users }) => {
|
const handler = (users) => {
|
||||||
const newCollaborationUsers = users
|
const newCollaborationUsers = users
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.filter((state) => state.user)
|
.filter((state) => state.user)
|
||||||
|
@ -97,10 +89,11 @@ export const DocumentCollaboration: React.FC<IProps> = ({ wikiId, documentId })
|
||||||
});
|
});
|
||||||
|
|
||||||
setCollaborationUsers(newCollaborationUsers);
|
setCollaborationUsers(newCollaborationUsers);
|
||||||
});
|
};
|
||||||
|
event.on(JOIN_USER, handler);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
CollaborationEventEmitter.destroy();
|
event.off(JOIN_USER, handler);
|
||||||
};
|
};
|
||||||
}, [collaborationUsers, currentUser]);
|
}, [collaborationUsers, currentUser]);
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import Router from 'next/router';
|
||||||
import { Typography, Space, Modal } from '@douyinfe/semi-ui';
|
import { Typography, Space, Modal } from '@douyinfe/semi-ui';
|
||||||
import { IconDelete } from '@douyinfe/semi-icons';
|
import { IconDelete } from '@douyinfe/semi-icons';
|
||||||
import { useDeleteDocument } from 'data/document';
|
import { useDeleteDocument } from 'data/document';
|
||||||
import { triggerRefreshTocs } from 'components/wiki/tocs/event';
|
import { triggerRefreshTocs } from 'event';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
wikiId: string;
|
wikiId: string;
|
||||||
|
|
|
@ -18,10 +18,9 @@ import {
|
||||||
destoryIndexdbProvider,
|
destoryIndexdbProvider,
|
||||||
} from 'tiptap';
|
} from 'tiptap';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { joinUser } from 'components/document/collaboration';
|
|
||||||
import { Banner } from 'components/banner';
|
import { Banner } from 'components/banner';
|
||||||
import { debounce } from 'helpers/debounce';
|
import { debounce } from 'helpers/debounce';
|
||||||
import { em, changeTitle, USE_DATA_VERSION } from './index';
|
import { event, triggerChangeDocumentTitle, triggerJoinUser, USE_DOCUMENT_VERSION } from 'event';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
|
@ -45,7 +44,7 @@ export const Editor: React.FC<IProps> = ({ user, documentId, authority, classNam
|
||||||
docType: 'document',
|
docType: 'document',
|
||||||
events: {
|
events: {
|
||||||
onAwarenessUpdate({ states }) {
|
onAwarenessUpdate({ states }) {
|
||||||
joinUser({ states });
|
triggerJoinUser(states);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -62,7 +61,7 @@ export const Editor: React.FC<IProps> = ({ user, documentId, authority, classNam
|
||||||
onTransaction: debounce(({ transaction }) => {
|
onTransaction: debounce(({ transaction }) => {
|
||||||
try {
|
try {
|
||||||
const title = transaction.doc.content.firstChild.content.firstChild.textContent;
|
const title = transaction.doc.content.firstChild.content.firstChild.textContent;
|
||||||
changeTitle(title);
|
triggerChangeDocumentTitle(title);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}, 50),
|
}, 50),
|
||||||
});
|
});
|
||||||
|
@ -92,10 +91,9 @@ export const Editor: React.FC<IProps> = ({ user, documentId, authority, classNam
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!editor) return;
|
if (!editor) return;
|
||||||
const handler = (data) => editor.commands.setContent(data);
|
const handler = (data) => editor.commands.setContent(data);
|
||||||
em.on(USE_DATA_VERSION, handler);
|
event.on(USE_DOCUMENT_VERSION, handler);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
em.off(USE_DATA_VERSION, handler);
|
event.off(USE_DOCUMENT_VERSION, handler);
|
||||||
};
|
};
|
||||||
}, [editor]);
|
}, [editor]);
|
||||||
|
|
||||||
|
|
|
@ -16,24 +16,12 @@ import { DocumentVersion } from 'components/document/version';
|
||||||
import { User } from 'components/user';
|
import { User } from 'components/user';
|
||||||
import { Divider } from 'components/divider';
|
import { Divider } from 'components/divider';
|
||||||
import { useDocumentStyle } from 'hooks/use-document-style';
|
import { useDocumentStyle } from 'hooks/use-document-style';
|
||||||
import { EventEmitter } from 'helpers/event-emitter';
|
import { event, CHANGE_DOCUMENT_TITLE, triggerUseDocumentVersion } from 'event';
|
||||||
import { Editor } from './editor';
|
import { Editor } from './editor';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
export const em = new EventEmitter();
|
|
||||||
const TITLE_CHANGE_EVENT = 'TITLE_CHANGE_EVENT';
|
|
||||||
export const USE_DATA_VERSION = 'USE_DATA_VERSION';
|
|
||||||
|
|
||||||
export const changeTitle = (title) => {
|
|
||||||
em.emit(TITLE_CHANGE_EVENT, title);
|
|
||||||
};
|
|
||||||
|
|
||||||
const useVersion = (data) => {
|
|
||||||
em.emit(USE_DATA_VERSION, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
documentId: string;
|
documentId: string;
|
||||||
}
|
}
|
||||||
|
@ -77,10 +65,10 @@ export const DocumentEditor: React.FC<IProps> = ({ documentId }) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
em.on(TITLE_CHANGE_EVENT, setTitle);
|
event.on(CHANGE_DOCUMENT_TITLE, setTitle);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
em.destroy();
|
event.off(CHANGE_DOCUMENT_TITLE, setTitle);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -97,7 +85,7 @@ export const DocumentEditor: React.FC<IProps> = ({ documentId }) => {
|
||||||
<DocumentCollaboration key="collaboration" wikiId={document.wikiId} documentId={documentId} />
|
<DocumentCollaboration key="collaboration" wikiId={document.wikiId} documentId={documentId} />
|
||||||
)}
|
)}
|
||||||
<DocumentShare key="share" documentId={documentId} />
|
<DocumentShare key="share" documentId={documentId} />
|
||||||
<DocumentVersion key="version" documentId={documentId} onSelect={useVersion} />
|
<DocumentVersion key="version" documentId={documentId} onSelect={triggerUseDocumentVersion} />
|
||||||
<DocumentStar key="star" documentId={documentId} />
|
<DocumentStar key="star" documentId={documentId} />
|
||||||
<Popover key="style" zIndex={1061} position="bottomLeft" content={<DocumentStyle />}>
|
<Popover key="style" zIndex={1061} position="bottomLeft" content={<DocumentStyle />}>
|
||||||
<Button icon={<IconArticle />} theme="borderless" type="tertiary" />
|
<Button icon={<IconArticle />} theme="borderless" type="tertiary" />
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
} from 'tiptap';
|
} from 'tiptap';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { ImageViewer } from 'components/image-viewer';
|
import { ImageViewer } from 'components/image-viewer';
|
||||||
import { joinUser } from 'components/document/collaboration';
|
import { triggerJoinUser } from 'event';
|
||||||
import { CreateUser } from './user';
|
import { CreateUser } from './user';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ export const Editor: React.FC<IProps> = ({ user, documentId, document }) => {
|
||||||
docType: 'document',
|
docType: 'document',
|
||||||
events: {
|
events: {
|
||||||
onAwarenessUpdate({ states }) {
|
onAwarenessUpdate({ states }) {
|
||||||
joinUser({ states });
|
triggerJoinUser(states);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
import { IDocument, IWiki } from '@think/domains';
|
|
||||||
import { event } from 'helpers/event-emitter';
|
|
||||||
|
|
||||||
export const REFRESH_TOCS = `REFRESH_TOCS`; // 刷新知识库目录
|
|
||||||
export const CREATE_DOCUMENT = `CREATE_DOCUMENT`;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新知识库目录
|
|
||||||
*/
|
|
||||||
export const triggerRefreshTocs = () => {
|
|
||||||
event.emit(REFRESH_TOCS);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新建文档
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
export const triggerCreateDocument = (data: { wikiId: IWiki['id']; documentId: IDocument['id'] | null }) => {
|
|
||||||
event.emit(CREATE_DOCUMENT, data);
|
|
||||||
};
|
|
|
@ -9,8 +9,7 @@ import { Seo } from 'components/seo';
|
||||||
import { findParents } from 'components/wiki/tocs/utils';
|
import { findParents } from 'components/wiki/tocs/utils';
|
||||||
import { IconDocument, IconSetting, IconOverview, IconGlobe } from 'components/icons';
|
import { IconDocument, IconSetting, IconOverview, IconGlobe } from 'components/icons';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { event } from 'helpers/event-emitter';
|
import { event, REFRESH_TOCS, triggerCreateDocument } from 'event';
|
||||||
import { REFRESH_TOCS, triggerCreateDocument } from './event';
|
|
||||||
import { NavItem } from './nav-item';
|
import { NavItem } from './nav-item';
|
||||||
import { Tree } from './tree';
|
import { Tree } from './tree';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
|
@ -5,8 +5,7 @@ import { IconMore, IconPlus } from '@douyinfe/semi-icons';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
import { DocumentActions } from 'components/document/actions';
|
import { DocumentActions } from 'components/document/actions';
|
||||||
import { DocumentCreator as DocumenCreatorForm } from 'components/document/create';
|
import { DocumentCreator as DocumenCreatorForm } from 'components/document/create';
|
||||||
import { event } from 'helpers/event-emitter';
|
import { event, CREATE_DOCUMENT, triggerCreateDocument } from 'event';
|
||||||
import { CREATE_DOCUMENT, triggerCreateDocument } from './event';
|
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
const Actions = ({ node }) => {
|
const Actions = ({ node }) => {
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { IUser, IDocument, IWiki } from '@think/domains';
|
||||||
|
import { EventEmitter } from 'helpers/event-emitter';
|
||||||
|
|
||||||
|
export const event = new EventEmitter();
|
||||||
|
|
||||||
|
export const REFRESH_TOCS = `REFRESH_TOCS`; // 刷新知识库目录
|
||||||
|
export const CREATE_DOCUMENT = `CREATE_DOCUMENT`;
|
||||||
|
/**
|
||||||
|
* 刷新知识库目录
|
||||||
|
*/
|
||||||
|
export const triggerRefreshTocs = () => {
|
||||||
|
event.emit(REFRESH_TOCS);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 新建文档
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const triggerCreateDocument = (data: { wikiId: IWiki['id']; documentId: IDocument['id'] | null }) => {
|
||||||
|
event.emit(CREATE_DOCUMENT, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CHANGE_DOCUMENT_TITLE = `CHANGE_DOCUMENT_TITLE`;
|
||||||
|
/**
|
||||||
|
* 改变文档标题
|
||||||
|
* @param title
|
||||||
|
*/
|
||||||
|
export const triggerChangeDocumentTitle = (title: string) => {
|
||||||
|
event.emit(CHANGE_DOCUMENT_TITLE, title);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const USE_DOCUMENT_VERSION = `USE_DOCUMENT_VERSION`;
|
||||||
|
/**
|
||||||
|
* 使用文档版本
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const triggerUseDocumentVersion = (data: Record<string, unknown>) => {
|
||||||
|
event.emit(USE_DOCUMENT_VERSION, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const JOIN_USER = `JOIN_USER`;
|
||||||
|
type CollaborationUser = {
|
||||||
|
clientId: number;
|
||||||
|
user: IUser;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 文档协作:加入用户
|
||||||
|
* @param users
|
||||||
|
*/
|
||||||
|
export const triggerJoinUser = (users: Array<CollaborationUser>) => {
|
||||||
|
event.emit(JOIN_USER, users);
|
||||||
|
};
|
|
@ -39,5 +39,3 @@ export class EventEmitter {
|
||||||
this.callbacks = {};
|
this.callbacks = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const event = new EventEmitter();
|
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
"layout/*": ["layout/*"],
|
"layout/*": ["layout/*"],
|
||||||
"constants/*": ["constants/*"],
|
"constants/*": ["constants/*"],
|
||||||
"helpers/*": ["helpers/*"],
|
"helpers/*": ["helpers/*"],
|
||||||
"tiptap/*": ["tiptap/*"]
|
"tiptap/*": ["tiptap/*"],
|
||||||
|
"event/*": ["event/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||||
|
|
Loading…
Reference in New Issue