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:
parent
5cb9529900
commit
17f9f3b00b
@ -450,7 +450,7 @@ export const InternalAdminLayout = (props: any) => {
|
|||||||
{params.name && <Layout.Sider className={styles.sider} theme={'light'} ref={sideMenuRef}></Layout.Sider>}
|
{params.name && <Layout.Sider className={styles.sider} theme={'light'} ref={sideMenuRef}></Layout.Sider>}
|
||||||
<Layout.Content className={styles.main}>
|
<Layout.Content className={styles.main}>
|
||||||
<header className={styles.mainHeader}></header>
|
<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.Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { useRef, useState } from 'react';
|
import React, { useRef, useState } from 'react';
|
||||||
|
import { uid } from '@tachybase/utils/client';
|
||||||
|
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { App } from 'antd';
|
import { App } from 'antd';
|
||||||
@ -92,56 +93,91 @@ export const disableRightMenu = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const checkedAutoPage = (position, message, t) => {
|
const checkedAutoPage = (position, message, t) => {
|
||||||
const layoutSider = document.querySelector('.ant-layout-sider');
|
const element = document.elementFromPoint(position?.x, position?.y);
|
||||||
const layoutContent = document.querySelector('.ant-layout-content');
|
const blockElement = element.closest('.ant-card');
|
||||||
const sibling = layoutContent.previousElementSibling;
|
const gridRow = blockElement?.closest('.CardRow');
|
||||||
if (!sibling.classList.contains('autoPage')) {
|
const navbar = document.querySelector('.ant-layout-header');
|
||||||
const element = document.elementFromPoint(position?.x, position?.y);
|
const modal = blockElement.closest('.ant-modal-body');
|
||||||
const blockElement = element.closest('.ant-card');
|
const amplifierBlock = blockElement.closest('.amplifier-block');
|
||||||
const navbar = document.querySelector('.ant-layout-header');
|
const navbarHeight = navbar.getBoundingClientRect();
|
||||||
const navbarHeight = navbar.getBoundingClientRect();
|
const classId = uid();
|
||||||
if (blockElement) {
|
if (blockElement) {
|
||||||
//需要展示的区块
|
const page = blockElement?.closest('.ant-nb-page ');
|
||||||
const copyBlockElement = blockElement.cloneNode(true);
|
const drawer = blockElement?.closest('.ant-drawer-body');
|
||||||
copyBlockElement.style.width = '100%';
|
const modal = blockElement?.closest('.ant-modal-body');
|
||||||
copyBlockElement.style.height = '90vh';
|
const tabNav = amplifierBlock.querySelector('.ant-tabs-nav');
|
||||||
copyBlockElement.style.overflow = 'auto';
|
if (tabNav) tabNav.style.display = 'none';
|
||||||
copyBlockElement.style.backgroundColor = '#ffffff';
|
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.marginTop = `${navbarHeight.height}px`;
|
||||||
autoNode.style.width = '100%';
|
const header = document.querySelector('.ant-page-header');
|
||||||
autoNode.className = 'autoPage';
|
const layoutSider = document.querySelector('.ant-layout-sider');
|
||||||
//退出按钮
|
header.style.display = 'none';
|
||||||
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);
|
|
||||||
layoutSider.style.display = 'none';
|
layoutSider.style.display = 'none';
|
||||||
layoutContent.style.display = 'none';
|
page.style.marginTop = '30px';
|
||||||
layoutContent?.parentNode.insertBefore(fragment, layoutContent);
|
page.insertAdjacentElement('beforebegin', autoNode);
|
||||||
} else {
|
} else if (drawer) {
|
||||||
message.warning(t('There are no full screen blocks available at the current location'));
|
autoNode.style.position = '';
|
||||||
|
drawer.insertAdjacentElement('beforebegin', autoNode);
|
||||||
|
} else if (modal) {
|
||||||
|
autoNode.style.position = '';
|
||||||
|
autoNode.style.width = '100%';
|
||||||
|
modal.insertAdjacentElement('beforebegin', autoNode);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
removeNode(layoutSider);
|
message.warning(t('There are no full screen blocks available at the current location'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeNode = (layoutSider) => {
|
const removeNode = ({ gridRow: blockElement, classId }) => {
|
||||||
const layoutContent = document.querySelector('.ant-layout-content');
|
const page = blockElement?.closest('.ant-nb-page ');
|
||||||
const sibling = layoutContent.previousElementSibling;
|
const drawer = blockElement?.closest('.ant-drawer-body');
|
||||||
layoutSider.style.display = 'block';
|
const parentNode = blockElement.parentNode;
|
||||||
layoutContent.style.display = 'block';
|
const tabNav = document.querySelector('.ant-tabs-nav');
|
||||||
if (sibling.classList.contains('autoPage')) sibling.parentNode.removeChild(sibling);
|
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);
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
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 classNames from 'classnames';
|
||||||
|
|
||||||
import { OpenSize } from './';
|
import { OpenSize } from './';
|
||||||
@ -61,6 +63,10 @@ export const ActionDrawer: ComposedActionDrawer = observer(
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
className={`${props.className} ${css`
|
||||||
|
position: relative;
|
||||||
|
padding-top: 30px;
|
||||||
|
`} amplifier-block`}
|
||||||
>
|
>
|
||||||
<RecursionField
|
<RecursionField
|
||||||
basePath={field.address}
|
basePath={field.address}
|
||||||
@ -70,6 +76,24 @@ export const ActionDrawer: ComposedActionDrawer = observer(
|
|||||||
return s['x-component'] !== footerNodeName;
|
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>
|
</Drawer>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -86,3 +110,27 @@ ActionDrawer.Footer = observer(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export default ActionDrawer;
|
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);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
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 { createStyles } from 'antd-style';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
@ -61,8 +63,18 @@ export const ActionModal: ComposedActionDrawer<ModalProps> = observer(
|
|||||||
}}
|
}}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
open={visible}
|
open={visible}
|
||||||
onCancel={() => setVisible(false, true)}
|
closable={false}
|
||||||
className={classNames(others.className, modalProps?.className, styles.container)}
|
className={classNames(
|
||||||
|
others.className,
|
||||||
|
modalProps?.className,
|
||||||
|
styles.container,
|
||||||
|
'amplifier-block',
|
||||||
|
css`
|
||||||
|
.ant-modal-content {
|
||||||
|
padding-top: 32px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
)}
|
||||||
footer={
|
footer={
|
||||||
footerSchema ? (
|
footerSchema ? (
|
||||||
<RecursionField
|
<RecursionField
|
||||||
@ -86,6 +98,24 @@ export const ActionModal: ComposedActionDrawer<ModalProps> = observer(
|
|||||||
return s['x-component'] !== footerNodeName;
|
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>
|
</Modal>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -102,3 +132,39 @@ ActionModal.Footer = observer(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export default ActionModal;
|
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);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -57,6 +57,7 @@ export const ActionSheet: ComposedActionDrawer = observer(
|
|||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
}
|
}
|
||||||
|
className={`${props.className} amplifier-block`}
|
||||||
>
|
>
|
||||||
<RecursionField
|
<RecursionField
|
||||||
basePath={field.address}
|
basePath={field.address}
|
||||||
|
@ -504,7 +504,7 @@ Grid.Col = observer(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<GridColContext.Provider value={{ cols, schema }}>
|
<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}
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
</GridColContext.Provider>
|
</GridColContext.Provider>
|
||||||
|
Loading…
Reference in New Issue
Block a user