diff --git a/Gemfile.lock b/Gemfile.lock index c578fae74..d2fe3cd95 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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 diff --git a/app/assets/javascripts/components/NotesContextMenu.tsx b/app/assets/javascripts/components/NotesContextMenu.tsx index 3afd7df89..292e7265b 100644 --- a/app/assets/javascripts/components/NotesContextMenu.tsx +++ b/app/assets/javascripts/components/NotesContextMenu.tsx @@ -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, }} > - + ) : null; }); diff --git a/app/assets/javascripts/components/NotesOptions.tsx b/app/assets/javascripts/components/NotesOptions.tsx index 3f6d07052..3346ff1e4 100644 --- a/app/assets/javascripts/components/NotesOptions.tsx +++ b/app/assets/javascripts/components/NotesOptions.tsx @@ -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) => ( + +); + 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('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,18 +270,26 @@ export const NotesOptions = observer( Unarchive )} - {notTrashed && ( - - )} + {notTrashed && + (altKeyDown ? ( + { + await appState.notes.deleteNotesPermanently(); + }} + /> + ) : ( + + ))} {trashed && ( <> - + />