DS: moving the left menu to use the DS MainNav (#10689)

This commit is contained in:
Marvin Frachet 2021-08-06 11:02:31 +02:00 committed by GitHub
parent 7f5ca6b479
commit b7cd466d27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 237 additions and 795 deletions

View File

@ -1,5 +1,7 @@
import React from 'react'; import React from 'react';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import { ThemeProvider } from '@strapi/parts/ThemeProvider';
import { lightTheme } from '@strapi/parts/themes';
import merge from 'lodash/merge'; import merge from 'lodash/merge';
import pick from 'lodash/pick'; import pick from 'lodash/pick';
import isFunction from 'lodash/isFunction'; import isFunction from 'lodash/isFunction';
@ -10,7 +12,7 @@ import configureStore from './core/store/configureStore';
import { Plugin } from './core/apis'; import { Plugin } from './core/apis';
import App from './pages/App'; import App from './pages/App';
import AuthLogo from './assets/images/logo_strapi_auth.png'; import AuthLogo from './assets/images/logo_strapi_auth.png';
import MenuLogo from './assets/images/logo_strapi_menu.png'; import MenuLogo from './assets/images/strapi-img.png';
import Providers from './components/Providers'; import Providers from './components/Providers';
import Theme from './components/Theme'; import Theme from './components/Theme';
import languageNativeNames from './translations/languageNativeNames'; import languageNativeNames from './translations/languageNativeNames';
@ -423,44 +425,46 @@ class StrapiApp {
} = this.library; } = this.library;
return ( return (
<Theme theme={this.configurations.theme}> <ThemeProvider theme={lightTheme}>
<Providers <Theme theme={this.configurations.theme}>
authLogo={this.configurations.authLogo} <Providers
components={components} authLogo={this.configurations.authLogo}
fields={fields} components={components}
localeNames={localeNames} fields={fields}
getAdminInjectedComponents={this.getAdminInjectedComponents} localeNames={localeNames}
getPlugin={this.getPlugin} getAdminInjectedComponents={this.getAdminInjectedComponents}
messages={this.configurations.translations} getPlugin={this.getPlugin}
menu={this.menu} messages={this.configurations.translations}
menuLogo={this.configurations.menuLogo} menu={this.menu}
plugins={this.plugins} menuLogo={this.configurations.menuLogo}
runHookParallel={this.runHookParallel} plugins={this.plugins}
runHookWaterfall={(name, initialValue, async = false) => { runHookParallel={this.runHookParallel}
return this.runHookWaterfall(name, initialValue, async, store); runHookWaterfall={(name, initialValue, async = false) => {
}} return this.runHookWaterfall(name, initialValue, async, store);
runHookSeries={this.runHookSeries} }}
settings={this.settings} runHookSeries={this.runHookSeries}
showTutorials={this.configurations.tutorials} settings={this.settings}
showReleaseNotification={this.configurations.notifications.releases} showTutorials={this.configurations.tutorials}
store={store} showReleaseNotification={this.configurations.notifications.releases}
> store={store}
<> >
<Helmet <>
link={[ <Helmet
{ link={[
rel: 'icon', {
type: 'image/png', rel: 'icon',
href: this.configurations.head.favicon, type: 'image/png',
}, href: this.configurations.head.favicon,
]} },
/> ]}
<BrowserRouter basename={basename}> />
<App store={store} /> <BrowserRouter basename={basename}>
</BrowserRouter> <App store={store} />
</> </BrowserRouter>
</Providers> </>
</Theme> </Providers>
</Theme>
</ThemeProvider>
); );
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -6,176 +6,6 @@ import '@fortawesome/fontawesome-free/css/all.css';
import '@fortawesome/fontawesome-free/js/all.min.js'; import '@fortawesome/fontawesome-free/js/all.min.js';
import { createGlobalStyle } from 'styled-components'; import { createGlobalStyle } from 'styled-components';
const GlobalStyle = createGlobalStyle` const GlobalStyle = createGlobalStyle``;
html {
font-size: 62.5%;
}
body {
font-family: 'Lato';
font-size: 1.4rem;
line-height: 1.5;
color: #292b2c;
}
* {
-webkit-font-smoothing: antialiased;
box-sizing: border-box;
font-family: 'Lato';
}
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
line-height: 1.1;
}
.btn {
font-size: 1.4rem;
padding: 0;
}
.cursor-pointer {
cursor: pointer;
}
/*
* Override
*/
.modal {
background: transparent;
.modal-dialog {
max-width: 74.5rem;
margin: 16rem auto 3rem calc(50% - #{$left - menu - width});
position: relative;
z-index: 999;
}
}
.modal-backdrop.show {
opacity: 0.15;
}
.modal-content {
border-radius: .2rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
border: none;
}
.modal-header {
button {
&.close {
margin: 0;
padding: 2rem;
}
}
}
.modal-body {
.video-react {
background: transparent;
}
}
form .row {
text-align: left;
}
.form-check {
padding-left: 0;
.form-check-label {
padding-left: 1.25rem;
}
}
.form-control:focus {
outline: none;
box-shadow: none;
}
textarea.form-control {
height: 10.6rem;
}
.input-group-addon {
padding-left: 0.75rem;
padding-right: 0.75rem;
}
.btn-secondary:not(:disabled):not(.disabled):active:focus,
.btn-secondary:not(:disabled):not(.disabled).active:focus,
.btn-secondary,
.show > .btn-secondary.dropdown-toggle:focus {
&:focus, &:active, &:hover, &.focus {
box-shadow: 0 0 0 0px rgba(134,142,150,0.5);
color: rgb(51, 55, 64);
background-color: rgb(250, 250, 251) !important;
}
}
/*
* Notifications animation
*/
.notification-enter {
opacity: 0;
top: -70px;
}
.notification-enter.notification-enter-active {
opacity: 1;
transition: all 400ms ease-in;
top: 0;
}
.notification-exit {
opacity: 1;
}
.notification-exit.notification-exit-active {
opacity: 0;
transition: all 400ms ease-in;
}
::-webkit-scrollbar {
width: 9px;
height: 5px;
}
::-webkit-scrollbar-track {
background-color: #eee;
}
::-webkit-scrollbar-track:hover {
background-color: #ddd;
}
::-webkit-scrollbar-thumb {
background-color: #ccc;
border-radius: 0.5rem;
}
::-webkit-scrollbar-thumb:hover {
background-color: #bbb;
}
::-webkit-scrollbar-button {
display: none;
}
/* firefox scrollbar */
/* stylelint-disable */
* {
scrollbar-color: #bbb #eee;
scrollbar-width: thin;
}
/* stylelint-enable */
a::-moz-focus-inner {
border: 0;
}
`;
export default GlobalStyle; export default GlobalStyle;

