fix: 完善右键全屏 (#1572)

Reviewed-on: daoyoucloud/tachybase#1572
Co-authored-by: wjh <wwwjh0710@163.com>
Co-committed-by: wjh <wwwjh0710@163.com>
This commit is contained in:
wjh 2024-09-27 12:04:30 +08:00 committed by bai.zixv
parent 5cb9529900
commit 17f9f3b00b
6 changed files with 203 additions and 52 deletions

View File

@ -450,7 +450,7 @@ export const InternalAdminLayout = (props: any) => {
{params.name && <Layout.Sider className={styles.sider} theme={'light'} ref={sideMenuRef}></Layout.Sider>}
<Layout.Content className={styles.main}>
<header className={styles.mainHeader}></header>
{params.name && pageStyle === 'tab' ? <PageTab /> : <Outlet />}
<div className="amplifier-block">{params.name && pageStyle === 'tab' ? <PageTab /> : <Outlet />}</div>
</Layout.Content>
</Layout>
);

View File

@ -1,4 +1,5 @@
import React, { useRef, useState } from 'react';
import { uid } from '@tachybase/utils/client';
import { css } from '@emotion/css';
import { App } from 'antd';
@ -92,56 +93,91 @@ export const disableRightMenu = {
};
const checkedAutoPage = (position, message, t) => {
const layoutSider = document.querySelector('.ant-layout-sider');
const layoutContent = document.querySelector('.ant-layout-content');
const sibling = layoutContent.previousElementSibling;
if (!sibling.classList.contains('autoPage')) {
const element = document.elementFromPoint(position?.x, position?.y);
const blockElement = element.closest('.ant-card');
const navbar = document.querySelector('.ant-layout-header');
const navbarHeight = navbar.getBoundingClientRect();
if (blockElement) {
//需要展示的区块
const copyBlockElement = blockElement.cloneNode(true);
copyBlockElement.style.width = '100%';
copyBlockElement.style.height = '90vh';
copyBlockElement.style.overflow = 'auto';
copyBlockElement.style.backgroundColor = '#ffffff';
const element = document.elementFromPoint(position?.x, position?.y);
const blockElement = element.closest('.ant-card');
const gridRow = blockElement?.closest('.CardRow');
const navbar = document.querySelector('.ant-layout-header');
const modal = blockElement.closest('.ant-modal-body');
const amplifierBlock = blockElement.closest('.amplifier-block');
const navbarHeight = navbar.getBoundingClientRect();
const classId = uid();
if (blockElement) {
const page = blockElement?.closest('.ant-nb-page ');
const drawer = blockElement?.closest('.ant-drawer-body');
const modal = blockElement?.closest('.ant-modal-body');
const tabNav = amplifierBlock.querySelector('.ant-tabs-nav');
if (tabNav) tabNav.style.display = 'none';
const parentNode = gridRow.parentNode;
Array.from(parentNode.children).forEach((sibling) => {
if (sibling !== gridRow) {
sibling.style.display = 'none';
}
});
const autoNode = document.createElement('div');
autoNode.style.width = amplifierBlock.getBoundingClientRect().width + 'px';
autoNode.className = 'autoPage' + classId;
autoNode.style.position = 'fixed';
autoNode.style.top = '0';
autoNode.style.zIndex = '100';
//退出按钮
const exitNode = document.createElement('div');
exitNode.style.width = '100%';
exitNode.style.height = '30px';
exitNode.style.textAlign = 'center';
exitNode.style.lineHeight = '30px';
exitNode.style.backgroundColor = '#e6e6e6';
exitNode.textContent = `${t('Exit Full Screen')}`;
autoNode.appendChild(exitNode);
autoNode.addEventListener('click', () => {
removeNode({ gridRow, classId });
});
const autoNode = document.createElement('div');
if (page) {
autoNode.style.marginTop = `${navbarHeight.height}px`;
autoNode.style.width = '100%';
autoNode.className = 'autoPage';
//退出按钮
const exitNode = document.createElement('div');
exitNode.style.width = '100%';
exitNode.style.height = '4vh';
exitNode.style.textAlign = 'center';
exitNode.style.lineHeight = '4vh';
exitNode.style.backgroundColor = '#e6e6e6';
exitNode.textContent = `${t('Exit Full Screen')}`;
autoNode.appendChild(exitNode);
autoNode.appendChild(copyBlockElement);
autoNode.addEventListener('click', () => {
removeNode(layoutSider);
});
const fragment = document.createDocumentFragment();
fragment.appendChild(autoNode);
const header = document.querySelector('.ant-page-header');
const layoutSider = document.querySelector('.ant-layout-sider');
header.style.display = 'none';
layoutSider.style.display = 'none';
layoutContent.style.display = 'none';
layoutContent?.parentNode.insertBefore(fragment, layoutContent);
} else {
message.warning(t('There are no full screen blocks available at the current location'));
page.style.marginTop = '30px';
page.insertAdjacentElement('beforebegin', autoNode);
} else if (drawer) {
autoNode.style.position = '';
drawer.insertAdjacentElement('beforebegin', autoNode);
} else if (modal) {
autoNode.style.position = '';
autoNode.style.width = '100%';
modal.insertAdjacentElement('beforebegin', autoNode);
}
} else {
removeNode(layoutSider);
message.warning(t('There are no full screen blocks available at the current location'));
}
};
const removeNode = (layoutSider) => {
const layoutContent = document.querySelector('.ant-layout-content');
const sibling = layoutContent.previousElementSibling;
layoutSider.style.display = 'block';
layoutContent.style.display = 'block';
if (sibling.classList.contains('autoPage')) sibling.parentNode.removeChild(sibling);
const removeNode = ({ gridRow: blockElement, classId }) => {
const page = blockElement?.closest('.ant-nb-page ');
const drawer = blockElement?.closest('.ant-drawer-body');
const parentNode = blockElement.parentNode;
const tabNav = document.querySelector('.ant-tabs-nav');
if (tabNav) tabNav.style.display = '';
Array.from(parentNode.children).forEach((sibling) => {
if (sibling !== blockElement) {
sibling.style.display = '';
}
if ((sibling.id as string).includes('DndDescribedBy')) {
sibling.style.display = 'none';
}
});
if (page) {
page.style.marginTop = '';
const layoutSider = document.querySelector('.ant-layout-sider');
const header = document.querySelector('.ant-page-header');
layoutSider.style.display = '';
header.style.display = '';
} else if (drawer) {
drawer.style.marginTop = '';
}
const autoPage = document.querySelector('.autoPage' + classId);
if (autoPage) autoPage.parentNode.removeChild(autoPage);
};

View File

@ -1,7 +1,9 @@
import React from 'react';
import React, { useState } from 'react';
import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
import { Drawer } from 'antd';
import { ArrowsAltOutlined, CloseOutlined, FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons';
import { css } from '@emotion/css';
import { Button, Drawer } from 'antd';
import classNames from 'classnames';
import { OpenSize } from './';
@ -61,6 +63,10 @@ export const ActionDrawer: ComposedActionDrawer = observer(
</div>
)
}
className={`${props.className} ${css`
position: relative;
padding-top: 30px;
`} amplifier-block`}
>
<RecursionField
basePath={field.address}
@ -70,6 +76,24 @@ export const ActionDrawer: ComposedActionDrawer = observer(
return s['x-component'] !== footerNodeName;
}}
/>
<div
className={css`
position: absolute;
top: 0;
right: 5px;
display: flex;
`}
>
<Amplifier />
<Button
icon={<CloseOutlined />}
className={css`
background: none;
border: none;
`}
onClick={() => setVisible(false, true)}
/>
</div>
</Drawer>
);
},
@ -86,3 +110,27 @@ ActionDrawer.Footer = observer(
);
export default ActionDrawer;
export const Amplifier = () => {
const [isAmplifier, setIsAmplifier] = useState(false);
const [blockWidth, setBlockWidth] = useState('');
return (
<Button
icon={isAmplifier ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
className={css`
background: none;
border: none;
`}
onClick={(e) => {
const element = e.target.closest('.ant-drawer-content-wrapper');
if (isAmplifier) {
element.style.width = blockWidth;
} else {
setBlockWidth(element.getBoundingClientRect().width + 'px');
element.style.width = '100%';
}
setIsAmplifier(!isAmplifier);
}}
/>
);
};

View File

@ -1,7 +1,9 @@
import React from 'react';
import React, { useState } from 'react';
import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
import { Modal, ModalProps } from 'antd';
import { CloseOutlined, FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons';
import { css } from '@emotion/css';
import { Button, Modal, ModalProps } from 'antd';
import { createStyles } from 'antd-style';
import classNames from 'classnames';
@ -61,8 +63,18 @@ export const ActionModal: ComposedActionDrawer<ModalProps> = observer(
}}
destroyOnClose
open={visible}
onCancel={() => setVisible(false, true)}
className={classNames(others.className, modalProps?.className, styles.container)}
closable={false}
className={classNames(
others.className,
modalProps?.className,
styles.container,
'amplifier-block',
css`
.ant-modal-content {
padding-top: 32px;
}
`,
)}
footer={
footerSchema ? (
<RecursionField
@ -86,6 +98,24 @@ export const ActionModal: ComposedActionDrawer<ModalProps> = observer(
return s['x-component'] !== footerNodeName;
}}
/>
<div
className={css`
position: absolute;
top: 0;
right: 5px;
display: flex;
`}
>
<Amplifier />
<Button
icon={<CloseOutlined />}
className={css`
background: none;
border: none;
`}
onClick={() => setVisible(false, true)}
/>
</div>
</Modal>
);
},
@ -102,3 +132,39 @@ ActionModal.Footer = observer(
);
export default ActionModal;
export const Amplifier = () => {
const [isAmplifier, setIsAmplifier] = useState(false);
const [blockWidth, setBlockWidth] = useState('');
return (
<Button
icon={isAmplifier ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
className={css`
background: none;
border: none;
`}
onClick={(e) => {
const element = e.target.closest('.ant-modal-content');
const modal = document.querySelector('.ant-modal');
const mask = document.querySelector('.ant-modal-mask');
if (isAmplifier) {
modal.style.width = blockWidth;
element.style.width = '';
modal.style.top = '';
modal.style.padding = '';
modal.style.margin = '';
mask.style.backgroundColor = '';
} else {
setBlockWidth(modal.getBoundingClientRect().width + 'px');
element.style.width = '100vw';
modal.style.width = '100%';
modal.style.top = '0';
modal.style.padding = '0';
modal.style.margin = '0';
mask.style.backgroundColor = '#f3f3f3';
}
setIsAmplifier(!isAmplifier);
}}
/>
);
};

View File

@ -57,6 +57,7 @@ export const ActionSheet: ComposedActionDrawer = observer(
</Button>
</Space>
}
className={`${props.className} amplifier-block`}
>
<RecursionField
basePath={field.address}

View File

@ -504,7 +504,7 @@ Grid.Col = observer(
return (
<GridColContext.Provider value={{ cols, schema }}>
<div ref={setNodeRef} style={{ ...style, ...droppableStyle }} className={cls('nb-grid-col')}>
<div ref={setNodeRef} style={{ ...style, ...droppableStyle }} className={cls('nb-grid-col CardCol')}>
{props.children}
</div>
</GridColContext.Provider>