aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/layout/Sidebar.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/layout/Sidebar.jsx')
-rw-r--r--src/components/layout/Sidebar.jsx336
1 files changed, 336 insertions, 0 deletions
diff --git a/src/components/layout/Sidebar.jsx b/src/components/layout/Sidebar.jsx
new file mode 100644
index 000000000..6949544b4
--- /dev/null
+++ b/src/components/layout/Sidebar.jsx
@@ -0,0 +1,336 @@
1import { Component } from 'react';
2import PropTypes from 'prop-types';
3import ReactTooltip from 'react-tooltip';
4import { defineMessages, injectIntl } from 'react-intl';
5import { inject, observer } from 'mobx-react';
6import {
7 mdiCheckAll,
8 mdiViewGrid,
9 mdiPlusBox,
10 mdiCog,
11 mdiBellOff,
12 mdiBell,
13 mdiLock,
14 mdiMenu,
15 mdiChevronDown,
16 mdiChevronRight,
17 mdiViewSplitVertical,
18} from '@mdi/js';
19
20import Tabbar from '../services/tabs/Tabbar';
21import {
22 settingsShortcutKey,
23 lockFerdiumShortcutKey,
24 todosToggleShortcutKey,
25 workspaceToggleShortcutKey,
26 addNewServiceShortcutKey,
27 splitModeToggleShortcutKey,
28 muteFerdiumShortcutKey,
29} from '../../environment';
30import { todosStore } from '../../features/todos';
31import { todoActions } from '../../features/todos/actions';
32import AppStore from '../../stores/AppStore';
33import SettingsStore from '../../stores/SettingsStore';
34import globalMessages from '../../i18n/globalMessages';
35import { Icon } from '../ui/icon';
36
37const messages = defineMessages({
38 addNewService: {
39 id: 'sidebar.addNewService',
40 defaultMessage: 'Add new service',
41 },
42 splitModeToggle: {
43 id: 'sidebar.splitModeToggle',
44 defaultMessage: 'Split Mode Toggle',
45 },
46 mute: {
47 id: 'sidebar.muteApp',
48 defaultMessage: 'Disable notifications & audio',
49 },
50 unmute: {
51 id: 'sidebar.unmuteApp',
52 defaultMessage: 'Enable notifications & audio',
53 },
54 openWorkspaceDrawer: {
55 id: 'sidebar.openWorkspaceDrawer',
56 defaultMessage: 'Open workspace drawer',
57 },
58 closeWorkspaceDrawer: {
59 id: 'sidebar.closeWorkspaceDrawer',
60 defaultMessage: 'Close workspace drawer',
61 },
62 openTodosDrawer: {
63 id: 'sidebar.openTodosDrawer',
64 defaultMessage: 'Open Ferdium Todos',
65 },
66 closeTodosDrawer: {
67 id: 'sidebar.closeTodosDrawer',
68 defaultMessage: 'Close Ferdium Todos',
69 },
70 lockFerdium: {
71 id: 'sidebar.lockFerdium',
72 defaultMessage: 'Lock Ferdium',
73 },
74});
75
76class Sidebar extends Component {
77 static propTypes = {
78 openSettings: PropTypes.func.isRequired,
79 closeSettings: PropTypes.func.isRequired,
80 setActive: PropTypes.func.isRequired,
81 reorder: PropTypes.func.isRequired,
82 reload: PropTypes.func.isRequired,
83 toggleNotifications: PropTypes.func.isRequired,
84 toggleAudio: PropTypes.func.isRequired,
85 toggleDarkMode: PropTypes.func.isRequired,
86 showServicesUpdatedInfoBar: PropTypes.bool.isRequired,
87 showMessageBadgeWhenMutedSetting: PropTypes.bool.isRequired,
88 showServiceNameSetting: PropTypes.bool.isRequired,
89 showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired,
90 deleteService: PropTypes.func.isRequired,
91 updateService: PropTypes.func.isRequired,
92 hibernateService: PropTypes.func.isRequired,
93 wakeUpService: PropTypes.func.isRequired,
94 toggleMuteApp: PropTypes.func.isRequired,
95 isAppMuted: PropTypes.bool.isRequired,
96 toggleCollapseMenu: PropTypes.func.isRequired,
97 isMenuCollapsed: PropTypes.bool.isRequired,
98 isWorkspaceDrawerOpen: PropTypes.bool.isRequired,
99 toggleWorkspaceDrawer: PropTypes.func.isRequired,
100 isTodosServiceActive: PropTypes.bool.isRequired,
101 stores: PropTypes.shape({
102 app: PropTypes.instanceOf(AppStore).isRequired,
103 settings: PropTypes.instanceOf(SettingsStore).isRequired,
104 }).isRequired,
105 actions: PropTypes.shape({
106 settings: PropTypes.instanceOf(SettingsStore).isRequired,
107 }).isRequired,
108 };
109
110 constructor(props) {
111 super(props);
112
113 this.state = {
114 tooltipEnabled: true,
115 };
116 }
117
118 componentDidUpdate() {
119 ReactTooltip.rebuild();
120 }
121
122 enableToolTip() {
123 this.setState({ tooltipEnabled: true });
124 }
125
126 disableToolTip() {
127 this.setState({ tooltipEnabled: false });
128 }
129
130 updateToolTip() {
131 this.disableToolTip();
132 setTimeout(this.enableToolTip.bind(this));
133 }
134
135 render() {
136 const {
137 openSettings,
138 toggleMuteApp,
139 toggleCollapseMenu,
140 isAppMuted,
141 isWorkspaceDrawerOpen,
142 toggleWorkspaceDrawer,
143 stores,
144 actions,
145 isTodosServiceActive,
146 } = this.props;
147 const {
148 hideCollapseButton,
149 hideRecipesButton,
150 hideWorkspacesButton,
151 hideNotificationsButton,
152 hideSettingsButton,
153 hideSplitModeButton,
154 useVerticalStyle,
155 splitMode,
156 } = stores.settings.app;
157 const { intl } = this.props;
158 const todosToggleMessage = todosStore.isTodosPanelVisible
159 ? messages.closeTodosDrawer
160 : messages.openTodosDrawer;
161
162 const workspaceToggleMessage = isWorkspaceDrawerOpen
163 ? messages.closeWorkspaceDrawer
164 : messages.openWorkspaceDrawer;
165
166 const numberActiveButtons = [
167 !hideRecipesButton,
168 !hideWorkspacesButton,
169 !hideNotificationsButton,
170 !hideSettingsButton,
171 !hideSplitModeButton,
172 todosStore.isFeatureEnabledByUser,
173 ].filter(Boolean).length;
174
175 const { isMenuCollapsed } = stores.settings.all.app;
176
177 return (
178 <div className="sidebar">
179 <Tabbar
180 {...this.props}
181 enableToolTip={() => this.enableToolTip()}
182 disableToolTip={() => this.disableToolTip()}
183 useVerticalStyle={stores.settings.all.app.useVerticalStyle}
184 />
185 <>
186 {numberActiveButtons <= 1 || hideCollapseButton ? null : (
187 <button
188 type="button"
189 onClick={() => toggleCollapseMenu()}
190 className="sidebar__button sidebar__button--hamburger-menu"
191 >
192 {isMenuCollapsed && !useVerticalStyle ? (
193 <Icon icon={mdiMenu} size={1.5} />
194 ) : null}
195
196 {isMenuCollapsed && useVerticalStyle ? (
197 <Icon icon={mdiChevronRight} size={1.5} />
198 ) : null}
199
200 {!isMenuCollapsed ? (
201 <Icon icon={mdiChevronDown} size={1.5} />
202 ) : null}
203 </button>
204 )}
205 {!hideRecipesButton && !isMenuCollapsed ? (
206 <button
207 type="button"
208 onClick={() => openSettings({ path: 'recipes' })}
209 className="sidebar__button sidebar__button--new-service"
210 data-tip={`${intl.formatMessage(
211 messages.addNewService,
212 )} (${addNewServiceShortcutKey(false)})`}
213 >
214 <Icon icon={mdiPlusBox} size={1.5} />
215 </button>
216 ) : null}
217 {!hideSplitModeButton && !isMenuCollapsed ? (
218 <button
219 type="button"
220 onClick={() => {
221 actions.settings.update({
222 type: 'app',
223 data: {
224 splitMode: !splitMode,
225 },
226 });
227 }}
228 className="sidebar__button sidebar__button--split-mode-toggle"
229 data-tip={`${intl.formatMessage(
230 messages.splitModeToggle,
231 )} (${splitModeToggleShortcutKey(false)})`}
232 >
233 <Icon icon={mdiViewSplitVertical} size={1.5} />
234 </button>
235 ) : null}
236 {!hideWorkspacesButton && !isMenuCollapsed ? (
237 <button
238 type="button"
239 onClick={() => {
240 toggleWorkspaceDrawer();
241 this.updateToolTip();
242 }}
243 className={`sidebar__button sidebar__button--workspaces ${
244 isWorkspaceDrawerOpen ? 'is-active' : ''
245 }`}
246 data-tip={`${intl.formatMessage(
247 workspaceToggleMessage,
248 )} (${workspaceToggleShortcutKey(false)})`}
249 >
250 <Icon icon={mdiViewGrid} size={1.5} />
251 </button>
252 ) : null}
253 {!hideNotificationsButton && !isMenuCollapsed ? (
254 <button
255 type="button"
256 onClick={() => {
257 toggleMuteApp();
258 this.updateToolTip();
259 }}
260 className={`sidebar__button sidebar__button--audio ${
261 isAppMuted ? 'is-muted' : ''
262 }`}
263 data-tip={`${intl.formatMessage(
264 isAppMuted ? messages.unmute : messages.mute,
265 )} (${muteFerdiumShortcutKey(false)})`}
266 >
267 <Icon icon={isAppMuted ? mdiBellOff : mdiBell} size={1.5} />
268 </button>
269 ) : null}
270 {todosStore.isFeatureEnabledByUser && !isMenuCollapsed ? (
271 <button
272 type="button"
273 onClick={() => {
274 todoActions.toggleTodosPanel();
275 this.updateToolTip();
276 }}
277 disabled={isTodosServiceActive}
278 className={`sidebar__button sidebar__button--todos ${
279 todosStore.isTodosPanelVisible ? 'is-active' : ''
280 }`}
281 data-tip={`${intl.formatMessage(
282 todosToggleMessage,
283 )} (${todosToggleShortcutKey(false)})`}
284 >
285 <Icon icon={mdiCheckAll} size={1.5} />
286 </button>
287 ) : null}
288 {stores.settings.all.app.lockingFeatureEnabled ? (
289 <button
290 type="button"
291 className="sidebar__button"
292 onClick={() => {
293 actions.settings.update({
294 type: 'app',
295 data: {
296 locked: true,
297 },
298 });
299 }}
300 data-tip={`${intl.formatMessage(
301 messages.lockFerdium,
302 )} (${lockFerdiumShortcutKey(false)})`}
303 >
304 <Icon icon={mdiLock} size={1.5} />
305 </button>
306 ) : null}
307 </>
308 {this.state.tooltipEnabled && (
309 <ReactTooltip place="right" type="dark" effect="solid" />
310 )}
311 {!hideSettingsButton && !isMenuCollapsed ? (
312 <button
313 type="button"
314 onClick={() => openSettings({ path: 'app' })}
315 className="sidebar__button sidebar__button--settings"
316 data-tip={`${intl.formatMessage(
317 globalMessages.settings,
318 )} (${settingsShortcutKey(false)})`}
319 >
320 <Icon icon={mdiCog} size={1.5} />
321 {this.props.stores.settings.app.automaticUpdates &&
322 (this.props.stores.app.updateStatus ===
323 this.props.stores.app.updateStatusTypes.AVAILABLE ||
324 this.props.stores.app.updateStatus ===
325 this.props.stores.app.updateStatusTypes.DOWNLOADED ||
326 this.props.showServicesUpdatedInfoBar) && (
327 <span className="update-available">•</span>
328 )}
329 </button>
330 ) : null}
331 </div>
332 );
333 }
334}
335
336export default injectIntl(inject('stores', 'actions')(observer(Sidebar)));