feat: add empty trash option
This commit is contained in:
3
app/assets/icons/ic-trash-sweep.svg
Normal file
3
app/assets/icons/ic-trash-sweep.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12.5001 13.3333H15.8334V14.9999H12.5001V13.3333ZM12.5001 6.66658H18.3334V8.33325H12.5001V6.66658ZM12.5001 9.99992H17.5001V11.6666H12.5001V9.99992ZM9.16675 8.33325V14.9999H4.16675V8.33325H9.16675ZM10.8334 6.66658H2.50008V14.9999C2.50008 15.4419 2.67568 15.8659 2.98824 16.1784C3.3008 16.491 3.72472 16.6666 4.16675 16.6666H9.16675C9.60878 16.6666 10.0327 16.491 10.3453 16.1784C10.6578 15.8659 10.8334 15.4419 10.8334 14.9999V6.66658ZM11.6667 4.16659H9.16675L8.33342 3.33325H5.00008L4.16675 4.16659H1.66675V5.83325H11.6667V4.16659Z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 648 B |
@@ -10,6 +10,7 @@ import ChevronRightIcon from '../../icons/ic-chevron-right.svg';
|
|||||||
import RestoreIcon from '../../icons/ic-restore.svg';
|
import RestoreIcon from '../../icons/ic-restore.svg';
|
||||||
import CloseIcon from '../../icons/ic-close.svg';
|
import CloseIcon from '../../icons/ic-close.svg';
|
||||||
import PasswordIcon from '../../icons/ic-textbox-password.svg';
|
import PasswordIcon from '../../icons/ic-textbox-password.svg';
|
||||||
|
import TrashSweepIcon from '../../icons/ic-trash-sweep.svg';
|
||||||
import { toDirective } from './utils';
|
import { toDirective } from './utils';
|
||||||
|
|
||||||
const ICONS = {
|
const ICONS = {
|
||||||
@@ -25,6 +26,7 @@ const ICONS = {
|
|||||||
'restore': RestoreIcon,
|
'restore': RestoreIcon,
|
||||||
'close': CloseIcon,
|
'close': CloseIcon,
|
||||||
'password': PasswordIcon,
|
'password': PasswordIcon,
|
||||||
|
'trash-sweep': TrashSweepIcon,
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|||||||
@@ -238,29 +238,44 @@ export const NotesOptions = observer(
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{trashed && (
|
{trashed && (
|
||||||
<button
|
<>
|
||||||
onBlur={closeOnBlur}
|
<button
|
||||||
className={`${buttonClass} py-1.5`}
|
onBlur={closeOnBlur}
|
||||||
onClick={async () => {
|
className={`${buttonClass} py-1.5`}
|
||||||
await appState.notes.setTrashSelectedNotes(false);
|
onClick={async () => {
|
||||||
}}
|
await appState.notes.setTrashSelectedNotes(false);
|
||||||
>
|
}}
|
||||||
<Icon type='restore' className={iconClass} />
|
>
|
||||||
Restore
|
<Icon type='restore' className={iconClass} />
|
||||||
</button>
|
Restore
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onBlur={closeOnBlur}
|
||||||
|
className={`${buttonClass} py-1.5`}
|
||||||
|
onClick={async () => {
|
||||||
|
await appState.notes.deleteNotesPermanently();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon type="close" className="fill-current color-danger mr-2" />
|
||||||
|
<span className="color-danger">Delete permanently</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onBlur={closeOnBlur}
|
||||||
|
className={`${buttonClass} py-1.5`}
|
||||||
|
onClick={async () => {
|
||||||
|
await appState.notes.emptyTrash();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex items-start">
|
||||||
|
<Icon type="trash-sweep" className="fill-current color-danger mr-2" />
|
||||||
|
<div className="flex-row">
|
||||||
|
<div className="color-danger">Empty Trash</div>
|
||||||
|
<div className="text-xs">{appState.notes.trashedNotesCount} notes in Trash</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
{appState.selectedTag?.isTrashTag && (
|
|
||||||
<button
|
|
||||||
onBlur={closeOnBlur}
|
|
||||||
className={`${buttonClass} py-1.5`}
|
|
||||||
onClick={async () => {
|
|
||||||
await appState.notes.deleteNotesPermanently();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon type="close" className="fill-current color-danger mr-2" />
|
|
||||||
<span className="color-danger">Delete permanently</span>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { confirmDialog } from '@/services/alertService';
|
import { confirmDialog } from '@/services/alertService';
|
||||||
import { KeyboardModifier } from '@/services/ioService';
|
import { KeyboardModifier } from '@/services/ioService';
|
||||||
import { Strings, StringUtils } from '@/strings';
|
import { StringEmptyTrash, Strings, StringUtils } from '@/strings';
|
||||||
import {
|
import {
|
||||||
UuidString,
|
UuidString,
|
||||||
SNNote,
|
SNNote,
|
||||||
@@ -40,6 +40,7 @@ export class NotesState {
|
|||||||
showProtectedWarning: observable,
|
showProtectedWarning: observable,
|
||||||
|
|
||||||
selectedNotesCount: computed,
|
selectedNotesCount: computed,
|
||||||
|
trashedNotesCount: computed,
|
||||||
|
|
||||||
deleteNotesPermanently: action,
|
deleteNotesPermanently: action,
|
||||||
selectNote: action,
|
selectNote: action,
|
||||||
@@ -55,6 +56,7 @@ export class NotesState {
|
|||||||
removeTagFromSelectedNotes: action,
|
removeTagFromSelectedNotes: action,
|
||||||
isTagInSelectedNotes: action,
|
isTagInSelectedNotes: action,
|
||||||
setShowProtectedWarning: action,
|
setShowProtectedWarning: action,
|
||||||
|
emptyTrash: action,
|
||||||
});
|
});
|
||||||
|
|
||||||
appEventListeners.push(
|
appEventListeners.push(
|
||||||
@@ -78,6 +80,10 @@ export class NotesState {
|
|||||||
return Object.keys(this.selectedNotes).length;
|
return Object.keys(this.selectedNotes).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get trashedNotesCount(): number {
|
||||||
|
return this.application.getTrashedItems().length;
|
||||||
|
}
|
||||||
|
|
||||||
async runProtectedAction(action: (note: SNNote) => void, notes: SNNote[]): Promise<void> {
|
async runProtectedAction(action: (note: SNNote) => void, notes: SNNote[]): Promise<void> {
|
||||||
let protectedNotesAccessRequest: Promise<boolean>;
|
let protectedNotesAccessRequest: Promise<boolean>;
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@@ -358,6 +364,18 @@ export class NotesState {
|
|||||||
this.showProtectedWarning = show;
|
this.showProtectedWarning = show;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async emptyTrash() {
|
||||||
|
if (
|
||||||
|
await confirmDialog({
|
||||||
|
text: StringEmptyTrash(this.trashedNotesCount),
|
||||||
|
confirmButtonStyle: 'danger',
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
this.application.emptyTrash();
|
||||||
|
this.application.sync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private get io() {
|
private get io() {
|
||||||
return this.application.io;
|
return this.application.io;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,6 +139,10 @@
|
|||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.items-start {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A button that is just an icon. Separated from .sn-button because there
|
* A button that is just an icon. Separated from .sn-button because there
|
||||||
* is almost no style overlap.
|
* is almost no style overlap.
|
||||||
|
|||||||
Reference in New Issue
Block a user