client: improve render editor

pull/60/head
fantasticit 2022-05-25 13:05:24 +08:00
parent 6768ecc0e2
commit a534e799c1
4 changed files with 119 additions and 263 deletions

View File

@ -51,19 +51,18 @@ export const DocumentEditor: React.FC<IProps> = ({ documentId }) => {
}, [document, documentId]); }, [document, documentId]);
const actions = useMemo( const actions = useMemo(
() => () => (
docAuthLoading ? null : ( <Space>
<Space> {document && authority.readable && (
{document && authority.readable && ( <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={triggerUseDocumentVersion} />
<DocumentVersion key="version" documentId={documentId} onSelect={triggerUseDocumentVersion} /> <DocumentStar key="star" documentId={documentId} />
<DocumentStar key="star" documentId={documentId} /> <DocumentStyle />
<DocumentStyle /> </Space>
</Space> ),
), [documentId, document, authority]
[docAuthLoading, documentId, document, authority]
); );
useEffect(() => { useEffect(() => {
@ -120,36 +119,18 @@ export const DocumentEditor: React.FC<IProps> = ({ documentId }) => {
{isMobile && <div className={styles.mobileToolbar}>{actions}</div>} {isMobile && <div className={styles.mobileToolbar}>{actions}</div>}
</header> </header>
<main className={styles.contentWrap}> <main className={styles.contentWrap}>
<DataRender {docAuthError && (
loading={docAuthLoading} <div style={{ margin: '10vh', textAlign: 'center' }}>
loadingContent={ <SecureDocumentIllustration />
<div style={{ margin: '10vh auto' }}> </div>
<Spin tip="正在为您读取文档中..."> )}
{/* FIXME: semi-design 的问题,不加 div文字会换行! */} {document && <Seo title={document.title} />}
<div></div> <Editor
</Spin> user={user}
</div> documentId={documentId}
} authority={authority}
error={docAuthError} className={editorWrapClassNames}
errorContent={ style={{ fontSize }}
<div style={{ margin: '10vh', textAlign: 'center' }}>
<SecureDocumentIllustration />
</div>
}
normalContent={() => {
return (
<>
<Seo title={document.title} />
<Editor
user={user}
documentId={document.id}
authority={authority}
className={editorWrapClassNames}
style={{ fontSize }}
/>
</>
);
}}
/> />
</main> </main>
</div> </div>

View File

@ -76,34 +76,31 @@ export const DocumentReader: React.FC<IProps> = ({ documentId }) => {
}, [document]); }, [document]);
const actions = useMemo( const actions = useMemo(
() => () => (
docAuthLoading ? null : ( <Space>
<Space> {document && authority.readable && (
{document && authority.readable && ( <DocumentCollaboration key="collaboration" wikiId={document.wikiId} documentId={documentId} />
<DocumentCollaboration key="collaboration" wikiId={document.wikiId} documentId={documentId} /> )}
)} {authority && authority.editable && (
{authority && authority.editable && ( <Tooltip key="edit" content="编辑" position="bottom">
<Tooltip key="edit" content="编辑" position="bottom"> <Button icon={<IconEdit />} onMouseDown={gotoEdit} />
<Button icon={<IconEdit />} onMouseDown={gotoEdit} /> </Tooltip>
</Tooltip> )}
)} {authority && authority.readable && (
{authority && authority.readable && ( <>
<> <DocumentShare key="share" documentId={documentId} />
<DocumentShare key="share" documentId={documentId} /> <DocumentVersion key="version" documentId={documentId} />
<DocumentVersion key="version" documentId={documentId} /> <DocumentStar key="star" documentId={documentId} />
<DocumentStar key="star" documentId={documentId} /> </>
</> )}
)} <DocumentStyle />
<DocumentStyle /> </Space>
</Space> ),
), [document, documentId, authority, gotoEdit]
[docAuthLoading, document, documentId, authority, gotoEdit]
); );
const editBtnStyle = useMemo(() => getEditBtnStyle(isMobile ? 16 : 100), [isMobile]); const editBtnStyle = useMemo(() => getEditBtnStyle(isMobile ? 16 : 100), [isMobile]);
if (!documentId) return null;
return ( return (
<div className={styles.wrap}> <div className={styles.wrap}>
<Header className={styles.headerWrap}> <Header className={styles.headerWrap}>
@ -134,50 +131,31 @@ export const DocumentReader: React.FC<IProps> = ({ documentId }) => {
<Layout className={styles.contentWrap}> <Layout className={styles.contentWrap}>
<div ref={setContainer}> <div ref={setContainer}>
<div className={cls(styles.editorWrap, editorWrapClassNames)} style={{ fontSize }}> <div className={cls(styles.editorWrap, editorWrapClassNames)} style={{ fontSize }}>
<DataRender <div id="js-reader-container">
loading={docAuthLoading} {document && <Seo title={document.title} />}
error={docAuthError} {user && (
loadingContent={ <CollaborationEditor
<div style={{ margin: '10vh auto' }}> editable={false}
<Spin tip="正在为您读取文档中..."> user={user}
{/* FIXME: semi-design 的问题,不加 div文字会换行! */} id={documentId}
<div></div> type="document"
</Spin> renderInEditorPortal={renderAuthor}
onAwarenessUpdate={triggerJoinUser}
/>
)}
{user && (
<div className={styles.commentWrap}>
<CommentEditor documentId={documentId} />
</div> </div>
} )}
normalContent={() => { {!isMobile && authority && authority.editable && container && (
return ( <BackTop style={editBtnStyle} onClick={gotoEdit} target={() => container} visibilityHeight={200}>
<div id="js-reader-container"> <IconEdit />
<Seo title={document.title} /> </BackTop>
{user && ( )}
<CollaborationEditor <ImageViewer containerSelector="#js-reader-container" />
editable={false} {container && <BackTop style={{ bottom: 65, right: isMobile ? 16 : 100 }} target={() => container} />}
user={user} </div>
id={documentId}
type="document"
initialContent={document.content}
renderInEditorPortal={renderAuthor}
onAwarenessUpdate={triggerJoinUser}
/>
)}
{user && (
<div className={styles.commentWrap}>
<CommentEditor documentId={document.id} />
</div>
)}
{!isMobile && authority && authority.editable && container && (
<BackTop style={editBtnStyle} onClick={gotoEdit} target={() => container} visibilityHeight={200}>
<IconEdit />
</BackTop>
)}
<ImageViewer containerSelector="#js-reader-container" />
{container && (
<BackTop style={{ bottom: 65, right: isMobile ? 16 : 100 }} target={() => container} />
)}
</div>
);
}}
/>
</div> </div>
</div> </div>
</Layout> </Layout>

View File

@ -1,7 +1,6 @@
import { IconChevronLeft } from '@douyinfe/semi-icons'; import { IconChevronLeft } from '@douyinfe/semi-icons';
import { Button, Nav, Popconfirm, Space, Spin, Switch, Tooltip, Typography } from '@douyinfe/semi-ui'; import { Button, Nav, Popconfirm, Space, Switch, Tooltip, Typography } from '@douyinfe/semi-ui';
import cls from 'classnames'; import cls from 'classnames';
import { DataRender } from 'components/data-render';
import { DocumentStyle } from 'components/document/style'; import { DocumentStyle } from 'components/document/style';
import { Seo } from 'components/seo'; import { Seo } from 'components/seo';
import { Theme } from 'components/theme'; import { Theme } from 'components/theme';
@ -52,68 +51,55 @@ export const TemplateEditor: React.FC<IProps> = ({ templateId }) => {
}, [data]); }, [data]);
return ( return (
<DataRender <>
loading={loading} {data && <Seo title={data.title} />}
loadingContent={ <div className={styles.wrap}>
<div style={{ margin: 24 }}> <header>
<Spin></Spin> <Nav
</div> style={{ overflow: 'auto' }}
} mode="horizontal"
error={error} header={
normalContent={() => { <>
return ( <Tooltip content="返回" position="bottom">
<> <Button onClick={goback} icon={<IconChevronLeft />} style={{ marginRight: 16 }} />
<Seo title={data.title} /> </Tooltip>
<div className={styles.wrap}> <Text strong ellipsis={{ showTooltip: true }} style={{ width: ~~(windowWidth / 4) }}>
<header> {title}
<Nav </Text>
style={{ overflow: 'auto' }} </>
mode="horizontal" }
header={ footer={
<> <Space>
<Tooltip content="返回" position="bottom"> <DocumentStyle />
<Button onClick={goback} icon={<IconChevronLeft />} style={{ marginRight: 16 }} /> <Tooltip position="bottom" content={isPublic ? '公开模板' : '个人模板'}>
</Tooltip> <Switch checked={isPublic} onChange={(v) => updateTemplate({ isPublic: v })}></Switch>
<Text strong ellipsis={{ showTooltip: true }} style={{ width: ~~(windowWidth / 4) }}> </Tooltip>
{title} <Popconfirm title="删除模板" content="模板删除后不可恢复,谨慎操作!" onConfirm={handleDelte}>
</Text> <Button type="danger"></Button>
</> </Popconfirm>
} <Theme />
footer={ <User />
<Space> </Space>
<DocumentStyle /> }
<Tooltip position="bottom" content={isPublic ? '公开模板' : '个人模板'}> ></Nav>
<Switch checked={isPublic} onChange={(v) => updateTemplate({ isPublic: v })}></Switch> </header>
</Tooltip> <main className={styles.contentWrap}>
<Popconfirm title="删除模板" content="模板删除后不可恢复,谨慎操作!" onConfirm={handleDelte}> <div className={styles.editorWrap}>
<Button type="danger"></Button> <div className={cls(styles.contentWrap, editorWrapClassNames)} style={{ fontSize }}>
</Popconfirm> {mounted && data && (
<Theme /> <CollaborationEditor
<User /> menubar
</Space> editable
} user={user}
></Nav> id={data.id}
</header> type="template"
<main className={styles.contentWrap}> onTitleUpdate={setTitle}
<div className={styles.editorWrap}> />
<div className={cls(styles.contentWrap, editorWrapClassNames)} style={{ fontSize }}> )}
{mounted && (
<CollaborationEditor
menubar
editable
user={user}
id={data.id}
type="template"
onTitleUpdate={setTitle}
/>
)}
</div>
</div>
</main>
</div> </div>
</> </div>
); </main>
}} </div>
/> </>
); );
}; };

View File

@ -1,89 +0,0 @@
import { IconChevronLeft } from '@douyinfe/semi-icons';
import { Button, Nav, Popconfirm, Space, Switch, Tooltip, Typography } from '@douyinfe/semi-ui';
import { ILoginUser, ITemplate } from '@think/domains';
import cls from 'classnames';
import { DocumentStyle } from 'components/document/style';
import { Theme } from 'components/theme';
import { User } from 'components/user';
import { useDocumentStyle } from 'hooks/use-document-style';
import { useWindowSize } from 'hooks/use-window-size';
import Router from 'next/router';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { CollaborationEditor } from 'tiptap/editor';
import styles from './index.module.scss';
const { Text } = Typography;
interface IProps {
user: ILoginUser;
data: ITemplate;
updateTemplate: (arg) => Promise<ITemplate>;
deleteTemplate: () => Promise<void>;
}
export const Editor: React.FC<IProps> = ({ user, data, updateTemplate, deleteTemplate }) => {
const { width: windowWidth } = useWindowSize();
const [title, setTitle] = useState(data.title);
const [isPublic, setPublic] = useState(false);
const { width, fontSize } = useDocumentStyle();
const editorWrapClassNames = useMemo(() => {
return width === 'standardWidth' ? styles.isStandardWidth : styles.isFullWidth;
}, [width]);
const goback = useCallback(() => {
Router.back();
}, []);
const handleDelte = useCallback(() => {
deleteTemplate().then(() => {
goback();
});
}, [deleteTemplate, goback]);
useEffect(() => {
if (!data) return;
setPublic(data.isPublic);
}, [data]);
return (
<div className={styles.wrap}>
<header>
<Nav
style={{ overflow: 'auto' }}
mode="horizontal"
header={
<>
<Tooltip content="返回" position="bottom">
<Button onClick={goback} icon={<IconChevronLeft />} style={{ marginRight: 16 }} />
</Tooltip>
<Text strong ellipsis={{ showTooltip: true }} style={{ width: ~~(windowWidth / 4) }}>
{title}
</Text>
</>
}
footer={
<Space>
<DocumentStyle />
<Tooltip position="bottom" content={isPublic ? '公开模板' : '个人模板'}>
<Switch onChange={(v) => updateTemplate({ isPublic: v })}></Switch>
</Tooltip>
<Popconfirm title="删除模板" content="模板删除后不可恢复,谨慎操作!" onConfirm={handleDelte}>
<Button type="danger"></Button>
</Popconfirm>
<Theme />
<User />
</Space>
}
></Nav>
</header>
<main className={styles.contentWrap}>
<div className={styles.editorWrap}>
<div className={cls(styles.contentWrap, editorWrapClassNames)} style={{ fontSize }}>
<CollaborationEditor menubar editable user={user} id={data.id} type="template" onTitleUpdate={setTitle} />
</div>
</div>
</main>
</div>
);
};