aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/layout
diff options
context:
space:
mode:
authorLibravatar Dominik Guzei <dominik.guzei@gmail.com>2019-04-11 16:54:01 +0200
committerLibravatar Stefan Malzner <stefan@adlk.io>2019-04-11 16:54:01 +0200
commit47c1c99d893517efc679ab29d675cc0bf44be8be (patch)
tree9cab9697096bef0ce56d8ee8709bc1c2c3a42deb /src/components/layout
parenttest package order (diff)
downloadferdium-app-47c1c99d893517efc679ab29d675cc0bf44be8be.tar.gz
ferdium-app-47c1c99d893517efc679ab29d675cc0bf44be8be.tar.zst
ferdium-app-47c1c99d893517efc679ab29d675cc0bf44be8be.zip
feat(App): Added Workspaces for all your daily routines 🥳
* merge default and fetched feature configs * ignore intellij project files * basic setup for workspaces feature * define workspaces as premium feature * add workspaces menu item in settings dialog * basic setup of workspaces settings screen * fix eslint error * assign react key prop to workspace items * add styles for workspace table * setup logic to display workspace edit page * consolidate workspace feature for further development * prepare basic workspace edit form * add on enter key handler for form input component * add form for creating workspaces * small fixes * adds flow for deleting workspaces * stop tracking google analytics in components * pin gulp-sass-variables version to 1.1.1 * fix merge conflict * fix bug in form input library * improve workspace form setup * finish basic workspace settings * finish workspaces mvp * fix eslint issues * remove dev logs * detach service when underlying webview unmounts * disable no-param-reassign eslint rule * add workspace drawer * change workspace switch shortcuts to start with zero * add workspace drawer toggle menu item and shortcut * improve workspace switching ux * style add workspace icon in drawer like the sidebar icons * improve workspace drawer layout * add i18n messages for service loading and workspace switching * small fixes * add tooltip to add workspace button in drawer * add workspaces count badge in settings navigation * fix merge conflicts with latest develop * refactor state management for workspace feature * reset api requests when workspace feature is stopped * hide workspace feature if it is disabled * handle get workspaces request errors in the ui * show infobox when updating workspaces * indicate any server interaction with spinners and infoboxes * add analytic events for workspace actions * improve styling of workspace switch indicator * add workspace premium notice to dashboard * add workspace feature info in drawer for free users * add workspace premium badge in settings nav * fix premium workspace badge in settings menu for light theme * fix active workspaces settings premium badge in light theme * give upgrade account button a bit more padding * add open last used workspace logic * use mobx-localstorage directly in the store * fix wrong workspace tooltip shortcut in sidebar * fix bug in workspace feature initialization * show workspaces intro in drawer when user has none yet * fix issues for users that have workspace but downgraded to free * border radius for premium intro in workspace settings * close workspace drawer after clicking on a workspace * add hover effect for drawer workspace items * ensure drawer is open on workspace settings routes * add small text label for adding new workspace to drawer * make workspace settings list items taller * refactor workspace table css away from legacy styles * render workspace service list like services + toggle * change plus icon in workspace drawer to settings icon * autofocus create workspace input field * add css transition to drawer workspace item hover * fix drawer add workspace label styles * refactors workspace theme vars into object structure * improve contrast of workspace switching indicator * added generic pro badge component for settings nav * add premium badge to workspace drawer headline * add context menu for workspace drawer items * handle deleted services that are attached to workspaces
Diffstat (limited to 'src/components/layout')
-rw-r--r--src/components/layout/AppLayout.js26
-rw-r--r--src/components/layout/Sidebar.js49
2 files changed, 70 insertions, 5 deletions
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js
index 593149e72..b7f7722dd 100644
--- a/src/components/layout/AppLayout.js
+++ b/src/components/layout/AppLayout.js
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, intlShape } from 'react-intl';
5import { TitleBar } from 'electron-react-titlebar'; 5import { TitleBar } from 'electron-react-titlebar';
6import injectSheet from 'react-jss';
6 7
7import InfoBar from '../ui/InfoBar'; 8import InfoBar from '../ui/InfoBar';
8import { Component as DelayApp } from '../../features/delayApp'; 9import { Component as DelayApp } from '../../features/delayApp';
@@ -13,6 +14,8 @@ import ErrorBoundary from '../util/ErrorBoundary';
13// import globalMessages from '../../i18n/globalMessages'; 14// import globalMessages from '../../i18n/globalMessages';
14 15
15import { isWindows } from '../../environment'; 16import { isWindows } from '../../environment';
17import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator';
18import { workspaceStore } from '../../features/workspaces';
16 19
17function createMarkup(HTMLString) { 20function createMarkup(HTMLString) {
18 return { __html: HTMLString }; 21 return { __html: HTMLString };
@@ -45,10 +48,23 @@ const messages = defineMessages({
45 }, 48 },
46}); 49});
47 50
48export default @observer class AppLayout extends Component { 51const styles = theme => ({
52 appContent: {
53 width: `calc(100% + ${theme.workspaces.drawer.width}px)`,
54 transition: 'transform 0.5s ease',
55 transform() {
56 return workspaceStore.isWorkspaceDrawerOpen ? 'translateX(0)' : `translateX(-${theme.workspaces.drawer.width}px)`;
57 },
58 },
59});
60
61@injectSheet(styles) @observer
62class AppLayout extends Component {
49 static propTypes = { 63 static propTypes = {
64 classes: PropTypes.object.isRequired,
50 isFullScreen: PropTypes.bool.isRequired, 65 isFullScreen: PropTypes.bool.isRequired,
51 sidebar: PropTypes.element.isRequired, 66 sidebar: PropTypes.element.isRequired,
67 workspacesDrawer: PropTypes.element.isRequired,
52 services: PropTypes.element.isRequired, 68 services: PropTypes.element.isRequired,
53 children: PropTypes.element, 69 children: PropTypes.element,
54 news: MobxPropTypes.arrayOrObservableArray.isRequired, 70 news: MobxPropTypes.arrayOrObservableArray.isRequired,
@@ -76,7 +92,9 @@ export default @observer class AppLayout extends Component {
76 92
77 render() { 93 render() {
78 const { 94 const {
95 classes,
79 isFullScreen, 96 isFullScreen,
97 workspacesDrawer,
80 sidebar, 98 sidebar,
81 services, 99 services,
82 children, 100 children,
@@ -102,9 +120,11 @@ export default @observer class AppLayout extends Component {
102 <div className={(darkMode ? 'theme__dark' : '')}> 120 <div className={(darkMode ? 'theme__dark' : '')}>
103 <div className="app"> 121 <div className="app">
104 {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon="assets/images/logo.svg" />} 122 {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon="assets/images/logo.svg" />}
105 <div className="app__content"> 123 <div className={`app__content ${classes.appContent}`}>
124 {workspacesDrawer}
106 {sidebar} 125 {sidebar}
107 <div className="app__service"> 126 <div className="app__service">
127 <WorkspaceSwitchingIndicator />
108 {news.length > 0 && news.map(item => ( 128 {news.length > 0 && news.map(item => (
109 <InfoBar 129 <InfoBar
110 key={item.id} 130 key={item.id}
@@ -176,3 +196,5 @@ export default @observer class AppLayout extends Component {
176 ); 196 );
177 } 197 }
178} 198}
199
200export default AppLayout;
diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js
index 609a3b604..36c1f2e39 100644
--- a/src/components/layout/Sidebar.js
+++ b/src/components/layout/Sidebar.js
@@ -6,6 +6,8 @@ import { observer } from 'mobx-react';
6 6
7import Tabbar from '../services/tabs/Tabbar'; 7import Tabbar from '../services/tabs/Tabbar';
8import { ctrlKey } from '../../environment'; 8import { ctrlKey } from '../../environment';
9import { GA_CATEGORY_WORKSPACES, workspaceStore } from '../../features/workspaces';
10import { gaEvent } from '../../lib/analytics';
9 11
10const messages = defineMessages({ 12const messages = defineMessages({
11 settings: { 13 settings: {
@@ -24,6 +26,14 @@ const messages = defineMessages({
24 id: 'sidebar.unmuteApp', 26 id: 'sidebar.unmuteApp',
25 defaultMessage: '!!!Enable notifications & audio', 27 defaultMessage: '!!!Enable notifications & audio',
26 }, 28 },
29 openWorkspaceDrawer: {
30 id: 'sidebar.openWorkspaceDrawer',
31 defaultMessage: '!!!Open workspace drawer',
32 },
33 closeWorkspaceDrawer: {
34 id: 'sidebar.closeWorkspaceDrawer',
35 defaultMessage: '!!!Close workspace drawer',
36 },
27}); 37});
28 38
29export default @observer class Sidebar extends Component { 39export default @observer class Sidebar extends Component {
@@ -31,7 +41,9 @@ export default @observer class Sidebar extends Component {
31 openSettings: PropTypes.func.isRequired, 41 openSettings: PropTypes.func.isRequired,
32 toggleMuteApp: PropTypes.func.isRequired, 42 toggleMuteApp: PropTypes.func.isRequired,
33 isAppMuted: PropTypes.bool.isRequired, 43 isAppMuted: PropTypes.bool.isRequired,
34 } 44 isWorkspaceDrawerOpen: PropTypes.bool.isRequired,
45 toggleWorkspaceDrawer: PropTypes.func.isRequired,
46 };
35 47
36 static contextTypes = { 48 static contextTypes = {
37 intl: intlShape, 49 intl: intlShape,
@@ -53,9 +65,23 @@ export default @observer class Sidebar extends Component {
53 this.setState({ tooltipEnabled: false }); 65 this.setState({ tooltipEnabled: false });
54 } 66 }
55 67
68 updateToolTip() {
69 this.disableToolTip();
70 setTimeout(this.enableToolTip.bind(this));
71 }
72
56 render() { 73 render() {
57 const { openSettings, toggleMuteApp, isAppMuted } = this.props; 74 const {
75 openSettings,
76 toggleMuteApp,
77 isAppMuted,
78 isWorkspaceDrawerOpen,
79 toggleWorkspaceDrawer,
80 } = this.props;
58 const { intl } = this.context; 81 const { intl } = this.context;
82 const workspaceToggleMessage = (
83 isWorkspaceDrawerOpen ? messages.closeWorkspaceDrawer : messages.openWorkspaceDrawer
84 );
59 85
60 return ( 86 return (
61 <div className="sidebar"> 87 <div className="sidebar">
@@ -64,9 +90,26 @@ export default @observer class Sidebar extends Component {
64 enableToolTip={() => this.enableToolTip()} 90 enableToolTip={() => this.enableToolTip()}
65 disableToolTip={() => this.disableToolTip()} 91 disableToolTip={() => this.disableToolTip()}
66 /> 92 />
93 {workspaceStore.isFeatureEnabled ? (
94 <button
95 type="button"
96 onClick={() => {
97 toggleWorkspaceDrawer();
98 this.updateToolTip();
99 gaEvent(GA_CATEGORY_WORKSPACES, 'toggleDrawer', 'sidebar');
100 }}
101 className={`sidebar__button sidebar__button--workspaces ${isWorkspaceDrawerOpen ? 'is-active' : ''}`}
102 data-tip={`${intl.formatMessage(workspaceToggleMessage)} (${ctrlKey}+D)`}
103 >
104 <i className="mdi mdi-view-grid" />
105 </button>
106 ) : null}
67 <button 107 <button
68 type="button" 108 type="button"
69 onClick={toggleMuteApp} 109 onClick={() => {
110 toggleMuteApp();
111 this.updateToolTip();
112 }}
70 className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`} 113 className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`}
71 data-tip={`${intl.formatMessage(isAppMuted ? messages.unmute : messages.mute)} (${ctrlKey}+Shift+M)`} 114 data-tip={`${intl.formatMessage(isAppMuted ? messages.unmute : messages.mute)} (${ctrlKey}+Shift+M)`}
72 > 115 >