View File

@ -1,61 +0,0 @@
/**
*
* Wrapper
*
*/
import styled from 'styled-components';
import PropTypes from 'prop-types';
const Wrapper = styled.div`
position: fixed;
float: left;
top: 0;
left: 0;
height: 100vh;
width: ${props => props.theme.main.sizes.leftMenu.width};
background: ${props => props.theme.main.colors.strapi['blue-darker']};
/* scrollbar overrides */
* {
::-webkit-scrollbar {
width: 7px;
}
::-webkit-scrollbar-track,
::-webkit-scrollbar-track:hover {
background-color: transparent;
}
::-webkit-scrollbar-thumb {
background-color: ${props => props.theme.main.colors.leftMenu['title-color']};
}
::-webkit-scrollbar-thumb:hover {
background-color: ${props => props.theme.main.colors.leftMenu['link-color']};
}
/* firefox */
scrollbar-color: ${props => props.theme.main.colors.leftMenu['title-color']} transparent;
}
`;
Wrapper.defaultProps = {
theme: {
main: {
colors: {
strapi: {},
},
sizes: {
header: {},
leftMenu: {},
},
},
},
};
Wrapper.propTypes = {
theme: PropTypes.object,
};
export default Wrapper;

View File

@ -1,51 +0,0 @@
import styled from 'styled-components';
import PropTypes from 'prop-types';
const Wrapper = styled.div`
position: absolute;
width: 100%;
background: ${props => props.theme.main.colors.strapi['blue-darker']};
bottom: 0;
.poweredBy {
width: 100%;
bottom: 0;
height: 3rem;
padding-left: 15px;
padding-right: 15px;
line-height: 3rem;
background-color: rgba(255, 255, 255, 0.02);
font-size: 1rem;
font-weight: 400;
letter-spacing: 0.05rem;
vertical-align: middle;
color: ${({ theme }) => theme.main.colors.strapi['gray-light']};
}
`;
const A = styled.a`
&:hover {
color: #007bff;
text-decoration: underline;
}
`;
Wrapper.defaultProps = {
theme: {
main: {
colors: {
strapi: {},
},
sizes: {
header: {},
leftMenu: {},
},
},
},
};
Wrapper.propTypes = {
theme: PropTypes.object,
};
export default Wrapper;
export { A };

