Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: change workspace names to icons #1240

Closed
wants to merge 9 commits into from
17 changes: 16 additions & 1 deletion src/components/layout/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,21 @@ const styles = (theme: { workspaces: { drawer: { width: any } } }) => ({
// width: `calc(100% + ${theme.workspaces.drawer.width}px)`,
width: '100%',
transition,
},
appContentTransformTextWorkspace: {
transform() {
return workspaceStore.isWorkspaceDrawerOpen
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to move the ternary to be evaluated inside the translateX() like so?

return 'translateX(`workspaceStore.isWorkspaceDrawerOpen ? 0 : -75px`)');

(Syntax might be incorrect since I'm not typing inside an editor)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, we can do that

? 'translateX(0)'
: `translateX(-${theme.workspaces.drawer.width}px)`;
},
},
appContentTransformIconWorkspace: {
transform() {
return workspaceStore.isWorkspaceDrawerOpen
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that it is more readable.
If it's ok for you, I can push that change

  appContentTransformTextWorkspace: {
    transform() {
      return `translateX(${
        workspaceStore.isWorkspaceDrawerOpen
          ? '0'
          : `-${theme.workspaces.drawer.width}px`
      })`;
    },
  },
  appContentTransformIconWorkspace: {
    transform() {
      return `translateX(${
        workspaceStore.isWorkspaceDrawerOpen ? '0' : `-75px`
      })`;
    },
  },

? 'translateX(0)'
: 'translateX(-75px)';
},
},
titleBar: {
display: 'block',
zIndex: 1,
Expand Down Expand Up @@ -149,7 +158,13 @@ class AppLayout extends Component<PropsWithChildren<IProps>, IState> {
className={classes.titleBar}
/>
)}
<div className={`app__content ${classes.appContent}`}>
<div
className={`app__content ${classes.appContent} ${
settings.all.app.useWorkspaceDrawerIconStyle
? classes.appContentTransformIconWorkspace
: classes.appContentTransformTextWorkspace
}`}
>
{workspacesDrawer}
{sidebar}
<div className="app__service">
Expand Down
2 changes: 2 additions & 0 deletions src/components/settings/settings/EditSettingsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,8 @@ class EditSettingsForm extends Component<IProps, IState> {
<Toggle {...form.$('hideDownloadButton').bind()} />

<Toggle {...form.$('alwaysShowWorkspaces').bind()} />

<Toggle {...form.$('useWorkspaceDrawerIconStyle').bind()} />
</div>
)}

Expand Down
71 changes: 71 additions & 0 deletions src/components/ui/WorkspaceIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Component, ReactNode } from 'react';
import { observer } from 'mobx-react';
import withStyles, { WithStylesProps } from 'react-jss';
import classnames from 'classnames';
import { mdiInfinity } from '@mdi/js';
import Icon from './icon';

const styles = theme => ({
root: {
height: `${theme.serviceIcon.width}px`,
width: `${theme.serviceIcon.width}px`,
textAlign: 'center',
display: 'table-cell',
verticalAlign: 'middle',
},
icon: {
height: 'auto',
width: `${theme.serviceIcon.width}px`,
maxHeight: `${theme.serviceIcon.width}px`,
},
iconLetterContainer: {
border: `1px solid ${theme.colorText}`,
borderRadius: '20%',
},
iconLetter: {
fontSize: 'x-large',
fontWeight: '500',
},
});

interface IProps extends WithStylesProps<typeof styles> {
className?: string;
name: string | null;
iconUrl: string;
}

@observer
class WorkspaceIcon extends Component<IProps> {
render(): ReactNode {
const { classes, className, name, iconUrl } = this.props;
if (iconUrl === 'allServices') {
return (
<div className={classnames([classes.root, className])}>
<Icon icon={mdiInfinity} size={1.5} />
</div>
);
}
if (iconUrl) {
return (
<div className={classnames([classes.root, className])}>
<img src={iconUrl} className={classes.icon} alt={name || undefined} />{' '}
</div>
);
}
return (
<div
className={classnames([
classes.root,
classes.iconLetterContainer,
className,
])}
>
<span className={classes.iconLetter}>
{(name || ' ').slice(0, 1).toLocaleUpperCase()}
</span>
</div>
);
}
}

