diff options
-rw-r--r-- | src/components/layout/AppLayout.js | 126 | ||||
-rw-r--r-- | src/containers/auth/AuthLayoutContainer.js | 8 | ||||
-rw-r--r-- | src/containers/layout/AppLayoutContainer.js | 1 | ||||
-rw-r--r-- | src/containers/settings/SettingsWindow.js | 35 | ||||
-rw-r--r-- | src/index.html | 1 | ||||
-rw-r--r-- | src/stores/UIStore.js | 28 |
6 files changed, 117 insertions, 82 deletions
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js index 499bc097a..ebb9849ea 100644 --- a/src/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.js | |||
@@ -68,7 +68,6 @@ class AppLayout extends Component { | |||
68 | areRequiredRequestsSuccessful: PropTypes.bool.isRequired, | 68 | areRequiredRequestsSuccessful: PropTypes.bool.isRequired, |
69 | retryRequiredRequests: PropTypes.func.isRequired, | 69 | retryRequiredRequests: PropTypes.func.isRequired, |
70 | areRequiredRequestsLoading: PropTypes.bool.isRequired, | 70 | areRequiredRequestsLoading: PropTypes.bool.isRequired, |
71 | darkMode: PropTypes.bool.isRequired, | ||
72 | isDelayAppScreenVisible: PropTypes.bool.isRequired, | 71 | isDelayAppScreenVisible: PropTypes.bool.isRequired, |
73 | }; | 72 | }; |
74 | 73 | ||
@@ -101,7 +100,6 @@ class AppLayout extends Component { | |||
101 | areRequiredRequestsSuccessful, | 100 | areRequiredRequestsSuccessful, |
102 | retryRequiredRequests, | 101 | retryRequiredRequests, |
103 | areRequiredRequestsLoading, | 102 | areRequiredRequestsLoading, |
104 | darkMode, | ||
105 | isDelayAppScreenVisible, | 103 | isDelayAppScreenVisible, |
106 | } = this.props; | 104 | } = this.props; |
107 | 105 | ||
@@ -109,69 +107,67 @@ class AppLayout extends Component { | |||
109 | 107 | ||
110 | return ( | 108 | return ( |
111 | <ErrorBoundary> | 109 | <ErrorBoundary> |
112 | <div className={(darkMode ? 'theme__dark' : '')}> | 110 | <div className="app"> |
113 | <div className="app"> | 111 | {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon="assets/images/logo.svg" />} |
114 | {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon="assets/images/logo.svg" />} | 112 | <div className={`app__content ${classes.appContent}`}> |
115 | <div className={`app__content ${classes.appContent}`}> | 113 | {workspacesDrawer} |
116 | {workspacesDrawer} | 114 | {sidebar} |
117 | {sidebar} | 115 | <div className="app__service"> |
118 | <div className="app__service"> | 116 | <WorkspaceSwitchingIndicator /> |
119 | <WorkspaceSwitchingIndicator /> | 117 | {news.length > 0 && news.map(item => ( |
120 | {news.length > 0 && news.map(item => ( | 118 | <InfoBar |
121 | <InfoBar | 119 | key={item.id} |
122 | key={item.id} | 120 | position="top" |
123 | position="top" | 121 | type={item.type} |
124 | type={item.type} | 122 | sticky={item.sticky} |
125 | sticky={item.sticky} | 123 | onHide={() => removeNewsItem({ newsId: item.id })} |
126 | onHide={() => removeNewsItem({ newsId: item.id })} | 124 | > |
127 | > | 125 | <span dangerouslySetInnerHTML={createMarkup(item.message)} /> |
128 | <span dangerouslySetInnerHTML={createMarkup(item.message)} /> | 126 | </InfoBar> |
129 | </InfoBar> | 127 | ))} |
130 | ))} | 128 | {/* {!isOnline && ( |
131 | {/* {!isOnline && ( | 129 | <InfoBar |
132 | <InfoBar | 130 | type="danger" |
133 | type="danger" | 131 | sticky |
134 | sticky | 132 | > |
135 | > | 133 | <span className="mdi mdi-flash" /> |
136 | <span className="mdi mdi-flash" /> | 134 | {intl.formatMessage(globalMessages.notConnectedToTheInternet)} |
137 | {intl.formatMessage(globalMessages.notConnectedToTheInternet)} | 135 | </InfoBar> |
138 | </InfoBar> | 136 | )} */} |
139 | )} */} | 137 | {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( |
140 | {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( | 138 | <InfoBar |
141 | <InfoBar | 139 | type="danger" |
142 | type="danger" | 140 | ctaLabel="Try again" |
143 | ctaLabel="Try again" | 141 | ctaLoading={areRequiredRequestsLoading} |
144 | ctaLoading={areRequiredRequestsLoading} | 142 | sticky |
145 | sticky | 143 | onClick={retryRequiredRequests} |
146 | onClick={retryRequiredRequests} | 144 | > |
147 | > | 145 | <span className="mdi mdi-flash" /> |
148 | <span className="mdi mdi-flash" /> | 146 | {intl.formatMessage(messages.requiredRequestsFailed)} |
149 | {intl.formatMessage(messages.requiredRequestsFailed)} | 147 | </InfoBar> |
150 | </InfoBar> | 148 | )} |
151 | )} | 149 | {showServicesUpdatedInfoBar && ( |
152 | {showServicesUpdatedInfoBar && ( | 150 | <InfoBar |
153 | <InfoBar | 151 | type="primary" |
154 | type="primary" | 152 | ctaLabel={intl.formatMessage(messages.buttonReloadServices)} |
155 | ctaLabel={intl.formatMessage(messages.buttonReloadServices)} | 153 | onClick={reloadServicesAfterUpdate} |
156 | onClick={reloadServicesAfterUpdate} | 154 | sticky |
157 | sticky | 155 | > |
158 | > | 156 | <span className="mdi mdi-power-plug" /> |
159 | <span className="mdi mdi-power-plug" /> | 157 | {intl.formatMessage(messages.servicesUpdated)} |
160 | {intl.formatMessage(messages.servicesUpdated)} | 158 | </InfoBar> |
161 | </InfoBar> | 159 | )} |
162 | )} | 160 | {appUpdateIsDownloaded && ( |
163 | {appUpdateIsDownloaded && ( | 161 | <AppUpdateInfoBar |
164 | <AppUpdateInfoBar | 162 | nextAppReleaseVersion={nextAppReleaseVersion} |
165 | nextAppReleaseVersion={nextAppReleaseVersion} | 163 | onInstallUpdate={installAppUpdate} |
166 | onInstallUpdate={installAppUpdate} | 164 | /> |
167 | /> | 165 | )} |
168 | )} | 166 | {isDelayAppScreenVisible && (<DelayApp />)} |
169 | {isDelayAppScreenVisible && (<DelayApp />)} | 167 | <BasicAuth /> |
170 | <BasicAuth /> | 168 | <ShareFranz /> |
171 | <ShareFranz /> | 169 | {services} |
172 | {services} | 170 | {children} |
173 | {children} | ||
174 | </div> | ||
175 | </div> | 171 | </div> |
176 | </div> | 172 | </div> |
177 | </div> | 173 | </div> |
diff --git a/src/containers/auth/AuthLayoutContainer.js b/src/containers/auth/AuthLayoutContainer.js index 1f9c1ea61..20b88c500 100644 --- a/src/containers/auth/AuthLayoutContainer.js +++ b/src/containers/auth/AuthLayoutContainer.js | |||
@@ -24,24 +24,22 @@ export default @inject('stores', 'actions') @observer class AuthLayoutContainer | |||
24 | stores, actions, children, location, | 24 | stores, actions, children, location, |
25 | } = this.props; | 25 | } = this.props; |
26 | const { | 26 | const { |
27 | app, features, globalError, settings, | 27 | app, features, globalError, |
28 | } = stores; | 28 | } = stores; |
29 | 29 | ||
30 | const isLoadingBaseFeatures = features.defaultFeaturesRequest.isExecuting | 30 | const isLoadingBaseFeatures = features.defaultFeaturesRequest.isExecuting |
31 | && !features.defaultFeaturesRequest.wasExecuted; | 31 | && !features.defaultFeaturesRequest.wasExecuted; |
32 | 32 | ||
33 | const themeType = theme(settings.app.darkMode ? 'dark' : 'default'); | ||
34 | |||
35 | if (isLoadingBaseFeatures) { | 33 | if (isLoadingBaseFeatures) { |
36 | return ( | 34 | return ( |
37 | <ThemeProvider theme={theme(themeType)}> | 35 | <ThemeProvider theme={stores.ui.theme}> |
38 | <AppLoader /> | 36 | <AppLoader /> |
39 | </ThemeProvider> | 37 | </ThemeProvider> |
40 | ); | 38 | ); |
41 | } | 39 | } |
42 | 40 | ||
43 | return ( | 41 | return ( |
44 | <ThemeProvider theme={theme(themeType)}> | 42 | <ThemeProvider theme={stores.ui.theme}> |
45 | <AuthLayout | 43 | <AuthLayout |
46 | error={globalError.response} | 44 | error={globalError.response} |
47 | pathname={location.pathname} | 45 | pathname={location.pathname} |
diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js index d290a6094..cf3da71e8 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.js | |||
@@ -148,7 +148,6 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e | |||
148 | areRequiredRequestsSuccessful={requests.areRequiredRequestsSuccessful} | 148 | areRequiredRequestsSuccessful={requests.areRequiredRequestsSuccessful} |
149 | retryRequiredRequests={retryRequiredRequests} | 149 | retryRequiredRequests={retryRequiredRequests} |
150 | areRequiredRequestsLoading={requests.areRequiredRequestsLoading} | 150 | areRequiredRequestsLoading={requests.areRequiredRequestsLoading} |
151 | darkMode={settings.all.app.darkMode} | ||
152 | isDelayAppScreenVisible={delayAppState.isDelayAppScreenVisible} | 151 | isDelayAppScreenVisible={delayAppState.isDelayAppScreenVisible} |
153 | > | 152 | > |
154 | {React.Children.count(children) > 0 ? children : null} | 153 | {React.Children.count(children) > 0 ? children : null} |
diff --git a/src/containers/settings/SettingsWindow.js b/src/containers/settings/SettingsWindow.js index 663b9e2e4..440d32a46 100644 --- a/src/containers/settings/SettingsWindow.js +++ b/src/containers/settings/SettingsWindow.js | |||
@@ -1,4 +1,5 @@ | |||
1 | import React, { Component } from 'react'; | 1 | import React, { Component } from 'react'; |
2 | import ReactDOM from 'react-dom'; | ||
2 | import PropTypes from 'prop-types'; | 3 | import PropTypes from 'prop-types'; |
3 | import { observer, inject } from 'mobx-react'; | 4 | import { observer, inject } from 'mobx-react'; |
4 | 5 | ||
@@ -10,10 +11,23 @@ import ErrorBoundary from '../../components/util/ErrorBoundary'; | |||
10 | import { workspaceStore } from '../../features/workspaces'; | 11 | import { workspaceStore } from '../../features/workspaces'; |
11 | 12 | ||
12 | export default @inject('stores', 'actions') @observer class SettingsContainer extends Component { | 13 | export default @inject('stores', 'actions') @observer class SettingsContainer extends Component { |
14 | portalRoot = document.querySelector('#portalContainer'); | ||
15 | |||
16 | el = document.createElement('div'); | ||
17 | |||
18 | componentDidMount() { | ||
19 | this.portalRoot.appendChild(this.el); | ||
20 | } | ||
21 | |||
22 | componentWillUnmount() { | ||
23 | this.portalRoot.removeChild(this.el); | ||
24 | } | ||
25 | |||
13 | render() { | 26 | render() { |
14 | const { children, stores } = this.props; | 27 | const { children, stores } = this.props; |
15 | const { closeSettings } = this.props.actions.ui; | 28 | const { closeSettings } = this.props.actions.ui; |
16 | 29 | ||
30 | |||
17 | const navigation = ( | 31 | const navigation = ( |
18 | <Navigation | 32 | <Navigation |
19 | serviceCount={stores.services.all.length} | 33 | serviceCount={stores.services.all.length} |
@@ -21,15 +35,18 @@ export default @inject('stores', 'actions') @observer class SettingsContainer ex | |||
21 | /> | 35 | /> |
22 | ); | 36 | ); |
23 | 37 | ||
24 | return ( | 38 | return ReactDOM.createPortal( |
25 | <ErrorBoundary> | 39 | ( |
26 | <Layout | 40 | <ErrorBoundary> |
27 | navigation={navigation} | 41 | <Layout |
28 | closeSettings={closeSettings} | 42 | navigation={navigation} |
29 | > | 43 | closeSettings={closeSettings} |
30 | {children} | 44 | > |
31 | </Layout> | 45 | {children} |
32 | </ErrorBoundary> | 46 | </Layout> |
47 | </ErrorBoundary> | ||
48 | ), | ||
49 | this.el, | ||
33 | ); | 50 | ); |
34 | } | 51 | } |
35 | } | 52 | } |
diff --git a/src/index.html b/src/index.html index bf15e2d4e..f29aa2686 100644 --- a/src/index.html +++ b/src/index.html | |||
@@ -10,6 +10,7 @@ | |||
10 | <div class="window-draggable"></div> | 10 | <div class="window-draggable"></div> |
11 | <div class="dev-warning">DEV MODE</div> | 11 | <div class="dev-warning">DEV MODE</div> |
12 | <div id="root"></div> | 12 | <div id="root"></div> |
13 | <div id="portalContainer"></div> | ||
13 | <script> | 14 | <script> |
14 | document.querySelector('body').classList.add(process.env.OS_PLATFORM ? process.env.OS_PLATFORM : process.platform); | 15 | document.querySelector('body').classList.add(process.env.OS_PLATFORM ? process.env.OS_PLATFORM : process.platform); |
15 | 16 | ||
diff --git a/src/stores/UIStore.js b/src/stores/UIStore.js index a95a8e1e0..61e0c5010 100644 --- a/src/stores/UIStore.js +++ b/src/stores/UIStore.js | |||
@@ -1,4 +1,9 @@ | |||
1 | import { action, observable, computed } from 'mobx'; | 1 | import { |
2 | action, | ||
3 | observable, | ||
4 | computed, | ||
5 | reaction, | ||
6 | } from 'mobx'; | ||
2 | import { theme } from '@meetfranz/theme'; | 7 | import { theme } from '@meetfranz/theme'; |
3 | 8 | ||
4 | import Store from './lib/Store'; | 9 | import Store from './lib/Store'; |
@@ -15,6 +20,14 @@ export default class UIStore extends Store { | |||
15 | this.actions.ui.toggleServiceUpdatedInfoBar.listen(this._toggleServiceUpdatedInfoBar.bind(this)); | 20 | this.actions.ui.toggleServiceUpdatedInfoBar.listen(this._toggleServiceUpdatedInfoBar.bind(this)); |
16 | } | 21 | } |
17 | 22 | ||
23 | setup() { | ||
24 | reaction( | ||
25 | () => this.isDarkThemeActive, | ||
26 | () => this._setupThemeInDOM(), | ||
27 | { fireImmediately: true }, | ||
28 | ); | ||
29 | } | ||
30 | |||
18 | @computed get showMessageBadgesEvenWhenMuted() { | 31 | @computed get showMessageBadgesEvenWhenMuted() { |
19 | const settings = this.stores.settings.all; | 32 | const settings = this.stores.settings.all; |
20 | 33 | ||
@@ -26,7 +39,7 @@ export default class UIStore extends Store { | |||
26 | } | 39 | } |
27 | 40 | ||
28 | @computed get theme() { | 41 | @computed get theme() { |
29 | if (this.isDarkThemeActive) return theme('dark'); | 42 | if (this.isDarkThemeActive || this.stores.settings.app.darkMode) return theme('dark'); |
30 | return theme('default'); | 43 | return theme('default'); |
31 | } | 44 | } |
32 | 45 | ||
@@ -47,4 +60,15 @@ export default class UIStore extends Store { | |||
47 | } | 60 | } |
48 | this.showServicesUpdatedInfoBar = visibility; | 61 | this.showServicesUpdatedInfoBar = visibility; |
49 | } | 62 | } |
63 | |||
64 | // Reactions | ||
65 | _setupThemeInDOM() { | ||
66 | const body = document.querySelector('body'); | ||
67 | |||
68 | if (!this.isDarkThemeActive) { | ||
69 | body.classList.remove('theme__dark'); | ||
70 | } else { | ||
71 | body.classList.add('theme__dark'); | ||
72 | } | ||
73 | } | ||
50 | } | 74 | } |