mirror of
https://github.com/strapi/strapi.git
synced 2025-12-14 16:51:55 +00:00
DS: moving the left menu to use the DS MainNav (#10689)
This commit is contained in:
parent
7f5ca6b479
commit
b7cd466d27
@ -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 |
BIN
packages/core/admin/admin/src/assets/images/strapi-img.png
Normal file
BIN
packages/core/admin/admin/src/assets/images/strapi-img.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
@ -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;
|
||||||
|
|||||||
@ -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;
|
|
||||||
@ -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 };
|
|
||||||
@ -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>
|
|
||||||
|
|
||||||
<A
|
|
||||||
href={`https://github.com/strapi/strapi/releases/tag/v${strapiVersion}`}
|
|
||||||
key="github"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
v{strapiVersion}
|
|
||||||
</A>
|
|
||||||
|
|
||||||
<A href="https://strapi.io" target="_blank" rel="noopener noreferrer">
|
|
||||||
— {projectType} Edition
|
|
||||||
</A>
|
|
||||||
</div>
|
|
||||||
</Wrapper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LeftMenuFooter;
|
|
||||||
@ -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;
|
|
||||||
@ -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;
|
|
||||||
@ -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;
|
|
||||||
@ -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;
|
|
||||||
@ -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;
|
|
||||||
@ -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;
|
|
||||||
@ -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;
|
|
||||||
@ -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;
|
|
||||||
@ -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;
|
|
||||||
@ -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;
|
|
||||||
@ -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;
|
|
||||||
@ -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';
|
|
||||||
@ -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;
|
||||||
|
|||||||
30
packages/core/admin/admin/src/layouts/AppLayout.js
Normal file
30
packages/core/admin/admin/src/layouts/AppLayout.js
Normal 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;
|
||||||
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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 };
|
|
||||||
@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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;
|
||||||
@ -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';
|
||||||
|
|||||||
18
yarn.lock
18
yarn.lock
@ -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"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user