diff options
Diffstat (limited to 'src/components/layout')
-rw-r--r-- | src/components/layout/AppLayout.js | 94 | ||||
-rw-r--r-- | src/components/layout/Sidebar.js | 35 |
2 files changed, 73 insertions, 56 deletions
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js index a60270a6f..d5e1deb39 100644 --- a/src/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.js | |||
@@ -19,10 +19,7 @@ import { isWindows } from '../../environment'; | |||
19 | import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator'; | 19 | import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator'; |
20 | import { workspaceStore } from '../../features/workspaces'; | 20 | import { workspaceStore } from '../../features/workspaces'; |
21 | import AppUpdateInfoBar from '../AppUpdateInfoBar'; | 21 | import AppUpdateInfoBar from '../AppUpdateInfoBar'; |
22 | import TrialActivationInfoBar from '../TrialActivationInfoBar'; | ||
23 | import Todos from '../../features/todos/containers/TodosScreen'; | 22 | import Todos from '../../features/todos/containers/TodosScreen'; |
24 | import PlanSelection from '../../features/planSelection/containers/PlanSelectionScreen'; | ||
25 | import TrialStatusBar from '../../features/trialStatusBar/containers/TrialStatusBarScreen'; | ||
26 | 23 | ||
27 | function createMarkup(HTMLString) { | 24 | function createMarkup(HTMLString) { |
28 | return { __html: HTMLString }; | 25 | return { __html: HTMLString }; |
@@ -43,22 +40,32 @@ const messages = defineMessages({ | |||
43 | }, | 40 | }, |
44 | authRequestFailed: { | 41 | authRequestFailed: { |
45 | id: 'infobar.authRequestFailed', | 42 | id: 'infobar.authRequestFailed', |
46 | defaultMessage: '!!!There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.', | 43 | defaultMessage: |
44 | '!!!There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.', | ||
47 | }, | 45 | }, |
48 | }); | 46 | }); |
49 | 47 | ||
48 | let transition = 'none'; | ||
49 | |||
50 | if (window && window.matchMedia('(prefers-reduced-motion: no-preference)')) { | ||
51 | transition = 'transform 0.5s ease'; | ||
52 | } | ||
53 | |||
50 | const styles = theme => ({ | 54 | const styles = theme => ({ |
51 | appContent: { | 55 | appContent: { |
52 | // width: `calc(100% + ${theme.workspaces.drawer.width}px)`, | 56 | // width: `calc(100% + ${theme.workspaces.drawer.width}px)`, |
53 | width: '100%', | 57 | width: '100%', |
54 | transition: 'transform 0.5s ease', | 58 | transition, |
55 | transform() { | 59 | transform() { |
56 | return workspaceStore.isWorkspaceDrawerOpen ? 'translateX(0)' : `translateX(-${theme.workspaces.drawer.width}px)`; | 60 | return workspaceStore.isWorkspaceDrawerOpen |
61 | ? 'translateX(0)' | ||
62 | : `translateX(-${theme.workspaces.drawer.width}px)`; | ||
57 | }, | 63 | }, |
58 | }, | 64 | }, |
59 | }); | 65 | }); |
60 | 66 | ||
61 | @injectSheet(styles) @observer | 67 | @injectSheet(styles) |
68 | @observer | ||
62 | class AppLayout extends Component { | 69 | class AppLayout extends Component { |
63 | static propTypes = { | 70 | static propTypes = { |
64 | classes: PropTypes.object.isRequired, | 71 | classes: PropTypes.object.isRequired, |
@@ -79,12 +86,11 @@ class AppLayout extends Component { | |||
79 | areRequiredRequestsSuccessful: PropTypes.bool.isRequired, | 86 | areRequiredRequestsSuccessful: PropTypes.bool.isRequired, |
80 | retryRequiredRequests: PropTypes.func.isRequired, | 87 | retryRequiredRequests: PropTypes.func.isRequired, |
81 | areRequiredRequestsLoading: PropTypes.bool.isRequired, | 88 | areRequiredRequestsLoading: PropTypes.bool.isRequired, |
82 | hasActivatedTrial: PropTypes.bool.isRequired, | ||
83 | }; | 89 | }; |
84 | 90 | ||
85 | state = { | 91 | state = { |
86 | shouldShowAppUpdateInfoBar: true, | 92 | shouldShowAppUpdateInfoBar: true, |
87 | } | 93 | }; |
88 | 94 | ||
89 | static defaultProps = { | 95 | static defaultProps = { |
90 | children: [], | 96 | children: [], |
@@ -115,7 +121,6 @@ class AppLayout extends Component { | |||
115 | areRequiredRequestsSuccessful, | 121 | areRequiredRequestsSuccessful, |
116 | retryRequiredRequests, | 122 | retryRequiredRequests, |
117 | areRequiredRequestsLoading, | 123 | areRequiredRequestsLoading, |
118 | hasActivatedTrial, | ||
119 | } = this.props; | 124 | } = this.props; |
120 | 125 | ||
121 | const { intl } = this.context; | 126 | const { intl } = this.context; |
@@ -123,45 +128,48 @@ class AppLayout extends Component { | |||
123 | return ( | 128 | return ( |
124 | <ErrorBoundary> | 129 | <ErrorBoundary> |
125 | <div className="app"> | 130 | <div className="app"> |
126 | {isWindows && !isFullScreen && <TitleBar menu={window.ferdi.menu.template} icon="assets/images/logo.svg" />} | 131 | {isWindows && !isFullScreen && ( |
132 | <TitleBar | ||
133 | menu={window.ferdi.menu.template} | ||
134 | icon="assets/images/logo.svg" | ||
135 | /> | ||
136 | )} | ||
127 | <div className={`app__content ${classes.appContent}`}> | 137 | <div className={`app__content ${classes.appContent}`}> |
128 | {workspacesDrawer} | 138 | {workspacesDrawer} |
129 | {sidebar} | 139 | {sidebar} |
130 | <div className="app__service"> | 140 | <div className="app__service"> |
131 | <WorkspaceSwitchingIndicator /> | 141 | <WorkspaceSwitchingIndicator /> |
132 | {news.length > 0 && news.map(item => ( | 142 | {news.length > 0 && |
143 | news.map(item => ( | ||
144 | <InfoBar | ||
145 | key={item.id} | ||
146 | position="top" | ||
147 | type={item.type} | ||
148 | sticky={item.sticky} | ||
149 | onHide={() => removeNewsItem({ newsId: item.id })} | ||
150 | > | ||
151 | <span | ||
152 | dangerouslySetInnerHTML={createMarkup(item.message)} | ||
153 | onClick={event => { | ||
154 | const { target } = event; | ||
155 | if (target && target.hasAttribute('data-is-news-cta')) { | ||
156 | removeNewsItem({ newsId: item.id }); | ||
157 | } | ||
158 | }} | ||
159 | /> | ||
160 | </InfoBar> | ||
161 | ))} | ||
162 | {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( | ||
133 | <InfoBar | 163 | <InfoBar |
134 | key={item.id} | 164 | type="danger" |
135 | position="top" | 165 | ctaLabel="Try again" |
136 | type={item.type} | 166 | ctaLoading={areRequiredRequestsLoading} |
137 | sticky={item.sticky} | 167 | sticky |
138 | onHide={() => removeNewsItem({ newsId: item.id })} | 168 | onClick={retryRequiredRequests} |
139 | > | 169 | > |
140 | <span | 170 | <span className="mdi mdi-flash" /> |
141 | dangerouslySetInnerHTML={createMarkup(item.message)} | 171 | {intl.formatMessage(messages.requiredRequestsFailed)} |
142 | onClick={(event) => { | ||
143 | const { target } = event; | ||
144 | if (target && target.hasAttribute('data-is-news-cta')) { | ||
145 | removeNewsItem({ newsId: item.id }); | ||
146 | } | ||
147 | }} | ||
148 | /> | ||
149 | </InfoBar> | 172 | </InfoBar> |
150 | ))} | ||
151 | {hasActivatedTrial && ( | ||
152 | <TrialActivationInfoBar /> | ||
153 | )} | ||
154 | {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( | ||
155 | <InfoBar | ||
156 | type="danger" | ||
157 | ctaLabel="Try again" | ||
158 | ctaLoading={areRequiredRequestsLoading} | ||
159 | sticky | ||
160 | onClick={retryRequiredRequests} | ||
161 | > | ||
162 | <span className="mdi mdi-flash" /> | ||
163 | {intl.formatMessage(messages.requiredRequestsFailed)} | ||
164 | </InfoBar> | ||
165 | )} | 173 | )} |
166 | {authRequestFailed && ( | 174 | {authRequestFailed && ( |
167 | <InfoBar | 175 | <InfoBar |
@@ -186,7 +194,7 @@ class AppLayout extends Component { | |||
186 | {intl.formatMessage(messages.servicesUpdated)} | 194 | {intl.formatMessage(messages.servicesUpdated)} |
187 | </InfoBar> | 195 | </InfoBar> |
188 | )} | 196 | )} |
189 | { appUpdateIsDownloaded && this.state.shouldShowAppUpdateInfoBar && ( | 197 | {appUpdateIsDownloaded && this.state.shouldShowAppUpdateInfoBar && ( |
190 | <AppUpdateInfoBar | 198 | <AppUpdateInfoBar |
191 | nextAppReleaseVersion={nextAppReleaseVersion} | 199 | nextAppReleaseVersion={nextAppReleaseVersion} |
192 | onInstallUpdate={installAppUpdate} | 200 | onInstallUpdate={installAppUpdate} |
@@ -202,11 +210,9 @@ class AppLayout extends Component { | |||
202 | <PublishDebugInfo /> | 210 | <PublishDebugInfo /> |
203 | {services} | 211 | {services} |
204 | {children} | 212 | {children} |
205 | <TrialStatusBar /> | ||
206 | </div> | 213 | </div> |
207 | <Todos /> | 214 | <Todos /> |
208 | </div> | 215 | </div> |
209 | <PlanSelection /> | ||
210 | </div> | 216 | </div> |
211 | </ErrorBoundary> | 217 | </ErrorBoundary> |
212 | ); | 218 | ); |
diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js index 802538eba..daa5642c3 100644 --- a/src/components/layout/Sidebar.js +++ b/src/components/layout/Sidebar.js | |||
@@ -6,16 +6,13 @@ import { inject, observer } from 'mobx-react'; | |||
6 | import { Link } from 'react-router'; | 6 | import { Link } from 'react-router'; |
7 | 7 | ||
8 | import Tabbar from '../services/tabs/Tabbar'; | 8 | import Tabbar from '../services/tabs/Tabbar'; |
9 | import { ctrlKey, isMac } from '../../environment'; | 9 | import { settingsShortcutKey, lockFerdiShortcutKey, todosToggleShortcutKey, workspaceToggleShortcutKey, addNewServiceShortcutKey, muteFerdiShortcutKey } from '../../environment'; |
10 | import { workspaceStore } from '../../features/workspaces'; | 10 | import { workspaceStore } from '../../features/workspaces'; |
11 | import { todosStore } from '../../features/todos'; | 11 | import { todosStore } from '../../features/todos'; |
12 | import { todoActions } from '../../features/todos/actions'; | 12 | import { todoActions } from '../../features/todos/actions'; |
13 | import AppStore from '../../stores/AppStore'; | 13 | import AppStore from '../../stores/AppStore'; |
14 | import SettingsStore from '../../stores/SettingsStore'; | 14 | import SettingsStore from '../../stores/SettingsStore'; |
15 | 15 | ||
16 | // Platform specific shortcut keys | ||
17 | const settingsShortcutKey = isMac ? ',' : 'P'; | ||
18 | |||
19 | const messages = defineMessages({ | 16 | const messages = defineMessages({ |
20 | settings: { | 17 | settings: { |
21 | id: 'sidebar.settings', | 18 | id: 'sidebar.settings', |
@@ -58,6 +55,19 @@ const messages = defineMessages({ | |||
58 | export default @inject('stores', 'actions') @observer class Sidebar extends Component { | 55 | export default @inject('stores', 'actions') @observer class Sidebar extends Component { |
59 | static propTypes = { | 56 | static propTypes = { |
60 | openSettings: PropTypes.func.isRequired, | 57 | openSettings: PropTypes.func.isRequired, |
58 | closeSettings: PropTypes.func.isRequired, | ||
59 | setActive: PropTypes.func.isRequired, | ||
60 | reorder: PropTypes.func.isRequired, | ||
61 | reload: PropTypes.func.isRequired, | ||
62 | toggleNotifications: PropTypes.func.isRequired, | ||
63 | toggleAudio: PropTypes.func.isRequired, | ||
64 | toggleDarkMode: PropTypes.func.isRequired, | ||
65 | showMessageBadgeWhenMutedSetting: PropTypes.bool.isRequired, | ||
66 | showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired, | ||
67 | deleteService: PropTypes.func.isRequired, | ||
68 | updateService: PropTypes.func.isRequired, | ||
69 | hibernateService: PropTypes.func.isRequired, | ||
70 | wakeUpService: PropTypes.func.isRequired, | ||
61 | toggleMuteApp: PropTypes.func.isRequired, | 71 | toggleMuteApp: PropTypes.func.isRequired, |
62 | isAppMuted: PropTypes.bool.isRequired, | 72 | isAppMuted: PropTypes.bool.isRequired, |
63 | isWorkspaceDrawerOpen: PropTypes.bool.isRequired, | 73 | isWorkspaceDrawerOpen: PropTypes.bool.isRequired, |
@@ -139,7 +149,7 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp | |||
139 | }, | 149 | }, |
140 | }); | 150 | }); |
141 | }} | 151 | }} |
142 | data-tip={`${intl.formatMessage(messages.lockFerdi)} (${ctrlKey}+Shift+L)`} | 152 | data-tip={`${intl.formatMessage(messages.lockFerdi)} (${lockFerdiShortcutKey(false)})`} |
143 | > | 153 | > |
144 | <i className="mdi mdi-lock" /> | 154 | <i className="mdi mdi-lock" /> |
145 | </button> | 155 | </button> |
@@ -152,8 +162,8 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp | |||
152 | this.updateToolTip(); | 162 | this.updateToolTip(); |
153 | }} | 163 | }} |
154 | disabled={isTodosServiceActive} | 164 | disabled={isTodosServiceActive} |
155 | className={`sidebar__button sidebar__button--todos ${todosStore.isTodosPanelVisible ? 'is-active' : ''}`} | 165 | className={`sidebar__button sidebar__button--todos ${todosStore.isTodosPanelVisible ? 'is-active' : ''}`} |
156 | data-tip={`${intl.formatMessage(todosToggleMessage)} (${ctrlKey}+T)`} | 166 | data-tip={`${intl.formatMessage(todosToggleMessage)} (${todosToggleShortcutKey(false)})`} |
157 | > | 167 | > |
158 | <i className="mdi mdi-check-all" /> | 168 | <i className="mdi mdi-check-all" /> |
159 | </button> | 169 | </button> |
@@ -166,7 +176,7 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp | |||
166 | this.updateToolTip(); | 176 | this.updateToolTip(); |
167 | }} | 177 | }} |
168 | className={`sidebar__button sidebar__button--workspaces ${isWorkspaceDrawerOpen ? 'is-active' : ''}`} | 178 | className={`sidebar__button sidebar__button--workspaces ${isWorkspaceDrawerOpen ? 'is-active' : ''}`} |
169 | data-tip={`${intl.formatMessage(workspaceToggleMessage)} (${ctrlKey}+D)`} | 179 | data-tip={`${intl.formatMessage(workspaceToggleMessage)} (${workspaceToggleShortcutKey(false)})`} |
170 | > | 180 | > |
171 | <i className="mdi mdi-view-grid" /> | 181 | <i className="mdi mdi-view-grid" /> |
172 | </button> | 182 | </button> |
@@ -178,7 +188,7 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp | |||
178 | this.updateToolTip(); | 188 | this.updateToolTip(); |
179 | }} | 189 | }} |
180 | className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`} | 190 | className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`} |
181 | data-tip={`${intl.formatMessage(isAppMuted ? messages.unmute : messages.mute)} (${ctrlKey}+Shift+M)`} | 191 | data-tip={`${intl.formatMessage(isAppMuted ? messages.unmute : messages.mute)} (${muteFerdiShortcutKey(false)})`} |
182 | > | 192 | > |
183 | <i className={`mdi mdi-bell${isAppMuted ? '-off' : ''}`} /> | 193 | <i className={`mdi mdi-bell${isAppMuted ? '-off' : ''}`} /> |
184 | </button> | 194 | </button> |
@@ -186,7 +196,7 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp | |||
186 | type="button" | 196 | type="button" |
187 | onClick={() => openSettings({ path: 'recipes' })} | 197 | onClick={() => openSettings({ path: 'recipes' })} |
188 | className="sidebar__button sidebar__button--new-service" | 198 | className="sidebar__button sidebar__button--new-service" |
189 | data-tip={`${intl.formatMessage(messages.addNewService)} (${ctrlKey}+N)`} | 199 | data-tip={`${intl.formatMessage(messages.addNewService)} (${addNewServiceShortcutKey(false)})`} |
190 | > | 200 | > |
191 | <i className="mdi mdi-plus-box" /> | 201 | <i className="mdi mdi-plus-box" /> |
192 | </button> | 202 | </button> |
@@ -204,9 +214,10 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp | |||
204 | type="button" | 214 | type="button" |
205 | onClick={() => openSettings({ path: 'app' })} | 215 | onClick={() => openSettings({ path: 'app' })} |
206 | className="sidebar__button sidebar__button--settings" | 216 | className="sidebar__button sidebar__button--settings" |
207 | data-tip={`${intl.formatMessage(messages.settings)} (${ctrlKey}+${settingsShortcutKey})`} | 217 | data-tip={`${intl.formatMessage(messages.settings)} (${settingsShortcutKey(false)})`} |
208 | > | 218 | > |
209 | <i className="mdi mdi-settings" /> | 219 | {/* TODO: Because of https://github.com/Templarian/MaterialDesign-Webfont/issues/81 bug in @mdi/font in 5.9.55, added `mdi-memory` as a fallback */} |
220 | <i className="mdi mdi-settings mdi-memory" /> | ||
210 | { (this.props.stores.app.updateStatus === this.props.stores.app.updateStatusTypes.AVAILABLE | 221 | { (this.props.stores.app.updateStatus === this.props.stores.app.updateStatusTypes.AVAILABLE |
211 | || this.props.stores.app.updateStatus === this.props.stores.app.updateStatusTypes.DOWNLOADED) && ( | 222 | || this.props.stores.app.updateStatus === this.props.stores.app.updateStatusTypes.DOWNLOADED) && ( |
212 | <span className="update-available"> | 223 | <span className="update-available"> |