Skip to content

Commit 0f49690

Browse files
committed
feat: add workspace drawer icon display
1 parent 260c309 commit 0f49690

File tree

9 files changed

+194
-29
lines changed

9 files changed

+194
-29
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { Component, ReactNode } from 'react';
2+
import { observer } from 'mobx-react';
3+
import withStyles, { WithStylesProps } from 'react-jss';
4+
import classnames from 'classnames';
5+
import { mdiInfinity } from '@mdi/js';
6+
import Icon from './icon';
7+
8+
const styles = theme => ({
9+
root: {
10+
height: `${theme.serviceIcon.width}px`,
11+
width: `${theme.serviceIcon.width}px`,
12+
textAlign: 'center',
13+
display: 'table-cell',
14+
verticalAlign: 'middle',
15+
},
16+
icon: {
17+
height: 'auto',
18+
width: `${theme.serviceIcon.width}px`,
19+
maxHeight: `${theme.serviceIcon.width}px`,
20+
},
21+
iconLetterContainer: {
22+
border: `1px solid ${theme.colorText}`,
23+
borderRadius: '20%',
24+
},
25+
iconLetter: {
26+
fontSize: 'x-large',
27+
fontWeight: '500',
28+
},
29+
});
30+
31+
interface IProps extends WithStylesProps<typeof styles> {
32+
className?: string;
33+
name: string | null;
34+
iconUrl: string;
35+
}
36+
37+
@observer
38+
class WorkspaceIcon extends Component<IProps> {
39+
render(): ReactNode {
40+
const { classes, className, name, iconUrl } = this.props;
41+
if (iconUrl === 'allServices') {
42+
return (
43+
<div className={classnames([classes.root, className])}>
44+
<Icon icon={mdiInfinity} size={1.5} />
45+
</div>
46+
);
47+
}
48+
if (iconUrl) {
49+
return (
50+
<div className={classnames([classes.root, className])}>
51+
<img src={iconUrl} className={classes.icon} alt={name || undefined} />{' '}
52+
</div>
53+
);
54+
}
55+
return (
56+
<div
57+
className={classnames([
58+
classes.root,
59+
classes.iconLetterContainer,
60+
className,
61+
])}
62+
>
63+
<span className={classes.iconLetter}>
64+
{(name || ' ').slice(0, 1).toLocaleUpperCase()}
65+
</span>
66+
</div>
67+
);
68+
}
69+
}
70+
71+
export default withStyles(styles, { injectTheme: true })(WorkspaceIcon);

src/containers/layout/AppLayoutContainer.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class AppLayoutContainer extends Component<IProps> {
8080
? workspaceStore.getWorkspaceServices(workspace).map(s => s.name)
8181
: services.all.map(s => s.name)
8282
}
83+
useIconDisplayStyle={settings.all.app.useWorkspaceDrawerIconStyle}
8384
/>
8485
);
8586