View File

@ -1,40 +0,0 @@
/**
*
* LeftMenuFooter
*
*/
import React from 'react';
import { useAppInfos } from '@strapi/helper-plugin';
import Wrapper, { A } from './Wrapper';
function LeftMenuFooter() {
const projectType = strapi.projectType;
const { strapiVersion } = useAppInfos();
return (
<Wrapper>
<div className="poweredBy">
<A key="website" href="https://strapi.io" target="_blank" rel="noopener noreferrer">
Strapi
</A>
&nbsp;
<A
href={`https://github.com/strapi/strapi/releases/tag/v${strapiVersion}`}
key="github"
target="_blank"
rel="noopener noreferrer"
>
v{strapiVersion}
</A>
&nbsp;
<A href="https://strapi.io" target="_blank" rel="noopener noreferrer">
{projectType} Edition
</A>
</div>
</Wrapper>
);
}
export default LeftMenuFooter;

View File

@ -1,48 +0,0 @@
import styled from 'styled-components';
import PropTypes from 'prop-types';
const Wrapper = styled.div`
background-color: ${props => props.theme.main.colors.leftMenu['background-header-link']};
padding-left: 2rem;
height: ${props => props.theme.main.sizes.leftMenu.height};
.leftMenuHeaderLink {
&:hover {
text-decoration: none;
}
}
.projectName {
display: block;
width: 100%;
height: ${props => props.theme.main.sizes.leftMenu.height};
font-size: 2rem;
letter-spacing: 0.2rem;
color: $white;
background-image: url(${props => props.logo});
background-repeat: no-repeat;
background-position: left center;
background-size: auto 2.5rem;
}
`;
Wrapper.defaultProps = {
theme: {
main: {
colors: {
leftMenu: {},
},
sizes: {
header: {},
leftMenu: {},
},
},
},
};
Wrapper.propTypes = {
theme: PropTypes.object,
};
export default Wrapper;

View File

@ -1,18 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { useConfigurations } from '../../../../hooks';
import Wrapper from './Wrapper';
const LeftMenuHeader = () => {
const { menuLogo } = useConfigurations();
return (
<Wrapper logo={menuLogo}>
<Link to="/" className="leftMenuHeaderLink">
<span className="projectName" />
</Link>
</Wrapper>
);
};
export default LeftMenuHeader;

View File

@ -1,23 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
const FaIcon = styled(({ small, ...props }) => <FontAwesomeIcon {...props} />)`
position: absolute;
top: ${({ small }) => (small ? 'calc(50% - 0.3rem)' : 'calc(50% - 0.9rem + 0.3rem)')};
left: ${({ small }) => (small ? '2.2rem' : '1.6rem')};
width: ${({ small }) => (small ? 'auto' : '1.3rem')} !important;
font-size: ${({ small }) => (small ? '.5rem' : '1.3rem')};
`;
const LeftMenuIcon = ({ icon }) => <FaIcon small={icon === 'circle'} icon={icon} />;
LeftMenuIcon.propTypes = {
icon: PropTypes.string,
};
LeftMenuIcon.defaultProps = {
icon: 'circle',
};
export default LeftMenuIcon;

View File

