client: optimize render actions

pull/60/head
fantasticit 2022-05-27 21:41:03 +08:00
parent a3b2e3d97d
commit eef782f096
3 changed files with 115 additions and 67 deletions

View File

@ -1,5 +1,5 @@
import { IconMore, IconPlus, IconStar } from '@douyinfe/semi-icons'; import { IconMore, IconPlus, IconStar } from '@douyinfe/semi-icons';
import { Button, Dropdown, Space, Typography } from '@douyinfe/semi-ui'; import { Button, Dropdown, Popover, Space, Typography } from '@douyinfe/semi-ui';
import { DocumentCreator } from 'components/document/create'; import { DocumentCreator } from 'components/document/create';
import { DocumentDeletor } from 'components/document/delete'; import { DocumentDeletor } from 'components/document/delete';
import { DocumentLinkCopyer } from 'components/document/link'; import { DocumentLinkCopyer } from 'components/document/link';
@ -29,22 +29,40 @@ export const DocumentActions: React.FC<IProps> = ({
showCreateDocument, showCreateDocument,
children, children,
}) => { }) => {
const [visible, toggleVisible] = useToggle(false); const [popoverVisible, togglePopoverVisible] = useToggle(false);
const [createVisible, toggleCreateVisible] = useToggle(false);
const prevent = useCallback((e) => { const create = useCallback(() => {
e.preventDefault(); togglePopoverVisible(false);
e.stopPropagation(); toggleCreateVisible(true);
}, []); }, [togglePopoverVisible, toggleCreateVisible]);
const wrapedOnDelete = useCallback(() => {
togglePopoverVisible(false);
onDelete && onDelete();
}, [onDelete, togglePopoverVisible]);
const wrapOnVisibleChange = useCallback(
(visible) => {
togglePopoverVisible(visible);
onVisibleChange && onVisibleChange();
},
[onVisibleChange, togglePopoverVisible]
);
return ( return (
<> <>
<Dropdown <Popover
onVisibleChange={onVisibleChange} showArrow
render={ style={{ padding: 0 }}
trigger="click"
visible={popoverVisible}
onVisibleChange={wrapOnVisibleChange}
content={
<Dropdown.Menu> <Dropdown.Menu>
{showCreateDocument && ( {showCreateDocument && (
<Dropdown.Item onClick={prevent}> <Dropdown.Item onClick={create}>
<Text onClick={toggleVisible}> <Text>
<Space> <Space>
<IconPlus /> <IconPlus />
@ -52,15 +70,16 @@ export const DocumentActions: React.FC<IProps> = ({
</Text> </Text>
</Dropdown.Item> </Dropdown.Item>
)} )}
<Dropdown.Item onClick={prevent}>
<DocumentStar <DocumentStar
documentId={documentId} documentId={documentId}
render={({ star, toggleStar, text }) => ( render={({ star, toggleStar, text }) => (
<Text <Dropdown.Item
onClick={() => { onClick={() => {
toggleStar().then(onStar); toggleStar().then(onStar);
}} }}
> >
<Text>
<Space> <Space>
<IconStar <IconStar
style={{ style={{
@ -70,27 +89,40 @@ export const DocumentActions: React.FC<IProps> = ({
{text} {text}
</Space> </Space>
</Text> </Text>
)} </Dropdown.Item>
/> )}
</Dropdown.Item> />
<Dropdown.Item onClick={prevent}>
<DocumentLinkCopyer wikiId={wikiId} documentId={documentId} /> <DocumentLinkCopyer
</Dropdown.Item> wikiId={wikiId}
documentId={documentId}
render={({ copy, children }) => {
return <Dropdown.Item onClick={copy}>{children}</Dropdown.Item>;
}}
/>
<Dropdown.Divider /> <Dropdown.Divider />
<Dropdown.Item onClick={prevent}>
<DocumentDeletor wikiId={wikiId} documentId={documentId} onDelete={onDelete} /> <DocumentDeletor
</Dropdown.Item> wikiId={wikiId}
documentId={documentId}
onDelete={wrapedOnDelete}
render={({ children }) => {
return <Dropdown.Item>{children}</Dropdown.Item>;
}}
/>
</Dropdown.Menu> </Dropdown.Menu>
} }
> >
{children || <Button onClick={prevent} icon={<IconMore />} theme="borderless" type="tertiary" />} {children || <Button icon={<IconMore />} theme="borderless" type="tertiary" />}
</Dropdown> </Popover>
{showCreateDocument && ( {showCreateDocument && (
<DocumentCreator <DocumentCreator
wikiId={wikiId} wikiId={wikiId}
parentDocumentId={documentId} parentDocumentId={documentId}
visible={visible} visible={createVisible}
toggleVisible={toggleVisible} toggleVisible={toggleCreateVisible}
onCreate={onCreate} onCreate={onCreate}
/> />
)} )}

View File

@ -1,52 +1,61 @@
import { IconDelete } from '@douyinfe/semi-icons'; import { IconDelete } from '@douyinfe/semi-icons';
import { Modal, Space, Typography } from '@douyinfe/semi-ui'; import { Modal, Popconfirm, Space, Typography } from '@douyinfe/semi-ui';
import { useDeleteDocument } from 'data/document'; import { useDeleteDocument } from 'data/document';
import { useRouterQuery } from 'hooks/use-router-query'; import { useRouterQuery } from 'hooks/use-router-query';
import Router from 'next/router'; import Router from 'next/router';
import React, { useCallback } from 'react'; import React, { useCallback, useMemo } from 'react';
interface IProps { interface IProps {
wikiId: string; wikiId: string;
documentId: string; documentId: string;
onDelete?: () => void; onDelete?: () => void;
render?: (arg: { children: React.ReactNode }) => React.ReactNode;
} }
const { Text } = Typography; const { Text } = Typography;
export const DocumentDeletor: React.FC<IProps> = ({ wikiId, documentId, onDelete }) => { export const DocumentDeletor: React.FC<IProps> = ({ wikiId, documentId, render, onDelete }) => {
const { wikiId: currentWikiId, documentId: currentDocumentId } = const { wikiId: currentWikiId, documentId: currentDocumentId } =
useRouterQuery<{ wikiId?: string; documentId?: string }>(); useRouterQuery<{ wikiId?: string; documentId?: string }>();
const { deleteDocument: api, loading } = useDeleteDocument(documentId); const { deleteDocument: api, loading } = useDeleteDocument(documentId);
const deleteAction = useCallback(() => { const deleteAction = useCallback(() => {
Modal.error({ api().then(() => {
title: '确定删除吗?', const navigate = () => {
content: <Text></Text>, if (wikiId !== currentWikiId || documentId !== currentDocumentId) {
onOk: () => { return;
api().then(() => { }
const navigate = () => { Router.push({
if (wikiId !== currentWikiId || documentId !== currentDocumentId) { pathname: `/wiki/${wikiId}`,
return;
}
Router.push({
pathname: `/wiki/${wikiId}`,
});
};
onDelete ? onDelete() : navigate();
}); });
}, };
okButtonProps: { loading, type: 'danger' },
style: { maxWidth: '96vw' }, onDelete ? onDelete() : navigate();
}); });
}, [wikiId, documentId, api, loading, onDelete, currentWikiId, currentDocumentId]); }, [wikiId, documentId, api, onDelete, currentWikiId, currentDocumentId]);
const content = useMemo(
() => (
<Text type="danger">
<Space>
<IconDelete />
</Space>
</Text>
),
[]
);
return ( return (
<Text type="danger" onClick={deleteAction}> <Popconfirm
<Space> title="确定删除吗?"
<IconDelete /> content="文档删除后不可恢复!"
onConfirm={deleteAction}
</Space> okButtonProps={{ loading }}
</Text> zIndex={1070}
showArrow
>
{render ? render({ children: content }) : content}
</Popconfirm>
); );
}; };

View File

@ -7,21 +7,28 @@ import React, { useCallback } from 'react';
interface IProps { interface IProps {
wikiId: string; wikiId: string;
documentId: string; documentId: string;
render?: (arg: { copy: () => void; children: React.ReactNode }) => React.ReactNode;
} }
const { Text } = Typography; const { Text } = Typography;
export const DocumentLinkCopyer: React.FC<IProps> = ({ wikiId, documentId }) => { export const DocumentLinkCopyer: React.FC<IProps> = ({ wikiId, documentId, render }) => {
const handle = useCallback(() => { const handle = useCallback(() => {
copy(buildUrl(`/wiki/${wikiId}/document/${documentId}`)); copy(buildUrl(`/wiki/${wikiId}/document/${documentId}`));
}, [wikiId, documentId]); }, [wikiId, documentId]);
return ( const content = (
<Space>
<IconLink />
</Space>
);
return render ? (
<>{render({ copy: handle, children: content })}</>
) : (
<Text onClick={handle} style={{ cursor: 'pointer' }}> <Text onClick={handle} style={{ cursor: 'pointer' }}>
<Space> {content}
<IconLink />
</Space>
</Text> </Text>
); );
}; };