diff --git a/ElectronClient/app.js b/ElectronClient/app.js index 066e0d676..7985cb875 100644 --- a/ElectronClient/app.js +++ b/ElectronClient/app.js @@ -622,7 +622,7 @@ class Application extends BaseApplication { // the following menu items will be available for all OS under Tools const toolsItemsAll = [{ - label: _('Resources'), + label: _('Note attachments...'), click: () => { this.dispatch({ type: 'NAV_GO', diff --git a/ElectronClient/gui/Header.jsx b/ElectronClient/gui/Header.jsx index 6787d3896..402ed38f6 100644 --- a/ElectronClient/gui/Header.jsx +++ b/ElectronClient/gui/Header.jsx @@ -267,6 +267,7 @@ class HeaderComponent extends React.Component { boxSizing: 'border-box', cursor: 'default', whiteSpace: 'nowrap', + userSelect: 'none', }; if (showBackButton) { diff --git a/ElectronClient/gui/ResourceScreen.tsx b/ElectronClient/gui/ResourceScreen.tsx index c6944b329..0cc046a5d 100644 --- a/ElectronClient/gui/ResourceScreen.tsx +++ b/ElectronClient/gui/ResourceScreen.tsx @@ -8,9 +8,14 @@ const { Header } = require('./Header.min.js'); const prettyBytes = require('pretty-bytes'); const Resource = require('lib/models/Resource.js'); +interface Style { + width: number + height: number +} + interface Props { - style: any; theme: any; + style: Style } interface Resource { @@ -32,6 +37,8 @@ interface ResourceTable { onResourceClick: (resource: Resource) => any onResourceDelete: (resource: Resource) => any onToggleSorting: (order: SortingOrder) => any + theme: any + style: Style } type SortingOrder = 'size' | 'name' @@ -45,29 +52,58 @@ interface ActiveSorting { const ResourceTable: React.FC = (props: ResourceTable) => { const sortOrderEngagedMarker = (s: SortingOrder) => { return ( - props.onToggleSorting(s) }>{ - (props.sorting.order === s && props.sorting.type === 'desc') ? '▾' : '▴' } + props.onToggleSorting(s)}>{ + (props.sorting.order === s && props.sorting.type === 'desc') ? '▾' : '▴'} ); }; - return + + const titleCellStyle = { + ...props.theme.textStyle, + textOverflow: 'ellipsis', + overflowX: 'hidden', + maxWidth: 1, + width: '100%', + whiteSpace: 'nowrap', + }; + + const cellStyle = { + ...props.theme.textStyleMinor, + whiteSpace: 'nowrap', + width: 1, + }; + + const headerStyle = { + ...props.theme.textStyle, + whiteSpace: 'nowrap', + width: 1, + fontWeight: 'bold', + }; + + return
- - - - + + + + {props.resources.map((resource: Resource, index: number) => - - - - + + )} @@ -123,6 +159,13 @@ class ResourceScreenComponent extends React.Component { } onResourceDelete(resource: Resource) { + const ok = bridge().showConfirmMessageBox(_('Delete attachment "%s"?', resource.title), { + buttons: [_('Delete'), _('Cancel')], + defaultId: 1, + }); + if (!ok) { + return; + } Resource.delete(resource.id) .catch((error: Error) => { bridge().showErrorMessageBox(error.message); @@ -158,9 +201,23 @@ class ResourceScreenComponent extends React.Component { const style = this.props.style; const theme = themeStyle(this.props.theme); const headerStyle = Object.assign({}, theme.headerStyle, { width: style.width }); - return
+ + const rootStyle = { + ...style, + overflowY: 'scroll', + color: theme.color, + padding: 20, + boxSizing: 'border-box', + }; + rootStyle.height = style.height - 35; // Minus the header height + delete rootStyle.width; + + return
-
+
+
{ + _('This is an advanced tool to show the attachments that are linked to your notes. Please be careful when deleting one of them as they cannot be restored afterwards.') + }
{this.state.isLoading &&
{_('Please wait...')}
} {!this.state.isLoading &&
{!this.state.resources &&
@@ -171,11 +228,13 @@ class ResourceScreenComponent extends React.Component {
{_('Warning: not all resources shown for performance reasons (limit: %s).', MAX_RESOURCES)}
} {this.state.resources && this.onToggleSortOrder(order) } - onResourceClick={ (resource) => this.openResource(resource) } - onResourceDelete={ (resource) => this.onResourceDelete(resource) } + theme={theme} + style={style} + resources={this.state.resources} + sorting={this.state.sorting} + onToggleSorting={(order) => this.onToggleSortOrder(order)} + onResourceClick={(resource) => this.openResource(resource)} + onResourceDelete={(resource) => this.onResourceDelete(resource)} />}
} diff --git a/ElectronClient/gui/Root.jsx b/ElectronClient/gui/Root.jsx index 9fced80f1..03fe29754 100644 --- a/ElectronClient/gui/Root.jsx +++ b/ElectronClient/gui/Root.jsx @@ -92,7 +92,7 @@ class RootComponent extends React.Component { DropboxLogin: { screen: DropboxLoginScreen, title: () => _('Dropbox Login') }, Import: { screen: ImportScreen, title: () => _('Import') }, Config: { screen: ConfigScreen, title: () => _('Options') }, - Resources: { screen: ResourceScreen, title: () => _('Resources') }, + Resources: { screen: ResourceScreen, title: () => _('Note attachments') }, Status: { screen: StatusScreen, title: () => _('Synchronisation Status') }, }; diff --git a/ElectronClient/gui/SideBar.jsx b/ElectronClient/gui/SideBar.jsx index ab00bd3cc..8199d6eb8 100644 --- a/ElectronClient/gui/SideBar.jsx +++ b/ElectronClient/gui/SideBar.jsx @@ -131,6 +131,7 @@ class SideBarComponent extends React.Component { display: 'flex', flex: 1, alignItems: 'center', + userSelect: 'none', }, listItemSelected: { backgroundColor: theme.selectedColor2, @@ -160,6 +161,7 @@ class SideBarComponent extends React.Component { paddingLeft: 8, display: 'flex', alignItems: 'center', + userSelect: 'none', }, button: { padding: 6, @@ -176,6 +178,7 @@ class SideBarComponent extends React.Component { marginLeft: 5, marginRight: 5, cursor: 'default', + userSelect: 'none', }, syncReport: { fontFamily: theme.fontFamily, @@ -195,6 +198,7 @@ class SideBarComponent extends React.Component { noteCount: { paddingLeft: 5, opacity: 0.5, + userSelect: 'none', }, }; diff --git a/ElectronClient/gui/style/ConfigMenuBar.js b/ElectronClient/gui/style/ConfigMenuBar.js index 543b99f5d..077b00321 100644 --- a/ElectronClient/gui/style/ConfigMenuBar.js +++ b/ElectronClient/gui/style/ConfigMenuBar.js @@ -16,6 +16,7 @@ const style = createSelector( alignItems: 'center', padding: 9, backgroundColor: theme.backgroundColor, + userSelect: 'none', }, buttonIcon: { fontSize: 24, diff --git a/ElectronClient/gui/style/theme/dark.js b/ElectronClient/gui/style/theme/dark.js index 5c8c721c9..837a4ee54 100644 --- a/ElectronClient/gui/style/theme/dark.js +++ b/ElectronClient/gui/style/theme/dark.js @@ -5,7 +5,7 @@ const darkStyle = { color: '#dddddd', colorError: 'red', colorWarn: '#9A5B00', - colorFaded: '#777777', // For less important text + colorFaded: '#999999', // For less important text colorBright: '#ffffff', // For important text dividerColor: '#555555', selectedColor: '#333333', diff --git a/ElectronClient/theme.js b/ElectronClient/theme.js index 6abd17267..9198361d1 100644 --- a/ElectronClient/theme.js +++ b/ElectronClient/theme.js @@ -201,6 +201,14 @@ function addExtraStyles(style) { marginRight: 6, }; + style.notificationBox = { + backgroundColor: style.warningBackgroundColor, + display: 'flex', + alignItems: 'center', + padding: 10, + fontSize: style.fontSize, + }; + style.dialogTitle = Object.assign({}, style.h1Style, { marginBottom: '1.2em' }); style.dropdownList = Object.assign({}, style.inputStyle); @@ -299,6 +307,7 @@ function themeStyle(theme) { color: output.color, backgroundColor: output.backgroundColor, borderColor: output.dividerColor, + userSelect: 'none', } );
{_('Title')} { sortOrderEngagedMarker('name') }{_('Size')} { sortOrderEngagedMarker('size') }{_('ID')}{_('Action')}{_('Title')} {sortOrderEngagedMarker('name')}{_('Size')} {sortOrderEngagedMarker('size')}{_('ID')}{_('Action')}
- props.onResourceClick(resource)}>{resource.title} + + props.onResourceClick(resource)}>{resource.title || `(${_('Untitled')})`} + {prettyBytes(resource.size)}{resource.id} - + {prettyBytes(resource.size)}{resource.id} +