@ -1,40 +0,0 @@
import { NavLink } from 'react-router-dom';
import styled from 'styled-components';
const Link = styled(NavLink)`
display: flex;
position: relative;
padding-top: 1rem;
padding-bottom: 0.2rem;
padding-left: 1.6rem;
min-height: 3.6rem;
line-height: 1.8rem;
border-left: 0.3rem solid transparent;
cursor: pointer;
color: ${props => props.theme.main.colors.leftMenu['link-color']};
text-decoration: none;
-webkit-font-smoothing: antialiased;
&:hover {
color: ${props => props.theme.main.colors.white};
background: ${props => props.theme.main.colors.leftMenu['link-hover']};
border-left: 0.3rem solid ${props => props.theme.main.colors.strapi.blue};
text-decoration: none;
}
&:focus {
color: ${props => props.theme.main.colors.white};
text-decoration: none;
}
&:visited {
color: ${props => props.theme.main.colors.leftMenu['link-color']};
}
&.active {
color: white !important;
border-left: 0.3rem solid ${props => props.theme.main.colors.strapi.blue};
}
`;
export default Link;

View File

@ -1,10 +0,0 @@
import styled from 'styled-components';
const LinkLabel = styled.span`
display: inline-block;
width: 100%;
padding-right: 1rem;
padding-left: 2.5rem;
`;
export default LinkLabel;

View File

@ -1,32 +0,0 @@
import React from 'react';
import styled from 'styled-components';
import PropTypes from 'prop-types';
import { Text } from '@buffetjs/core';
const NotificationWrapper = styled.div`
height: 14px;
margin-top: 4px;
margin-right: 20px;
padding: 0px 4px;
background-color: #383d49;
border-radius: 2px;
font-size: 11px;
`;
const NotificationCount = ({ count }) => (
<NotificationWrapper>
<Text fontWeight="bold" fontSize="xs" lineHeight="14px" color="#919bae">
{count}
</Text>
</NotificationWrapper>
);
NotificationCount.defaultProps = {
count: 0,
};
NotificationCount.propTypes = {
count: PropTypes.number,
};
export default NotificationCount;

View File

@ -1,40 +0,0 @@
/**
*
* LeftMenuLink
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import LinkLabel from './LinkLabel';
import Link from './Link';
import LeftMenuIcon from './LeftMenuIcon';
import NotificationCount from './NotificationCount';
const LeftMenuLink = ({ to, icon, intlLabel, notificationsCount }) => {
return (
<Link to={to}>
<LeftMenuIcon icon={icon} />
{/* TODO change with new DS */}
<FormattedMessage {...intlLabel}>
{message => <LinkLabel>{message}</LinkLabel>}
</FormattedMessage>
{notificationsCount > 0 && <NotificationCount count={notificationsCount} />}
</Link>
);
};
LeftMenuLink.propTypes = {
to: PropTypes.string.isRequired,
icon: PropTypes.string,
intlLabel: PropTypes.object.isRequired,
notificationsCount: PropTypes.number,
};
LeftMenuLink.defaultProps = {
icon: 'circle',
notificationsCount: 0,
};
export default LeftMenuLink;

View File

@ -1,31 +0,0 @@
import styled from 'styled-components';
import PropTypes from 'prop-types';
const LinksContainer = styled.div`
padding-top: 0.7rem;
position: absolute;
top: ${props => props.theme.main.sizes.leftMenu.height};
right: 0;
bottom: 0;
left: 0;
overflow-y: auto;
height: calc(100vh - (${props => props.theme.main.sizes.leftMenu.height} + 3rem));
box-sizing: border-box;
`;
LinksContainer.defaultProps = {
theme: {
main: {
sizes: {
header: {},
leftMenu: {},
},
},
},
};
LinksContainer.propTypes = {
theme: PropTypes.object,
};
export default LinksContainer;

View File

@ -1,10 +0,0 @@
import styled from 'styled-components';
const LeftMenuListLink = styled.div`
max-height: 180px;
margin-bottom: 19px;
margin-right: 25px;
overflow: auto;
`;
export default LeftMenuListLink;

View File

@ -1,22 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import LeftMenuLink from '../Link';
import LeftMenuListLink from './LeftMenuListLink';
const LeftMenuLinksSection = ({ links }) => {
return (
<>
<LeftMenuListLink>
{links.map(link => (
<LeftMenuLink {...link} key={link.to} />
))}
</LeftMenuListLink>
</>
);
};
LeftMenuLinksSection.propTypes = {
links: PropTypes.arrayOf(PropTypes.object).isRequired,
};
export default LeftMenuLinksSection;

View File

