aboutsummaryrefslogtreecommitdiffstats
path: root/packages
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 /packages
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 'packages')
-rw-r--r--packages/forms/src/input/index.tsx12
-rw-r--r--packages/forms/src/input/styles.ts5
-rw-r--r--packages/forms/src/label/styles.ts4
-rw-r--r--packages/forms/src/select/index.tsx6
-rw-r--r--packages/forms/src/toggle/index.tsx4
-rw-r--r--packages/theme/src/themes/dark/index.ts67
-rw-r--r--packages/theme/src/themes/default/index.ts78
-rw-r--r--packages/ui/src/badge/ProBadge.tsx64
-rw-r--r--packages/ui/src/index.ts1
-rw-r--r--packages/ui/src/infobox/index.tsx7
-rw-r--r--packages/ui/src/loader/index.tsx4
11 files changed, 245 insertions, 7 deletions
diff --git a/packages/forms/src/input/index.tsx b/packages/forms/src/input/index.tsx
index 5178904d3..a2d7c62d5 100644
--- a/packages/forms/src/input/index.tsx
+++ b/packages/forms/src/input/index.tsx
@@ -25,6 +25,7 @@ interface IProps extends React.InputHTMLAttributes<HTMLInputElement>, IFormField
25 showPasswordToggle?: boolean; 25 showPasswordToggle?: boolean;
26 data: IData; 26 data: IData;
27 inputClassName?: string; 27 inputClassName?: string;
28 onEnterKey?: Function;
28} 29}
29 30
30interface IState { 31interface IState {
@@ -33,7 +34,7 @@ interface IState {
33} 34}
34 35
35class InputComponent extends Component<IProps, IState> { 36class InputComponent extends Component<IProps, IState> {
36 public static defaultProps = { 37 static defaultProps = {
37 focus: false, 38 focus: false,
38 onChange: () => {}, 39 onChange: () => {},
39 onBlur: () => {}, 40 onBlur: () => {},
@@ -81,6 +82,13 @@ class InputComponent extends Component<IProps, IState> {
81 } 82 }
82 } 83 }
83 84
85 onInputKeyPress(e: React.KeyboardEvent) {
86 if (e.key === "Enter") {
87 const { onEnterKey } = this.props;
88 onEnterKey && onEnterKey();
89 }
90 }
91
84 render() { 92 render() {
85 const { 93 const {
86 classes, 94 classes,
@@ -124,6 +132,7 @@ class InputComponent extends Component<IProps, IState> {
124 title={label} 132 title={label}
125 showLabel={showLabel} 133 showLabel={showLabel}
126 htmlFor={id} 134 htmlFor={id}
135 className={classes.label}
127 isRequired={required} 136 isRequired={required}
128 > 137 >
129 <div 138 <div
@@ -152,6 +161,7 @@ class InputComponent extends Component<IProps, IState> {
152 onFocus={onFocus} 161 onFocus={onFocus}
153 onBlur={onBlur} 162 onBlur={onBlur}
154 disabled={disabled} 163 disabled={disabled}
164 onKeyPress={this.onInputKeyPress.bind(this)}
155 min={min} 165 min={min}
156 max={max} 166 max={max}
157 step={step} 167 step={step}
diff --git a/packages/forms/src/input/styles.ts b/packages/forms/src/input/styles.ts
index c038295cd..e2ab30a4f 100644
--- a/packages/forms/src/input/styles.ts
+++ b/packages/forms/src/input/styles.ts
@@ -10,6 +10,11 @@ const prefixStyles = (theme: Theme) => ({
10}); 10});
11 11
12export default (theme: Theme) => ({ 12export default (theme: Theme) => ({
13 label: {
14 '& > div': {
15 marginTop: 5,
16 }
17 },
13 disabled: { 18 disabled: {
14 opacity: theme.inputDisabledOpacity, 19 opacity: theme.inputDisabledOpacity,
15 }, 20 },
diff --git a/packages/forms/src/label/styles.ts b/packages/forms/src/label/styles.ts
index f3998de04..c64c9b285 100644
--- a/packages/forms/src/label/styles.ts
+++ b/packages/forms/src/label/styles.ts
@@ -1,9 +1,7 @@
1import { Theme } from '../../../theme/lib'; 1import { Theme } from '../../../theme/lib';
2 2
3export default (theme: Theme) => ({ 3export default (theme: Theme) => ({
4 content: { 4 content: {},
5 marginTop: 5,
6 },
7 label: { 5 label: {
8 color: theme.labelColor, 6 color: theme.labelColor,
9 fontSize: theme.uiFontSize, 7 fontSize: theme.uiFontSize,
diff --git a/packages/forms/src/select/index.tsx b/packages/forms/src/select/index.tsx
index f419d0351..0e5ded176 100644
--- a/packages/forms/src/select/index.tsx
+++ b/packages/forms/src/select/index.tsx
@@ -56,6 +56,11 @@ const styles = (theme: Theme) => ({
56 textAlign: 'left', 56 textAlign: 'left',
57 color: theme.selectColor, 57 color: theme.selectColor,
58 }, 58 },
59 label: {
60 '& > div': {
61 marginTop: 5,
62 }
63 },
59 popup: { 64 popup: {
60 opacity: 0, 65 opacity: 0,
61 height: 0, 66 height: 0,
@@ -335,6 +340,7 @@ class SelectComponent extends Component<IProps> {
335 title={label} 340 title={label}
336 showLabel={showLabel} 341 showLabel={showLabel}
337 htmlFor={id} 342 htmlFor={id}
343 className={classes.label}
338 isRequired={required} 344 isRequired={required}
339 > 345 >
340 <div 346 <div
diff --git a/packages/forms/src/toggle/index.tsx b/packages/forms/src/toggle/index.tsx
index 6487f1d07..d84508a5f 100644
--- a/packages/forms/src/toggle/index.tsx
+++ b/packages/forms/src/toggle/index.tsx
@@ -1,7 +1,7 @@
1import { Theme } from '@meetfranz/theme'; 1import { Theme } from '@meetfranz/theme';
2import classnames from 'classnames'; 2import classnames from 'classnames';
3import CSS from 'csstype'; 3import CSS from 'csstype';
4import React, { Component, createRef } from 'react'; 4import React, { Component } from 'react';
5import injectStyle from 'react-jss'; 5import injectStyle from 'react-jss';
6 6
7import { IFormField, IWithStyle, Omit } from '../typings/generic'; 7import { IFormField, IWithStyle, Omit } from '../typings/generic';
@@ -45,11 +45,11 @@ const styles = (theme: Theme) => ({
45 }, 45 },
46 toggleLabel: { 46 toggleLabel: {
47 display: 'flex', 47 display: 'flex',
48 alignItems: 'center',
48 49
49 '& > span': { 50 '& > span': {
50 order: 1, 51 order: 1,
51 marginLeft: 15, 52 marginLeft: 15,
52 marginTop: 2,
53 }, 53 },
54 }, 54 },
55}); 55});
diff --git a/packages/theme/src/themes/dark/index.ts b/packages/theme/src/themes/dark/index.ts
index 3a56719b2..fd04b106c 100644
--- a/packages/theme/src/themes/dark/index.ts
+++ b/packages/theme/src/themes/dark/index.ts
@@ -1,4 +1,5 @@
1import color from 'color'; 1import color from 'color';
2import { merge, cloneDeep } from 'lodash';
2 3
3import * as defaultStyles from '../default'; 4import * as defaultStyles from '../default';
4import * as legacyStyles from '../legacy'; 5import * as legacyStyles from '../legacy';
@@ -63,3 +64,69 @@ export const selectSearchColor = inputBackground;
63 64
64// Modal 65// Modal
65export const colorModalOverlayBackground = color(legacyStyles.darkThemeBlack).alpha(0.8).rgb().string(); 66export const colorModalOverlayBackground = color(legacyStyles.darkThemeBlack).alpha(0.8).rgb().string();
67
68// Services
69export const services = merge({}, defaultStyles.services, {
70 listItems: {
71 borderColor: legacyStyles.darkThemeGrayDarker,
72 hoverBgColor: legacyStyles.darkThemeGrayDarker,
73 disabled: {
74 color: legacyStyles.darkThemeGray,
75 },
76 },
77});
78
79// Service Icon
80export const serviceIcon = merge({}, defaultStyles.serviceIcon, {
81 isCustom: {
82 border: `1px solid ${legacyStyles.darkThemeGrayDark}`,
83 },
84});
85
86// Workspaces
87const drawerBg = color(colorBackground).lighten(0.3).hex();
88
89export const workspaces = merge({}, defaultStyles.workspaces, {
90 settings: {
91 listItems: cloneDeep(services.listItems),
92 },
93 drawer: {
94 background: drawerBg,
95 addButton: {
96 color: legacyStyles.darkThemeGrayLighter,
97 hoverColor: legacyStyles.darkThemeGraySmoke,
98 },
99 listItem: {
100 border: color(drawerBg).lighten(0.2).hex(),
101 hoverBackground: color(drawerBg).lighten(0.2).hex(),
102 activeBackground: defaultStyles.brandPrimary,
103 name: {
104 color: colorText,
105 activeColor: 'white',
106 },
107 services: {
108 color: color(colorText).darken(0.5).hex(),
109 active: color(defaultStyles.brandPrimary).lighten(0.5).hex(),
110 },
111 },
112 },
113});
114
115// // Workspace settings
116// export const workspaceSettings = merge({}, defaultStyles.workspaceSettings, {
117// listItemBorderColor: legacyStyles.darkThemeGrayDarker,
118// listItemHoverBgColor: legacyStyles.darkThemeGrayDarker,
119// });
120//
121// // Workspace Drawer
122// export const workspaceDrawerBackground = color(colorBackground).lighten(0.3).hex();
123// export const workspaceDrawerAddButtonColor = legacyStyles.darkThemeGrayLighter;
124// export const workspaceDrawerAddButtonHoverColor = legacyStyles.darkThemeGraySmoke;
125// export const workspaceDrawerItemBorder = color(workspaceDrawerBackground).lighten(0.2).hex();
126// export const workspaceDrawerItemHoverBackground = color(workspaceDrawerBackground).lighten(0.2).hex();
127// export const workspaceDrawerItemActiveBackground = defaultStyles.brandPrimary;
128// export const workspaceDrawerItemNameColor = colorText;
129// export const workspaceDrawerItemNameActiveColor = 'white';
130// export const workspaceDrawerServicesColor = color(colorText).darken(0.5).hex();
131// export const workspaceDrawerServicesActiveColor = color(defaultStyles.brandPrimary).lighten(0.5).hex();
132//
diff --git a/packages/theme/src/themes/default/index.ts b/packages/theme/src/themes/default/index.ts
index 273792d46..d0493b82f 100644
--- a/packages/theme/src/themes/default/index.ts
+++ b/packages/theme/src/themes/default/index.ts
@@ -1,4 +1,5 @@
1import color from 'color'; 1import color from 'color';
2import { cloneDeep } from 'lodash';
2 3
3import * as legacyStyles from '../legacy'; 4import * as legacyStyles from '../legacy';
4 5
@@ -142,3 +143,80 @@ export const badgeBorderRadius = 50;
142 143
143// Modal 144// Modal
144export const colorModalOverlayBackground = color('#000').alpha(0.5).rgb().string(); 145export const colorModalOverlayBackground = color('#000').alpha(0.5).rgb().string();
146
147// Services
148export const services = {
149 listItems: {
150 padding: 10,
151 height: 57,
152 borderColor: legacyStyles.themeGrayLightest,
153 hoverBgColor: legacyStyles.themeGrayLightest,
154 disabled: {
155 color: legacyStyles.themeGrayLight,
156 },
157 },
158};
159
160// Service Icon
161export const serviceIcon = {
162 width: 35,
163 isCustom: {
164 border: `1px solid ${legacyStyles.themeGrayLighter}`,
165 borderRadius: legacyStyles.themeBorderRadius,
166 width: 37,
167 },
168};
169
170// Workspaces
171const drawerBg = color(colorBackground).lighten(0.1).hex();
172
173export const workspaces = {
174 settings: {
175 listItems: cloneDeep(services.listItems),
176 },
177 drawer: {
178 width: 300,
179 padding: 20,
180 background: drawerBg,
181 buttons: {
182 color: color(legacyStyles.themeGrayLight).lighten(0.1).hex(),
183 hoverColor: legacyStyles.themeGrayLight,
184 },
185 listItem: {
186 hoverBackground: color(drawerBg).darken(0.01).hex(),
187 activeBackground: legacyStyles.themeGrayLightest,
188 border: color(drawerBg).darken(0.05).hex(),
189 name: {
190 color: colorText,
191 activeColor: colorText,
192 },
193 services: {
194 color: color(colorText).lighten(1.5).hex(),
195 active: color(colorText).lighten(1.5).hex(),
196 },
197 },
198 },
199 switchingIndicator: {
200 spinnerColor: 'white',
201 },
202};
203
204// export const workspaceSettings = {
205// listItemHeight: 57,
206// listItemBorderColor: legacyStyles.themeGrayLightest,
207// listItemHoverBgColor: legacyStyles.themeGrayLightest,
208// };
209//
210// // Workspace Drawer
211// export const workspaceDrawerWidth = 300;
212// export const workspaceDrawerPadding = 20;
213// export const workspaceDrawerBackground = color(colorBackground).lighten(0.1).hex();
214// export const workspaceDrawerAddButtonColor = legacyStyles.themeGrayLight;
215// export const workspaceDrawerAddButtonHoverColor = color(legacyStyles.themeGrayLight).lighten(0.1).hex();
216// export const workspaceDrawerItemHoverBackground = color(workspaceDrawerBackground).darken(0.01).hex();
217// export const workspaceDrawerItemActiveBackground = legacyStyles.themeGrayLightest;
218// export const workspaceDrawerItemBorder = color(workspaceDrawerBackground).darken(0.05).hex();
219// export const workspaceDrawerItemNameColor = colorText;
220// export const workspaceDrawerItemNameActiveColor = colorText;
221// export const workspaceDrawerServicesColor = color(colorText).lighten(1.5).hex();
222// export const workspaceDrawerServicesActiveColor = workspaceDrawerServicesColor;
diff --git a/packages/ui/src/badge/ProBadge.tsx b/packages/ui/src/badge/ProBadge.tsx
new file mode 100644
index 000000000..612e23210
--- /dev/null
+++ b/packages/ui/src/badge/ProBadge.tsx
@@ -0,0 +1,64 @@
1import { Theme } from '@meetfranz/theme';
2import classnames from 'classnames';
3import React, { Component } from 'react';
4import injectStyle from 'react-jss';
5
6import { Icon, Badge } from '../';
7import { IWithStyle } from '../typings/generic';
8
9interface IProps extends IWithStyle {
10 badgeClasses?: string;
11 iconClasses?: string;
12 inverted?: boolean;
13}
14
15const styles = (theme: Theme) => ({
16 badge: {
17 height: 'auto',
18 padding: [4, 6, 2, 7],
19 borderRadius: theme.borderRadiusSmall,
20 },
21 invertedBadge: {
22 background: theme.styleTypes.primary.contrast,
23 color: theme.styleTypes.primary.accent,
24 },
25 icon: {
26 fill: theme.styleTypes.primary.contrast,
27 },
28 invertedIcon: {
29 fill: theme.styleTypes.primary.accent,
30 },
31});
32
33class ProBadgeComponent extends Component<IProps> {
34 render() {
35 const {
36 classes,
37 badgeClasses,
38 iconClasses,
39 inverted,
40 } = this.props;
41
42 return (
43 <Badge
44 type="primary"
45 className={classnames([
46 classes.badge,
47 inverted && classes.invertedBadge,
48 badgeClasses,
49 ])}
50 >
51 <Icon
52 icon="mdiStar"
53 className={classnames([
54 classes.icon,
55 inverted && classes.invertedIcon,
56 iconClasses,
57 ])}
58 />
59 </Badge>
60 );
61 }
62}
63
64export const ProBadge = injectStyle(styles)(ProBadgeComponent);
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index 1eeec5144..666495ce9 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -3,3 +3,4 @@ export { Infobox } from './infobox';
3export * from './headline'; 3export * from './headline';
4export { Loader } from './loader'; 4export { Loader } from './loader';
5export { Badge } from './badge'; 5export { Badge } from './badge';
6export { ProBadge } from './badge/ProBadge';
diff --git a/packages/ui/src/infobox/index.tsx b/packages/ui/src/infobox/index.tsx
index 1a442a733..9066a623e 100644
--- a/packages/ui/src/infobox/index.tsx
+++ b/packages/ui/src/infobox/index.tsx
@@ -11,6 +11,7 @@ interface IProps extends IWithStyle {
11 type?: string; 11 type?: string;
12 dismissable?: boolean; 12 dismissable?: boolean;
13 onDismiss?: () => void; 13 onDismiss?: () => void;
14 onUnmount?: () => void;
14 ctaOnClick?: () => void; 15 ctaOnClick?: () => void;
15 ctaLabel?: string; 16 ctaLabel?: string;
16 ctaLoading?: boolean; 17 ctaLoading?: boolean;
@@ -46,6 +47,7 @@ const styles = (theme: Theme) => ({
46 wrapper: { 47 wrapper: {
47 position: 'relative', 48 position: 'relative',
48 overflow: 'hidden', 49 overflow: 'hidden',
50 height: 'auto',
49 }, 51 },
50 infobox: { 52 infobox: {
51 alignItems: 'center', 53 alignItems: 'center',
@@ -129,6 +131,11 @@ class InfoboxComponent extends Component<IProps, IState> {
129 }, 3000); 131 }, 3000);
130 } 132 }
131 133
134 componentWillUnmount(): void {
135 const { onUnmount } = this.props;
136 if (onUnmount) onUnmount();
137 }
138
132 render() { 139 render() {
133 const { 140 const {
134 classes, 141 classes,
diff --git a/packages/ui/src/loader/index.tsx b/packages/ui/src/loader/index.tsx
index 46545c786..4a3c8274f 100644
--- a/packages/ui/src/loader/index.tsx
+++ b/packages/ui/src/loader/index.tsx
@@ -8,6 +8,7 @@ import { IWithStyle } from '../typings/generic';
8 8
9interface IProps extends IWithStyle { 9interface IProps extends IWithStyle {
10 className?: string; 10 className?: string;
11 color?: string;
11} 12}
12 13
13const styles = (theme: Theme) => ({ 14const styles = (theme: Theme) => ({
@@ -22,6 +23,7 @@ class LoaderComponent extends Component<IProps> {
22 const { 23 const {
23 classes, 24 classes,
24 className, 25 className,
26 color,
25 theme, 27 theme,
26 } = this.props; 28 } = this.props;
27 29
@@ -37,7 +39,7 @@ class LoaderComponent extends Component<IProps> {
37 loaded={false} 39 loaded={false}
38 width={4} 40 width={4}
39 scale={0.75} 41 scale={0.75}
40 color={theme.colorText} 42 color={color || theme.colorText}
41 parentClassName={classes.loader} 43 parentClassName={classes.loader}
42 /> 44 />
43 </div> 45 </div>