@strapi/admin 4.1.4-alpha.0 → 4.2.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/.env +0 -0
  2. package/admin/src/StrapiApp.js +40 -42
  3. package/admin/src/components/GuidedTour/Modal/components/Modal.js +1 -1
  4. package/admin/src/components/Providers/index.js +65 -32
  5. package/admin/src/components/Theme/index.js +11 -12
  6. package/admin/src/components/ThemeToggleProvider/index.js +66 -0
  7. package/admin/src/content-manager/components/SelectWrapper/utils/getSelectStyles.js +3 -1
  8. package/admin/src/content-manager/components/Wysiwyg/EditorStylesContainer.js +4 -2
  9. package/admin/src/contexts/ThemeToggle/index.js +5 -0
  10. package/admin/src/contexts/index.js +1 -0
  11. package/admin/src/hooks/index.js +2 -0
  12. package/admin/src/hooks/useFetchPluginsFromMarketPlace/index.js +49 -0
  13. package/admin/src/hooks/useThemeToggle/index.js +10 -0
  14. package/admin/src/pages/Admin/Onboarding/index.js +1 -1
  15. package/admin/src/pages/HomePage/SocialLinks.js +0 -3
  16. package/admin/src/pages/InstalledPluginsPage/Plugins.js +15 -6
  17. package/admin/src/{hooks/useFetchInstalledPlugins → pages/InstalledPluginsPage}/utils/api.js +4 -2
  18. package/admin/src/pages/MarketplacePage/MarketplaceBanner/Wrapper.js +28 -0
  19. package/admin/src/pages/MarketplacePage/MarketplaceBanner/index.js +37 -0
  20. package/admin/src/pages/MarketplacePage/PluginCard/Wrapper.js +148 -0
  21. package/admin/src/pages/MarketplacePage/PluginCard/index.js +185 -0
  22. package/admin/src/pages/MarketplacePage/Wrapper.js +5 -0
  23. package/admin/src/pages/MarketplacePage/assets/marketplace-coming-soon.png +0 -0
  24. package/admin/src/pages/MarketplacePage/index.js +109 -198
  25. package/admin/src/pages/ProfilePage/index.js +74 -10
  26. package/admin/src/pages/ProfilePage/utils/api.js +4 -2
  27. package/admin/src/translations/en.json +18 -18
  28. package/build/01a600d9e6e0dea21e33.png +0 -0
  29. package/build/4362.86a4e939.chunk.js +1 -0
  30. package/build/{6250.836851ca.chunk.js → 6404.3c2d0a81.chunk.js} +1 -1
  31. package/build/{Admin-authenticatedApp.27fba46d.chunk.js → Admin-authenticatedApp.2d44e117.chunk.js} +1 -1
  32. package/build/{Admin_homePage.964ff5d7.chunk.js → Admin_homePage.d6754c66.chunk.js} +1 -1
  33. package/build/Admin_marketplace.419010d8.chunk.js +1 -0
  34. package/build/Admin_pluginsPage.7d1bd7ce.chunk.js +1 -0
  35. package/build/Admin_profilePage.d7192d06.chunk.js +1 -0
  36. package/build/{Admin_settingsPage.55ec1f30.chunk.js → Admin_settingsPage.a8c7ded5.chunk.js} +1 -1
  37. package/build/admin-users.1fda1f27.chunk.js +1 -0
  38. package/build/content-manager.de808f2c.chunk.js +1 -0
  39. package/build/{content-type-builder.de5d18ad.chunk.js → content-type-builder.cda4ba3c.chunk.js} +1 -1
  40. package/build/{email-settings-page.27ee4a98.chunk.js → email-settings-page.40ee2bda.chunk.js} +1 -1
  41. package/build/en-json.b35c285f.chunk.js +1 -0
  42. package/build/index.html +1 -1
  43. package/build/{main.22e9a5c5.js → main.34ee547b.js} +2 -2
  44. package/build/{main.22e9a5c5.js.LICENSE.txt → main.34ee547b.js.LICENSE.txt} +0 -0
  45. package/build/{runtime~main.e6326927.js → runtime~main.3ef9943c.js} +1 -1
  46. package/build/users-email-settings-page.5abb9575.chunk.js +1 -0
  47. package/package.json +5 -5
  48. package/server/controllers/admin.js +1 -12
  49. package/admin/src/assets/images/icon_made-by-strapi.svg +0 -5
  50. package/admin/src/hooks/useFetchInstalledPlugins/index.js +0 -23
  51. package/admin/src/hooks/useFetchMarketplacePlugins/index.js +0 -23
  52. package/admin/src/hooks/useFetchMarketplacePlugins/utils/api.js +0 -17
  53. package/admin/src/pages/MarketplacePage/components/EmptyPluginSearch/EmptyPluginGrid.js +0 -27
  54. package/admin/src/pages/MarketplacePage/components/EmptyPluginSearch/index.js +0 -30
  55. package/admin/src/pages/MarketplacePage/components/PluginCard/index.js +0 -186
  56. package/admin/src/pages/MarketplacePage/utils/api.js +0 -9
  57. package/admin/src/themes/colors.js +0 -51
  58. package/admin/src/themes/fontWeights.js +0 -8
  59. package/admin/src/themes/index.js +0 -13
  60. package/admin/src/themes/sizes.js +0 -31
  61. package/build/4362.5c92d240.chunk.js +0 -1
  62. package/build/90f49a385afb000fb1d4.svg +0 -5
  63. package/build/Admin_marketplace.e83567ff.chunk.js +0 -1
  64. package/build/Admin_pluginsPage.97a514db.chunk.js +0 -1
  65. package/build/Admin_profilePage.c497b39d.chunk.js +0 -1
  66. package/build/admin-users.2740c223.chunk.js +0 -1
  67. package/build/content-manager.e1189026.chunk.js +0 -1
  68. package/build/en-json.086acf41.chunk.js +0 -1
  69. package/build/users-email-settings-page.862eb51e.chunk.js +0 -1