export default withStyles(styles, { injectTheme: true })(WorkspaceIcon);
1 change: 1 addition & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@ export const DEFAULT_APP_SETTINGS = {
hideSettingsButton: false,
hideDownloadButton: false,
alwaysShowWorkspaces: false,
useWorkspaceDrawerIconStyle: true,
liftSingleInstanceLock: false,
enableLongPressServiceHint: false,
isTodosFeatureEnabled: true,
Expand Down
1 change: 1 addition & 0 deletions src/containers/layout/AppLayoutContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class AppLayoutContainer extends Component<IProps> {
? workspaceStore.getWorkspaceServices(workspace).map(s => s.name)
: services.all.map(s => s.name)
}
useIconDisplayStyle={settings.all.app.useWorkspaceDrawerIconStyle}
/>
);

Expand Down
16 changes: 16 additions & 0 deletions src/containers/settings/EditSettingsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,10 @@ const messages = defineMessages({
id: 'settings.app.form.alwaysShowWorkspaces',
defaultMessage: 'Always show workspace drawer',
},
useWorkspaceDrawerIconStyle: {
id: 'settings.app.form.useWorkspaceDrawerIconStyle',
defaultMessage: 'Use workspace drawer icon style',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I was suggesting to have the user choose whether they want the name or the first character of the workspace name AND/OR the icon. Could the feature be imagined like that?

Copy link
Author

@orgrimarr orgrimarr Jun 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly.

The letter is currently a fallback for workspaces that don't have an icon.

The setting should be a select with theses choices :

  • text (current display)
  • (letter OR icon) AND text
  • letter AND icon (if icon configured)
  • letter OR icon (current PR)

It means, 3 different workspace drawer sizes

  • the current (300px by default)
  • icon OR letter only (35 - 75px)
  • letter + icon (let's say 75 - 150px)

Copy link
Author

@orgrimarr orgrimarr Jun 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the workspace drawer bar be the same size of the service bar ?
I means use the serviceRibbonWidth parameter for both workspace and service bar (only when displaying icon)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vraravam Can you confirm that I have understood correctly ?
If yes, I will start the dev this week   😀

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't need to complicate so much. only 2 options that i was suggesting:

  1. workspace name (current)
  2. icon or first character of workspace name (if the user wants to use a smaller-width option for the workspace drawer)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To permanently save this field you would probably need to sync with the server (internal and external) if I'm correct.

I'm not recalling if the server is saving workspace data as a plain JSON or not (only by checking the endpoint we can be sure of that). If that is not the case, you would need to touch both the server and the internal-server... but with the ongoing Adonis update this could be a hassle :/ I can help on that tho.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, can we make this option the default one? I like this new look (even though I'm not using workspaces).

Great work!!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, you will need to sync to the internal and external servers. The db schema is the same across both - and there's a table called workspaces to store this info.
Screenshot 2023-09-05 at 8 18 24 AM

As seen in the above pic (taken from my internal server), you can either add a new column for the useIcon or you can add it into the data column which holds JSONB datatype. (I personally prefer option 1.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, you will need to sync to the internal and external servers. The db schema is the same across both - and there's a table called workspaces to store this info. Screenshot 2023-09-05 at 8 18 24 AM

As seen in the above pic (taken from my internal server), you can either add a new column for the useIcon or you can add it into the data column which holds JSONB datatype. (I personally prefer option 1.

Even though I would prefer option 1 (just like you) I would advise into adding it to "data" column (but first lets be sure what type of data is being retrieved there) so that it doesn't make the migration to the new Adonis's even more complicated (as we would to update both the code in the current ferdium-server, internal server and on the current adonis update PR)

Copy link
Author

@orgrimarr orgrimarr Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As suggested, i added the iconUrl field in data

WIP related PR on the server : ferdium/ferdium-server#102

},
accentColor: {
id: 'settings.app.form.accentColor',
defaultMessage: 'Accent color',
Expand Down Expand Up @@ -435,6 +439,9 @@ class EditSettingsScreen extends Component<
hideSettingsButton: Boolean(settingsData.hideSettingsButton),
hideDownloadButton: Boolean(settingsData.hideDownloadButton),
alwaysShowWorkspaces: Boolean(settingsData.alwaysShowWorkspaces),
useWorkspaceDrawerIconStyle: Boolean(
settingsData.useWorkspaceDrawerIconStyle,
),
accentColor: settingsData.accentColor,
progressbarAccentColor: settingsData.progressbarAccentColor,
showMessageBadgeWhenMuted: Boolean(
Expand Down Expand Up @@ -1120,6 +1127,15 @@ class EditSettingsScreen extends Component<
default: DEFAULT_APP_SETTINGS.alwaysShowWorkspaces,
type: 'checkbox',
},
useWorkspaceDrawerIconStyle: {
label: intl.formatMessage(messages.useWorkspaceDrawerIconStyle),
value: ifUndefined<boolean>(
settings.all.app.useWorkspaceDrawerIconStyle,
DEFAULT_APP_SETTINGS.useWorkspaceDrawerIconStyle,
),
default: DEFAULT_APP_SETTINGS.useWorkspaceDrawerIconStyle,
type: 'checkbox',
},
accentColor: {
label: intl.formatMessage(messages.accentColor),
value: ifUndefined<string>(
Expand Down
18 changes: 14 additions & 4 deletions src/features/appearance/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,11 @@ function generateShowDragAreaStyle(accentColor) {
`;
}

function generateVerticalStyle(widthStr, alwaysShowWorkspaces) {
function generateVerticalStyle(
widthStr,
alwaysShowWorkspaces,
useWorkspaceDrawerIconStyle,
) {
if (!document.querySelector('#vertical-style')) {
const link = document.createElement('link');
link.id = 'vertical-style';
Expand All @@ -343,13 +347,14 @@ function generateVerticalStyle(widthStr, alwaysShowWorkspaces) {
const width = Number(widthStr);
const sidebarWidth = width - 4;
const verticalStyleOffset = 29;
const drawerWidth = useWorkspaceDrawerIconStyle ? '75px' : '300px';

return `
.sidebar {
${
alwaysShowWorkspaces
alwaysShowWorkspaces || useWorkspaceDrawerIconStyle
? `
width: calc(100% - 300px) !important;
width: calc(100% - ${drawerWidth}) !important;
`
: ''
}
Expand Down Expand Up @@ -395,6 +400,7 @@ function generateStyle(settings, app) {
useHorizontalStyle,
alwaysShowWorkspaces,
showServiceName,
useWorkspaceDrawerIconStyle,
} = settings;

const { isFullScreen } = app;
Expand Down Expand Up @@ -423,7 +429,11 @@ function generateStyle(settings, app) {
style += generateShowDragAreaStyle(accentColor);
}
if (useHorizontalStyle) {
style += generateVerticalStyle(serviceRibbonWidth, alwaysShowWorkspaces);
style += generateVerticalStyle(
serviceRibbonWidth,
alwaysShowWorkspaces,
useWorkspaceDrawerIconStyle,
);
} else if (document.querySelector('#vertical-style')) {
const link = document.querySelector('#vertical-style');
if (link) {
Expand Down
2 changes: 1 addition & 1 deletion src/features/workspaces/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const workspaceApi = {
const url = `${apiBase()}/workspace/${workspace.id}`;
const options = {
method: 'PUT',
body: JSON.stringify(pick(workspace, ['name', 'services'])),
body: JSON.stringify(pick(workspace, ['name', 'services', 'iconUrl'])),
};
debug('updateWorkspace UPDATE', url, options);
const result = await sendAuthRequest(url, options);
Expand Down
11 changes: 11 additions & 0 deletions src/features/workspaces/components/EditWorkspaceForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ const messages = defineMessages({
id: 'settings.workspace.form.name',
defaultMessage: 'Name',
},
iconUrl: {
id: 'settings.workspace.form.iconUrl',
defaultMessage: 'Workspace icon url',
},
yourWorkspaces: {
id: 'settings.workspace.form.yourWorkspaces',
defaultMessage: 'Your workspaces',
Expand Down Expand Up @@ -107,6 +111,12 @@ class EditWorkspaceForm extends Component<IProps> {
value: workspace.name,
validators: [required],
},
iconUrl: {
label: intl.formatMessage(messages.iconUrl),
placeholder: intl.formatMessage(messages.iconUrl),
value: workspace.iconUrl || '',
validators: [],
},
keepLoaded: {
label: intl.formatMessage(messages.keepLoaded),
value: workspace.services.includes(KEEP_WS_LOADED_USID),
Expand Down Expand Up @@ -181,6 +191,7 @@ class EditWorkspaceForm extends Component<IProps> {
)}
<div className={classes.nameInput}>
<Input {...form.$('name').bind()} />
<Input {...form.$('iconUrl').bind()} />
<Toggle {...form.$('keepLoaded').bind()} />
<p className={`${classes.keepLoadedInfo} franz-form__label`}>
{intl.formatMessage(messages.keepLoadedInfo)}
Expand Down
63 changes: 53 additions & 10 deletions src/features/workspaces/components/WorkspaceDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,25 @@ const messages = defineMessages({
const styles = theme => ({
drawer: {
background: theme.workspaces.drawer.background,
width: `${theme.workspaces.drawer.width}px`,
display: 'flex',
flexDirection: 'column',
},
drawerWithText: {
width: `${theme.workspaces.drawer.width}px`,
},
drawerWithIcon: {
width: '75px',
},
headline: {
fontSize: '24px',
marginTop: '38px',
marginBottom: '25px',
marginLeft: theme.workspaces.drawer.padding,
},
headlineWithicon: {
marginLeft: '0',
color: theme.workspaces.drawer.buttons.color,
},
workspacesSettingsButton: {
float: 'right',
marginRight: theme.workspaces.drawer.padding,
Expand Down Expand Up @@ -90,6 +99,7 @@ const styles = theme => ({

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

@observer
Expand All @@ -104,19 +114,24 @@ class WorkspaceDrawer extends Component<IProps> {
}

render(): ReactElement {
const { classes, getServicesForWorkspace } = this.props;
const { classes, getServicesForWorkspace, useIconDisplayStyle } =
this.props;
const { intl } = this.props;
const { activeWorkspace, isSwitchingWorkspace, nextWorkspace, workspaces } =
workspaceStore;
const actualWorkspace = isSwitchingWorkspace
? nextWorkspace
: activeWorkspace;

const drawerWithClass = useIconDisplayStyle
? classes.drawerWithIcon
: classes.drawerWithText;
return (
<div className={`${classes.drawer} workspaces-drawer`}>
<H1 className={classes.headline}>
{intl.formatMessage(messages.headline)}
<span
className={classes.workspacesSettingsButton}
<div className={`${classes.drawer} ${drawerWithClass} workspaces-drawer`}>
{useIconDisplayStyle ? (
<button
type="button"
className={`${classes.headline} ${classes.headlineWithicon}`}
onKeyDown={noop}
onClick={() => {
workspaceActions.openWorkspaceSettings();
Expand All @@ -131,11 +146,34 @@ class WorkspaceDrawer extends Component<IProps> {
size={1.5}
className={classes.workspacesSettingsButtonIcon}
/>
</span>
</H1>
</button>
) : (
<H1 className={classes.headline}>
{intl.formatMessage(messages.headline)}
<span
className={classes.workspacesSettingsButton}
onKeyDown={noop}
onClick={() => {
workspaceActions.openWorkspaceSettings();
}}
data-tip={`${intl.formatMessage(
messages.workspacesSettingsTooltip,
)}`}
>
<Icon
icon={mdiCog}
size={1.5}
className={classes.workspacesSettingsButtonIcon}
/>
</span>
</H1>
)}

<div className={classes.workspaces}>
<WorkspaceDrawerItem
name={intl.formatMessage(messages.allServices)}
iconUrl="allServices"
useIconDisplayStyle={useIconDisplayStyle}
onClick={() => {
workspaceActions.deactivate();
workspaceActions.toggleWorkspaceDrawer();
Expand All @@ -148,6 +186,8 @@ class WorkspaceDrawer extends Component<IProps> {
<WorkspaceDrawerItem
key={workspace.id}
name={workspace.name}
iconUrl={workspace.iconUrl}
useIconDisplayStyle={useIconDisplayStyle}
isActive={actualWorkspace === workspace}
onClick={() => {
if (actualWorkspace === workspace) {
Expand All @@ -172,9 +212,12 @@ class WorkspaceDrawer extends Component<IProps> {
>
<Icon
icon={mdiPlusBox}
size={useIconDisplayStyle ? 1.5 : 1}
className={classes.workspacesSettingsButtonIcon}
/>
<span>{intl.formatMessage(messages.addNewWorkspaceLabel)}</span>
{useIconDisplayStyle !== true && (
<span>{intl.formatMessage(messages.addNewWorkspaceLabel)}</span>
)}{' '}
</div>
</div>
<ReactTooltip
Expand Down
Loading