feat: toggle move to trash to delete permanently on alt key down
This commit is contained in:
@@ -213,7 +213,7 @@ DEPENDENCIES
|
||||
dotenv-rails
|
||||
haml
|
||||
lograge (~> 0.11.2)
|
||||
newrelic_rpm
|
||||
newrelic_rpm (~> 7.0)
|
||||
non-stupid-digest-assets
|
||||
puma
|
||||
rack-cors
|
||||
|
||||
@@ -3,12 +3,14 @@ import { toDirective, useCloseOnBlur, useCloseOnClickOutside } from './utils';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { NotesOptions } from './NotesOptions';
|
||||
import { useCallback, useEffect, useRef } from 'preact/hooks';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
|
||||
type Props = {
|
||||
application: WebApplication;
|
||||
appState: AppState;
|
||||
};
|
||||
|
||||
const NotesContextMenu = observer(({ appState }: Props) => {
|
||||
const NotesContextMenu = observer(({ application, appState }: Props) => {
|
||||
const {
|
||||
contextMenuOpen,
|
||||
contextMenuPosition,
|
||||
@@ -46,7 +48,11 @@ const NotesContextMenu = observer(({ appState }: Props) => {
|
||||
maxHeight: contextMenuMaxHeight,
|
||||
}}
|
||||
>
|
||||
<NotesOptions appState={appState} closeOnBlur={closeOnBlur} />
|
||||
<NotesOptions
|
||||
application={application}
|
||||
appState={appState}
|
||||
closeOnBlur={closeOnBlur}
|
||||
/>
|
||||
</div>
|
||||
) : null;
|
||||
});
|
||||
|
||||
@@ -9,15 +9,33 @@ import {
|
||||
DisclosurePanel,
|
||||
} from '@reach/disclosure';
|
||||
import { SNNote } from '@standardnotes/snjs/dist/@types';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { KeyboardModifier } from '@/services/ioService';
|
||||
|
||||
type Props = {
|
||||
application: WebApplication;
|
||||
appState: AppState;
|
||||
closeOnBlur: (event: { relatedTarget: EventTarget | null }) => void;
|
||||
onSubmenuChange?: (submenuOpen: boolean) => void;
|
||||
};
|
||||
|
||||
type DeletePermanentlyButtonProps = {
|
||||
closeOnBlur: Props["closeOnBlur"];
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
const DeletePermanentlyButton = ({
|
||||
closeOnBlur,
|
||||
onClick,
|
||||
}: DeletePermanentlyButtonProps) => (
|
||||
<button onBlur={closeOnBlur} className="sn-dropdown-item" onClick={onClick}>
|
||||
<Icon type="close" className="color-danger mr-2" />
|
||||
<span className="color-danger">Delete permanently</span>
|
||||
</button>
|
||||
);
|
||||
|
||||
export const NotesOptions = observer(
|
||||
({ appState, closeOnBlur, onSubmenuChange }: Props) => {
|
||||
({ application, appState, closeOnBlur, onSubmenuChange }: Props) => {
|
||||
const [tagsMenuOpen, setTagsMenuOpen] = useState(false);
|
||||
const [tagsMenuPosition, setTagsMenuPosition] = useState<{
|
||||
top: number;
|
||||
@@ -29,6 +47,7 @@ export const NotesOptions = observer(
|
||||
});
|
||||
const [tagsMenuMaxHeight, setTagsMenuMaxHeight] =
|
||||
useState<number | 'auto'>('auto');
|
||||
const [altKeyDown, setAltKeyDown] = useState(false);
|
||||
|
||||
const toggleOn = (condition: (note: SNNote) => boolean) => {
|
||||
const notesMatchingAttribute = notes.filter(condition);
|
||||
@@ -59,6 +78,22 @@ export const NotesOptions = observer(
|
||||
}
|
||||
}, [tagsMenuOpen, onSubmenuChange]);
|
||||
|
||||
useEffect(() => {
|
||||
const removeAltKeyObserver = application.io.addKeyObserver({
|
||||
modifiers: [KeyboardModifier.Alt],
|
||||
onKeyDown: () => {
|
||||
setAltKeyDown(true);
|
||||
},
|
||||
onKeyUp: () => {
|
||||
setAltKeyDown(false);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
removeAltKeyObserver();
|
||||
};
|
||||
}, [application]);
|
||||
|
||||
const openTagsMenu = () => {
|
||||
const defaultFontSize = window.getComputedStyle(
|
||||
document.documentElement
|
||||
@@ -235,7 +270,15 @@ export const NotesOptions = observer(
|
||||
Unarchive
|
||||
</button>
|
||||
)}
|
||||
{notTrashed && (
|
||||
{notTrashed &&
|
||||
(altKeyDown ? (
|
||||
<DeletePermanentlyButton
|
||||
closeOnBlur={closeOnBlur}
|
||||
onClick={async () => {
|
||||
await appState.notes.deleteNotesPermanently();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
@@ -246,7 +289,7 @@ export const NotesOptions = observer(
|
||||
<Icon type="trash" className={iconClass} />
|
||||
Move to Trash
|
||||
</button>
|
||||
)}
|
||||
))}
|
||||
{trashed && (
|
||||
<>
|
||||
<button
|
||||
@@ -259,16 +302,12 @@ export const NotesOptions = observer(
|
||||
<Icon type="restore" className={iconClass} />
|
||||
Restore
|
||||
</button>
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
<DeletePermanentlyButton
|
||||
closeOnBlur={closeOnBlur}
|
||||
onClick={async () => {
|
||||
await appState.notes.deleteNotesPermanently();
|
||||
}}
|
||||
>
|
||||
<Icon type="close" className="color-danger mr-2" />
|
||||
<span className="color-danger">Delete permanently</span>
|
||||
</button>
|
||||
/>
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
|
||||
@@ -10,12 +10,14 @@ import {
|
||||
import { useRef, useState } from 'preact/hooks';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { NotesOptions } from './NotesOptions';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
|
||||
type Props = {
|
||||
application: WebApplication;
|
||||
appState: AppState;
|
||||
};
|
||||
|
||||
export const NotesOptionsPanel = observer(({ appState }: Props) => {
|
||||
export const NotesOptionsPanel = observer(({ application, appState }: Props) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [position, setPosition] = useState({
|
||||
top: 0,
|
||||
@@ -76,6 +78,7 @@ export const NotesOptionsPanel = observer(({ appState }: Props) => {
|
||||
>
|
||||
{open && (
|
||||
<NotesOptions
|
||||
application={application}
|
||||
appState={appState}
|
||||
closeOnBlur={closeOnBlur}
|
||||
onSubmenuChange={onSubmenuChange}
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
on-dismiss="self.removeChallenge(challenge)"
|
||||
)
|
||||
notes-context-menu(
|
||||
application='self.application'
|
||||
app-state='self.appState'
|
||||
)
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
) {{self.state.noteStatus.message}}
|
||||
.desc(ng-show='self.state.noteStatus.desc') {{self.state.noteStatus.desc}}
|
||||
notes-options-panel(
|
||||
application='self.application',
|
||||
app-state='self.appState',
|
||||
ng-if='self.appState.notes.selectedNotesCount > 0'
|
||||
)
|
||||
|
||||
@@ -64,7 +64,6 @@ type EditorState = {
|
||||
showOptionsMenu: boolean;
|
||||
showEditorMenu: boolean;
|
||||
showHistoryMenu: boolean;
|
||||
altKeyDown: boolean;
|
||||
spellcheck: boolean;
|
||||
/**
|
||||
* Setting to false then true will allow the current editor component-view to be destroyed
|
||||
@@ -217,7 +216,6 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
||||
showOptionsMenu: false,
|
||||
showEditorMenu: false,
|
||||
showHistoryMenu: false,
|
||||
altKeyDown: false,
|
||||
noteStatus: undefined,
|
||||
editorUnloading: false,
|
||||
textareaUnloading: false,
|
||||
@@ -277,7 +275,6 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
||||
showOptionsMenu: false,
|
||||
showEditorMenu: false,
|
||||
showHistoryMenu: false,
|
||||
altKeyDown: false,
|
||||
noteStatus: undefined,
|
||||
});
|
||||
this.editorValues.title = note.title;
|
||||
@@ -843,22 +840,6 @@ class EditorViewCtrl extends PureViewCtrl<unknown, EditorState> {
|
||||
}
|
||||
|
||||
registerKeyboardShortcuts() {
|
||||
this.removeAltKeyObserver = this.application
|
||||
.io
|
||||
.addKeyObserver({
|
||||
modifiers: [KeyboardModifier.Alt],
|
||||
onKeyDown: () => {
|
||||
this.setState({
|
||||
altKeyDown: true,
|
||||
});
|
||||
},
|
||||
onKeyUp: () => {
|
||||
this.setState({
|
||||
altKeyDown: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
this.removeTrashKeyObserver = this.application
|
||||
.io
|
||||
.addKeyObserver({
|
||||
|
||||
Reference in New Issue
Block a user