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 (
|
return (
|
||||||
<PremiumModalProvider application={application} viewControllerManager={viewControllerManager}>
|
<PremiumModalProvider application={application} viewControllerManager={viewControllerManager}>
|
||||||
<div className={platformString + ' main-ui-view sn-component'}>
|
<ResponsivePaneProvider>
|
||||||
<div id="app" className={appClass + ' app app-column-container'}>
|
<div className={platformString + ' main-ui-view sn-component'}>
|
||||||
<FileDragNDropProvider
|
<div id="app" className={appClass + ' app app-column-container'}>
|
||||||
application={application}
|
<FileDragNDropProvider
|
||||||
featuresController={viewControllerManager.featuresController}
|
application={application}
|
||||||
filesController={viewControllerManager.filesController}
|
featuresController={viewControllerManager.featuresController}
|
||||||
>
|
filesController={viewControllerManager.filesController}
|
||||||
<ResponsivePaneProvider>
|
>
|
||||||
<Navigation application={application} />
|
<Navigation application={application} />
|
||||||
<ContentListView
|
<ContentListView
|
||||||
application={application}
|
application={application}
|
||||||
@@ -197,52 +197,52 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
|
|||||||
searchOptionsController={viewControllerManager.searchOptionsController}
|
searchOptionsController={viewControllerManager.searchOptionsController}
|
||||||
/>
|
/>
|
||||||
<NoteGroupView application={application} />
|
<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>
|
</div>
|
||||||
|
</ResponsivePaneProvider>
|
||||||
<>
|
|
||||||
<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>
|
|
||||||
</PremiumModalProvider>
|
</PremiumModalProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import { FilesController } from '@/Controllers/FilesController'
|
|||||||
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
|
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
|
||||||
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
||||||
import { formatSizeToReadableString } from '@standardnotes/filepicker'
|
import { formatSizeToReadableString } from '@standardnotes/filepicker'
|
||||||
|
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||||
|
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
closeMenu: () => void
|
closeMenu: () => void
|
||||||
@@ -30,6 +32,7 @@ const FileMenuOptions: FunctionComponent<Props> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { selectedFiles } = selectionController
|
const { selectedFiles } = selectionController
|
||||||
const { handleFileAction } = filesController
|
const { handleFileAction } = filesController
|
||||||
|
const { toggleAppPane } = useResponsiveAppPane()
|
||||||
|
|
||||||
const hasProtectedFiles = useMemo(() => selectedFiles.some((file) => file.protected), [selectedFiles])
|
const hasProtectedFiles = useMemo(() => selectedFiles.some((file) => file.protected), [selectedFiles])
|
||||||
const hasSelectedMultipleFiles = useMemo(() => selectedFiles.length > 1, [selectedFiles.length])
|
const hasSelectedMultipleFiles = useMemo(() => selectedFiles.length > 1, [selectedFiles.length])
|
||||||
@@ -68,6 +71,11 @@ const FileMenuOptions: FunctionComponent<Props> = ({
|
|||||||
closeMenu()
|
closeMenu()
|
||||||
}, [closeMenu, handleFileAction, selectedFiles])
|
}, [closeMenu, handleFileAction, selectedFiles])
|
||||||
|
|
||||||
|
const closeMenuAndToggleFilesList = useCallback(() => {
|
||||||
|
toggleAppPane(AppPaneId.Items)
|
||||||
|
closeMenu()
|
||||||
|
}, [closeMenu, toggleAppPane])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
@@ -139,6 +147,7 @@ const FileMenuOptions: FunctionComponent<Props> = ({
|
|||||||
<button
|
<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"
|
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={() => {
|
onClick={() => {
|
||||||
|
closeMenuAndToggleFilesList()
|
||||||
void filesController.deleteFilesPermanently(selectionController.selectedFiles)
|
void filesController.deleteFilesPermanently(selectionController.selectedFiles)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -23,10 +23,12 @@ const NotesContextMenu = ({
|
|||||||
noteTagsController,
|
noteTagsController,
|
||||||
historyModalController,
|
historyModalController,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { contextMenuOpen, contextMenuClickLocation } = notesController
|
const { contextMenuOpen, contextMenuClickLocation, setContextMenuOpen } = notesController
|
||||||
|
|
||||||
const contextMenuRef = useRef<HTMLDivElement>(null)
|
const contextMenuRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
const closeMenu = () => setContextMenuOpen(!contextMenuOpen)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover
|
<Popover
|
||||||
align="start"
|
align="start"
|
||||||
@@ -37,7 +39,7 @@ const NotesContextMenu = ({
|
|||||||
className="py-2"
|
className="py-2"
|
||||||
open={contextMenuOpen}
|
open={contextMenuOpen}
|
||||||
side="right"
|
side="right"
|
||||||
togglePopover={() => notesController.setContextMenuOpen(!contextMenuOpen)}
|
togglePopover={closeMenu}
|
||||||
>
|
>
|
||||||
<div ref={contextMenuRef}>
|
<div ref={contextMenuRef}>
|
||||||
<NotesOptions
|
<NotesOptions
|
||||||
@@ -46,6 +48,7 @@ const NotesContextMenu = ({
|
|||||||
notesController={notesController}
|
notesController={notesController}
|
||||||
noteTagsController={noteTagsController}
|
noteTagsController={noteTagsController}
|
||||||
historyModalController={historyModalController}
|
historyModalController={historyModalController}
|
||||||
|
closeMenu={closeMenu}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import { NotesOptionsProps } from './NotesOptionsProps'
|
|||||||
import { NotesController } from '@/Controllers/NotesController'
|
import { NotesController } from '@/Controllers/NotesController'
|
||||||
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
||||||
import { formatDateForContextMenu } from '@/Utils/DateUtils'
|
import { formatDateForContextMenu } from '@/Utils/DateUtils'
|
||||||
|
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||||
|
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
|
||||||
|
|
||||||
type DeletePermanentlyButtonProps = {
|
type DeletePermanentlyButtonProps = {
|
||||||
onClick: () => void
|
onClick: () => void
|
||||||
@@ -175,8 +177,10 @@ const NotesOptions = ({
|
|||||||
notesController,
|
notesController,
|
||||||
noteTagsController,
|
noteTagsController,
|
||||||
historyModalController,
|
historyModalController,
|
||||||
|
closeMenu,
|
||||||
}: NotesOptionsProps) => {
|
}: NotesOptionsProps) => {
|
||||||
const [altKeyDown, setAltKeyDown] = useState(false)
|
const [altKeyDown, setAltKeyDown] = useState(false)
|
||||||
|
const { toggleAppPane } = useResponsiveAppPane()
|
||||||
|
|
||||||
const toggleOn = (condition: (note: SNNote) => boolean) => {
|
const toggleOn = (condition: (note: SNNote) => boolean) => {
|
||||||
const notesMatchingAttribute = notes.filter(condition)
|
const notesMatchingAttribute = notes.filter(condition)
|
||||||
@@ -252,11 +256,15 @@ const NotesOptions = ({
|
|||||||
}
|
}
|
||||||
}, [application, getNoteFileName, notes])
|
}, [application, getNoteFileName, notes])
|
||||||
|
|
||||||
const duplicateSelectedItems = useCallback(() => {
|
const closeMenuAndToggleNotesList = useCallback(() => {
|
||||||
notes.forEach((note) => {
|
toggleAppPane(AppPaneId.Items)
|
||||||
application.mutator.duplicateItem(note).catch(console.error)
|
closeMenu()
|
||||||
})
|
}, [closeMenu, toggleAppPane])
|
||||||
}, [application, notes])
|
|
||||||
|
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(() => {
|
const openRevisionHistoryModal = useCallback(() => {
|
||||||
historyModalController.openModal(notesController.firstSelectedNote)
|
historyModalController.openModal(notesController.firstSelectedNote)
|
||||||
@@ -365,8 +373,9 @@ const NotesOptions = ({
|
|||||||
{unarchived && (
|
{unarchived && (
|
||||||
<button
|
<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"
|
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={() => {
|
onClick={async () => {
|
||||||
notesController.setArchiveSelectedNotes(true).catch(console.error)
|
await notesController.setArchiveSelectedNotes(true).catch(console.error)
|
||||||
|
closeMenuAndToggleNotesList()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Icon type="archive" className={iconClassWarning} />
|
<Icon type="archive" className={iconClassWarning} />
|
||||||
@@ -376,8 +385,9 @@ const NotesOptions = ({
|
|||||||
{archived && (
|
{archived && (
|
||||||
<button
|
<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"
|
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={() => {
|
onClick={async () => {
|
||||||
notesController.setArchiveSelectedNotes(false).catch(console.error)
|
await notesController.setArchiveSelectedNotes(false).catch(console.error)
|
||||||
|
closeMenuAndToggleNotesList()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Icon type="unarchive" className={iconClassWarning} />
|
<Icon type="unarchive" className={iconClassWarning} />
|
||||||
@@ -389,6 +399,7 @@ const NotesOptions = ({
|
|||||||
<DeletePermanentlyButton
|
<DeletePermanentlyButton
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await notesController.deleteNotesPermanently()
|
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"
|
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 () => {
|
onClick={async () => {
|
||||||
await notesController.setTrashSelectedNotes(true)
|
await notesController.setTrashSelectedNotes(true)
|
||||||
|
closeMenuAndToggleNotesList()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Icon type="trash" className={iconClassDanger} />
|
<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"
|
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 () => {
|
onClick={async () => {
|
||||||
await notesController.setTrashSelectedNotes(false)
|
await notesController.setTrashSelectedNotes(false)
|
||||||
|
closeMenuAndToggleNotesList()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Icon type="restore" className={iconClassSuccess} />
|
<Icon type="restore" className={iconClassSuccess} />
|
||||||
@@ -416,12 +429,14 @@ const NotesOptions = ({
|
|||||||
<DeletePermanentlyButton
|
<DeletePermanentlyButton
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await notesController.deleteNotesPermanently()
|
await notesController.deleteNotesPermanently()
|
||||||
|
closeMenuAndToggleNotesList()
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<button
|
<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"
|
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 () => {
|
onClick={async () => {
|
||||||
await notesController.emptyTrash()
|
await notesController.emptyTrash()
|
||||||
|
closeMenuAndToggleNotesList()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex items-start">
|
<div className="flex items-start">
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ const NotesOptionsPanel = ({
|
|||||||
notesController={notesController}
|
notesController={notesController}
|
||||||
noteTagsController={noteTagsController}
|
noteTagsController={noteTagsController}
|
||||||
historyModalController={historyModalController}
|
historyModalController={historyModalController}
|
||||||
|
closeMenu={toggleMenu}
|
||||||
/>
|
/>
|
||||||
</Popover>
|
</Popover>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -10,4 +10,5 @@ export type NotesOptionsProps = {
|
|||||||
notesController: NotesController
|
notesController: NotesController
|
||||||
noteTagsController: NoteTagsController
|
noteTagsController: NoteTagsController
|
||||||
historyModalController: HistoryModalController
|
historyModalController: HistoryModalController
|
||||||
|
closeMenu: () => void
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ElementIds } from '@/Constants/ElementIDs'
|
import { ElementIds } from '@/Constants/ElementIDs'
|
||||||
import { isMobileScreen } from '@/Utils'
|
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'
|
import { AppPaneId } from './AppPaneMetadata'
|
||||||
|
|
||||||
type ResponsivePaneData = {
|
type ResponsivePaneData = {
|
||||||
@@ -24,6 +24,8 @@ type Props = {
|
|||||||
children: ReactNode
|
children: ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MemoizedChildren = memo(({ children }: Props) => <div>{children}</div>)
|
||||||
|
|
||||||
const ResponsivePaneProvider = ({ children }: Props) => {
|
const ResponsivePaneProvider = ({ children }: Props) => {
|
||||||
const [currentSelectedPane, setCurrentSelectedPane] = useState<AppPaneId>(
|
const [currentSelectedPane, setCurrentSelectedPane] = useState<AppPaneId>(
|
||||||
isMobileScreen() ? AppPaneId.Items : AppPaneId.Editor,
|
isMobileScreen() ? AppPaneId.Items : AppPaneId.Editor,
|
||||||
@@ -63,7 +65,11 @@ const ResponsivePaneProvider = ({ children }: Props) => {
|
|||||||
[currentSelectedPane, toggleAppPane],
|
[currentSelectedPane, toggleAppPane],
|
||||||
)
|
)
|
||||||
|
|
||||||
return <ResponsivePaneContext.Provider value={contextValue}>{children}</ResponsivePaneContext.Provider>
|
return (
|
||||||
|
<ResponsivePaneContext.Provider value={contextValue}>
|
||||||
|
<MemoizedChildren children={children} />
|
||||||
|
</ResponsivePaneContext.Provider>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ResponsivePaneProvider
|
export default ResponsivePaneProvider
|
||||||
|
|||||||
Reference in New Issue
Block a user