mirror of
https://github.com/strapi/strapi.git
synced 2025-11-27 15:40:36 +00:00
Merge branch 'upgrade-plan' of https://github.com/strapi/strapi into upgrade-plan
This commit is contained in:
commit
0c0d8b940c
@ -0,0 +1,33 @@
|
|||||||
|
<!--- UpgradePlanModal.stories.mdx --->
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { ArgsTable, Meta, Canvas, Story } from '@storybook/addon-docs';
|
||||||
|
import { Button } from '@strapi/parts/Button';
|
||||||
|
import UpgradePlanModal from './index';
|
||||||
|
|
||||||
|
<Meta title="components/UpgradePlanModal" />
|
||||||
|
|
||||||
|
# UpgradePlanModal
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Story name="base">
|
||||||
|
{() => {
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
const handleToggle = () => setIsVisible(prev => !prev);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button onClick={handleToggle}>Click me</Button>
|
||||||
|
<UpgradePlanModal isOpen={isVisible} onClose={handleToggle} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Story>
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
### Props
|
||||||
|
|
||||||
|
<ArgsTable of={UpgradePlanModal} />
|
||||||
@ -0,0 +1,127 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
import { setOpacity } from '../../utils/setOpacity';
|
||||||
|
import { useLockScroll } from '../../utils/useLockScroll';
|
||||||
|
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 AirBalloon from './../../../../../admin/admin/src/assets/images/hot-air-balloon.png';
|
||||||
|
import BigArrow from './../../../../../admin/admin/src/assets/images/upgrade-details.png';
|
||||||
|
|
||||||
|
const UpragdeWrapper = styled.div`
|
||||||
|
position: absolute;
|
||||||
|
z-index: 3;
|
||||||
|
inset: 0;
|
||||||
|
background: ${({ theme }) => setOpacity(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: bold;
|
||||||
|
`;
|
||||||
|
|
||||||
|
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>
|
||||||
|
<UpragdeWrapper>
|
||||||
|
<FocusTrap onClose={onClose}>
|
||||||
|
<UpgradeContainer aria-labelledby="upgrade-plan" background="neutral0" hasRadius>
|
||||||
|
<img src={AirBalloon} />
|
||||||
|
<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} />
|
||||||
|
</UpgradeContainer>
|
||||||
|
</FocusTrap>
|
||||||
|
</UpragdeWrapper>
|
||||||
|
</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={true} 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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -186,6 +186,7 @@ export { default as LoadingIndicatorPage } from './components/LoadingIndicatorPa
|
|||||||
export { default as SettingsPageTitle } from './components/SettingsPageTitle';
|
export { default as SettingsPageTitle } from './components/SettingsPageTitle';
|
||||||
export { default as Search } from './components/Search';
|
export { default as Search } from './components/Search';
|
||||||
export { default as Status } from './components/Status';
|
export { default as Status } from './components/Status';
|
||||||
|
export { default as UpgradePlanModal } from './components/UpgradePlanModal';
|
||||||
|
|
||||||
// New icons
|
// New icons
|
||||||
export { default as SortIcon } from './icons/SortIcon';
|
export { default as SortIcon } from './icons/SortIcon';
|
||||||
|
|||||||
4
packages/core/helper-plugin/lib/src/utils/setOpacity.js
Normal file
4
packages/core/helper-plugin/lib/src/utils/setOpacity.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export const setOpacity = (hex, alpha) =>
|
||||||
|
`${hex}${Math.floor(alpha * 255)
|
||||||
|
.toString(16)
|
||||||
|
.padStart(2, 0)}`;
|
||||||
12
packages/core/helper-plugin/lib/src/utils/useLockScroll.js
Normal file
12
packages/core/helper-plugin/lib/src/utils/useLockScroll.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
export const useLockScroll = lockScroll => {
|
||||||
|
useEffect(() => {
|
||||||
|
if (lockScroll) {
|
||||||
|
document.body.classList.add('lock-body-scroll');
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
document.body.classList.remove('lock-body-scroll');
|
||||||
|
};
|
||||||
|
}, [lockScroll]);
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user