@ -1,30 +0,0 @@
import styled from 'styled-components';
const SectionTitle = styled.div`
display: flex;
justify-content: space-between;
padding-left: 2rem;
padding-right: 1.6rem;
padding-top: 1rem;
margin-bottom: 0.9rem;
color: ${props => props.theme.main.colors.leftMenu['title-color']};
text-transform: uppercase;
font-size: 1.1rem;
letter-spacing: 0.1rem;
font-weight: 800;
max-height: 26px;
`;
SectionTitle.defaultProps = {
theme: {
main: {
colors: {
leftMenu: {
'title-color': '#5b626f',
},
},
},
},
};
export default SectionTitle;

View File

@ -1,5 +0,0 @@
export { default as Footer } from './Footer';
export { default as Header } from './Header';
export { default as LinksContainer } from './Links';
export { default as LinksSection } from './LinksSection';
export { default as SectionTitle } from './SectionTitle';

View File

@ -1,58 +1,84 @@
import React, { memo } from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { BaselineAlignment } from '@strapi/helper-plugin'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Footer, Header, LinksContainer, LinksSection, SectionTitle } from './compos'; import get from 'lodash/get';
import LeftMenuLink from './compos/Link'; import {
MainNav,
import Wrapper from './Wrapper'; NavBrand,
NavSections,
NavLink,
NavSection,
NavUser,
NavCondense,
Divider,
} from '@strapi/parts';
import ContentIcon from '@strapi/icons/ContentIcon';
import { auth, usePersistentState } from '@strapi/helper-plugin';
import useConfigurations from '../../hooks/useConfigurations';
const LeftMenu = ({ generalSectionLinks, pluginsSectionLinks }) => { const LeftMenu = ({ generalSectionLinks, pluginsSectionLinks }) => {
const { menuLogo } = useConfigurations();
const [condensed, setCondensed] = usePersistentState('navbar-condensed', false);
const userInfo = auth.getUserInfo();
let displayName;
if (userInfo && userInfo.firstname && userInfo.lastname) {
displayName = `${userInfo.firstname} ${userInfo.lastname}`;
} else {
displayName = get(userInfo, 'username', '');
}
return ( return (
<Wrapper> <MainNav condensed={condensed}>
<Header /> <NavBrand
workplace="Workplace"
title="Strapi Dashboard"
icon={<img src={menuLogo} alt="" />}
/>
<LinksContainer> <Divider />
<BaselineAlignment top size="16px" />
<LeftMenuLink
to="/content-manager"
icon="book-open"
intlLabel={{
id: `content-manager.plugin.name`,
defaultMessage: 'Content manager',
}}
/>
<BaselineAlignment bottom size="2px" />
{pluginsSectionLinks.length > 0 && ( <NavSections>
<> <NavLink to="/content-manager" icon={<ContentIcon />}>
<SectionTitle> <FormattedMessage id="content-manager.plugin.name" defaultMessage="Content manager" />
<FormattedMessage </NavLink>
id="app.components.LeftMenuLinkContainer.listPlugins"
defaultMessage="Plugins" {pluginsSectionLinks.length > 0 ? (
/> <NavSection label="Plugins">
</SectionTitle> {pluginsSectionLinks.map(link => (
<LinksSection <NavLink to={link.to} key={link.to} icon={<FontAwesomeIcon icon={link.icon} />}>
links={pluginsSectionLinks} <FormattedMessage {...link.intlLabel} />
searchable={false} </NavLink>
emptyLinksListMessage="app.components.LeftMenuLinkContainer.noPluginsInstalled" ))}
/> </NavSection>
</> ) : null}
{generalSectionLinks.length > 0 ? (
<NavSection label="General">
{generalSectionLinks.map(link => (
<NavLink to={link.to} key={link.to} icon={<FontAwesomeIcon icon={link.icon} />}>
<FormattedMessage {...link.intlLabel} />
</NavLink>
))}
</NavSection>
) : null}
</NavSections>
<NavUser src="https://avatars.githubusercontent.com/u/3874873?v=4" to="/me">
{displayName}
</NavUser>
<NavCondense onClick={() => setCondensed(s => !s)}>
{condensed ? (
<FormattedMessage id="app.components.LeftMenu.expand" />
) : (
<FormattedMessage id="app.components.LeftMenu.collapse" />
)} )}
{generalSectionLinks.length > 0 && ( </NavCondense>
<> </MainNav>
<SectionTitle>
<FormattedMessage
id="app.components.LeftMenuLinkContainer.general"
defaultMessage="General"
/>
</SectionTitle>
<LinksSection links={generalSectionLinks} searchable={false} />
</>
)}
</LinksContainer>
<Footer key="footer" />
</Wrapper>
); );
}; };
@ -61,4 +87,4 @@ LeftMenu.propTypes = {
pluginsSectionLinks: PropTypes.array.isRequired, pluginsSectionLinks: PropTypes.array.isRequired,
}; };
export default memo(LeftMenu); export default LeftMenu;

