feat: SDA-2775: Notification Position Window New UI (#1164)

* SDA-2775: notification position window new ui

- Create new user interface for notification position window
- Add unit tests

* SDA-2775: increase test coverage and format css
This commit is contained in:
Vishwas Shashidhar 2020-12-31 10:06:25 +05:30 committed by GitHub
parent 6fdb80857f
commit 8912c25003
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 562 additions and 125 deletions

View File

@ -0,0 +1,133 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Notification Settings should mount, unmount and render component should render the component 1`] = `
<div
className="content"
>
<header
className="header"
>
<span
className="header-title"
>
Set Notification Position
</span>
</header>
<div
className="form"
>
<label
className="display-label"
>
Show on display
</label>
<div
className="display-container"
id="screens"
>
<select
className="display-selector"
id="screen-selector"
onChange={[Function]}
title="position"
value={1}
/>
</div>
<label
className="position-label"
>
Position
</label>
<div
className="position-container"
>
<div
className="button-set-left"
>
<div
className="position-button-container"
>
<button
className="position-button upper-left"
id="upper-left"
name="position"
onClick={[Function]}
type="button"
value="upper-left"
>
Top Left
</button>
</div>
<div
className="position-button-container"
>
<button
className="position-button lower-left"
id="lower-left"
name="position"
onClick={[Function]}
type="button"
value="lower-left"
>
Bottom Left
</button>
</div>
</div>
<div
className="button-set-right"
>
<div
className="position-button-container"
>
<button
className="position-button position-button-selected upper-right"
id="upper-right"
name="position"
onClick={[Function]}
type="button"
value="upper-right"
>
Top Right
</button>
</div>
<div
className="position-button-container"
>
<button
className="position-button lower-right"
id="lower-right"
name="position"
onClick={[Function]}
type="button"
value="lower-right"
>
Bottom Right
</button>
</div>
</div>
</div>
</div>
<footer
className="footer"
>
<div
className="footer-button-container"
>
<button
className="footer-button footer-button-dismiss"
id="cancel"
onClick={[Function]}
>
CANCEL
</button>
<button
className="footer-button footer-button-ok"
id="ok-button"
onClick={[Function]}
>
OK
</button>
</div>
</footer>
</div>
`;

View File

@ -0,0 +1,224 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import NotificationSettings from '../src/renderer/components/notification-settings';
import { ipcRenderer } from './__mocks__/electron';
describe('Notification Settings', () => {
const notificationSettingsLabel = 'notification-settings-data';
const notificationSettingsMock = {
position: 'upper-right',
screens: [
{
id: '6713899',
},
{
id: '3512909',
},
],
display: '6713899',
};
const onLabelEvent = 'on';
const sendEvent = 'send';
const removeListenerLabelEvent = 'removeListener';
describe('should mount, unmount and render component', () => {
it('should render the component', () => {
const wrapper = shallow(React.createElement(NotificationSettings));
expect(wrapper).toMatchSnapshot();
});
it('should call `notification-settings-data` event when component is mounted', () => {
const spy = jest.spyOn(ipcRenderer, onLabelEvent);
shallow(React.createElement(NotificationSettings));
expect(spy).toBeCalledWith(notificationSettingsLabel, expect.any(Function));
});
it('should call `updateState` when component is mounted', () => {
const spy = jest.spyOn(NotificationSettings.prototype, 'setState');
shallow(React.createElement(NotificationSettings));
ipcRenderer.send('notification-settings-data', notificationSettingsMock);
expect(spy).toBeCalledWith(notificationSettingsMock);
});
it('should remove listener `notification-settings-data` when component is unmounted', () => {
const spyMount = jest.spyOn(ipcRenderer, onLabelEvent);
const spyUnmount = jest.spyOn(ipcRenderer, removeListenerLabelEvent);
const wrapper = shallow(React.createElement(NotificationSettings));
expect(spyMount).toBeCalledWith(notificationSettingsLabel, expect.any(Function));
wrapper.unmount();
expect(spyUnmount).toBeCalledWith(notificationSettingsLabel, expect.any(Function));
});
});
describe('should select display', () => {
it('should select display from drop down', () => {
const notificationSettingsMock = {
position: 'upper-right',
screens: [],
display: '6713899',
};
const spy = jest.spyOn(NotificationSettings.prototype, 'setState');
const selectDisplaySpy = jest.spyOn(NotificationSettings.prototype, 'selectDisplay');
const wrapper = shallow(React.createElement(NotificationSettings));
ipcRenderer.send('notification-settings-data', notificationSettingsMock);
const positionButton = `select.display-selector`;
const input = wrapper.find(positionButton);
input.simulate('change', { target: { value: '6713899' } });
expect(selectDisplaySpy).toBeCalled();
expect(spy).toBeCalledWith(notificationSettingsMock);
});
});
describe('should set display position', () => {
it('should select top right position', () => {
const notificationSettingsMock = {
position: 'upper-right',
screens: [],
display: '6713899',
};
const spy = jest.spyOn(NotificationSettings.prototype, 'setState');
const togglePositionButtonSpy = jest.spyOn(NotificationSettings.prototype, 'togglePosition');
const wrapper = shallow(React.createElement(NotificationSettings));
ipcRenderer.send('notification-settings-data', notificationSettingsMock);
const positionButton = `button.upper-right`;
const input = wrapper.find(positionButton);
input.simulate('click', { target: { value: 'upper-right' } });
expect(togglePositionButtonSpy).toBeCalled();
expect(spy).toBeCalledWith(notificationSettingsMock);
});
it('should select bottom right position', () => {
const notificationSettingsMock = {
position: 'bottom-right',
screens: [],
display: '6713899',
};
const spy = jest.spyOn(NotificationSettings.prototype, 'setState');
const togglePositionButtonSpy = jest.spyOn(NotificationSettings.prototype, 'togglePosition');
const wrapper = shallow(React.createElement(NotificationSettings));
ipcRenderer.send('notification-settings-data', notificationSettingsMock);
const positionButton = `button.lower-right`;
const input = wrapper.find(positionButton);
input.simulate('click', { target: { value: 'lower-right' } });
expect(togglePositionButtonSpy).toBeCalled();
expect(spy).toBeCalledWith(notificationSettingsMock);
});
it('should select top left position', () => {
const notificationSettingsMock = {
position: 'upper-left',
screens: [],
display: '6713899',
};
const spy = jest.spyOn(NotificationSettings.prototype, 'setState');
const togglePositionButtonSpy = jest.spyOn(NotificationSettings.prototype, 'togglePosition');
const wrapper = shallow(React.createElement(NotificationSettings));
ipcRenderer.send('notification-settings-data', notificationSettingsMock);
const positionButton = `button.upper-left`;
const input = wrapper.find(positionButton);
input.simulate('click', { target: { value: 'upper-left' } });
expect(togglePositionButtonSpy).toBeCalled();
expect(spy).toBeCalledWith(notificationSettingsMock);
});
it('should select bottom left position', () => {
const notificationSettingsMock = {
position: 'lower-left',
screens: [],
display: '6713899',
};
const spy = jest.spyOn(NotificationSettings.prototype, 'setState');
const togglePositionButtonSpy = jest.spyOn(NotificationSettings.prototype, 'togglePosition');
const wrapper = shallow(React.createElement(NotificationSettings));
ipcRenderer.send('notification-settings-data', notificationSettingsMock);
const positionButton = `button.lower-left`;
const input = wrapper.find(positionButton);
input.simulate('click', { target: { value: 'lower-left' } });
expect(togglePositionButtonSpy).toBeCalled();
expect(spy).toBeCalledWith(notificationSettingsMock);
});
});
describe('should submit or cancel new preferences', () => {
it('should close window on pressing cancel button', () => {
const notificationSettingsMock = {
position: 'lower-left',
screens: [],
display: '6713899',
};
const spy = jest.spyOn(ipcRenderer, sendEvent);
const closeButtonSpy = jest.spyOn(NotificationSettings.prototype, 'close');
const wrapper = shallow(React.createElement(NotificationSettings));
ipcRenderer.send('notification-settings-data', notificationSettingsMock);
const closeButton = `button.footer-button-dismiss`;
const input = wrapper.find(closeButton);
input.simulate('click');
expect(closeButtonSpy).toBeCalled();
expect(spy).toBeCalledWith('symphony-api', {
cmd: 'close-window',
windowType: 'notification-settings',
});
});
it('should submit new preferences on pressing ok button', () => {
const notificationSettingsMock = {
position: 'lower-left',
screens: [],
display: '6713899',
};
const spy = jest.spyOn(ipcRenderer, sendEvent);
const closeButtonSpy = jest.spyOn(NotificationSettings.prototype, 'close');
const wrapper = shallow(React.createElement(NotificationSettings));
ipcRenderer.send('notification-settings-data', notificationSettingsMock);
const closeButton = `button.footer-button-ok`;
const input = wrapper.find(closeButton);
input.simulate('click');
expect(closeButtonSpy).toBeCalled();
expect(spy).toBeCalledWith('notification-settings-update', {
position: 'lower-left',
display: '6713899',
});
});
});
});

View File

@ -1336,8 +1336,8 @@ export class WindowHandler {
public createNotificationSettingsWindow(windowName: string): void { public createNotificationSettingsWindow(windowName: string): void {
const opts = this.getWindowOpts( const opts = this.getWindowOpts(
{ {
width: 460, width: 540,
height: 360, height: 440,
show: false, show: false,
modal: true, modal: true,
minimizable: false, minimizable: false,

View File

@ -107,7 +107,9 @@
"Position": "Position", "Position": "Position",
"Symphony - Configure Notification Position": "Symphony - Configure Notification Position", "Symphony - Configure Notification Position": "Symphony - Configure Notification Position",
"Top Left": "Top Left", "Top Left": "Top Left",
"Top Right": "Top Right" "Top Right": "Top Right",
"Show on display": "Show on display",
"Set Notification Position": "Set Notification Position"
}, },
"Oops! Looks like we have had a crash.": "Oops! Looks like we have had a crash.", "Oops! Looks like we have had a crash.": "Oops! Looks like we have had a crash.",
"Oops! Looks like we have had a crash. Please reload or close this window.": "Oops! Looks like we have had a crash. Please reload or close this window.", "Oops! Looks like we have had a crash. Please reload or close this window.": "Oops! Looks like we have had a crash. Please reload or close this window.",

View File

@ -107,7 +107,9 @@
"Position": "Position", "Position": "Position",
"Symphony - Configure Notification Position": "Symphony - Configure Notification Position", "Symphony - Configure Notification Position": "Symphony - Configure Notification Position",
"Top Left": "Top Left", "Top Left": "Top Left",
"Top Right": "Top Right" "Top Right": "Top Right",
"Show on display": "Show on display",
"Set Notification Position": "Set Notification Position"
}, },
"Oops! Looks like we have had a crash.": "Oops! Looks like we have had a crash.", "Oops! Looks like we have had a crash.": "Oops! Looks like we have had a crash.",
"Oops! Looks like we have had a crash. Please reload or close this window.": "Oops! Looks like we have had a crash. Please reload or close this window.", "Oops! Looks like we have had a crash. Please reload or close this window.": "Oops! Looks like we have had a crash. Please reload or close this window.",

View File

@ -107,7 +107,9 @@
"Position": "Position", "Position": "Position",
"Symphony - Configure Notification Position": "Symphony - Configurer la position des notifications", "Symphony - Configure Notification Position": "Symphony - Configurer la position des notifications",
"Top Left": "Gauche supérieure", "Top Left": "Gauche supérieure",
"Top Right": "Droite supérieure" "Top Right": "Droite supérieure",
"Show on display": "Afficher sur écran",
"Set Notification Position": "Définir la position de notification"
}, },
"Oops! Looks like we have had a crash.": "Oops! On dirait que nous avons eu un crash.", "Oops! Looks like we have had a crash.": "Oops! On dirait que nous avons eu un crash.",
"Oops! Looks like we have had a crash. Please reload or close this window.": "Oops! On dirait que nous avons eu un crash. Veuillez recharger ou fermer cette fenêtre.", "Oops! Looks like we have had a crash. Please reload or close this window.": "Oops! On dirait que nous avons eu un crash. Veuillez recharger ou fermer cette fenêtre.",
@ -215,4 +217,4 @@
"Zoom": "Zoom", "Zoom": "Zoom",
"Zoom In": "Zoom Avant", "Zoom In": "Zoom Avant",
"Zoom Out": "Zoom Arrière" "Zoom Out": "Zoom Arrière"
} }

View File

@ -107,7 +107,9 @@
"Position": "Position", "Position": "Position",
"Symphony - Configure Notification Position": "Symphony - Configurer la position des notifications", "Symphony - Configure Notification Position": "Symphony - Configurer la position des notifications",
"Top Left": "Gauche supérieure", "Top Left": "Gauche supérieure",
"Top Right": "Droite supérieure" "Top Right": "Droite supérieure",
"Show on display": "Afficher sur écran",
"Set Notification Position": "Définir la position de notification"
}, },
"Oops! Looks like we have had a crash.": "Oops! On dirait que nous avons eu un crash.", "Oops! Looks like we have had a crash.": "Oops! On dirait que nous avons eu un crash.",
"Oops! Looks like we have had a crash. Please reload or close this window.": "Oops! On dirait que nous avons eu un crash. Veuillez recharger ou fermer cette fenêtre.", "Oops! Looks like we have had a crash. Please reload or close this window.": "Oops! On dirait que nous avons eu un crash. Veuillez recharger ou fermer cette fenêtre.",
@ -215,4 +217,4 @@
"Zoom": "Zoom", "Zoom": "Zoom",
"Zoom In": "Zoom Avant", "Zoom In": "Zoom Avant",
"Zoom Out": "Zoom Arrière" "Zoom Out": "Zoom Arrière"
} }

View File

@ -107,7 +107,9 @@
"Position": "位置", "Position": "位置",
"Symphony - Configure Notification Position": "Symphony - 通知位置の設定", "Symphony - Configure Notification Position": "Symphony - 通知位置の設定",
"Top Left": "左上", "Top Left": "左上",
"Top Right": "右上" "Top Right": "右上",
"Show on display": "ディスプレイに表示",
"Set Notification Position": "通知位置を設定する"
}, },
"Oops! Looks like we have had a crash.": "おっと!クラッシュしたようです。", "Oops! Looks like we have had a crash.": "おっと!クラッシュしたようです。",
"Oops! Looks like we have had a crash. Please reload or close this window.": "おっと!クラッシュしたようです。このウィンドウを再度読み込むか閉じてください。", "Oops! Looks like we have had a crash. Please reload or close this window.": "おっと!クラッシュしたようです。このウィンドウを再度読み込むか閉じてください。",
@ -215,4 +217,4 @@
"Zoom": "ズーム", "Zoom": "ズーム",
"Zoom In": "ズームイン", "Zoom In": "ズームイン",
"Zoom Out": "ズームアウト" "Zoom Out": "ズームアウト"
} }

View File

@ -107,7 +107,9 @@
"Position": "位置", "Position": "位置",
"Symphony - Configure Notification Position": "Symphony - 通知位置の設定", "Symphony - Configure Notification Position": "Symphony - 通知位置の設定",
"Top Left": "左上", "Top Left": "左上",
"Top Right": "右上" "Top Right": "右上",
"Show on display": "ディスプレイに表示",
"Set Notification Position": "通知位置を設定する"
}, },
"Oops! Looks like we have had a crash.": "おっと!クラッシュしたようです。", "Oops! Looks like we have had a crash.": "おっと!クラッシュしたようです。",
"Oops! Looks like we have had a crash. Please reload or close this window.": "おっと!クラッシュしたようです。このウィンドウを再度読み込むか閉じてください。", "Oops! Looks like we have had a crash. Please reload or close this window.": "おっと!クラッシュしたようです。このウィンドウを再度読み込むか閉じてください。",
@ -215,4 +217,4 @@
"Zoom": "ズーム", "Zoom": "ズーム",
"Zoom In": "ズームイン", "Zoom In": "ズームイン",
"Zoom Out": "ズームアウト" "Zoom Out": "ズームアウト"
} }

View File

@ -15,17 +15,10 @@ interface IState {
} }
/** /**
* Window that display app version and copyright info * Notification Window component
*/ */
export default class NotificationSettings extends React.Component<{}, IState> { export default class NotificationSettings extends React.Component<{}, IState> {
private readonly eventHandlers = {
onTogglePosition: (e: React.ChangeEvent<HTMLInputElement>) => this.togglePosition(e),
onDisplaySelect: (e: React.ChangeEvent<HTMLSelectElement>) => this.selectDisplay(e),
onClose: () => this.close(),
onSubmit: () => this.submit(),
};
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
@ -37,128 +30,98 @@ export default class NotificationSettings extends React.Component<{}, IState> {
} }
/** /**
* main render function * Renders the notification settings window
*/ */
public render(): JSX.Element { public render(): JSX.Element {
return ( return (
<div className='content'> <div className='content'>
<header className='header'> <header className='header'>
<span className='header__title'> <span className='header-title'>
{i18n.t('Notification Settings', NOTIFICATION_SETTINGS_NAMESPACE)()} {i18n.t('Set Notification Position', NOTIFICATION_SETTINGS_NAMESPACE)()}
</span> </span>
</header> </header>
<div className='form'> <div className='form'>
<form> <label className='display-label'>{i18n.t('Show on display', NOTIFICATION_SETTINGS_NAMESPACE)()}</label>
<label className='label'>{i18n.t('Monitor', NOTIFICATION_SETTINGS_NAMESPACE)()}</label> <div id='screens' className='display-container'>
<div id='screens' className='main'> <select
<label> className='display-selector'
{i18n.t('Notification shown on Monitor: ', NOTIFICATION_SETTINGS_NAMESPACE)()} id='screen-selector'
</label> title='position'
<select value={this.state.display}
className='selector' onChange={this.selectDisplay.bind(this)}
id='screen-selector' >
title='position' {this.renderScreens()}
value={this.state.display} </select>
onChange={this.eventHandlers.onDisplaySelect} </div>
>
{this.renderScreens()} <label className='position-label'>{i18n.t('Position', NOTIFICATION_SETTINGS_NAMESPACE)()}</label>
</select> <div className='position-container'>
<div className='button-set-left'>
{this.renderPositionButton('upper-left', 'Top Left')}
{this.renderPositionButton('lower-left', 'Bottom Left')}
</div> </div>
<label className='label'>{i18n.t('Position', NOTIFICATION_SETTINGS_NAMESPACE)()}</label> <div className='button-set-right'>
<div className='main'> {this.renderPositionButton('upper-right', 'Top Right')}
<div className='first-set'> {this.renderPositionButton('lower-right', 'Bottom Right')}
{this.renderRadioButtons('upper-left', 'Top Left')}
{this.renderRadioButtons('lower-left', 'Bottom Left')}
</div>
<div className='second-set'>
{this.renderRadioButtons('upper-right', 'Top Right')}
{this.renderRadioButtons('lower-right', 'Bottom Right')}
</div>
</div> </div>
</form> </div>
</div> </div>
<footer className='footer'> <footer className='footer'>
<div className='buttonLayout'> <div className='footer-button-container'>
<button id='cancel' className='buttonDismiss' onClick={this.eventHandlers.onClose}> <button id='cancel' className='footer-button footer-button-dismiss' onClick={this.close.bind(this)}>
{i18n.t('CANCEL', NOTIFICATION_SETTINGS_NAMESPACE)()} {i18n.t('CANCEL', NOTIFICATION_SETTINGS_NAMESPACE)()}
</button> </button>
<button id='ok-button' className='button' onClick={this.eventHandlers.onSubmit}> <button id='ok-button' className='footer-button footer-button-ok' onClick={this.submit.bind(this)}>
{i18n.t('OK', NOTIFICATION_SETTINGS_NAMESPACE)()} {i18n.t('OK', NOTIFICATION_SETTINGS_NAMESPACE)()}
</button> </button>
</div> </div>
</footer> </footer>
</div> </div>
); );
} }
/**
* Handles event when the component is mounted
*/
public componentDidMount(): void { public componentDidMount(): void {
ipcRenderer.on('notification-settings-data', this.updateState); ipcRenderer.on('notification-settings-data', this.updateState);
} }
/**
* Handles event when the component is unmounted
*/
public componentWillUnmount(): void { public componentWillUnmount(): void {
ipcRenderer.removeListener('notification-settings-data', this.updateState); ipcRenderer.removeListener('notification-settings-data', this.updateState);
} }
/**
* Renders all 4 different notification position options
*
* @param id
* @param content
*/
private renderRadioButtons(id: startCorner, content: string): JSX.Element {
return (
<div className='radio'>
<label className='radio__label' htmlFor={id}>
{i18n.t(`${content}`, NOTIFICATION_SETTINGS_NAMESPACE)()}
</label>
<input
onChange={this.eventHandlers.onTogglePosition}
className={id}
id={id}
type='radio'
name='position'
checked={this.state.position === id}
value={id} />
</div>
);
}
/**
* Renders the drop down list of available screen
*/
private renderScreens(): JSX.Element[] {
const { screens } = this.state;
return screens.map((screen, index) => {
return (
<option id={String(screen.id)} key={screen.id} value={screen.id}>{index + 1}</option>
);
});
}
/** /**
* Updates the selected display state * Updates the selected display state
* *
* @param event * @param event
*/ */
private selectDisplay(event): void { public selectDisplay(event): void {
this.setState({ display: event.target.value }); this.setState({ display: event.target.value });
} }
/** /**
* Updated the selected notification position * Updates the selected notification position
* *
* @param event * @param event
*/ */
private togglePosition(event): void { public togglePosition(event): void {
this.setState({ this.setState({
position: event.currentTarget.value, position: event.target.id,
}); });
} }
/** /**
* Sends the user selected notification settings options * Submits the new settings to the main process
*/ */
private submit(): void { public submit(): void {
const { position, display } = this.state; const { position, display } = this.state;
ipcRenderer.send('notification-settings-update', { position, display }); ipcRenderer.send('notification-settings-update', { position, display });
} }
@ -166,13 +129,49 @@ export default class NotificationSettings extends React.Component<{}, IState> {
/** /**
* Closes the notification settings window * Closes the notification settings window
*/ */
private close(): void { public close(): void {
ipcRenderer.send(apiName.symphonyApi, { ipcRenderer.send(apiName.symphonyApi, {
cmd: apiCmds.closeWindow, cmd: apiCmds.closeWindow,
windowType: 'notification-settings', windowType: 'notification-settings',
}); });
} }
/**
* Renders the position buttons
*
* @param id
* @param content
*/
private renderPositionButton(id: startCorner, content: string): JSX.Element {
const style = this.state.position === id ? `position-button position-button-selected ${id}` : `position-button ${id}`;
return (
<div className='position-button-container'>
<button
onClick={this.togglePosition.bind(this)}
className={style}
id={id} type='button'
name='position'
value={id}
>
{i18n.t(`${content}`, NOTIFICATION_SETTINGS_NAMESPACE)()}
</button>
</div>
);
}
/**
* Renders the drop down list of available screens
*/
private renderScreens(): JSX.Element[] {
const { screens } = this.state;
return screens.map((screen, index) => {
const screenId = screen.id;
return (
<option id={String(screenId)} key={screenId} value={screenId}>{index + 1}/{screens.length}</option>
);
});
}
/** /**
* Sets the component state * Sets the component state
* *

View File

@ -30,8 +30,8 @@ body {
padding: 16px; padding: 16px;
} }
.header__title { .header-title {
font-weight: 500; font-weight: 300;
font-style: normal; font-style: normal;
margin: 0 0 0 4px; margin: 0 0 0 4px;
font-size: 1.4rem; font-size: 1.4rem;
@ -49,51 +49,104 @@ body {
margin: 0 auto; margin: 0 auto;
} }
.selector { .display-label {
padding: 0 9px 0 16px; width: 304px;
cursor: pointer; height: 16px;
margin-left: 10px;
font-size: 12px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: #525760;
} }
.main { .display-container {
margin-bottom: 20px;
margin-top: 5px;
}
.display-selector {
padding: 0 20px 0 30px;
cursor: pointer;
width: 304px;
height: 32px;
border: 2px solid #7C7F86;
border-radius: 2px;
background-color: #FFFFFF;
}
.position-label {
font-size: 12px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
width: 304px;
height: 16px;
color: #525760;
}
.position-container {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
margin-bottom: 20px;
height: 100%;
border: 1px solid #ccc !important;
padding: 10px;
.first-set { width: 304px;
height: 100%;
left: 8px;
top: 102px;
border-radius: 4px;
margin-bottom: 20px;
margin-top: 5px;
background: #F8F8F9;
.button-set-left {
flex-grow: 1; flex-grow: 1;
} }
.second-set { .button-set-right {
flex-grow: 1; flex-grow: 1;
text-align: right; text-align: right;
} }
} }
.radio { .position-button-container {
line-height: 1.7; line-height: 1.7;
.upper-right, .lower-right { .position-button {
float: right; width: 116px;
margin-top: 6px; height: 32px;
top: 1px;
margin: 20px 20px 20px 20px;
border: 2px solid #7C7F86;
border-radius: 4px;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 14px;
line-height: 20px;
align-items: center;
color: #17181B;
} }
.upper-left, .lower-left { .position-button-selected {
background-color: #008EFF;
}
.upper-left,
.lower-left {
float: left; float: left;
margin-top: 6px;
} }
}
.radio__label { .upper-right,
cursor: pointer; .lower-right {
padding: 5px; float: right;
input {
cursor: pointer;
} }
} }
.footer { .footer {
@ -103,12 +156,28 @@ body {
align-items: center; align-items: center;
} }
.buttonLayout { .footer-button-container {
margin-left: auto; margin-left: auto;
display: flex; display: flex;
align-items: center; align-items: center;
}
.buttonDismiss { .footer-button {
margin-right: 10px; border: 2px solid #7C7F86;
border-radius: 4px;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 14px;
line-height: 20px;
align-items: center;
}
.footer-button-ok {
margin-right: 5px;
}
.footer-button-dismiss {
margin-right: 10px;
}
} }