src/features/appearance/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,15 @@ function generateOpenWorkspaceStyle() {
380380
`;
381381
}
382382

383+
function generateWorkspaceWidthStyle(widthStr) {
384+
const width = Number(widthStr);
385+
return `
386+
.drawerWithIconWidth {
387+
width: ${width}
388+
}
389+
`;
390+
}
391+
383392
function generateStyle(settings, app) {
384393
let style = '';
385394

@@ -418,6 +427,8 @@ function generateStyle(settings, app) {
418427
isFullScreen,
419428
);
420429

430+
style += generateWorkspaceWidthStyle(serviceRibbonWidth);
431+
421432
if (shouldShowDragArea) {
422433
style += generateShowDragAreaStyle(accentColor);
423434
}

src/features/workspaces/components/EditWorkspaceForm.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ const messages = defineMessages({
3030
id: 'settings.workspace.form.name',
3131
defaultMessage: 'Name',
3232
},
33+
iconUrl: {
34+
id: 'settings.workspace.form.iconUrl',
35+
defaultMessage: 'Icon',
36+
},
3337
yourWorkspaces: {
3438
id: 'settings.workspace.form.yourWorkspaces',
3539
defaultMessage: 'Your workspaces',
@@ -107,6 +111,12 @@ class EditWorkspaceForm extends Component<IProps> {
107111
value: workspace.name,
108112
validators: [required],
109113
},
114+
iconUrl: {
115+
label: intl.formatMessage(messages.iconUrl),
116+
placeholder: intl.formatMessage(messages.iconUrl),
117+
value: workspace.iconUrl || '',
118+
validators: [],
119+
},
110120
keepLoaded: {
111121
label: intl.formatMessage(messages.keepLoaded),
112122
value: workspace.services.includes(KEEP_WS_LOADED_USID),
@@ -181,6 +191,7 @@ class EditWorkspaceForm extends Component<IProps> {
181191
)}
182192
<div className={classes.nameInput}>
183193
<Input {...form.$('name').bind()} />
194+
<Input {...form.$('iconUrl').bind()} />
184195
<Toggle {...form.$('keepLoaded').bind()} />
185196
<p className={`${classes.keepLoadedInfo} franz-form__label`}>
186197
{intl.formatMessage(messages.keepLoadedInfo)}

src/features/workspaces/components/WorkspaceDrawer.tsx

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,22 @@ const messages = defineMessages({
4040
const styles = theme => ({
4141
drawer: {
4242
background: theme.workspaces.drawer.background,
43-
width: `${theme.workspaces.drawer.width}px`,
4443
display: 'flex',
4544
flexDirection: 'column',
4645
},
46+
drawerWithText: {
47+
width: `${theme.workspaces.drawer.width}px`,
48+
},
4749
headline: {
4850
fontSize: '24px',
4951
marginTop: '38px',
5052
marginBottom: '25px',
5153
marginLeft: theme.workspaces.drawer.padding,
5254
},
55+
headlineWithicon: {
56+
marginLeft: '0',
57+
color: theme.workspaces.drawer.buttons.color,
58+
},
5359
workspacesSettingsButton: {
5460
float: 'right',
5561
marginRight: theme.workspaces.drawer.padding,
@@ -90,6 +96,7 @@ const styles = theme => ({
9096

9197
interface IProps extends WithStylesProps<typeof styles>, WrappedComponentProps {
9298
getServicesForWorkspace: (workspace: Workspace | null) => string[];
99+
useIconDisplayStyle: boolean;
93100
}
94101

95102
@observer
@@ -104,19 +111,24 @@ class WorkspaceDrawer extends Component<IProps> {
104111
}
105112

106113
render(): ReactElement {
107-
const { classes, getServicesForWorkspace } = this.props;
114+
const { classes, getServicesForWorkspace, useIconDisplayStyle } =
115+
this.props;
108116
const { intl } = this.props;
109117
const { activeWorkspace, isSwitchingWorkspace, nextWorkspace, workspaces } =
110118
workspaceStore;
111119
const actualWorkspace = isSwitchingWorkspace
112120
? nextWorkspace
113121
: activeWorkspace;
122+
123+
const drawerWithClass = useIconDisplayStyle
124+
? 'drawerWithIconWidth'
125+
: classes.drawerWithText;
114126
return (
115-
<div className={`${classes.drawer} workspaces-drawer`}>
116-
<H1 className={classes.headline}>
117-
{intl.formatMessage(messages.headline)}
118-
<span
119-
className={classes.workspacesSettingsButton}
127+
<div className={`${classes.drawer} ${drawerWithClass} workspaces-drawer`}>
128+
{useIconDisplayStyle ? (
129+
<button
130+
type="button"
131+
className={`${classes.headline} ${classes.headlineWithicon}`}
120132
onKeyDown={noop}
121133
onClick={() => {
122134
workspaceActions.openWorkspaceSettings();
@@ -130,11 +142,34 @@ class WorkspaceDrawer extends Component<IProps> {
130142
size={1.5}
131143
className={classes.workspacesSettingsButtonIcon}
132144
/>
133-
</span>
134-
</H1>
145+
</button>
146+
) : (
147+
<H1 className={classes.headline}>
148+
{intl.formatMessage(messages.headline)}
149+
<span
150+
className={classes.workspacesSettingsButton}
151+
onKeyDown={noop}
152+
onClick={() => {
153+
workspaceActions.openWorkspaceSettings();
154+
}}
155+
data-tip={`${intl.formatMessage(
156+
messages.workspacesSettingsTooltip,
157+
)}`}
158+
>
159+
<Icon
160+
icon={mdiCog}
161+
size={1.5}
162+
className={classes.workspacesSettingsButtonIcon}
163+
/>
164+
</span>
165+
</H1>
166+
)}
167+
135168
<div className={classes.workspaces}>
136169
<WorkspaceDrawerItem
137170
name={intl.formatMessage(messages.allServices)}
171+
iconUrl="allServices"
172+
useIconDisplayStyle={useIconDisplayStyle}
138173
onClick={() => {
139174
workspaceActions.deactivate();
140175
workspaceActions.toggleWorkspaceDrawer();
@@ -147,6 +182,8 @@ class WorkspaceDrawer extends Component<IProps> {
147182
<WorkspaceDrawerItem
148183
key={workspace.id}
149184
name={workspace.name}
185+
iconUrl={workspace.iconUrl}
186+
useIconDisplayStyle={useIconDisplayStyle}
150187
isActive={actualWorkspace === workspace}
151188
onClick={() => {
152189
if (actualWorkspace === workspace) {
@@ -171,9 +208,12 @@ class WorkspaceDrawer extends Component<IProps> {
171208
>
172209
<Icon
173210
icon={mdiPlusBox}
211+
size={useIconDisplayStyle ? 1.5 : 1}
174212
className={classes.workspacesSettingsButtonIcon}
175213
/>
176-
<span>{intl.formatMessage(messages.addNewWorkspaceLabel)}</span>
214+
{useIconDisplayStyle !== true && (
215+
<span>{intl.formatMessage(messages.addNewWorkspaceLabel)}</span>
216+
)}{' '}
177217
</div>
178218
</div>
179219
<ReactTooltip place="right" type="dark" effect="solid" />

src/features/workspaces/components/WorkspaceDrawerItem.tsx

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Menu } from '@electron/remote';
88
import { MenuItemConstructorOptions } from 'electron';
99
import { altKey, cmdOrCtrlShortcutKey } from '../../../environment';
1010
import { acceleratorString } from '../../../jsUtils';
11+
import WorkspaceIcon from '../../../components/ui/WorkspaceIcon';
1112

1213
const messages = defineMessages({
1314
noServicesAddedYet: {
@@ -49,6 +50,11 @@ const styles = theme => ({
4950
marginTop: '4px',
5051
color: theme.workspaces.drawer.listItem.name.color,
5152
},
53+
icon: {
54+
maxWidth: '30px',
55+
maxHeight: '30px',
56+
margin: 'auto',
57+
},
5258
activeName: {
5359
color: theme.workspaces.drawer.listItem.name.activeColor,
5460
},
@@ -70,6 +76,8 @@ const styles = theme => ({
7076
interface IProps extends WithStylesProps<typeof styles>, WrappedComponentProps {
7177
isActive: boolean;
7278
name: string;
79+
iconUrl: string;
80+
useIconDisplayStyle: boolean;
7381
onClick: MouseEventHandler<HTMLInputElement>;
7482
services: string[];
7583
onContextMenuEditClick?: () => void | null;
@@ -83,6 +91,8 @@ class WorkspaceDrawerItem extends Component<IProps> {
8391
classes,
8492
isActive,
8593
name,
94+
iconUrl,
95+
useIconDisplayStyle,
8696
onClick,
8797
onContextMenuEditClick = null,
8898
services,
@@ -124,24 +134,30 @@ class WorkspaceDrawerItem extends Component<IProps> {
124134
`${cmdOrCtrlShortcutKey(false)}+${altKey(false)}`,
125135
)}
126136
>
127-
<span
128-
className={classnames([
129-
classes.name,
130-
isActive ? classes.activeName : null,
131-
])}
132-
>
133-
{name}
134-
</span>
135-
<span
136-
className={classnames([
137-
classes.services,
138-
isActive ? classes.activeServices : null,
139-
])}
140-
>
141-
{services.length > 0
142-
? services.join(', ')
143-
: intl.formatMessage(messages.noServicesAddedYet)}
144-
</span>
137+
{useIconDisplayStyle === true ? (
138+
<WorkspaceIcon name={name} iconUrl={iconUrl} />
139+
) : (
140+
<>
141+
<span
142+
className={classnames([
143+
classes.name,
144+
isActive ? classes.activeName : null,
145+
])}
146+
>
147+
{name}
148+
</span>
149+
<span
150+
className={classnames([
151+
classes.services,
152+
isActive ? classes.activeServices : null,
153+
])}
154+
>
155+
{services.length > 0
156+
? services.join(', ')
157+
: intl.formatMessage(messages.noServicesAddedYet)}
158+
</span>
159+
</>
160+
)}
145161
</div>
146162
);
147163
}

src/features/workspaces/components/WorkspaceItem.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { observer } from 'mobx-react';
44
import withStyles, { WithStylesProps } from 'react-jss';
55
import { noop } from 'lodash';
66
import Workspace from '../models/Workspace';
7+
import WorkspaceIcon from '../../../components/ui/WorkspaceIcon';
78

89
const styles = theme => ({
910
row: {
@@ -13,7 +14,10 @@ const styles = theme => ({
1314
background: theme.workspaces.settings.listItems.hoverBgColor,
1415
},
1516
},
16-
columnName: {},
17+
columnName: {
18+
width: '60px',
19+
borderCollapse: 'separate',
20+
},
1721
});
1822

1923
interface IProps extends WithStylesProps<typeof styles> {
@@ -28,6 +32,13 @@ class WorkspaceItem extends Component<IProps> {
2832

2933
return (
3034
<tr className={classes.row}>
35+
<td
36+
className={classes.columnName}
37+
onClick={() => onItemClick(workspace)}
38+
onKeyDown={noop}
39+
>
40+
<WorkspaceIcon name={workspace.name} iconUrl={workspace.iconUrl} />
41+
</td>
3142
<td onClick={() => onItemClick(workspace)} onKeyDown={noop}>
3243
{workspace.name}
3344
</td>

src/features/workspaces/models/Workspace.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ export default class Workspace {
77

88
@observable name = null;
99

10+
@observable iconUrl = '';
11+
1012
@observable order = null;
1113

1214
@observable services: string[] = [];
@@ -22,6 +24,7 @@ export default class Workspace {
2224

2325
this.id = data.id;
2426
this.name = data.name;
27+
this.iconUrl = data.iconUrl;
2528
this.order = data.order;
2629

2730
let { services } = data;

0 commit comments

Comments
 (0)