View File

@ -0,0 +1,30 @@
import React from 'react';
import { Row, Box, SkipToContent } from '@strapi/parts';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { FormattedMessage } from 'react-intl';
const FlexBox = styled(Box)`
flex: 1;
`;
const AppLayout = ({ children, sideNav }) => {
return (
<Box background="neutral100">
<SkipToContent>
<FormattedMessage id="skipToContent" />
</SkipToContent>
<Row alignItems="flex-start">
{sideNav}
<FlexBox>{children}</FlexBox>
</Row>
</Box>
);
};
AppLayout.propTypes = {
children: PropTypes.node.isRequired,
sideNav: PropTypes.node.isRequired,
};
export default AppLayout;

View File

@ -16,15 +16,11 @@ import {
import { DndProvider } from 'react-dnd'; import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend'; import { HTML5Backend } from 'react-dnd-html5-backend';
import adminPermissions from '../../permissions'; import adminPermissions from '../../permissions';
import Header from '../../components/Header/index';
import NavTopRightWrapper from '../../components/NavTopRightWrapper';
import LeftMenu from '../../components/LeftMenu'; import LeftMenu from '../../components/LeftMenu';
import Onboarding from '../../components/Onboarding'; import Onboarding from '../../components/Onboarding';
import { useMenu, useReleaseNotification } from '../../hooks'; import { useMenu, useReleaseNotification } from '../../hooks';
import Logout from './Logout';
import Wrapper from './Wrapper';
import Content from './Content';
import { createRoute } from '../../utils'; import { createRoute } from '../../utils';
import AppLayout from '../../layouts/AppLayout';
const CM = lazy(() => const CM = lazy(() =>
import(/* webpackChunkName: "content-manager" */ '../../content-manager/pages/App') import(/* webpackChunkName: "content-manager" */ '../../content-manager/pages/App')
@ -83,46 +79,42 @@ const Admin = () => {
return ( return (
<DndProvider backend={HTML5Backend}> <DndProvider backend={HTML5Backend}>
<Wrapper> <AppLayout
<LeftMenu sideNav={
generalSectionLinks={generalSectionLinks} // eslint-disable-next-line react/jsx-wrap-multilines
pluginsSectionLinks={pluginsSectionLinks} <LeftMenu
/> generalSectionLinks={generalSectionLinks}
<NavTopRightWrapper> pluginsSectionLinks={pluginsSectionLinks}
<Logout /> />
</NavTopRightWrapper> }
<div className="adminPageRightWrapper"> >
<Header /> <Suspense fallback={<LoadingIndicatorPage />}>
<Content> <Switch>
<Suspense fallback={<LoadingIndicatorPage />}> <Route path="/" component={HomePage} exact />
<Switch> <Route path="/me" component={ProfilePage} exact />
<Route path="/" component={HomePage} exact />
<Route path="/me" component={ProfilePage} exact />
<Route path="/content-manager" component={CM} /> <Route path="/content-manager" component={CM} />
<Route path="/plugins/content-type-builder" component={CTB} /> <Route path="/plugins/content-type-builder" component={CTB} />
<Route path="/plugins/upload" component={Upload} /> <Route path="/plugins/upload" component={Upload} />
{routes} {routes}
<Route path="/settings/:settingId" component={SettingsPage} /> <Route path="/settings/:settingId" component={SettingsPage} />
<Route path="/settings" component={SettingsPage} exact /> <Route path="/settings" component={SettingsPage} exact />
<Route path="/marketplace"> <Route path="/marketplace">
<CheckPagePermissions permissions={adminPermissions.marketplace.main}> <CheckPagePermissions permissions={adminPermissions.marketplace.main}>
<MarketplacePage /> <MarketplacePage />
</CheckPagePermissions> </CheckPagePermissions>
</Route> </Route>
<Route path="/list-plugins" exact> <Route path="/list-plugins" exact>
<CheckPagePermissions permissions={adminPermissions.marketplace.main}> <CheckPagePermissions permissions={adminPermissions.marketplace.main}>
<InstalledPluginsPage /> <InstalledPluginsPage />
</CheckPagePermissions> </CheckPagePermissions>
</Route> </Route>
<Route path="/404" component={NotFoundPage} /> <Route path="/404" component={NotFoundPage} />
<Route path="" component={NotFoundPage} /> <Route path="" component={NotFoundPage} />
</Switch> </Switch>
</Suspense> </Suspense>
</Content>
</div>
<Onboarding /> <Onboarding />
</Wrapper> </AppLayout>
</DndProvider> </DndProvider>
); );
}; };

View File

@ -1,15 +0,0 @@
import styled from 'styled-components';
const Wrapper = styled.div`
font-family: 'Lato';
font-size: 1.4rem;
font-weight: 400;
line-height: 1.5;
color: #292b2c;
`;
const Content = styled.div`
display: block;
`;
export { Content, Wrapper };

View File

@ -18,7 +18,6 @@ import { createRoute, makeUniqueRoutes } from '../../utils';
import AuthPage from '../AuthPage'; import AuthPage from '../AuthPage';
import NotFoundPage from '../NotFoundPage'; import NotFoundPage from '../NotFoundPage';
import { getUID } from './utils'; import { getUID } from './utils';
import { Content, Wrapper } from './components';
import routes from './utils/routes'; import routes from './utils/routes';
const AuthenticatedApp = lazy(() => const AuthenticatedApp = lazy(() =>
@ -107,22 +106,18 @@ function App() {
return ( return (
<Suspense fallback={<LoadingIndicatorPage />}> <Suspense fallback={<LoadingIndicatorPage />}>
<TrackingContext.Provider value={uuid}> <TrackingContext.Provider value={uuid}>
<Wrapper> <Switch>
<Content> {authRoutes}
<Switch> <Route
{authRoutes} path="/auth/:authType"
<Route render={routerProps => (
path="/auth/:authType" <AuthPage {...routerProps} setHasAdmin={setHasAdmin} hasAdmin={hasAdmin} />
render={routerProps => ( )}
<AuthPage {...routerProps} setHasAdmin={setHasAdmin} hasAdmin={hasAdmin} /> exact
)} />
exact <PrivateRoute path="/" component={AuthenticatedApp} />
/> <Route path="" component={NotFoundPage} />
<PrivateRoute path="/" component={AuthenticatedApp} /> </Switch>
<Route path="" component={NotFoundPage} />
</Switch>
</Content>
</Wrapper>
</TrackingContext.Provider> </TrackingContext.Provider>
</Suspense> </Suspense>
); );

View File

@ -219,6 +219,8 @@
"app.components.LeftMenuLinkContainer.plugins": "Plugins", "app.components.LeftMenuLinkContainer.plugins": "Plugins",
"app.components.LeftMenuLinkContainer.settings": "Settings", "app.components.LeftMenuLinkContainer.settings": "Settings",
"app.components.LeftMenuLinkContainer.singleTypes": "Single Types", "app.components.LeftMenuLinkContainer.singleTypes": "Single Types",
"app.components.LeftMenu.expand": "Expanded the navbar",
"app.components.LeftMenu.collapse": "Collapse the navbar",
"app.components.ListPluginsPage.deletePlugin.description": "It might take a few seconds to uninstall the plugin.", "app.components.ListPluginsPage.deletePlugin.description": "It might take a few seconds to uninstall the plugin.",
"app.components.ListPluginsPage.deletePlugin.title": "Uninstalling", "app.components.ListPluginsPage.deletePlugin.title": "Uninstalling",
"app.components.ListPluginsPage.description": "List of the installed plugins in the project.", "app.components.ListPluginsPage.description": "List of the installed plugins in the project.",
@ -553,5 +555,6 @@
"notification.version.update.link": "See more", "notification.version.update.link": "See more",
"notification.version.update.message": "A new version of Strapi is available!", "notification.version.update.message": "A new version of Strapi is available!",
"or": "OR", "or": "OR",
"request.error.model.unknown": "This model doesn't exist" "request.error.model.unknown": "This model doesn't exist",
"skipToContent": "Skip to content"
} }

View File

@ -41,6 +41,8 @@
"@strapi/babel-plugin-switch-ee-ce": "1.0.0", "@strapi/babel-plugin-switch-ee-ce": "1.0.0",
"@strapi/helper-plugin": "3.6.6", "@strapi/helper-plugin": "3.6.6",
"@strapi/utils": "3.6.6", "@strapi/utils": "3.6.6",
"@strapi/icons": "0.0.1-alpha.4",
"@strapi/parts": "0.0.1-alpha.4",
"axios": "^0.21.1", "axios": "^0.21.1",
"babel-loader": "8.2.2", "babel-loader": "8.2.2",
"babel-plugin-styled-components": "1.12.0", "babel-plugin-styled-components": "1.12.0",

View File

@ -0,0 +1,17 @@
import { useState, useEffect } from 'react';
const usePersistentState = (key, defaultValue) => {
const [value, setValue] = useState(() => {
const stickyValue = window.localStorage.getItem(key);
return stickyValue !== null ? JSON.parse(stickyValue) : defaultValue;
});
useEffect(() => {
window.localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
};
export default usePersistentState;

View File

@ -128,6 +128,7 @@ export { default as useOverlayBlocker } from './hooks/useOverlayBlocker';
export { default as useAutoReloadOverlayBlocker } from './hooks/useAutoReloadOverlayBlocker'; export { default as useAutoReloadOverlayBlocker } from './hooks/useAutoReloadOverlayBlocker';
export { default as useRBACProvider } from './hooks/useRBACProvider'; export { default as useRBACProvider } from './hooks/useRBACProvider';
export { default as useRBAC } from './hooks/useRBAC'; export { default as useRBAC } from './hooks/useRBAC';
export { default as usePersistentState } from './hooks/usePersistentState';
// Providers // Providers
export { default as LibraryProvider } from './providers/LibraryProvider'; export { default as LibraryProvider } from './providers/LibraryProvider';

View File

@ -3490,6 +3490,19 @@
tslib "^2.0.0" tslib "^2.0.0"
upath "2.0.1" upath "2.0.1"
"@strapi/icons@0.0.1-alpha.4":
version "0.0.1-alpha.4"
resolved "https://registry.yarnpkg.com/@strapi/icons/-/icons-0.0.1-alpha.4.tgz#f3e66f05b8aa0ae1615380e68cc0125fe405777e"
integrity sha512-Lnfam0vCD2PWNdvnyG9ZHtvTKgDdSc7AvqzqlxC3BlbvrNBMov3XtvCZFfW1TgXZ4iwGbCmuN+JDmiFtiAWygA==
"@strapi/parts@0.0.1-alpha.4":
version "0.0.1-alpha.4"
resolved "https://registry.yarnpkg.com/@strapi/parts/-/parts-0.0.1-alpha.4.tgz#ffeeb856d2e4b0b6f5ae84f28e071e73e1c3d07e"
integrity sha512-1LBipdmZiCEdO6RC+YSsVEkHV3XxStTFxTKPz3bsorb5Rt52FchOB2CkHTjIK4+WmNvHdDJh1b98ZC0M0gJCEQ==
dependencies:
compute-scroll-into-view "^1.0.17"
prop-types "^15.7.2"
"@stylelint/postcss-css-in-js@^0.37.2": "@stylelint/postcss-css-in-js@^0.37.2":
version "0.37.2" version "0.37.2"
resolved "https://registry.yarnpkg.com/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.2.tgz#7e5a84ad181f4234a2480803422a47b8749af3d2" resolved "https://registry.yarnpkg.com/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.2.tgz#7e5a84ad181f4234a2480803422a47b8749af3d2"
@ -6853,6 +6866,11 @@ compression@^1.7.4:
safe-buffer "5.1.2" safe-buffer "5.1.2"
vary "~1.1.2" vary "~1.1.2"
compute-scroll-into-view@^1.0.17:
version "1.0.17"
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz#6a88f18acd9d42e9cf4baa6bec7e0522607ab7ab"
integrity sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==
concat-map@0.0.1: concat-map@0.0.1:
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"