mirror of https://github.com/fantasticit/think.git
client: improve render editor
parent
6768ecc0e2
commit
a534e799c1
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
/>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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>
|
|
||||||
);
|
|
||||||
};
|
|
Loading…
Reference in New Issue