mirror of
https://github.com/strapi/strapi.git
synced 2025-09-09 16:47:06 +00:00
commit
4be4b3ef01
BIN
packages/core/admin/admin/src/assets/images/big-logo-home.png
Normal file
BIN
packages/core/admin/admin/src/assets/images/big-logo-home.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
BIN
packages/core/admin/admin/src/assets/images/hot-air-balloon.png
Normal file
BIN
packages/core/admin/admin/src/assets/images/hot-air-balloon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 491 KiB |
BIN
packages/core/admin/admin/src/assets/images/upgrade-details.png
Normal file
BIN
packages/core/admin/admin/src/assets/images/upgrade-details.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.2 KiB |
@ -0,0 +1,126 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { Portal } from '@strapi/parts/Portal';
|
||||
import { FocusTrap } from '@strapi/parts/FocusTrap';
|
||||
import { IconButton } from '@strapi/parts/IconButton';
|
||||
import { LinkButton } from '@strapi/parts/LinkButton';
|
||||
import { Box } from '@strapi/parts/Box';
|
||||
import { Row } from '@strapi/parts/Row';
|
||||
import { Text, H1 } from '@strapi/parts/Text';
|
||||
import { Stack } from '@strapi/parts/Stack';
|
||||
import ExternalLink from '@strapi/icons/ExternalLink';
|
||||
import CloseAlertIcon from '@strapi/icons/CloseAlertIcon';
|
||||
import { setHexOpacity, useLockScroll } from '@strapi/helper-plugin';
|
||||
import AirBalloon from '../../assets/images/hot-air-balloon.png';
|
||||
import BigArrow from '../../assets/images/upgrade-details.png';
|
||||
|
||||
const UpgradeWrapper = styled.div`
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
inset: 0;
|
||||
background: ${({ theme }) => setHexOpacity(theme.colors.neutral800, 0.2)};
|
||||
padding: 0 ${({ theme }) => theme.spaces[8]};
|
||||
`;
|
||||
|
||||
const UpgradeContainer = styled(Row)`
|
||||
position: relative;
|
||||
max-width: ${830 / 16}rem;
|
||||
height: ${415 / 16}rem;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
margin-top: 10%;
|
||||
padding-left: ${64 / 16}rem;
|
||||
|
||||
img:first-of-type {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
max-width: ${360 / 16}rem;
|
||||
}
|
||||
|
||||
img:not(:first-of-type) {
|
||||
width: ${130 / 16}rem;
|
||||
margin-left: 12%;
|
||||
margin-right: ${20 / 16}rem;
|
||||
z-index: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const TextBold = styled(Text)`
|
||||
font-weight: 700;
|
||||
`;
|
||||
|
||||
const StackFlexStart = styled(Stack)`
|
||||
align-items: flex-start;
|
||||
max-width: ${400 / 16}rem;
|
||||
z-index: 0;
|
||||
`;
|
||||
|
||||
const CloseButtonContainer = styled(Box)`
|
||||
position: absolute;
|
||||
right: ${({ theme }) => theme.spaces[4]};
|
||||
top: ${({ theme }) => theme.spaces[4]};
|
||||
`;
|
||||
|
||||
const UpgradePlanModal = ({ onClose, isOpen }) => {
|
||||
useLockScroll(isOpen);
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<UpgradeWrapper>
|
||||
<FocusTrap onClose={onClose}>
|
||||
<UpgradeContainer aria-labelledby="upgrade-plan" background="neutral0" hasRadius>
|
||||
<img src={AirBalloon} alt="air-balloon" />
|
||||
<CloseButtonContainer>
|
||||
<IconButton onClick={onClose} label="Close" icon={<CloseAlertIcon />} />
|
||||
</CloseButtonContainer>
|
||||
<StackFlexStart size={6}>
|
||||
<TextBold textColor="primary600">
|
||||
{formatMessage({
|
||||
id: 'app.components.UpgradePlanModal.text-ce',
|
||||
defaultMessage: 'COMMUNITY EDITION',
|
||||
})}
|
||||
</TextBold>
|
||||
<Stack size={2}>
|
||||
<H1 as="h2" id="upgrade-plan">
|
||||
{formatMessage({
|
||||
id: 'app.components.UpgradePlanModal.limit-reached',
|
||||
defaultMessage: 'You have reached the limit',
|
||||
})}
|
||||
</H1>
|
||||
<Text>
|
||||
{formatMessage({
|
||||
id: 'app.components.UpgradePlanModal.text-power',
|
||||
defaultMessage:
|
||||
'Unlock the full power of Strapi by upgrading your plan to the Enterprise Edition',
|
||||
})}
|
||||
</Text>
|
||||
</Stack>
|
||||
<LinkButton href="https://strapi.io/pricing-self-hosted" endIcon={<ExternalLink />}>
|
||||
{formatMessage({
|
||||
id: 'app.components.UpgradePlanModal.button',
|
||||
defaultMessage: 'Learn more',
|
||||
})}
|
||||
</LinkButton>
|
||||
</StackFlexStart>
|
||||
<img src={BigArrow} alt="upgrade-arrow" />
|
||||
</UpgradeContainer>
|
||||
</FocusTrap>
|
||||
</UpgradeWrapper>
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
|
||||
UpgradePlanModal.propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default UpgradePlanModal;
|
@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { ThemeProvider, lightTheme } from '@strapi/parts';
|
||||
import UpgradePlanModal from '../index';
|
||||
|
||||
const App = (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<IntlProvider locale="en" messages={{ en: {} }} textComponent="span">
|
||||
<UpgradePlanModal isOpen onClose={jest.fn()} />
|
||||
</IntlProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
describe('UpgradePlanModal', () => {
|
||||
it('renders and matches the snapshot', async () => {
|
||||
const {
|
||||
container: { firstChild },
|
||||
} = render(App);
|
||||
|
||||
expect(firstChild).toMatchInlineSnapshot(`
|
||||
.c0 {
|
||||
border: 0;
|
||||
-webkit-clip: rect(0 0 0 0);
|
||||
clip: rect(0 0 0 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
<div
|
||||
class="c0"
|
||||
>
|
||||
<p
|
||||
aria-live="polite"
|
||||
id="live-region-log"
|
||||
role="log"
|
||||
/>
|
||||
<p
|
||||
aria-live="polite"
|
||||
id="live-region-status"
|
||||
role="status"
|
||||
/>
|
||||
<p
|
||||
aria-live="assertive"
|
||||
id="live-region-alert"
|
||||
role="alert"
|
||||
/>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
|
||||
it('renders and matches the snapshot', async () => {
|
||||
render(App);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('You have reached the limit')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
Binary file not shown.
Before Width: | Height: | Size: 13 KiB |
@ -1,16 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
import logo from './arrow.png';
|
||||
|
||||
const Img = styled.img`
|
||||
position: absolute;
|
||||
top: 130px;
|
||||
right: 195px;
|
||||
height: 82px;
|
||||
`;
|
||||
|
||||
Img.defaultProps = {
|
||||
alt: 'arrow',
|
||||
src: logo,
|
||||
};
|
||||
|
||||
export default Img;
|
@ -1,13 +0,0 @@
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Download = styled(FontAwesomeIcon)`
|
||||
margin-left: 10px;
|
||||
transform: rotate(-45deg);
|
||||
`;
|
||||
|
||||
Download.defaultProps = {
|
||||
icon: 'arrow-right',
|
||||
};
|
||||
|
||||
export default Download;
|
@ -1,12 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
height: 25px;
|
||||
max-width: fit-content;
|
||||
padding: 0 15px;
|
||||
background: rgba(0, 126, 255, 0.08);
|
||||
border: 1px solid rgba(0, 126, 255, 0.24);
|
||||
border-radius: 2px;
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
@ -1,18 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Text } from '@buffetjs/core';
|
||||
import { useIntl } from 'react-intl';
|
||||
import Wrapper from './Wrapper';
|
||||
|
||||
const Option = () => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
return (
|
||||
<Wrapper left right size="xs">
|
||||
<Text color="mediumBlue" lineHeight="23px">
|
||||
{formatMessage({ id: 'app.components.UpgradePlanModal.text-ce' })}
|
||||
</Text>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Option;
|
Binary file not shown.
Before Width: | Height: | Size: 423 KiB |
@ -1,14 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
import Balloon from './balloon.png';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
height: 390px;
|
||||
width: 100%;
|
||||
padding-top: 89px;
|
||||
padding-left: 65px;
|
||||
background-image: url(${Balloon});
|
||||
background-size: contain;
|
||||
background-position: right;
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
@ -1,4 +0,0 @@
|
||||
export { default as Arrow } from './Arrow';
|
||||
export { default as Download } from './Download';
|
||||
export { default as Option } from './Option';
|
||||
export { default as Wrapper } from './Wrapper';
|
@ -1,91 +0,0 @@
|
||||
/* eslint-disable jsx-a11y/anchor-has-content */
|
||||
/* eslint-disable jsx-a11y/control-has-associated-label */
|
||||
import React, { useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Padded, Text } from '@buffetjs/core';
|
||||
import { Modal } from '@strapi/helper-plugin';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { Arrow, Download, Option, Wrapper } from './components';
|
||||
|
||||
const UpgradePlanModal = ({ isOpen, onToggle }) => {
|
||||
const ref = useRef();
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const handleClick = () => {
|
||||
ref.current.click();
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onToggle={onToggle} closeButtonColor="#fff">
|
||||
<Wrapper>
|
||||
<Padded>
|
||||
<Option />
|
||||
<Padded top size="smd">
|
||||
<Padded top size="xs">
|
||||
<Text fontSize="xl" fontWeight="bold" lineHeight="24px">
|
||||
{formatMessage({
|
||||
id: 'app.components.UpgradePlanModal.limit-reached',
|
||||
defaultMessage: 'You have reached the limit',
|
||||
})}
|
||||
</Text>
|
||||
</Padded>
|
||||
</Padded>
|
||||
<Padded style={{ maxWidth: 405 }} top size="smd">
|
||||
<Text color="black" lineHeight="18px">
|
||||
<Text as="span" fontSize="md" fontWeight="semiBold">
|
||||
{formatMessage({
|
||||
id: 'app.components.UpgradePlanModal.text-power',
|
||||
defaultMessage: 'Unlock the full power',
|
||||
})}
|
||||
</Text>
|
||||
|
||||
<Text as="span" fontSize="md">
|
||||
{formatMessage({
|
||||
id: 'app.components.UpgradePlanModal.text-strapi',
|
||||
defaultMessage: 'of Strapi by upgrading your plan to the',
|
||||
})}
|
||||
</Text>
|
||||
<br />
|
||||
<Text as="span" fontSize="md" fontWeight="semiBold">
|
||||
{formatMessage({
|
||||
id: 'app.components.UpgradePlanModal.text-ee',
|
||||
defaultMessage: 'Enterprise Edititon',
|
||||
})}
|
||||
</Text>
|
||||
</Text>
|
||||
</Padded>
|
||||
<Padded top size="md">
|
||||
<Button color="primary" onClick={handleClick} style={{ paddingRight: 0 }}>
|
||||
{formatMessage({
|
||||
id: 'app.components.UpgradePlanModal.button',
|
||||
defaultMessage: 'LEARN MORE',
|
||||
})}
|
||||
<Download />
|
||||
</Button>
|
||||
</Padded>
|
||||
</Padded>
|
||||
<Arrow />
|
||||
</Wrapper>
|
||||
|
||||
<a
|
||||
href="https://strapi.io/pricing"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{ display: 'none' }}
|
||||
ref={ref}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
UpgradePlanModal.defaultProps = {
|
||||
isOpen: false,
|
||||
onToggle: () => {},
|
||||
};
|
||||
|
||||
UpgradePlanModal.propTypes = {
|
||||
isOpen: PropTypes.bool,
|
||||
onToggle: PropTypes.func,
|
||||
};
|
||||
|
||||
export default UpgradePlanModal;
|
@ -186,7 +186,7 @@ const RoleListPage = () => {
|
||||
</Table>
|
||||
{!rowCount && !isLoading && <EmptyRole />}
|
||||
</ContentLayout>
|
||||
<UpgradePlanModal isOpen={isModalOpen} onToggle={handleToggle} />
|
||||
<UpgradePlanModal isOpen={isModalOpen} onClose={handleToggle} />
|
||||
</Main>
|
||||
);
|
||||
};
|
||||
|
@ -400,10 +400,6 @@ describe('<ListPage />', () => {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.c37 {
|
||||
font-family: Lato;
|
||||
}
|
||||
|
||||
<main
|
||||
aria-labelledby="title"
|
||||
class="c0"
|
||||
@ -612,9 +608,6 @@ describe('<ListPage />', () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="c37"
|
||||
/>
|
||||
</main>
|
||||
`);
|
||||
});
|
||||
|
@ -279,11 +279,11 @@
|
||||
"app.components.PluginCard.compatible": "Compatible with your app",
|
||||
"app.components.PluginCard.compatibleCommunity": "Compatible with the community",
|
||||
"app.components.PluginCard.more-details": "More details",
|
||||
"app.components.UpgradePlanModal.button": "LEARN MORE",
|
||||
"app.components.UpgradePlanModal.button": "Learn more",
|
||||
"app.components.UpgradePlanModal.limit-reached": "You have reached the limit",
|
||||
"app.components.UpgradePlanModal.text-ce": "Community Edition",
|
||||
"app.components.UpgradePlanModal.text-ce": "COMMUNITY EDITION",
|
||||
"app.components.UpgradePlanModal.text-ee": "Enterprise Edition",
|
||||
"app.components.UpgradePlanModal.text-power": "Unlock the full power",
|
||||
"app.components.UpgradePlanModal.text-power": "Unlock the full power of Strapi by upgrading your plan to the Enterprise Edition",
|
||||
"app.components.UpgradePlanModal.text-strapi": "of Strapi by upgrading your plan to the",
|
||||
"app.components.Users.MagicLink.connect": "Send this link to the user for them to connect.",
|
||||
"app.components.Users.MagicLink.connect.sso": "Send this link to the user, the first login can be made via a SSO provider",
|
||||
|
@ -0,0 +1,15 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const useLockScroll = lockScroll => {
|
||||
useEffect(() => {
|
||||
if (lockScroll) {
|
||||
document.body.classList.add('lock-body-scroll');
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.body.classList.remove('lock-body-scroll');
|
||||
};
|
||||
}, [lockScroll]);
|
||||
};
|
||||
|
||||
export default useLockScroll;
|
@ -0,0 +1,36 @@
|
||||
<!--- useLockScroll.stories.mdx --->
|
||||
|
||||
import { Meta } from '@storybook/addon-docs';
|
||||
|
||||
<Meta title="hooks/useLockScroll" />
|
||||
|
||||
# useLockScroll
|
||||
|
||||
This hook is used in order to display a notification in the admin panel.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
import { useLockScroll } from '@strapi/helper-plugin';
|
||||
|
||||
const Modal = ({ onToggle, isOpen }) => {
|
||||
// boolean required to activate locked scroll when modal is open
|
||||
useLockScroll(isOpen);
|
||||
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<ModalWrapper>
|
||||
<FocusTrap onClose={onToggle}>
|
||||
<ModalContainer>
|
||||
Content of the modal
|
||||
</ModalContainer>
|
||||
</FocusTrap>
|
||||
</ModalWrapper>
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
```
|
@ -127,6 +127,7 @@ export { default as useRBACProvider } from './hooks/useRBACProvider';
|
||||
export { default as useRBAC } from './hooks/useRBAC';
|
||||
export { default as usePersistentState } from './hooks/usePersistentState';
|
||||
export { default as useFocusWhenNavigate } from './hooks/useFocusWhenNavigate';
|
||||
export { default as useLockScroll } from './hooks/useLockScroll';
|
||||
|
||||
// Providers
|
||||
export { default as LibraryProvider } from './providers/LibraryProvider';
|
||||
@ -164,6 +165,9 @@ export { default as prefixPluginTranslations } from './old/utils/prefixPluginTra
|
||||
export { default as pxToRem } from './utils/pxToRem';
|
||||
export { default as to } from './utils/await-to-js';
|
||||
|
||||
// NEW UTILS
|
||||
export { default as setHexOpacity } from './utils/setHexOpacity';
|
||||
|
||||
// SVGS
|
||||
export { default as LayoutIcon } from './old/svgs/Layout';
|
||||
export { default as ClearIcon } from './old/svgs/Clear';
|
||||
|
@ -0,0 +1,6 @@
|
||||
const setHexOpacity = (hex, alpha) =>
|
||||
`${hex}${Math.floor(alpha * 255)
|
||||
.toString(16)
|
||||
.padStart(2, 0)}`;
|
||||
|
||||
export default setHexOpacity;
|
@ -0,0 +1,23 @@
|
||||
<!--- setHexOpacity.stories.mdx --->
|
||||
|
||||
import { Meta } from '@storybook/addon-docs';
|
||||
|
||||
<Meta title="utils/setHexOpacity" />
|
||||
|
||||
# setHexOpacity
|
||||
|
||||
This hook is used in order to display a notification in the admin panel.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
import { setHexOpacity } from '@strapi/helper-plugin';
|
||||
|
||||
const BoxCustom = styled.div`
|
||||
// using strapi theme hex
|
||||
background: ${({ theme }) => setHexOpacity(theme.colors.neutral800, 0.2)};
|
||||
|
||||
// using hex
|
||||
background: setHexOpacity('#12100E', 0.2)};
|
||||
`;
|
||||
```
|
Loading…
x
Reference in New Issue
Block a user