Merge pull request #12651 from strapi/dark-mode/admin-setup

Dark mode admin setup
This commit is contained in:
Vincent 2022-02-25 13:52:12 +01:00 committed by GitHub
commit e6ce78a5e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 821 additions and 456 deletions

View File

@ -45,6 +45,7 @@ module.exports = {
'<rootDir>/packages/admin-test-utils/lib/mocks/LocalStorageMock.js',
'<rootDir>/packages/admin-test-utils/lib/mocks/IntersectionObserver.js',
'<rootDir>/packages/admin-test-utils/lib/mocks/ResizeObserver.js',
'<rootDir>/packages/admin-test-utils/lib/mocks/windowMatchMedia.js',
],
setupFilesAfterEnv: [
'<rootDir>/packages/admin-test-utils/lib/setup/enzyme-setup.js',

View File

@ -0,0 +1,3 @@
'use strict';
global.window.matchMedia = jest.fn(() => false);

View File

@ -1,6 +1,7 @@
import React from 'react';
import { BrowserRouter } from 'react-router-dom';
import { lightTheme } from '@strapi/design-system/themes';
import cloneDeep from 'lodash/cloneDeep';
import merge from 'lodash/merge';
import pick from 'lodash/pick';
import isFunction from 'lodash/isFunction';
@ -13,7 +14,6 @@ import App from './pages/App';
import AuthLogo from './assets/images/logo_strapi_auth_v4.png';
import MenuLogo from './assets/images/logo_strapi_menu.png';
import Providers from './components/Providers';
import Theme from './components/Theme';
import languageNativeNames from './translations/languageNativeNames';
import {
INJECT_COLUMN_IN_TABLE,
@ -22,6 +22,7 @@ import {
MUTATE_SINGLE_TYPES_LINKS,
} from './exposedHooks';
import injectionZones from './injectionZones';
import darkTheme from './temp-dark-theme';
import favicon from './favicon.ico';
class StrapiApp {
@ -34,7 +35,7 @@ class StrapiApp {
locales: ['en'],
menuLogo: MenuLogo,
notifications: { releases: true },
theme: lightTheme,
themes: { light: lightTheme, dark: darkTheme, custom: null },
translations: {},
tutorials: true,
};
@ -226,7 +227,10 @@ class StrapiApp {
}
if (this.customConfigurations?.theme) {
this.configurations.theme = merge(this.configurations.theme, this.customConfigurations.theme);
this.configurations.themes.custom = merge(
cloneDeep(this.configurations.themes.light),
this.customConfigurations.theme
);
}
if (this.customConfigurations?.notifications?.releases !== undefined) {
@ -427,44 +431,43 @@ class StrapiApp {
} = this.library;
return (
<Theme theme={this.configurations.theme}>
<Providers
authLogo={this.configurations.authLogo}
components={components}
fields={fields}
localeNames={localeNames}
getAdminInjectedComponents={this.getAdminInjectedComponents}
getPlugin={this.getPlugin}
messages={this.configurations.translations}
menu={this.menu}
menuLogo={this.configurations.menuLogo}
plugins={this.plugins}
runHookParallel={this.runHookParallel}
runHookWaterfall={(name, initialValue, async = false) => {
return this.runHookWaterfall(name, initialValue, async, store);
}}
runHookSeries={this.runHookSeries}
settings={this.settings}
showTutorials={this.configurations.tutorials}
showReleaseNotification={this.configurations.notifications.releases}
store={store}
>
<>
<Helmet
link={[
{
rel: 'icon',
type: 'image/png',
href: this.configurations.head.favicon,
},
]}
/>
<BrowserRouter basename={basename}>
<App store={store} />
</BrowserRouter>
</>
</Providers>
</Theme>
<Providers
authLogo={this.configurations.authLogo}
components={components}
fields={fields}
localeNames={localeNames}
getAdminInjectedComponents={this.getAdminInjectedComponents}
getPlugin={this.getPlugin}
messages={this.configurations.translations}
menu={this.menu}
menuLogo={this.configurations.menuLogo}
plugins={this.plugins}
runHookParallel={this.runHookParallel}
runHookWaterfall={(name, initialValue, async = false) => {
return this.runHookWaterfall(name, initialValue, async, store);
}}
runHookSeries={this.runHookSeries}
themes={this.configurations.themes}
settings={this.settings}
showTutorials={this.configurations.tutorials}
showReleaseNotification={this.configurations.notifications.releases}
store={store}
>
<>
<Helmet
link={[
{
rel: 'icon',
type: 'image/png',
href: this.configurations.head.favicon,
},
]}
/>
<BrowserRouter basename={basename}>
<App store={store} />
</BrowserRouter>
</>
</Providers>
);
}
}

View File

@ -2,6 +2,7 @@ import React from 'react';
import { render, waitFor } from '@testing-library/react';
import { QueryClientProvider, QueryClient } from 'react-query';
import { useGuidedTour } from '@strapi/helper-plugin';
import { lightTheme } from '@strapi/design-system';
import { ConfigurationsContext } from '../../../contexts';
import {
fetchAppInfo,
@ -11,6 +12,7 @@ import {
} from '../utils/api';
import packageJSON from '../../../../../package.json';
import Theme from '../../Theme';
import ThemeToggleProvider from '../../ThemeToggleProvider';
import AuthenticatedApp from '..';
const strapiVersion = packageJSON.version;
@ -43,13 +45,15 @@ const queryClient = new QueryClient({
});
const app = (
<Theme>
<QueryClientProvider client={queryClient}>
<ConfigurationsContext.Provider value={{ showReleaseNotification: false }}>
<AuthenticatedApp />
</ConfigurationsContext.Provider>
</QueryClientProvider>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<QueryClientProvider client={queryClient}>
<ConfigurationsContext.Provider value={{ showReleaseNotification: false }}>
<AuthenticatedApp />
</ConfigurationsContext.Provider>
</QueryClientProvider>
</Theme>
</ThemeToggleProvider>
);
describe('Admin | components | AuthenticatedApp', () => {

View File

@ -15,6 +15,9 @@ const GlobalStyle = createGlobalStyle`
body {
background: ${({ theme }) => theme.colors.neutral100};
}
input, textarea {
background-color: inherit;
}
`;
export default GlobalStyle;

View File

@ -2,7 +2,9 @@ import React from 'react';
import { render, screen } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import { useGuidedTour } from '@strapi/helper-plugin';
import { lightTheme } from '@strapi/design-system';
import Theme from '../../../Theme';
import ThemeToggleProvider from '../../../ThemeToggleProvider';
import GuidedTourModal from '../index';
jest.mock('@strapi/helper-plugin', () => ({
@ -28,11 +30,13 @@ jest.mock('@strapi/helper-plugin', () => ({
}));
const App = (
<Theme>
<IntlProvider locale="en" messages={{}} defaultLocale="en" textComponent="span">
<GuidedTourModal />
</IntlProvider>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<IntlProvider locale="en" messages={{}} defaultLocale="en" textComponent="span">
<GuidedTourModal />
</IntlProvider>
</Theme>
</ThemeToggleProvider>
);
describe('<GuidedTourModal />', () => {

View File

@ -9,7 +9,9 @@ import { render, fireEvent, screen } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import { useNotification } from '@strapi/helper-plugin';
import { act } from 'react-dom/test-utils';
import { lightTheme } from '@strapi/design-system';
import Theme from '../../Theme';
import ThemeToggleProvider from '../../ThemeToggleProvider';
import Notifications from '../index';
const messages = {};
@ -19,13 +21,15 @@ describe('<Notifications />', () => {
const {
container: { firstChild },
} = render(
<Theme>
<IntlProvider locale="en" messages={messages} defaultLocale="en" textComponent="span">
<Notifications>
<div />
</Notifications>
</IntlProvider>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<IntlProvider locale="en" messages={messages} defaultLocale="en" textComponent="span">
<Notifications>
<div />
</Notifications>
</IntlProvider>
</Theme>
</ThemeToggleProvider>
);
expect(firstChild).toMatchInlineSnapshot(`
@ -80,13 +84,15 @@ describe('<Notifications />', () => {
};
render(
<Theme>
<IntlProvider locale="en" defaultLocale="en" messages={messages} textComponent="span">
<Notifications>
<Button />
</Notifications>
</IntlProvider>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<IntlProvider locale="en" defaultLocale="en" messages={messages} textComponent="span">
<Notifications>
<Button />
</Notifications>
</IntlProvider>
</Theme>
</ThemeToggleProvider>
);
// Click button
@ -121,13 +127,15 @@ describe('<Notifications />', () => {
};
render(
<Theme>
<IntlProvider locale="en" defaultLocale="en" messages={messages} textComponent="span">
<Notifications>
<Button />
</Notifications>
</IntlProvider>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<IntlProvider locale="en" defaultLocale="en" messages={messages} textComponent="span">
<Notifications>
<Button />
</Notifications>
</IntlProvider>
</Theme>
</ThemeToggleProvider>
);
// Click button

View File

@ -9,6 +9,8 @@ import GuidedTour from '../GuidedTour';
import AutoReloadOverlayBlockerProvider from '../AutoReloadOverlayBlockerProvider';
import Notifications from '../Notifications';
import OverlayBlocker from '../OverlayBlocker';
import ThemeToggleProvider from '../ThemeToggleProvider';
import Theme from '../Theme';
const queryClient = new QueryClient({
defaultOptions: {
@ -36,41 +38,45 @@ const Providers = ({
settings,
showReleaseNotification,
showTutorials,
store,
themes,
}) => {
return (
<QueryClientProvider client={queryClient}>
<Provider store={store}>
<AdminContext.Provider value={{ getAdminInjectedComponents }}>
<ConfigurationsContext.Provider
value={{ authLogo, menuLogo, showReleaseNotification, showTutorials }}
>
<StrapiAppProvider
getPlugin={getPlugin}
menu={menu}
plugins={plugins}
runHookParallel={runHookParallel}
runHookWaterfall={runHookWaterfall}
runHookSeries={runHookSeries}
settings={settings}
>
<LibraryProvider components={components} fields={fields}>
<LanguageProvider messages={messages} localeNames={localeNames}>
<AutoReloadOverlayBlockerProvider>
<OverlayBlocker>
<GuidedTour>
<Notifications>{children}</Notifications>
</GuidedTour>
</OverlayBlocker>
</AutoReloadOverlayBlockerProvider>
</LanguageProvider>
</LibraryProvider>
</StrapiAppProvider>
</ConfigurationsContext.Provider>
</AdminContext.Provider>
</Provider>
</QueryClientProvider>
<ThemeToggleProvider themes={themes}>
<Theme>
<QueryClientProvider client={queryClient}>
<Provider store={store}>
<AdminContext.Provider value={{ getAdminInjectedComponents }}>
<ConfigurationsContext.Provider
value={{ authLogo, menuLogo, showReleaseNotification, showTutorials }}
>
<StrapiAppProvider
getPlugin={getPlugin}
menu={menu}
plugins={plugins}
runHookParallel={runHookParallel}
runHookWaterfall={runHookWaterfall}
runHookSeries={runHookSeries}
settings={settings}
>
<LibraryProvider components={components} fields={fields}>
<LanguageProvider messages={messages} localeNames={localeNames}>
<AutoReloadOverlayBlockerProvider>
<OverlayBlocker>
<GuidedTour>
<Notifications>{children}</Notifications>
</GuidedTour>
</OverlayBlocker>
</AutoReloadOverlayBlockerProvider>
</LanguageProvider>
</LibraryProvider>
</StrapiAppProvider>
</ConfigurationsContext.Provider>
</AdminContext.Provider>
</Provider>
</QueryClientProvider>
</Theme>
</ThemeToggleProvider>
);
};
@ -104,6 +110,33 @@ Providers.propTypes = {
showReleaseNotification: PropTypes.bool.isRequired,
showTutorials: PropTypes.bool.isRequired,
store: PropTypes.object.isRequired,
themes: PropTypes.shape({
light: PropTypes.shape({
colors: PropTypes.object.isRequired,
shadows: PropTypes.object.isRequired,
sizes: PropTypes.object.isRequired,
zIndices: PropTypes.array.isRequired,
spaces: PropTypes.array.isRequired,
borderRadius: PropTypes.string.isRequired,
mediaQueries: PropTypes.object.isRequired,
fontSizes: PropTypes.array.isRequired,
lineHeights: PropTypes.array.isRequired,
fontWeights: PropTypes.object.isRequired,
}).isRequired,
dark: PropTypes.shape({
colors: PropTypes.object.isRequired,
shadows: PropTypes.object.isRequired,
sizes: PropTypes.object.isRequired,
zIndices: PropTypes.array.isRequired,
spaces: PropTypes.array.isRequired,
borderRadius: PropTypes.string.isRequired,
mediaQueries: PropTypes.object.isRequired,
fontSizes: PropTypes.array.isRequired,
lineHeights: PropTypes.array.isRequired,
fontWeights: PropTypes.object.isRequired,
}).isRequired,
custom: PropTypes.object,
}).isRequired,
};
export default Providers;

View File

@ -1,23 +1,22 @@
import React from 'react';
import { ThemeProvider } from '@strapi/design-system/ThemeProvider';
import PropTypes from 'prop-types';
import { lightTheme } from '@strapi/design-system/themes';
import { useThemeToggle } from '../../hooks';
import GlobalStyle from '../GlobalStyle';
const Theme = ({ children, theme }) => (
<ThemeProvider theme={theme}>
{children}
<GlobalStyle />
</ThemeProvider>
);
const Theme = ({ children }) => {
const { currentTheme, themes } = useThemeToggle();
return (
<ThemeProvider theme={themes[currentTheme] || themes.light}>
{children}
<GlobalStyle />
</ThemeProvider>
);
};
Theme.propTypes = {
children: PropTypes.element.isRequired,
theme: PropTypes.object,
};
Theme.defaultProps = {
theme: lightTheme,
};
export default Theme;

View File

@ -0,0 +1,66 @@
/**
*
* ThemeToggleProvider
*
*/
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { ThemeToggleContext } from '../../contexts';
const THEME_KEY = 'STRAPI_THEME';
const getDefaultTheme = () => {
const browserTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
const persistedTheme = localStorage.getItem(THEME_KEY);
return persistedTheme || browserTheme;
};
const ThemeToggleProvider = ({ children, themes }) => {
const [currentTheme, setCurrentTheme] = useState(getDefaultTheme());
const handleChangeTheme = nextTheme => {
setCurrentTheme(nextTheme);
localStorage.setItem(THEME_KEY, nextTheme);
};
return (
<ThemeToggleContext.Provider value={{ currentTheme, onChangeTheme: handleChangeTheme, themes }}>
{children}
</ThemeToggleContext.Provider>
);
};
ThemeToggleProvider.propTypes = {
children: PropTypes.node.isRequired,
themes: PropTypes.shape({
light: PropTypes.shape({
colors: PropTypes.object.isRequired,
shadows: PropTypes.object.isRequired,
sizes: PropTypes.object.isRequired,
zIndices: PropTypes.array.isRequired,
spaces: PropTypes.array.isRequired,
borderRadius: PropTypes.string.isRequired,
mediaQueries: PropTypes.object.isRequired,
fontSizes: PropTypes.array.isRequired,
lineHeights: PropTypes.array.isRequired,
fontWeights: PropTypes.object.isRequired,
}).isRequired,
dark: PropTypes.shape({
colors: PropTypes.object.isRequired,
shadows: PropTypes.object.isRequired,
sizes: PropTypes.object.isRequired,
zIndices: PropTypes.array.isRequired,
spaces: PropTypes.array.isRequired,
borderRadius: PropTypes.string.isRequired,
mediaQueries: PropTypes.object.isRequired,
fontSizes: PropTypes.array.isRequired,
lineHeights: PropTypes.array.isRequired,
fontWeights: PropTypes.object.isRequired,
}).isRequired,
custom: PropTypes.object,
}).isRequired,
};
export default ThemeToggleProvider;

View File

@ -8,7 +8,9 @@ import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { render, screen } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import { lightTheme } from '@strapi/design-system';
import Theme from '../../../../components/Theme';
import ThemeToggleProvider from '../../../../components/ThemeToggleProvider';
import { App as ContentManagerApp } from '..';
import cmReducers from '../../../../reducers';
import useModels from '../useModels';
@ -96,15 +98,17 @@ describe('Content manager | App | main', () => {
const { container } = render(
<IntlProvider messages={{}} defaultLocale="en" locale="en">
<Theme>
<DndProvider backend={HTML5Backend}>
<Provider store={store}>
<Router history={history}>
<ContentManagerApp />
</Router>
</Provider>
</DndProvider>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<DndProvider backend={HTML5Backend}>
<Provider store={store}>
<Router history={history}>
<ContentManagerApp />
</Router>
</Provider>
</DndProvider>
</Theme>
</ThemeToggleProvider>
</IntlProvider>
);
@ -795,15 +799,17 @@ describe('Content manager | App | main', () => {
render(
<IntlProvider messages={{}} defaultLocale="en" locale="en">
<Theme>
<DndProvider backend={HTML5Backend}>
<Provider store={store}>
<Router history={history}>
<ContentManagerApp />
</Router>
</Provider>
</DndProvider>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<DndProvider backend={HTML5Backend}>
<Provider store={store}>
<Router history={history}>
<ContentManagerApp />
</Router>
</Provider>
</DndProvider>
</Theme>
</ThemeToggleProvider>
</IntlProvider>
);
@ -839,15 +845,17 @@ describe('Content manager | App | main', () => {
render(
<IntlProvider messages={{}} defaultLocale="en" locale="en">
<Theme>
<DndProvider backend={HTML5Backend}>
<Provider store={store}>
<Router history={history}>
<ContentManagerApp />
</Router>
</Provider>
</DndProvider>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<DndProvider backend={HTML5Backend}>
<Provider store={store}>
<Router history={history}>
<ContentManagerApp />
</Router>
</Provider>
</DndProvider>
</Theme>
</ThemeToggleProvider>
</IntlProvider>
);
@ -882,15 +890,17 @@ describe('Content manager | App | main', () => {
render(
<IntlProvider messages={{}} defaultLocale="en" locale="en">
<Theme>
<DndProvider backend={HTML5Backend}>
<Provider store={store}>
<Router history={history}>
<ContentManagerApp />
</Router>
</Provider>
</DndProvider>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<DndProvider backend={HTML5Backend}>
<Provider store={store}>
<Router history={history}>
<ContentManagerApp />
</Router>
</Provider>
</DndProvider>
</Theme>
</ThemeToggleProvider>
</IntlProvider>
);

View File

@ -8,7 +8,9 @@ import React from 'react';
import { render } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import { MemoryRouter } from 'react-router-dom';
import { lightTheme } from '@strapi/design-system';
import Theme from '../../../../../components/Theme';
import ThemeToggleProvider from '../../../../../components/ThemeToggleProvider';
import { Header } from '../index';
import components from '../utils/tests/data/compos-schema.json';
import ct from '../utils/tests/data/ct-schema.json';
@ -31,9 +33,11 @@ const makeApp = (props = defaultProps) => {
return (
<MemoryRouter>
<IntlProvider locale="en" defaultLocale="en" messages={{}}>
<Theme>
<Header {...props} />
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<Header {...props} />
</Theme>
</ThemeToggleProvider>
</IntlProvider>
</MemoryRouter>
);
@ -46,63 +50,6 @@ describe('CONTENT MANAGER | EditView | Header', () => {
} = render(makeApp());
expect(firstChild).toMatchInlineSnapshot(`
.c0 {
background: #f6f6f9;
padding-top: 24px;
padding-right: 56px;
padding-bottom: 40px;
padding-left: 56px;
}
.c1 {
padding-bottom: 8px;
}
.c6 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c7 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c8 {
color: #32324d;
font-weight: 600;
font-size: 2rem;
line-height: 1.25;
}
.c15 {
color: #666687;
font-size: 1rem;
line-height: 1.5;
}
.c14 {
font-weight: 600;
color: #32324d;
@ -180,7 +127,7 @@ describe('CONTENT MANAGER | EditView | Header', () => {
background: #4945ff;
}
.c12 .sc-egiyK {
.c12 .sc-fTQvRK {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -233,6 +180,86 @@ describe('CONTENT MANAGER | EditView | Header', () => {
background: #4945ff;
}
.c9 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c10 > * {
margin-left: 0;
margin-right: 0;
}
.c10 > * + * {
margin-left: 8px;
}
.c0 {
background: #f6f6f9;
padding-top: 24px;
padding-right: 56px;
padding-bottom: 40px;
padding-left: 56px;
}
.c1 {
padding-bottom: 8px;
}
.c6 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c7 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c8 {
color: #32324d;
font-weight: 600;
font-size: 2rem;
line-height: 1.25;
}
.c15 {
color: #666687;
font-size: 1rem;
line-height: 1.5;
}
.c5 {
color: #4945ff;
font-size: 0.75rem;
@ -303,29 +330,6 @@ describe('CONTENT MANAGER | EditView | Header', () => {
display: flex;
}
.c9 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c10 > * {
margin-left: 0;
margin-right: 0;
}
.c10 > * + * {
margin-left: 8px;
}
<div
style="height: 0px;"
>

View File

@ -8,7 +8,9 @@ import React from 'react';
import { render } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import { useCMEditViewDataManager } from '@strapi/helper-plugin';
import { lightTheme } from '@strapi/design-system';
import Theme from '../../../../../components/Theme';
import ThemeToggleProvider from '../../../../../components/ThemeToggleProvider';
import Informations from '../index';
jest.mock('@strapi/helper-plugin', () => ({
@ -22,9 +24,11 @@ const makeApp = () => {
defaultLocale="en"
messages={{ 'containers.Edit.information': 'Information' }}
>
<Theme>
<Informations />
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<Informations />
</Theme>
</ThemeToggleProvider>
</IntlProvider>
);
};

View File

@ -3,7 +3,9 @@ import { render } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import { lightTheme } from '@strapi/design-system';
import Theme from '../../../../components/Theme';
import ThemeToggleProvider from '../../../../components/ThemeToggleProvider';
import NoContentType from '../index';
jest.mock('@strapi/helper-plugin', () => ({
@ -17,9 +19,11 @@ describe('CONTENT MANAGER | pages | NoContentType', () => {
} = render(
<Router history={createMemoryHistory()}>
<IntlProvider messages={{}} defaultLocale="en" textComponent="span" locale="en">
<Theme>
<NoContentType />
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<NoContentType />
</Theme>
</ThemeToggleProvider>
</IntlProvider>
</Router>
);

View File

@ -7,7 +7,9 @@
import React from 'react';
import { render } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import { lightTheme } from '@strapi/design-system';
import Theme from '../../../../components/Theme';
import ThemeToggleProvider from '../../../../components/ThemeToggleProvider';
import NoPermissions from '../index';
jest.mock('@strapi/helper-plugin', () => ({
@ -21,9 +23,11 @@ describe('<NoPermissions />', () => {
container: { firstChild },
} = render(
<IntlProvider locale="en" messages={{}} defaultLocale="en" textComponent="span">
<Theme>
<NoPermissions />
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<NoPermissions />
</Theme>
</ThemeToggleProvider>
</IntlProvider>
);

View File

@ -0,0 +1,5 @@
import { createContext } from 'react';
const ThemeToggleContext = createContext({});
export default ThemeToggleContext;

View File

@ -1,3 +1,4 @@
export { default as AdminContext } from './Admin';
export { default as ConfigurationsContext } from './Configurations';
export { default as PermissionsDataManagerContext } from './PermisssionsDataManagerContext';
export { default as ThemeToggleContext } from './ThemeToggle';

View File

@ -9,3 +9,4 @@ export { default as useSettingsMenu } from './useSettingsMenu';
export { default as useSettingsForm } from './useSettingsForm';
export { default as usePermissionsDataManager } from './usePermissionsDataManager';
export { default as useReleaseNotification } from './useReleaseNotification';
export { default as useThemeToggle } from './useThemeToggle';

View File

@ -0,0 +1,10 @@
import { useContext } from 'react';
import { ThemeToggleContext } from '../../contexts';
const useThemeToggle = () => {
const context = useContext(ThemeToggleContext);
return context;
};
export default useThemeToggle;

View File

@ -12,9 +12,9 @@ import {
} from '@strapi/helper-plugin';
import { useIntl } from 'react-intl';
import { Formik } from 'formik';
import upperFirst from 'lodash/upperFirst';
import { useQuery, useMutation, useQueryClient } from 'react-query';
import pick from 'lodash/pick';
import omit from 'lodash/omit';
import { Helmet } from 'react-helmet';
import { Main } from '@strapi/design-system/Main';
import { Typography } from '@strapi/design-system/Typography';
@ -31,6 +31,7 @@ import Eye from '@strapi/icons/Eye';
import EyeStriked from '@strapi/icons/EyeStriked';
import Check from '@strapi/icons/Check';
import useLocalesProvider from '../../components/LocalesProvider/useLocalesProvider';
import { useThemeToggle } from '../../hooks';
import { fetchUser, putUser } from './utils/api';
import schema from './utils/schema';
import { getFullName } from '../../utils';
@ -62,6 +63,7 @@ const ProfilePage = () => {
const toggleNotification = useNotification();
const { lockApp, unlockApp } = useOverlayBlocker();
const { notifyStatus } = useNotifyAT();
const { currentTheme, themes: allApplicationThemes, onChangeTheme } = useThemeToggle();
useFocusWhenNavigate();
const { status, data } = useQuery('user', () => fetchUser(), {
@ -83,14 +85,17 @@ const ProfilePage = () => {
const isLoading = status !== 'success';
const submitMutation = useMutation(body => putUser(omit(body, 'confirmPassword')), {
const submitMutation = useMutation(body => putUser(body), {
onSuccess: async data => {
await queryClient.invalidateQueries('user');
auth.setUserInfo(data);
auth.setUserInfo(
pick(data, ['email', 'firstname', 'lastname', 'username', 'preferedLanguage'])
);
const userDisplayName = data.username || getFullName(data.firstname, data.lastname);
setUserDisplayName(userDisplayName);
changeLocale(data.preferedLanguage);
onChangeTheme(data.currentTheme);
toggleNotification({
type: 'success',
@ -128,9 +133,16 @@ const ProfilePage = () => {
);
};
const fieldsToPick = ['email', 'firstname', 'lastname', 'username', 'preferedLanguage'];
const fieldsToPick = [
'currentTheme',
'email',
'firstname',
'lastname',
'username',
'preferedLanguage',
];
const initialData = pick(data, fieldsToPick);
const initialData = pick({ ...data, currentTheme }, fieldsToPick);
if (isLoading) {
return (
@ -154,6 +166,10 @@ const ProfilePage = () => {
);
}
const themesToDisplay = Object.keys(allApplicationThemes).filter(
themeName => allApplicationThemes[themeName]
);
return (
<Main aria-busy={isSubmittingForm}>
<Helmet
@ -487,6 +503,47 @@ const ProfilePage = () => {
})}
</Select>
</GridItem>
<GridItem s={12} col={6}>
<Select
label={formatMessage({
id: 'Settings.profile.form.section.experience.mode.label',
defaultMessage: 'Interface mode',
})}
placeholder={formatMessage({
id: 'components.Select.placeholder',
defaultMessage: 'Select',
})}
hint={formatMessage({
id: 'Settings.profile.form.section.experience.mode.hint',
defaultMessage: 'Displays your interface in the chosen mode.',
})}
value={values.currentTheme}
onChange={e => {
handleChange({
target: { name: 'currentTheme', value: e },
});
}}
>
{themesToDisplay.map(theme => {
const label = formatMessage(
{
id:
'Settings.profile.form.section.experience.mode.option-label',
defaultMessage: '{name} mode',
},
{
name: upperFirst(theme),
}
);
return (
<Option value={theme} key={theme}>
{label}
</Option>
);
})}
</Select>
</GridItem>
</Grid>
</Stack>
</Box>

View File

@ -2,9 +2,11 @@ import React from 'react';
import { render, waitFor, screen } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import { QueryClient, QueryClientProvider } from 'react-query';
import { ThemeProvider, lightTheme } from '@strapi/design-system';
import { lightTheme } from '@strapi/design-system';
import ProfilePage from '../index';
import server from './utils/server';
import ThemeToggleProvider from '../../../components/ThemeToggleProvider';
import Theme from '../../../components/Theme';
jest.mock('../../../components/LocalesProvider/useLocalesProvider', () => () => ({
changeLocale: () => {},
@ -31,9 +33,11 @@ const client = new QueryClient({
const App = (
<QueryClientProvider client={client}>
<IntlProvider messages={{}} textComponent="span" locale="en">
<ThemeProvider theme={lightTheme}>
<ProfilePage />
</ThemeProvider>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<ProfilePage />
</Theme>
</ThemeToggleProvider>
</IntlProvider>
</QueryClientProvider>
);
@ -1327,6 +1331,90 @@ describe('ADMIN | Pages | Profile page', () => {
</div>
</div>
</div>
<div
class="c20"
>
<div
class=""
>
<div>
<div
class="c36"
>
<span
class="c37"
for="select-2"
id="select-2-label"
>
Interface mode
</span>
<div
class="c38 c39"
>
<button
aria-describedby="select-2-hint"
aria-disabled="false"
aria-expanded="false"
aria-haspopup="listbox"
aria-labelledby="select-2-label select-2-content"
class="c40"
id="select-2"
type="button"
/>
<div
class="c41 c42"
>
<div
class="c38"
>
<div
class="c43"
>
<span
class="c44"
id="select-2-content"
>
Light mode
</span>
</div>
</div>
<div
class="c38"
>
<button
aria-hidden="true"
class="c46 c45 c47"
tabindex="-1"
type="button"
>
<svg
fill="none"
height="1em"
viewBox="0 0 14 8"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
d="M14 .889a.86.86 0 01-.26.625L7.615 7.736A.834.834 0 017 8a.834.834 0 01-.615-.264L.26 1.514A.861.861 0 010 .889c0-.24.087-.45.26-.625A.834.834 0 01.875 0h12.25c.237 0 .442.088.615.264a.86.86 0 01.26.625z"
fill="#32324D"
fill-rule="evenodd"
/>
</svg>
</button>
</div>
</div>
</div>
<p
class="c48"
id="select-2-hint"
>
Displays your interface in the chosen mode.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,3 +1,4 @@
import omit from 'lodash/omit';
import { axiosInstance } from '../../../core/utils';
const fetchUser = async () => {
@ -7,9 +8,10 @@ const fetchUser = async () => {
};
const putUser = async body => {
const { data } = await axiosInstance.put('/admin/users/me', body);
const dataToSend = omit(body, ['confirmPassword', 'currentTheme']);
const { data } = await axiosInstance.put('/admin/users/me', dataToSend);
return data.data;
return { ...data.data, currentTheme: body.currentTheme };
};
export { fetchUser, putUser };

View File

@ -5,8 +5,10 @@ import { Router, Route } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import { useRBAC } from '@strapi/helper-plugin';
import { QueryClient, QueryClientProvider } from 'react-query';
import { lightTheme } from '@strapi/design-system';
import { axiosInstance } from '../../../../../../core/utils';
import Theme from '../../../../../../components/Theme';
import ThemeToggleProvider from '../../../../../../components/ThemeToggleProvider';
import ListView from '../index';
jest.mock('@strapi/helper-plugin', () => ({
@ -49,13 +51,15 @@ const makeApp = history => {
return (
<QueryClientProvider client={client}>
<IntlProvider messages={{}} defaultLocale="en" textComponent="span" locale="en">
<Theme>
<Router history={history}>
<Route path="/settings/api-tokens">
<ListView />
</Route>
</Router>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<Router history={history}>
<Route path="/settings/api-tokens">
<ListView />
</Route>
</Router>
</Theme>
</ThemeToggleProvider>
</IntlProvider>
</QueryClientProvider>
);

View File

@ -104,7 +104,7 @@ exports[`<EditPage /> renders and matches the snapshot 1`] = `
background: #4945ff;
}
.c13 .sc-eCImPb {
.c13 .sc-fTQvRK {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -169,7 +169,7 @@ exports[`<EditPage /> renders and matches the snapshot 1`] = `
background: #f0f0ff;
}
.c24 .sc-eCImPb {
.c24 .sc-fTQvRK {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;

View File

@ -10,7 +10,9 @@ import { IntlProvider } from 'react-intl';
import { Router, Switch, Route } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import moment from 'moment';
import { lightTheme } from '@strapi/design-system';
import Theme from '../../../../../../components/Theme';
import ThemeToggleProvider from '../../../../../../components/ThemeToggleProvider';
import EditPage from '../index';
@ -37,15 +39,17 @@ const makeApp = history => (
locale="en"
defaultLocale="en"
>
<Theme>
<Router history={history}>
<Switch>
<Route path="/settings/roles/:id">
<EditPage />
</Route>
</Switch>
</Router>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<Router history={history}>
<Switch>
<Route path="/settings/roles/:id">
<EditPage />
</Route>
</Switch>
</Router>
</Theme>
</ThemeToggleProvider>
</IntlProvider>
);

View File

@ -10,9 +10,11 @@ import { createMemoryHistory } from 'history';
import { Router } from 'react-router-dom';
import { IntlProvider } from 'react-intl';
import { useRBAC } from '@strapi/helper-plugin';
import { lightTheme } from '@strapi/design-system';
import { useRolesList } from '../../../../../../hooks';
import Theme from '../../../../../../components/Theme';
import ThemeToggleProvider from '../../../../../../components/ThemeToggleProvider';
import ListPage from '../index';
jest.mock('@strapi/helper-plugin', () => ({
@ -31,11 +33,13 @@ jest.mock('../../../../../../hooks', () => ({
const makeApp = history => (
<IntlProvider messages={{}} defaultLocale="en" textComponent="span" locale="en">
<Theme>
<Router history={history}>
<ListPage />
</Router>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<Router history={history}>
<ListPage />
</Router>
</Theme>
</ThemeToggleProvider>
</IntlProvider>
);

View File

@ -466,7 +466,7 @@ exports[`DynamicTable renders and matches the snapshot 1`] = `
</div>
<nav
aria-label="pagination"
class="sc-fHeRUh"
class="sc-jwQYvw"
>
<ul
class="c16 c17"

View File

@ -3,19 +3,23 @@ import { render } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import { createMemoryHistory } from 'history';
import { Router, Route } from 'react-router-dom';
import { lightTheme } from '@strapi/design-system';
import Theme from '../../../../../../../components/Theme';
import ThemeToggleProvider from '../../../../../../../components/ThemeToggleProvider';
import PaginationFooter from '../index';
const makeApp = (history, pagination) => {
return (
<IntlProvider messages={{}} textComponent="span" locale="en" defaultLocale="en">
<Theme>
<Router history={history}>
<Route path="/settings/user">
<PaginationFooter pagination={pagination} />
</Route>
</Router>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<Router history={history}>
<Route path="/settings/user">
<PaginationFooter pagination={pagination} />
</Route>
</Router>
</Theme>
</ThemeToggleProvider>
</IntlProvider>
);
};

View File

@ -5,7 +5,9 @@ import { Router, Route } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from 'react-query';
import { createMemoryHistory } from 'history';
import { useRBAC } from '@strapi/helper-plugin';
import { lightTheme } from '@strapi/design-system';
import Theme from '../../../../../../components/Theme';
import ThemeToggleProvider from '../../../../../../components/ThemeToggleProvider';
import ListPage from '../index';
import server from './utils/server';
@ -30,13 +32,15 @@ const makeApp = history => {
return (
<QueryClientProvider client={client}>
<IntlProvider messages={{}} defaultLocale="en" textComponent="span" locale="en">
<Theme>
<Router history={history}>
<Route path="/settings/user">
<ListPage />
</Route>
</Router>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<Router history={history}>
<Route path="/settings/user">
<ListPage />
</Route>
</Router>
</Theme>
</ThemeToggleProvider>
</IntlProvider>
</QueryClientProvider>
);

View File

@ -3,8 +3,10 @@ import userEvent from '@testing-library/user-event';
import React from 'react';
import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import { lightTheme } from '@strapi/design-system';
import en from '../../../../../../../../translations/en.json';
import Theme from '../../../../../../../../components/Theme';
import ThemeToggleProvider from '../../../../../../../../components/ThemeToggleProvider';
import LanguageProvider from '../../../../../../../../components/LanguageProvider';
import WebhookForm from '../index';
@ -15,9 +17,11 @@ const makeApp = component => {
return (
<LanguageProvider messages={messages} localeNames={localeNames}>
<Theme>
<Router history={history}>{component}</Router>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<Router history={history}>{component}</Router>
</Theme>
</ThemeToggleProvider>
</LanguageProvider>
);
};

View File

@ -4,13 +4,16 @@ import { StrapiAppProvider, AppInfosContext } from '@strapi/helper-plugin';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { createMemoryHistory } from 'history';
import { lightTheme } from '@strapi/design-system';
import Theme from '../../../components/Theme';
import ThemeToggleProvider from '../../../components/ThemeToggleProvider';
import { SettingsPage } from '..';
import { useSettingsMenu } from '../../../hooks';
jest.mock('../../../hooks', () => ({
useSettingsMenu: jest.fn(() => ({ isLoading: false, menu: [] })),
useAppInfos: jest.fn(() => ({ shouldUpdateStrapi: false })),
useThemeToggle: jest.fn(() => ({ currentTheme: 'light', themes: { light: lightTheme } })),
}));
jest.mock('@fortawesome/react-fontawesome', () => ({
@ -24,24 +27,26 @@ jest.mock('react-intl', () => ({
jest.mock('../pages/ApplicationInfosPage', () => () => <h1>App infos</h1>);
const makeApp = (history, settings) => (
<Theme>
<AppInfosContext.Provider value={{ shouldUpdateStrapi: false }}>
<StrapiAppProvider
settings={settings}
plugins={{}}
getPlugin={jest.fn()}
runHookParallel={jest.fn()}
runHookWaterfall={jest.fn()}
runHookSeries={jest.fn()}
menu={[]}
>
<Router history={history}>
<Route path="/settings/:settingId" component={SettingsPage} />
<Route path="/settings" component={SettingsPage} />
</Router>
</StrapiAppProvider>
</AppInfosContext.Provider>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<AppInfosContext.Provider value={{ shouldUpdateStrapi: false }}>
<StrapiAppProvider
settings={settings}
plugins={{}}
getPlugin={jest.fn()}
runHookParallel={jest.fn()}
runHookWaterfall={jest.fn()}
runHookSeries={jest.fn()}
menu={[]}
>
<Router history={history}>
<Route path="/settings/:settingId" component={SettingsPage} />
<Route path="/settings" component={SettingsPage} />
</Router>
</StrapiAppProvider>
</AppInfosContext.Provider>
</Theme>
</ThemeToggleProvider>
);
describe('ADMIN | pages | SettingsPage', () => {

View File

@ -0,0 +1,102 @@
// TODO delete this file when we release the DS.
const darkTheme = {
colors: {
alternative100: '#212134',
alternative200: '#4a4a6a',
alternative500: '#ac73e6',
alternative600: '#f6ecfc',
alternative700: '#e0c1f4',
danger100: '#212134',
danger200: '#4a4a6a',
danger500: '#ee5e52',
danger600: '#fcecea',
danger700: '#f5c0b8',
neutral0: '#212134',
neutral100: '#181826',
neutral1000: '#ffffff',
neutral150: '#4a4a6a',
neutral200: '#666687',
neutral300: '#666687',
neutral400: '#a5a5ba',
neutral500: '#c0c0cf',
neutral600: '#a5a5ba',
neutral700: '#eaeaef',
neutral800: '#ffffff',
neutral900: '#ffffff',
primary100: '#212134',
primary200: '#4a4a6a',
primary500: '#d9d8ff',
primary600: '#7b79ff',
primary700: '#7b79ff',
secondary100: '#212134',
secondary200: '#4a4a6a',
secondary500: '#66b7f1',
secondary600: '#eaf5ff',
secondary700: '#b8e1ff',
success100: '#212134',
success200: '#4a4a6a',
success500: '#5cb176',
success600: '#c6f0c2',
success700: '#c6f0c2',
warning100: '#212134',
warning200: '#4a4a6a',
warning500: '#f29d41',
warning600: '#fdf4dc',
warning700: '#fae7b9',
},
shadows: {
filterShadow: '0px 1px 4px rgba(33, 33, 52, 0.1)',
focus:
'inset 2px 0px 0px rgb(39, 31, 224), inset 0px 2px 0px rgb(39, 31, 224), inset -2px 0px 0px rgb(39, 31, 224), inset 0px -2px 0px rgb(39, 31, 224)',
focusShadow: '0px 0px 6px rgba(76, 191, 255, 0.75)',
popupShadow: '0px 2px 15px rgba(33, 33, 52, 0.1)',
tableShadow: '0px 1px 4px rgba(33, 33, 52, 0.1)',
},
sizes: {
input: {
S: `${32 / 16}rem`,
M: `${40 / 16}rem`,
},
accordions: {
S: `${48 / 16}rem`,
M: `${88 / 16}rem`,
},
},
zIndices: [5, 10, 15, 20], // TBD
spaces: [
'0px',
'4px',
'8px',
'12px',
'16px',
'20px',
'24px',
'32px',
'40px',
'48px',
'56px',
'64px',
],
borderRadius: '4px',
mediaQueries: {
tablet: `@media (max-width: ${1100 / 16}rem)`,
mobile: `@media (max-width: ${550 / 16}rem)`,
},
fontSizes: [
`${11 / 16}rem`,
`${12 / 16}rem`,
`${14 / 16}rem`,
'1rem',
`${18 / 16}rem`,
`${32 / 16}rem`,
],
lineHeights: [1.14, 1.22, 1.25, 1.33, 1.43, 1.45, 1.5],
fontWeights: {
regular: 400,
semiBold: 500,
bold: 600,
},
};
export default darkTheme;

View File

@ -299,7 +299,7 @@ describe('ADMIN | StrapiApp', () => {
app.createCustomConfigurations();
expect(app.configurations.theme.main.colors.red).toBe('black');
expect(app.configurations.themes.custom.main.colors.red).toBe('black');
});
it('should override the tutorials', () => {

View File

@ -1,51 +0,0 @@
const colors = {
black: '#333740',
white: '#ffffff',
red: '#ff203c',
orange: '#ff5d00',
lightOrange: '#f64d0a',
yellow: '#ffd500',
green: '#6dbb1a',
blue: '#0097f7',
teal: '#5bc0de',
pink: '#ff5b77',
purple: '#613d7c',
gray: '#464a4c',
border: '#e3e9f3',
'gray-dark': '#292b2c',
grayLight: '#636c72',
'gray-lighter': '#eceeef',
'gray-lightest': '#f7f7f9',
brightGrey: '#f0f3f8',
darkGrey: '#e3e9f3',
lightGrey: '#fafafa',
lightestGrey: '#fbfbfb',
mediumGrey: '#f2f3f4',
grey: '#9ea7b8',
greyDark: '#292b2c',
greyAlpha: 'rgba(227, 233, 243, 0.5)',
lightestBlue: '#e4f0fc',
lightBlue: '#e6f0fb',
mediumBlue: '#007eff',
darkBlue: '#aed4fb',
pale: '#f7f8f8',
content: {
background: '#fafafb',
'background-alpha': 'rgba(14, 22, 34, 0.02)',
},
leftMenu: {
'link-hover': '#1c2431',
'link-color': '#919bae',
'title-color': '#5b626f',
'background-header-link': '#007eff',
},
strapi: {
'gray-light': '#eff3f6',
gray: '#535f76',
'blue-darker': '#18202e',
'blue-dark': '#151c2e',
blue: '#0097f7',
},
};
export default colors;

View File

@ -1,8 +0,0 @@
const fontWeights = {
regular: 400,
semiBold: 500,
bold: 600,
black: 900,
};
export default fontWeights;

View File

@ -1,13 +0,0 @@
import colors from './colors';
import fontWeights from './fontWeights';
import sizes from './sizes';
const theme = {
main: {
colors,
fontWeights,
sizes,
},
};
export default theme;

View File

@ -1,31 +0,0 @@
const sizes = {
borderRadius: '2px',
header: {
height: '6rem',
},
leftMenu: {
height: '6rem',
width: '24rem',
},
margins: {
// TODO:
sm: '10px',
},
paddings: {
// TODO
xs: '5px',
sm: '10px',
smd: '20px',
md: '30px',
lg: '40px',
},
fonts: {
xs: '11px',
sm: '12px',
md: '13px',
lg: '18px',
xl: '24px',
},
};
export default sizes;

View File

@ -137,6 +137,9 @@
"Settings.profile.form.section.experience.interfaceLanguage": "Interface language",
"Settings.profile.form.section.experience.interfaceLanguage.hint": "This will only display your own interface in the chosen language.",
"Settings.profile.form.section.experience.interfaceLanguageHelp": "Selection will change the interface language only for you. Please refer to this {documentation} to make other languages available for your team.",
"Settings.profile.form.section.experience.mode.label": "Interface mode",
"Settings.profile.form.section.experience.mode.hint": "Displays your interface in the chosen mode.",
"Settings.profile.form.section.experience.mode.option-label": "{name} mode",
"Settings.profile.form.section.experience.title": "Experience",
"Settings.profile.form.section.helmet.title": "User profile",
"Settings.profile.form.section.password.title": "Change password",

View File

@ -97,7 +97,7 @@ exports[`<CreatePage /> renders and matches the snapshot 1`] = `
background: #f0f0ff;
}
.c13 .sc-eCImPb {
.c13 .sc-fTQvRK {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -179,7 +179,7 @@ exports[`<CreatePage /> renders and matches the snapshot 1`] = `
background: #4945ff;
}
.c16 .sc-eCImPb {
.c16 .sc-fTQvRK {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;

View File

@ -10,7 +10,9 @@ import { IntlProvider } from 'react-intl';
import { Router, Switch, Route } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import moment from 'moment';
import { lightTheme } from '@strapi/design-system';
import Theme from '../../../../../../../../admin/src/components/Theme';
import ThemeToggleProvider from '../../../../../../../../admin/src/components/ThemeToggleProvider';
import { CreatePage } from '../index';
@ -37,18 +39,20 @@ const makeApp = history => (
locale="en"
defaultLocale="en"
>
<Theme>
<Router history={history}>
<Switch>
<Route path="/settings/roles/duplicate/:id">
<CreatePage />
</Route>
<Route path="/settings/roles/new">
<CreatePage />
</Route>
</Switch>
</Router>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<Router history={history}>
<Switch>
<Route path="/settings/roles/duplicate/:id">
<CreatePage />
</Route>
<Route path="/settings/roles/new">
<CreatePage />
</Route>
</Switch>
</Router>
</Theme>
</ThemeToggleProvider>
</IntlProvider>
);

View File

@ -10,9 +10,11 @@ import { createMemoryHistory } from 'history';
import { Router } from 'react-router-dom';
import { IntlProvider } from 'react-intl';
import { useRBAC } from '@strapi/helper-plugin';
import { lightTheme } from '@strapi/design-system';
import { useRolesList } from '../../../../../../../../admin/src/hooks';
import Theme from '../../../../../../../../admin/src/components/Theme';
import ThemeToggleProvider from '../../../../../../../../admin/src/components/ThemeToggleProvider';
import ListPage from '../index';
jest.mock('@strapi/helper-plugin', () => ({
@ -31,11 +33,13 @@ jest.mock('../../../../../../../../admin/src/hooks', () => ({
const makeApp = history => (
<IntlProvider messages={{}} textComponent="span" locale="en">
<Theme>
<Router history={history}>
<ListPage />
</Router>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<Router history={history}>
<ListPage />
</Router>
</Theme>
</ThemeToggleProvider>
</IntlProvider>
);

View File

@ -4,13 +4,14 @@
*
*/
import { Layout } from '@strapi/design-system';
import { Layout, lightTheme } from '@strapi/design-system';
import { render } from '@testing-library/react';
import { createMemoryHistory } from 'history';
import React from 'react';
import { Router } from 'react-router-dom';
import LanguageProvider from '../../../../../../admin/admin/src/components/LanguageProvider';
import Theme from '../../../../../../admin/admin/src/components/Theme';
import ThemeToggleProvider from '../../../../../../admin/admin/src/components/ThemeToggleProvider';
import en from '../../../../../../admin/admin/src/translations/en.json';
import ContentTypeBuilderNav from '../index';
import mockData from './mockData';
@ -30,13 +31,15 @@ const makeApp = () => {
return (
<LanguageProvider messages={messages} localeNames={localeNames}>
<Theme>
<Router history={history}>
<Layout sideNav={<ContentTypeBuilderNav />}>
<div />
</Layout>
</Router>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<Router history={history}>
<Layout sideNav={<ContentTypeBuilderNav />}>
<div />
</Layout>
</Router>
</Theme>
</ThemeToggleProvider>
</LanguageProvider>
);
};

View File

@ -8,8 +8,10 @@ import { render } from '@testing-library/react';
import { createMemoryHistory } from 'history';
import React from 'react';
import { Router } from 'react-router-dom';
import { lightTheme } from '@strapi/design-system';
import LanguageProvider from '../../../../../../admin/admin/src/components/LanguageProvider';
import Theme from '../../../../../../admin/admin/src/components/Theme';
import ThemeToggleProvider from '../../../../../../admin/admin/src/components/ThemeToggleProvider';
import en from '../../../../../../admin/admin/src/translations/en.json';
import FormModalNavigationProvider from '../../../components/FormModalNavigationProvider';
import pluginEn from '../../../translations/en.json';
@ -52,13 +54,15 @@ const makeApp = () => {
return (
<LanguageProvider messages={messages} localeNames={localeNames}>
<Theme>
<Router history={history}>
<FormModalNavigationProvider>
<ListView />
</FormModalNavigationProvider>
</Router>
</Theme>
<ThemeToggleProvider themes={{ light: lightTheme }}>
<Theme>
<Router history={history}>
<FormModalNavigationProvider>
<ListView />
</FormModalNavigationProvider>
</Router>
</Theme>
</ThemeToggleProvider>
</LanguageProvider>
);
};

View File

@ -1,9 +1,12 @@
import { isEmpty } from 'lodash';
// TODO @soupette we need to refactor this file
import isEmpty from 'lodash/isEmpty';
const TOKEN_KEY = 'jwtToken';
const USER_INFO = 'userInfo';
const CURRENT_STEP = 'GUIDED_TOUR_CURRENT_STEP';
const COMPLETED_STEPS = 'GUIDED_TOUR_COMPLETED_STEPS';
const THEME_KEY = 'STRAPI_THEME'; // Also used in packages/core/admin/admin/src/components/ThemeToggleProvider/index.js
const parse = JSON.parse;
const stringify = JSON.stringify;
@ -29,6 +32,7 @@ const auth = {
const localeLang = localStorage.getItem('strapi-admin-language');
const guidedTourCurrentStep = auth.get(CURRENT_STEP);
const guidedTourState = auth.get(COMPLETED_STEPS);
const applicationTheme = localStorage.getItem(THEME_KEY);
localStorage.clear();
@ -38,6 +42,7 @@ const auth = {
localStorage.setItem('strapi-admin-language', localeLang);
localStorage.setItem(CURRENT_STEP, stringify(guidedTourCurrentStep));
localStorage.setItem(COMPLETED_STEPS, stringify(guidedTourState));
localStorage.setItem(THEME_KEY, applicationTheme);
}
if (sessionStorage) {