package/.env ADDED
File without changes
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { BrowserRouter } from 'react-router-dom';
3
- import { lightTheme } from '@strapi/design-system/themes';
3
+ import { lightTheme, darkTheme } from '@strapi/design-system/themes';
4
4
  import merge from 'lodash/merge';
5
5
  import pick from 'lodash/pick';
6
6
  import isFunction from 'lodash/isFunction';
@@ -13,7 +13,6 @@ import App from './pages/App';
13
13
  import AuthLogo from './assets/images/logo_strapi_auth_v4.png';
14
14
  import MenuLogo from './assets/images/logo_strapi_menu.png';
15
15
  import Providers from './components/Providers';
16
- import Theme from './components/Theme';
17
16
  import languageNativeNames from './translations/languageNativeNames';
18
17
  import {
19
18
  INJECT_COLUMN_IN_TABLE,
@@ -34,7 +33,7 @@ class StrapiApp {
34
33
  locales: ['en'],
35
34
  menuLogo: MenuLogo,
36
35
  notifications: { releases: true },
37
- theme: lightTheme,
36
+ themes: { light: lightTheme, dark: darkTheme },
38
37
  translations: {},
39
38
  tutorials: true,
40
39
  };
@@ -226,7 +225,7 @@ class StrapiApp {
226
225
  }
227
226
 
228
227
  if (this.customConfigurations?.theme) {
229
- this.configurations.theme = merge(this.configurations.theme, this.customConfigurations.theme);
228
+ merge(this.configurations.themes.light, this.customConfigurations.theme);
230
229
  }
231
230
 
232
231
  if (this.customConfigurations?.notifications?.releases !== undefined) {
@@ -427,44 +426,43 @@ class StrapiApp {
427
426
  } = this.library;
428
427
 
429
428
  return (
430
- <Theme theme={this.configurations.theme}>
431
- <Providers
432
- authLogo={this.configurations.authLogo}
433
- components={components}
434
- fields={fields}
435
- localeNames={localeNames}
436
- getAdminInjectedComponents={this.getAdminInjectedComponents}
437
- getPlugin={this.getPlugin}
438
- messages={this.configurations.translations}
439
- menu={this.menu}
440
- menuLogo={this.configurations.menuLogo}
441
- plugins={this.plugins}
442
- runHookParallel={this.runHookParallel}
443
- runHookWaterfall={(name, initialValue, async = false) => {
444
- return this.runHookWaterfall(name, initialValue, async, store);
445
- }}
446
- runHookSeries={this.runHookSeries}
447
- settings={this.settings}
448
- showTutorials={this.configurations.tutorials}
449
- showReleaseNotification={this.configurations.notifications.releases}
450
- store={store}
451
- >
452
- <>
453
- <Helmet
454
- link={[
455
- {
456
- rel: 'icon',
457
- type: 'image/png',
458
- href: this.configurations.head.favicon,
459
- },
460
- ]}
461
- />
462
- <BrowserRouter basename={basename}>
463
- <App store={store} />
464
- </BrowserRouter>
465
- </>
466
- </Providers>
467
- </Theme>
429
+ <Providers
430
+ authLogo={this.configurations.authLogo}
431
+ components={components}
432
+ fields={fields}
433
+ localeNames={localeNames}
434
+ getAdminInjectedComponents={this.getAdminInjectedComponents}
435
+ getPlugin={this.getPlugin}
436
+ messages={this.configurations.translations}
437
+ menu={this.menu}
438
+ menuLogo={this.configurations.menuLogo}
439
+ plugins={this.plugins}
440
+ runHookParallel={this.runHookParallel}
441
+ runHookWaterfall={(name, initialValue, async = false) => {
442
+ return this.runHookWaterfall(name, initialValue, async, store);
443
+ }}
444
+ runHookSeries={this.runHookSeries}
445
+ themes={this.configurations.themes}
446
+ settings={this.settings}
447
+ showTutorials={this.configurations.tutorials}
448
+ showReleaseNotification={this.configurations.notifications.releases}
449
+ store={store}
450
+ >
451
+ <>
452
+ <Helmet
453
+ link={[
454
+ {
455
+ rel: 'icon',
456
+ type: 'image/png',
457
+ href: this.configurations.head.favicon,
458
+ },
459
+ ]}
460
+ />
461
+ <BrowserRouter basename={basename}>
462
+ <App store={store} />
463
+ </BrowserRouter>
464
+ </>
465
+ </Providers>
468
466
  );
469
467
  }
470
468
  }
