diff --git a/app/assets/icons/ic-trash-sweep.svg b/app/assets/icons/ic-trash-sweep.svg new file mode 100644 index 000000000..3d8d89824 --- /dev/null +++ b/app/assets/icons/ic-trash-sweep.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/javascripts/components/Icon.tsx b/app/assets/javascripts/components/Icon.tsx index 39e893d2b..d3628ab40 100644 --- a/app/assets/javascripts/components/Icon.tsx +++ b/app/assets/javascripts/components/Icon.tsx @@ -10,6 +10,7 @@ import ChevronRightIcon from '../../icons/ic-chevron-right.svg'; import RestoreIcon from '../../icons/ic-restore.svg'; import CloseIcon from '../../icons/ic-close.svg'; import PasswordIcon from '../../icons/ic-textbox-password.svg'; +import TrashSweepIcon from '../../icons/ic-trash-sweep.svg'; import { toDirective } from './utils'; const ICONS = { @@ -25,6 +26,7 @@ const ICONS = { 'restore': RestoreIcon, 'close': CloseIcon, 'password': PasswordIcon, +'trash-sweep': TrashSweepIcon, }; type Props = { diff --git a/app/assets/javascripts/components/NotesOptions.tsx b/app/assets/javascripts/components/NotesOptions.tsx index 4fd6d5f89..4abeb24b6 100644 --- a/app/assets/javascripts/components/NotesOptions.tsx +++ b/app/assets/javascripts/components/NotesOptions.tsx @@ -238,29 +238,44 @@ export const NotesOptions = observer( )} {trashed && ( - + <> + + + + )} - {appState.selectedTag?.isTrashTag && ( - - )} ); } diff --git a/app/assets/javascripts/ui_models/app_state/notes_state.ts b/app/assets/javascripts/ui_models/app_state/notes_state.ts index a16456489..9b5bd3e37 100644 --- a/app/assets/javascripts/ui_models/app_state/notes_state.ts +++ b/app/assets/javascripts/ui_models/app_state/notes_state.ts @@ -1,6 +1,6 @@ import { confirmDialog } from '@/services/alertService'; import { KeyboardModifier } from '@/services/ioService'; -import { Strings, StringUtils } from '@/strings'; +import { StringEmptyTrash, Strings, StringUtils } from '@/strings'; import { UuidString, SNNote, @@ -40,6 +40,7 @@ export class NotesState { showProtectedWarning: observable, selectedNotesCount: computed, + trashedNotesCount: computed, deleteNotesPermanently: action, selectNote: action, @@ -55,6 +56,7 @@ export class NotesState { removeTagFromSelectedNotes: action, isTagInSelectedNotes: action, setShowProtectedWarning: action, + emptyTrash: action, }); appEventListeners.push( @@ -78,6 +80,10 @@ export class NotesState { return Object.keys(this.selectedNotes).length; } + get trashedNotesCount(): number { + return this.application.getTrashedItems().length; + } + async runProtectedAction(action: (note: SNNote) => void, notes: SNNote[]): Promise { let protectedNotesAccessRequest: Promise; await Promise.all( @@ -358,6 +364,18 @@ export class NotesState { this.showProtectedWarning = show; } + async emptyTrash() { + if ( + await confirmDialog({ + text: StringEmptyTrash(this.trashedNotesCount), + confirmButtonStyle: 'danger', + }) + ) { + this.application.emptyTrash(); + this.application.sync(); + } + } + private get io() { return this.application.io; } diff --git a/app/assets/stylesheets/_sn.scss b/app/assets/stylesheets/_sn.scss index 307f8d650..156419e9b 100644 --- a/app/assets/stylesheets/_sn.scss +++ b/app/assets/stylesheets/_sn.scss @@ -139,6 +139,10 @@ overflow-y: scroll; } +.items-start { + align-items: flex-start; +} + /** * A button that is just an icon. Separated from .sn-button because there * is almost no style overlap.