fix: close menu & toggle notes list when note action occurs (#1601)
This commit is contained in:
@@ -175,14 +175,14 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
|
||||
|
||||
return (
|
||||
<PremiumModalProvider application={application} viewControllerManager={viewControllerManager}>
|
||||
<div className={platformString + ' main-ui-view sn-component'}>
|
||||
<div id="app" className={appClass + ' app app-column-container'}>
|
||||
<FileDragNDropProvider
|
||||
application={application}
|
||||
featuresController={viewControllerManager.featuresController}
|
||||
filesController={viewControllerManager.filesController}
|
||||
>
|
||||
<ResponsivePaneProvider>
|
||||
<ResponsivePaneProvider>
|
||||
<div className={platformString + ' main-ui-view sn-component'}>
|
||||
<div id="app" className={appClass + ' app app-column-container'}>
|
||||
<FileDragNDropProvider
|
||||
application={application}
|
||||
featuresController={viewControllerManager.featuresController}
|
||||
filesController={viewControllerManager.filesController}
|
||||
>
|
||||
<Navigation application={application} />
|
||||
<ContentListView
|
||||
application={application}
|
||||
@@ -197,52 +197,52 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
|
||||
searchOptionsController={viewControllerManager.searchOptionsController}
|
||||
/>
|
||||
<NoteGroupView application={application} />
|
||||
</ResponsivePaneProvider>
|
||||
</FileDragNDropProvider>
|
||||
</FileDragNDropProvider>
|
||||
</div>
|
||||
|
||||
<>
|
||||
<Footer application={application} applicationGroup={mainApplicationGroup} />
|
||||
<SessionsModal application={application} viewControllerManager={viewControllerManager} />
|
||||
<PreferencesViewWrapper viewControllerManager={viewControllerManager} application={application} />
|
||||
<RevisionHistoryModal
|
||||
application={application}
|
||||
historyModalController={viewControllerManager.historyModalController}
|
||||
notesController={viewControllerManager.notesController}
|
||||
selectionController={viewControllerManager.selectionController}
|
||||
subscriptionController={viewControllerManager.subscriptionController}
|
||||
/>
|
||||
</>
|
||||
|
||||
{renderChallenges()}
|
||||
|
||||
<>
|
||||
<NotesContextMenu
|
||||
application={application}
|
||||
navigationController={viewControllerManager.navigationController}
|
||||
notesController={viewControllerManager.notesController}
|
||||
noteTagsController={viewControllerManager.noteTagsController}
|
||||
historyModalController={viewControllerManager.historyModalController}
|
||||
/>
|
||||
<TagContextMenuWrapper
|
||||
navigationController={viewControllerManager.navigationController}
|
||||
featuresController={viewControllerManager.featuresController}
|
||||
/>
|
||||
<FileContextMenuWrapper
|
||||
filesController={viewControllerManager.filesController}
|
||||
selectionController={viewControllerManager.selectionController}
|
||||
/>
|
||||
<PurchaseFlowWrapper application={application} viewControllerManager={viewControllerManager} />
|
||||
<ConfirmSignoutContainer
|
||||
applicationGroup={mainApplicationGroup}
|
||||
viewControllerManager={viewControllerManager}
|
||||
application={application}
|
||||
/>
|
||||
<ToastContainer />
|
||||
<FilePreviewModalWrapper application={application} viewControllerManager={viewControllerManager} />
|
||||
<PermissionsModalWrapper application={application} />
|
||||
</>
|
||||
</div>
|
||||
|
||||
<>
|
||||
<Footer application={application} applicationGroup={mainApplicationGroup} />
|
||||
<SessionsModal application={application} viewControllerManager={viewControllerManager} />
|
||||
<PreferencesViewWrapper viewControllerManager={viewControllerManager} application={application} />
|
||||
<RevisionHistoryModal
|
||||
application={application}
|
||||
historyModalController={viewControllerManager.historyModalController}
|
||||
notesController={viewControllerManager.notesController}
|
||||
selectionController={viewControllerManager.selectionController}
|
||||
subscriptionController={viewControllerManager.subscriptionController}
|
||||
/>
|
||||
</>
|
||||
|
||||
{renderChallenges()}
|
||||
|
||||
<>
|
||||
<NotesContextMenu
|
||||
application={application}
|
||||
navigationController={viewControllerManager.navigationController}
|
||||
notesController={viewControllerManager.notesController}
|
||||
noteTagsController={viewControllerManager.noteTagsController}
|
||||
historyModalController={viewControllerManager.historyModalController}
|
||||
/>
|
||||
<TagContextMenuWrapper
|
||||
navigationController={viewControllerManager.navigationController}
|
||||
featuresController={viewControllerManager.featuresController}
|
||||
/>
|
||||
<FileContextMenuWrapper
|
||||
filesController={viewControllerManager.filesController}
|
||||
selectionController={viewControllerManager.selectionController}
|
||||
/>
|
||||
<PurchaseFlowWrapper application={application} viewControllerManager={viewControllerManager} />
|
||||
<ConfirmSignoutContainer
|
||||
applicationGroup={mainApplicationGroup}
|
||||
viewControllerManager={viewControllerManager}
|
||||
application={application}
|
||||
/>
|
||||
<ToastContainer />
|
||||
<FilePreviewModalWrapper application={application} viewControllerManager={viewControllerManager} />
|
||||
<PermissionsModalWrapper application={application} />
|
||||
</>
|
||||
</div>
|
||||
</ResponsivePaneProvider>
|
||||
</PremiumModalProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import { FilesController } from '@/Controllers/FilesController'
|
||||
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
|
||||
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
||||
import { formatSizeToReadableString } from '@standardnotes/filepicker'
|
||||
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
|
||||
|
||||
type Props = {
|
||||
closeMenu: () => void
|
||||
@@ -30,6 +32,7 @@ const FileMenuOptions: FunctionComponent<Props> = ({
|
||||
}) => {
|
||||
const { selectedFiles } = selectionController
|
||||
const { handleFileAction } = filesController
|
||||
const { toggleAppPane } = useResponsiveAppPane()
|
||||
|
||||
const hasProtectedFiles = useMemo(() => selectedFiles.some((file) => file.protected), [selectedFiles])
|
||||
const hasSelectedMultipleFiles = useMemo(() => selectedFiles.length > 1, [selectedFiles.length])
|
||||
@@ -68,6 +71,11 @@ const FileMenuOptions: FunctionComponent<Props> = ({
|
||||
closeMenu()
|
||||
}, [closeMenu, handleFileAction, selectedFiles])
|
||||
|
||||
const closeMenuAndToggleFilesList = useCallback(() => {
|
||||
toggleAppPane(AppPaneId.Items)
|
||||
closeMenu()
|
||||
}, [closeMenu, toggleAppPane])
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
@@ -139,6 +147,7 @@ const FileMenuOptions: FunctionComponent<Props> = ({
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
onClick={() => {
|
||||
closeMenuAndToggleFilesList()
|
||||
void filesController.deleteFilesPermanently(selectionController.selectedFiles)
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -23,10 +23,12 @@ const NotesContextMenu = ({
|
||||
noteTagsController,
|
||||
historyModalController,
|
||||
}: Props) => {
|
||||
const { contextMenuOpen, contextMenuClickLocation } = notesController
|
||||
const { contextMenuOpen, contextMenuClickLocation, setContextMenuOpen } = notesController
|
||||
|
||||
const contextMenuRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const closeMenu = () => setContextMenuOpen(!contextMenuOpen)
|
||||
|
||||
return (
|
||||
<Popover
|
||||
align="start"
|
||||
@@ -37,7 +39,7 @@ const NotesContextMenu = ({
|
||||
className="py-2"
|
||||
open={contextMenuOpen}
|
||||
side="right"
|
||||
togglePopover={() => notesController.setContextMenuOpen(!contextMenuOpen)}
|
||||
togglePopover={closeMenu}
|
||||
>
|
||||
<div ref={contextMenuRef}>
|
||||
<NotesOptions
|
||||
@@ -46,6 +48,7 @@ const NotesContextMenu = ({
|
||||
notesController={notesController}
|
||||
noteTagsController={noteTagsController}
|
||||
historyModalController={historyModalController}
|
||||
closeMenu={closeMenu}
|
||||
/>
|
||||
</div>
|
||||
</Popover>
|
||||
|
||||
@@ -13,6 +13,8 @@ import { NotesOptionsProps } from './NotesOptionsProps'
|
||||
import { NotesController } from '@/Controllers/NotesController'
|
||||
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
||||
import { formatDateForContextMenu } from '@/Utils/DateUtils'
|
||||
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
|
||||
|
||||
type DeletePermanentlyButtonProps = {
|
||||
onClick: () => void
|
||||
@@ -175,8 +177,10 @@ const NotesOptions = ({
|
||||
notesController,
|
||||
noteTagsController,
|
||||
historyModalController,
|
||||
closeMenu,
|
||||
}: NotesOptionsProps) => {
|
||||
const [altKeyDown, setAltKeyDown] = useState(false)
|
||||
const { toggleAppPane } = useResponsiveAppPane()
|
||||
|
||||
const toggleOn = (condition: (note: SNNote) => boolean) => {
|
||||
const notesMatchingAttribute = notes.filter(condition)
|
||||
@@ -252,11 +256,15 @@ const NotesOptions = ({
|
||||
}
|
||||
}, [application, getNoteFileName, notes])
|
||||
|
||||
const duplicateSelectedItems = useCallback(() => {
|
||||
notes.forEach((note) => {
|
||||
application.mutator.duplicateItem(note).catch(console.error)
|
||||
})
|
||||
}, [application, notes])
|
||||
const closeMenuAndToggleNotesList = useCallback(() => {
|
||||
toggleAppPane(AppPaneId.Items)
|
||||
closeMenu()
|
||||
}, [closeMenu, toggleAppPane])
|
||||
|
||||
const duplicateSelectedItems = useCallback(async () => {
|
||||
await Promise.all(notes.map((note) => application.mutator.duplicateItem(note).catch(console.error)))
|
||||
closeMenuAndToggleNotesList()
|
||||
}, [application.mutator, closeMenuAndToggleNotesList, notes])
|
||||
|
||||
const openRevisionHistoryModal = useCallback(() => {
|
||||
historyModalController.openModal(notesController.firstSelectedNote)
|
||||
@@ -365,8 +373,9 @@ const NotesOptions = ({
|
||||
{unarchived && (
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
onClick={() => {
|
||||
notesController.setArchiveSelectedNotes(true).catch(console.error)
|
||||
onClick={async () => {
|
||||
await notesController.setArchiveSelectedNotes(true).catch(console.error)
|
||||
closeMenuAndToggleNotesList()
|
||||
}}
|
||||
>
|
||||
<Icon type="archive" className={iconClassWarning} />
|
||||
@@ -376,8 +385,9 @@ const NotesOptions = ({
|
||||
{archived && (
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
onClick={() => {
|
||||
notesController.setArchiveSelectedNotes(false).catch(console.error)
|
||||
onClick={async () => {
|
||||
await notesController.setArchiveSelectedNotes(false).catch(console.error)
|
||||
closeMenuAndToggleNotesList()
|
||||
}}
|
||||
>
|
||||
<Icon type="unarchive" className={iconClassWarning} />
|
||||
@@ -389,6 +399,7 @@ const NotesOptions = ({
|
||||
<DeletePermanentlyButton
|
||||
onClick={async () => {
|
||||
await notesController.deleteNotesPermanently()
|
||||
closeMenuAndToggleNotesList()
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
@@ -396,6 +407,7 @@ const NotesOptions = ({
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
onClick={async () => {
|
||||
await notesController.setTrashSelectedNotes(true)
|
||||
closeMenuAndToggleNotesList()
|
||||
}}
|
||||
>
|
||||
<Icon type="trash" className={iconClassDanger} />
|
||||
@@ -408,6 +420,7 @@ const NotesOptions = ({
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
onClick={async () => {
|
||||
await notesController.setTrashSelectedNotes(false)
|
||||
closeMenuAndToggleNotesList()
|
||||
}}
|
||||
>
|
||||
<Icon type="restore" className={iconClassSuccess} />
|
||||
@@ -416,12 +429,14 @@ const NotesOptions = ({
|
||||
<DeletePermanentlyButton
|
||||
onClick={async () => {
|
||||
await notesController.deleteNotesPermanently()
|
||||
closeMenuAndToggleNotesList()
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
onClick={async () => {
|
||||
await notesController.emptyTrash()
|
||||
closeMenuAndToggleNotesList()
|
||||
}}
|
||||
>
|
||||
<div className="flex items-start">
|
||||
|
||||
@@ -55,6 +55,7 @@ const NotesOptionsPanel = ({
|
||||
notesController={notesController}
|
||||
noteTagsController={noteTagsController}
|
||||
historyModalController={historyModalController}
|
||||
closeMenu={toggleMenu}
|
||||
/>
|
||||
</Popover>
|
||||
</>
|
||||
|
||||
@@ -10,4 +10,5 @@ export type NotesOptionsProps = {
|
||||
notesController: NotesController
|
||||
noteTagsController: NoteTagsController
|
||||
historyModalController: HistoryModalController
|
||||
closeMenu: () => void
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ElementIds } from '@/Constants/ElementIDs'
|
||||
import { isMobileScreen } from '@/Utils'
|
||||
import { useEffect, ReactNode, useMemo, createContext, useCallback, useContext, useState } from 'react'
|
||||
import { useEffect, ReactNode, useMemo, createContext, useCallback, useContext, useState, memo } from 'react'
|
||||
import { AppPaneId } from './AppPaneMetadata'
|
||||
|
||||
type ResponsivePaneData = {
|
||||
@@ -24,6 +24,8 @@ type Props = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
const MemoizedChildren = memo(({ children }: Props) => <div>{children}</div>)
|
||||
|
||||
const ResponsivePaneProvider = ({ children }: Props) => {
|
||||
const [currentSelectedPane, setCurrentSelectedPane] = useState<AppPaneId>(
|
||||
isMobileScreen() ? AppPaneId.Items : AppPaneId.Editor,
|
||||
@@ -63,7 +65,11 @@ const ResponsivePaneProvider = ({ children }: Props) => {
|
||||
[currentSelectedPane, toggleAppPane],
|
||||
)
|
||||
|
||||
return <ResponsivePaneContext.Provider value={contextValue}>{children}</ResponsivePaneContext.Provider>
|
||||
return (
|
||||
<ResponsivePaneContext.Provider value={contextValue}>
|
||||
<MemoizedChildren children={children} />
|
||||
</ResponsivePaneContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export default ResponsivePaneProvider
|
||||
|
||||
Reference in New Issue
Block a user