@@ -17,7 +17,7 @@ const ModalWrapper = styled(Flex)`
17
17
  z-index: 4;
18
18
  inset: 0;
19
19
  /* this is theme.colors.neutral800 with opacity */
20
- background: ${({ theme }) => `${theme.colors.neutral800}33`};
20
+ background: ${({ theme }) => `${theme.colors.neutral800}1F`};
21
21
  `;
22
22
 
23
23
  const Modal = ({ onClose, onSkip, children, hideSkip }) => {
@@ -9,6 +9,8 @@ import GuidedTour from '../GuidedTour';
9
9
  import AutoReloadOverlayBlockerProvider from '../AutoReloadOverlayBlockerProvider';
10
10
  import Notifications from '../Notifications';
11
11
  import OverlayBlocker from '../OverlayBlocker';
12
+ import ThemeToggleProvider from '../ThemeToggleProvider';
13
+ import Theme from '../Theme';
12
14
 
13
15
  const queryClient = new QueryClient({
14
16
  defaultOptions: {
@@ -36,41 +38,45 @@ const Providers = ({
36
38
  settings,
37
39
  showReleaseNotification,
38
40
  showTutorials,
39
-
40
41
  store,
42
+ themes,
41
43
  }) => {
42
44
  return (
43
- <QueryClientProvider client={queryClient}>
44
- <Provider store={store}>
45
- <AdminContext.Provider value={{ getAdminInjectedComponents }}>
46
- <ConfigurationsContext.Provider
47
- value={{ authLogo, menuLogo, showReleaseNotification, showTutorials }}
48
- >
49
- <StrapiAppProvider
50
- getPlugin={getPlugin}
51
- menu={menu}
52
- plugins={plugins}
53
- runHookParallel={runHookParallel}
54
- runHookWaterfall={runHookWaterfall}
55
- runHookSeries={runHookSeries}
56
- settings={settings}
57
- >
58
- <LibraryProvider components={components} fields={fields}>
59
- <LanguageProvider messages={messages} localeNames={localeNames}>
60
- <AutoReloadOverlayBlockerProvider>
61
- <OverlayBlocker>
62
- <GuidedTour>
63
- <Notifications>{children}</Notifications>
64
- </GuidedTour>
65
- </OverlayBlocker>
66
- </AutoReloadOverlayBlockerProvider>
67
- </LanguageProvider>
68
- </LibraryProvider>
69
- </StrapiAppProvider>
70
- </ConfigurationsContext.Provider>
71
- </AdminContext.Provider>
72
- </Provider>
73
- </QueryClientProvider>
45
+ <ThemeToggleProvider themes={themes}>
46
+ <Theme>
47
+ <QueryClientProvider client={queryClient}>
48
+ <Provider store={store}>
49
+ <AdminContext.Provider value={{ getAdminInjectedComponents }}>
50
+ <ConfigurationsContext.Provider
51
+ value={{ authLogo, menuLogo, showReleaseNotification, showTutorials }}
52
+ >
53
+ <StrapiAppProvider
54
+ getPlugin={getPlugin}
55
+ menu={menu}
56
+ plugins={plugins}
57
+ runHookParallel={runHookParallel}
58
+ runHookWaterfall={runHookWaterfall}
59
+ runHookSeries={runHookSeries}
60
+ settings={settings}
61
+ >
62
+ <LibraryProvider components={components} fields={fields}>
63
+ <LanguageProvider messages={messages} localeNames={localeNames}>
64
+ <AutoReloadOverlayBlockerProvider>
65
+ <OverlayBlocker>
66
+ <GuidedTour>
67
+ <Notifications>{children}</Notifications>
68
+ </GuidedTour>
69
+ </OverlayBlocker>
70
+ </AutoReloadOverlayBlockerProvider>
71
+ </LanguageProvider>
72
+ </LibraryProvider>
73
+ </StrapiAppProvider>
74
+ </ConfigurationsContext.Provider>
75
+ </AdminContext.Provider>
76
+ </Provider>
77
+ </QueryClientProvider>
78
+ </Theme>
79
+ </ThemeToggleProvider>
74
80
  );
75
81
  };
76
82
 
@@ -104,6 +110,33 @@ Providers.propTypes = {
104
110
  showReleaseNotification: PropTypes.bool.isRequired,
105
111
  showTutorials: PropTypes.bool.isRequired,
106
112
  store: PropTypes.object.isRequired,
113
+ themes: PropTypes.shape({
114
+ light: PropTypes.shape({
115
+ colors: PropTypes.object.isRequired,
116
+ shadows: PropTypes.object.isRequired,
117
+ sizes: PropTypes.object.isRequired,
118
+ zIndices: PropTypes.array.isRequired,
119
+ spaces: PropTypes.array.isRequired,
120
+ borderRadius: PropTypes.string.isRequired,
121
+ mediaQueries: PropTypes.object.isRequired,
122
+ fontSizes: PropTypes.array.isRequired,
123
+ lineHeights: PropTypes.array.isRequired,
124
+ fontWeights: PropTypes.object.isRequired,
125
+ }).isRequired,
126
+ dark: PropTypes.shape({
127
+ colors: PropTypes.object.isRequired,
128
+ shadows: PropTypes.object.isRequired,
129
+ sizes: PropTypes.object.isRequired,
130
+ zIndices: PropTypes.array.isRequired,
131
+ spaces: PropTypes.array.isRequired,
132
+ borderRadius: PropTypes.string.isRequired,
133
+ mediaQueries: PropTypes.object.isRequired,
134
+ fontSizes: PropTypes.array.isRequired,
135
+ lineHeights: PropTypes.array.isRequired,
136
+ fontWeights: PropTypes.object.isRequired,
137
+ }).isRequired,
138
+ custom: PropTypes.object,
139
+ }).isRequired,
107
140
  };
108
141
 
109
142
  export default Providers;
@@ -1,23 +1,22 @@
1
1
  import React from 'react';
2
2
  import { ThemeProvider } from '@strapi/design-system/ThemeProvider';
3
3
  import PropTypes from 'prop-types';
4
- import { lightTheme } from '@strapi/design-system/themes';
4
+ import { useThemeToggle } from '../../hooks';
5
5
  import GlobalStyle from '../GlobalStyle';
6
6
 
7
- const Theme = ({ children, theme }) => (
8
- <ThemeProvider theme={theme}>
9
- {children}
10
- <GlobalStyle />
11
- </ThemeProvider>
12
- );
7
+ const Theme = ({ children }) => {
8
+ const { currentTheme, themes } = useThemeToggle();
13
9
 
14
- Theme.propTypes = {
15
- children: PropTypes.element.isRequired,
16
- theme: PropTypes.object,
10
+ return (
11
+ <ThemeProvider theme={themes[currentTheme] || themes.light}>
12
+ {children}
13
+ <GlobalStyle />
14
+ </ThemeProvider>
15
+ );
17
16
  };
18
17
 
19
- Theme.defaultProps = {
20
- theme: lightTheme,
18
+ Theme.propTypes = {
19
+ children: PropTypes.element.isRequired,
21
20
  };
22
21
 
23
22
  export default Theme;
@@ -0,0 +1,66 @@
1
+ /**
2
+ *
3
+ * ThemeToggleProvider
4
+ *
5
+ */
6
+
7
+ import React, { useState } from 'react';
8
+ import PropTypes from 'prop-types';
9
+ import { ThemeToggleContext } from '../../contexts';
10
+
11
+ const THEME_KEY = 'STRAPI_THEME';
12
+
13
+ const getDefaultTheme = () => {
14
+ const browserTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
15
+ const persistedTheme = localStorage.getItem(THEME_KEY);
16
+
17
+ return persistedTheme || browserTheme;
18
+ };
19
+
20
+ const ThemeToggleProvider = ({ children, themes }) => {
21
+ const [currentTheme, setCurrentTheme] = useState(getDefaultTheme());
22
+
23
+ const handleChangeTheme = nextTheme => {
24
+ setCurrentTheme(nextTheme);
25
+ localStorage.setItem(THEME_KEY, nextTheme);
26
+ };
27
+
28
+ return (
29
+ <ThemeToggleContext.Provider value={{ currentTheme, onChangeTheme: handleChangeTheme, themes }}>
30
+ {children}
31
+ </ThemeToggleContext.Provider>
32
+ );
33
+ };
34
+
35
+ ThemeToggleProvider.propTypes = {
36
+ children: PropTypes.node.isRequired,
37
+ themes: PropTypes.shape({
38
+ light: PropTypes.shape({
39
+ colors: PropTypes.object.isRequired,
40
+ shadows: PropTypes.object.isRequired,
41
+ sizes: PropTypes.object.isRequired,
42
+ zIndices: PropTypes.array.isRequired,
43
+ spaces: PropTypes.array.isRequired,
44
+ borderRadius: PropTypes.string.isRequired,
45
+ mediaQueries: PropTypes.object.isRequired,
46
+ fontSizes: PropTypes.array.isRequired,
47
+ lineHeights: PropTypes.array.isRequired,
48
+ fontWeights: PropTypes.object.isRequired,
49
+ }).isRequired,
50
+ dark: PropTypes.shape({
51
+ colors: PropTypes.object.isRequired,
52
+ shadows: PropTypes.object.isRequired,
53
+ sizes: PropTypes.object.isRequired,
54
+ zIndices: PropTypes.array.isRequired,
55
+ spaces: PropTypes.array.isRequired,
56
+ borderRadius: PropTypes.string.isRequired,
57
+ mediaQueries: PropTypes.object.isRequired,
58
+ fontSizes: PropTypes.array.isRequired,
59
+ lineHeights: PropTypes.array.isRequired,
60
+ fontWeights: PropTypes.object.isRequired,
61
+ }).isRequired,
62
+ custom: PropTypes.object,
63
+ }).isRequired,
64
+ };
65
+
66
+ export default ThemeToggleProvider;
@@ -49,6 +49,8 @@ const getSelectStyles = theme => {
49
49
  ...base,
50
50
  width: '100%',
51
51
  marginTop: theme.spaces[1],
52
+ backgroundColor: theme.colors.neutral0,
53
+ color: theme.colors.neutral800,
52
54
  borderRadius: '4px !important',
53
55
  borderTopLeftRadius: '4px !important',
54
56
  borderTopRightRadius: '4px !important',
@@ -76,7 +78,7 @@ const getSelectStyles = theme => {
76
78
  return { ...base, lineHeight: theme.spaces[5], backgroundColor, borderRadius: 4 };
77
79
  },
78
80
  placeholder: base => ({ ...base, marginLeft: 0 }),
79
- singleValue: base => ({ ...base, marginLeft: 0 }),
81
+ singleValue: base => ({ ...base, marginLeft: 0, color: theme.colors.neutral800 }),
80
82
  valueContainer: base => ({
81
83
  ...base,
82
84
  padding: 0,
@@ -29,7 +29,8 @@ export const EditorStylesContainer = styled.div`
29
29
 
30
30
  .CodeMirror-scrollbar-filler,
31
31
  .CodeMirror-gutter-filler {
32
- background-color: white; /* The little square between H and V scrollbars */
32
+ /* The little square between H and V scrollbars */
33
+ background-color: ${({ theme }) => `${theme.colors.neutral0}`};
33
34
  }
34
35
 
35
36
  /* GUTTER */
@@ -158,7 +159,7 @@ export const EditorStylesContainer = styled.div`
158
159
  .CodeMirror {
159
160
  position: relative;
160
161
  overflow: hidden;
161
- background: white;
162
+ background: ${({ theme }) => `${theme.colors.neutral0}`};
162
163
  }
163
164
 
164
165
  .CodeMirror-scroll {
@@ -292,6 +293,7 @@ export const EditorStylesContainer = styled.div`
292
293
  .CodeMirror-cursor {
293
294
  position: absolute;
294
295
  pointer-events: none;
296
+ border-color: ${({ theme }) => `${theme.colors.neutral800}`};
295
297
  }
296
298
  .CodeMirror-measure pre {
297
299
  position: static;
@@ -0,0 +1,5 @@
1
+ import { createContext } from 'react';
2
+
3
+ const ThemeToggleContext = createContext({});
4
+
5
+ export default ThemeToggleContext;
@@ -1,3 +1,4 @@
1
1
  export { default as AdminContext } from './Admin';
2
2
  export { default as ConfigurationsContext } from './Configurations';
3
3
  export { default as PermissionsDataManagerContext } from './PermisssionsDataManagerContext';
4
+ export { default as ThemeToggleContext } from './ThemeToggle';
@@ -1,6 +1,7 @@
1
1
  export { default as useConfigurations } from './useConfigurations';
2
2
  export { default as useModels } from './useModels';
3
3
  export { default as useFetchPermissionsLayout } from './useFetchPermissionsLayout';
4
+ export { default as useFetchPluginsFromMarketPlace } from './useFetchPluginsFromMarketPlace';
4
5
  export { default as useFetchRole } from './useFetchRole';
5
6
  export { default as useMenu } from './useMenu';
6
7
  export { default as useRolesList } from './useRolesList';
@@ -8,3 +9,4 @@ export { default as useSettingsMenu } from './useSettingsMenu';
8
9
  export { default as useSettingsForm } from './useSettingsForm';
9
10
  export { default as usePermissionsDataManager } from './usePermissionsDataManager';
10
11
  export { default as useReleaseNotification } from './useReleaseNotification';
12
+ export { default as useThemeToggle } from './useThemeToggle';
@@ -0,0 +1,49 @@
1
+ import { useEffect, useState } from 'react';
2
+ import axios from 'axios';
3
+ import { useIntl } from 'react-intl';
4
+
5
+ const useFetchPluginsFromMarketPlace = () => {
6
+ const { locale: currentLocale } = useIntl();
7
+ const [state, setState] = useState({
8
+ error: false,
9
+ isLoading: true,
10
+ data: null,
11
+ });
12
+
13
+ useEffect(() => {
14
+ const CancelToken = axios.CancelToken;
15
+ const source = CancelToken.source();
16
+
17
+ const getData = async () => {
18
+ try {
19
+ const { data } = await axios.get('https://marketplace.strapi.io/plugins', {
20
+ cancelToken: source.token,
21
+ params: { lang: currentLocale },
22
+ });
23
+
24
+ setState({
25
+ isLoading: false,
26
+ data,
27
+ error: false,
28
+ });
29
+ } catch (err) {
30
+ if (axios.isCancel(err)) {
31
+ // Silent
32
+ } else {
33
+ // handle error
34
+ setState(prev => ({ ...prev, isLoading: false, error: true }));
35
+ }
36
+ }
37
+ };
38
+
39
+ getData();
40
+
41
+ return () => {
42
+ source.cancel();
43
+ };
44
+ }, [currentLocale]);
45
+
46
+ return state;
47
+ };
48
+
49
+ export default useFetchPluginsFromMarketPlace;
@@ -0,0 +1,10 @@
1
+ import { useContext } from 'react';
2
+ import { ThemeToggleContext } from '../../contexts';
3
+
4
+ const useThemeToggle = () => {
5
+ const context = useContext(ThemeToggleContext);
6
+
7
+ return context;
8
+ };
9
+
10
+ export default useThemeToggle;
@@ -21,7 +21,7 @@ const Button = styled.button`
21
21
  box-shadow: ${({ theme }) => theme.shadows.tableShadow};
22
22
  border-radius: 50%;
23
23
  svg {
24
- color: ${({ theme }) => theme.colors.neutral0};
24
+ color: ${({ theme }) => theme.colors.buttonNeutral0};
25
25
  }
26
26
  `;
27
27
 
@@ -30,9 +30,6 @@ const StyledReddit = styled(Reddit)`
30
30
  > path:first-child {
31
31
  fill: #ff4500;
32
32
  }
33
- > path:last-child {
34
- fill: ${({ theme }) => theme.colors.neutral0};
35
- }
36
33
  `;
37
34
  const StyledStrapi = styled(Strapi)`
38
35
  > path:first-child {
@@ -1,24 +1,26 @@
1
1
  import React from 'react';
2
+ import { useQuery } from 'react-query';
2
3
  import { useIntl } from 'react-intl';
3
- import { LoadingIndicatorPage, useFocusWhenNavigate } from '@strapi/helper-plugin';
4
- import { useNotifyAT } from '@strapi/design-system/LiveRegions';
4
+ import { LoadingIndicatorPage, useNotification, useFocusWhenNavigate } from '@strapi/helper-plugin';
5
5
  import { Layout, HeaderLayout, ContentLayout } from '@strapi/design-system/Layout';
6
6
  import { Main } from '@strapi/design-system/Main';
7
+ import { useNotifyAT } from '@strapi/design-system/LiveRegions';
7
8
  import { Typography } from '@strapi/design-system/Typography';
8
9
  import { Table, Thead, Tbody, Tr, Td, Th } from '@strapi/design-system/Table';
9
- import useFetchInstalledPlugins from '../../hooks/useFetchInstalledPlugins';
10
+ import { fetchPlugins } from './utils/api';
10
11
 
11
12
  const Plugins = () => {
12
13
  const { formatMessage } = useIntl();
13
- const { notifyStatus } = useNotifyAT();
14
14
  useFocusWhenNavigate();
15
+ const { notifyStatus } = useNotifyAT();
16
+ const toggleNotification = useNotification();
15
17
 
16
18
  const title = formatMessage({
17
19
  id: 'app.components.ListPluginsPage.title',
18
20
  defaultMessage: 'Plugins',
19
21
  });
20
22
 
21
- const notifyPluginPageLoad = () => {
23
+ const notifyLoad = () => {
22
24
  notifyStatus(
23
25
  formatMessage(
24
26
  {
@@ -30,7 +32,14 @@ const Plugins = () => {
30
32
  );
31
33
  };
32
34
 
33
- const { status, data } = useFetchInstalledPlugins(notifyPluginPageLoad);
35
+ const { status, data } = useQuery('list-plugins', () => fetchPlugins(notifyLoad), {
36
+ onError: () => {
37
+ toggleNotification({
38
+ type: 'warning',
39
+ message: { id: 'notification.error', defaultMessage: 'An error occured' },
40
+ });
41
+ },
42
+ });
34
43
 
35
44
  const isLoading = status !== 'success' && status !== 'error';
36
45
 
@@ -1,9 +1,11 @@
1
1
  import { axiosInstance } from '../../../core/utils';
2
2
 
3
- const fetchInstalledPlugins = async () => {
3
+ const fetchPlugins = async notify => {
4
4
  const { data } = await axiosInstance.get('/admin/plugins');
5
5
 
6
+ notify();
7
+
6
8
  return data;
7
9
  };
8
10
 
9
- export { fetchInstalledPlugins };
11
+ export { fetchPlugins };
@@ -0,0 +1,28 @@
1
+ import styled from 'styled-components';
2
+
3
+ // TODO : To migrate with @strapi/design-system
4
+ const Wrapper = styled.div`
5
+ display: flex;
6
+ align-items: center;
7
+ margin-top: 2rem;
8
+ border-radius: 4px;
9
+ border-left: 4px solid ${({ theme }) => theme.main.colors.mediumBlue};
10
+ box-shadow: 0 2px 4px ${({ theme }) => theme.main.colors.darkGrey};
11
+ padding: 8px 16px;
12
+
13
+ .bannerImage {
14
+ width: 48px;
15
+ height: 48px;
16
+ margin-right: 16px;
17
+ }
18
+
19
+ .bannerLink {
20
+ color: ${({ theme }) => theme.main.colors.mediumBlue};
21
+ font-weight: ${({ theme }) => theme.main.fontWeights.bold};
22
+ svg {
23
+ margin-left: 4px;
24
+ }
25
+ }
26
+ `;
27
+
28
+ export default Wrapper;
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ import { FormattedMessage, useIntl } from 'react-intl';
3
+ import { useTracking } from '@strapi/helper-plugin';
4
+ import Wrapper from './Wrapper';
5
+ import LogoStrapi from '../../../assets/images/banner_strapi-rocket.png';
6
+
7
+ const MarketplaceBanner = () => {
8
+ const { formatMessage } = useIntl();
9
+ const { trackUsage } = useTracking();
10
+
11
+ return (
12
+ <Wrapper>
13
+ <img
14
+ className="bannerImage"
15
+ src={LogoStrapi}
16
+ alt={formatMessage({ id: 'app.components.MarketplaceBanner.image.alt' })}
17
+ />
18
+ <div>
19
+ <div>
20
+ <FormattedMessage id="app.components.MarketplaceBanner" />
21
+ </div>
22
+ <a
23
+ href="https://github.com/strapi/awesome-strapi"
24
+ target="_blank"
25
+ rel="noopener noreferrer"
26
+ className="bannerLink"
27
+ onClick={() => trackUsage('didGoToStrapiAwesome')}
28
+ >
29
+ <FormattedMessage id="app.components.MarketplaceBanner.link" />
30
+ <i className="fa fa-external-link-alt" />
31
+ </a>
32
+ </div>
33
+ </Wrapper>
34
+ );
35
+ };
36
+
37
+ export default MarketplaceBanner;