feat: add files button to multiple selection view (#1067)
This commit is contained in:
@@ -191,7 +191,12 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
|
||||
{renderChallenges()}
|
||||
|
||||
<>
|
||||
<NotesContextMenu application={application} viewControllerManager={viewControllerManager} />
|
||||
<NotesContextMenu
|
||||
application={application}
|
||||
navigationController={viewControllerManager.navigationController}
|
||||
notesController={viewControllerManager.notesController}
|
||||
noteTagsController={viewControllerManager.noteTagsController}
|
||||
/>
|
||||
<TagsContextMenuWrapper viewControllerManager={viewControllerManager} />
|
||||
<FileContextMenuWrapper
|
||||
filesController={viewControllerManager.filesController}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { observer } from 'mobx-react-lite'
|
||||
import { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import { useCloseOnBlur } from '@/Hooks/useCloseOnBlur'
|
||||
import { ContentType, FileItem, SNNote } from '@standardnotes/snjs'
|
||||
import { FileItem, SNNote } from '@standardnotes/snjs'
|
||||
import { addToast, ToastType } from '@standardnotes/stylekit'
|
||||
import { StreamingFileReader } from '@standardnotes/filepicker'
|
||||
import AttachedFilesPopover from './AttachedFilesPopover'
|
||||
@@ -18,6 +18,7 @@ import { FilePreviewModalController } from '@/Controllers/FilePreviewModalContro
|
||||
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
|
||||
import { FeaturesController } from '@/Controllers/FeaturesController'
|
||||
import { FilesController } from '@/Controllers/FilesController'
|
||||
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -26,6 +27,7 @@ type Props = {
|
||||
filesController: FilesController
|
||||
navigationController: NavigationController
|
||||
notesController: NotesController
|
||||
selectionController: SelectedItemsController
|
||||
onClickPreprocessing?: () => Promise<void>
|
||||
}
|
||||
|
||||
@@ -36,8 +38,12 @@ const AttachedFilesButton: FunctionComponent<Props> = ({
|
||||
filePreviewModalController,
|
||||
navigationController,
|
||||
notesController,
|
||||
selectionController,
|
||||
onClickPreprocessing,
|
||||
}: Props) => {
|
||||
const { allFiles, attachedFiles } = filesController
|
||||
const attachedFilesCount = attachedFiles.length
|
||||
|
||||
const premiumModal = usePremiumModal()
|
||||
const note: SNNote | undefined = notesController.firstSelectedNote
|
||||
|
||||
@@ -63,22 +69,14 @@ const AttachedFilesButton: FunctionComponent<Props> = ({
|
||||
const [currentTab, setCurrentTab] = useState(
|
||||
navigationController.isInFilesView ? PopoverTabs.AllFiles : PopoverTabs.AttachedFiles,
|
||||
)
|
||||
const [allFiles, setAllFiles] = useState<FileItem[]>([])
|
||||
const [attachedFiles, setAttachedFiles] = useState<FileItem[]>([])
|
||||
const attachedFilesCount = attachedFiles.length
|
||||
|
||||
const isAttachedTabDisabled = navigationController.isInFilesView || selectionController.selectedItemsCount > 1
|
||||
|
||||
useEffect(() => {
|
||||
const unregisterFileStream = application.streamItems(ContentType.File, () => {
|
||||
setAllFiles(application.items.getDisplayableFiles())
|
||||
if (note) {
|
||||
setAttachedFiles(application.items.getFilesForNote(note))
|
||||
}
|
||||
})
|
||||
|
||||
return () => {
|
||||
unregisterFileStream()
|
||||
if (isAttachedTabDisabled && currentTab === PopoverTabs.AttachedFiles) {
|
||||
setCurrentTab(PopoverTabs.AllFiles)
|
||||
}
|
||||
}, [application, note])
|
||||
}, [currentTab, isAttachedTabDisabled])
|
||||
|
||||
const toggleAttachedFilesMenu = useCallback(async () => {
|
||||
const rect = buttonRef.current?.getBoundingClientRect()
|
||||
@@ -304,7 +302,7 @@ const AttachedFilesButton: FunctionComponent<Props> = ({
|
||||
currentTab={currentTab}
|
||||
isDraggingFiles={isDraggingFiles}
|
||||
setCurrentTab={setCurrentTab}
|
||||
attachedTabDisabled={navigationController.isInFilesView}
|
||||
attachedTabDisabled={isAttachedTabDisabled}
|
||||
/>
|
||||
)}
|
||||
</DisclosurePanel>
|
||||
|
||||
@@ -57,6 +57,7 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }:
|
||||
filesController={viewControllerManager.filesController}
|
||||
navigationController={viewControllerManager.navigationController}
|
||||
notesController={viewControllerManager.notesController}
|
||||
selectionController={viewControllerManager.selectionController}
|
||||
/>
|
||||
</div>
|
||||
<FileOptionsPanel
|
||||
|
||||
@@ -5,13 +5,32 @@ import { useCallback } from 'react'
|
||||
import FileOptionsPanel from '../FileContextMenu/FileOptionsPanel'
|
||||
import { FilesController } from '@/Controllers/FilesController'
|
||||
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { FeaturesController } from '@/Controllers/FeaturesController'
|
||||
import { FilePreviewModalController } from '@/Controllers/FilePreviewModalController'
|
||||
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
|
||||
import { NotesController } from '@/Controllers/NotesController'
|
||||
import AttachedFilesButton from '../AttachedFilesPopover/AttachedFilesButton'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
featuresController: FeaturesController
|
||||
filePreviewModalController: FilePreviewModalController
|
||||
filesController: FilesController
|
||||
navigationController: NavigationController
|
||||
notesController: NotesController
|
||||
selectionController: SelectedItemsController
|
||||
}
|
||||
|
||||
const MultipleSelectedFiles = ({ filesController, selectionController }: Props) => {
|
||||
const MultipleSelectedFiles = ({
|
||||
application,
|
||||
filesController,
|
||||
featuresController,
|
||||
filePreviewModalController,
|
||||
navigationController,
|
||||
notesController,
|
||||
selectionController,
|
||||
}: Props) => {
|
||||
const count = selectionController.selectedFilesCount
|
||||
|
||||
const cancelMultipleSelection = useCallback(() => {
|
||||
@@ -23,6 +42,17 @@ const MultipleSelectedFiles = ({ filesController, selectionController }: Props)
|
||||
<div className="flex items-center justify-between p-4 w-full">
|
||||
<h1 className="sk-h1 font-bold m-0">{count} selected files</h1>
|
||||
<div className="flex">
|
||||
<div className="mr-3">
|
||||
<AttachedFilesButton
|
||||
application={application}
|
||||
featuresController={featuresController}
|
||||
filePreviewModalController={filePreviewModalController}
|
||||
filesController={filesController}
|
||||
navigationController={navigationController}
|
||||
notesController={notesController}
|
||||
selectionController={selectionController}
|
||||
/>
|
||||
</div>
|
||||
<FileOptionsPanel filesController={filesController} selectionController={selectionController} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { ViewControllerManager } from '@/Services/ViewControllerManager'
|
||||
import { IlNotesIcon } from '@standardnotes/icons'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import NotesOptionsPanel from '@/Components/NotesOptions/NotesOptionsPanel'
|
||||
@@ -6,18 +5,41 @@ import { WebApplication } from '@/Application/Application'
|
||||
import PinNoteButton from '@/Components/PinNoteButton/PinNoteButton'
|
||||
import Button from '../Button/Button'
|
||||
import { useCallback } from 'react'
|
||||
import AttachedFilesButton from '../AttachedFilesPopover/AttachedFilesButton'
|
||||
import { FeaturesController } from '@/Controllers/FeaturesController'
|
||||
import { FilePreviewModalController } from '@/Controllers/FilePreviewModalController'
|
||||
import { FilesController } from '@/Controllers/FilesController'
|
||||
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
|
||||
import { NotesController } from '@/Controllers/NotesController'
|
||||
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
|
||||
import { NoteTagsController } from '@/Controllers/NoteTagsController'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
viewControllerManager: ViewControllerManager
|
||||
featuresController: FeaturesController
|
||||
filePreviewModalController: FilePreviewModalController
|
||||
filesController: FilesController
|
||||
navigationController: NavigationController
|
||||
notesController: NotesController
|
||||
noteTagsController: NoteTagsController
|
||||
selectionController: SelectedItemsController
|
||||
}
|
||||
|
||||
const MultipleSelectedNotes = ({ application, viewControllerManager }: Props) => {
|
||||
const count = viewControllerManager.notesController.selectedNotesCount
|
||||
const MultipleSelectedNotes = ({
|
||||
application,
|
||||
featuresController,
|
||||
filePreviewModalController,
|
||||
filesController,
|
||||
navigationController,
|
||||
notesController,
|
||||
noteTagsController,
|
||||
selectionController,
|
||||
}: Props) => {
|
||||
const count = notesController.selectedNotesCount
|
||||
|
||||
const cancelMultipleSelection = useCallback(() => {
|
||||
viewControllerManager.selectionController.cancelMultipleSelection()
|
||||
}, [viewControllerManager])
|
||||
selectionController.cancelMultipleSelection()
|
||||
}, [selectionController])
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full items-center">
|
||||
@@ -25,9 +47,25 @@ const MultipleSelectedNotes = ({ application, viewControllerManager }: Props) =>
|
||||
<h1 className="sk-h1 font-bold m-0">{count} selected notes</h1>
|
||||
<div className="flex">
|
||||
<div className="mr-3">
|
||||
<PinNoteButton viewControllerManager={viewControllerManager} />
|
||||
<AttachedFilesButton
|
||||
application={application}
|
||||
featuresController={featuresController}
|
||||
filePreviewModalController={filePreviewModalController}
|
||||
filesController={filesController}
|
||||
navigationController={navigationController}
|
||||
notesController={notesController}
|
||||
selectionController={selectionController}
|
||||
/>
|
||||
</div>
|
||||
<NotesOptionsPanel application={application} viewControllerManager={viewControllerManager} />
|
||||
<div className="mr-3">
|
||||
<PinNoteButton notesController={notesController} />
|
||||
</div>
|
||||
<NotesOptionsPanel
|
||||
application={application}
|
||||
navigationController={navigationController}
|
||||
notesController={notesController}
|
||||
noteTagsController={noteTagsController}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-grow flex flex-col justify-center items-center w-full max-w-md">
|
||||
|
||||
@@ -83,13 +83,27 @@ class NoteGroupView extends PureComponent<Props, State> {
|
||||
return (
|
||||
<div id={ElementIds.EditorColumn} className="h-full app-column app-column-third">
|
||||
{this.state.showMultipleSelectedNotes && (
|
||||
<MultipleSelectedNotes application={this.application} viewControllerManager={this.viewControllerManager} />
|
||||
<MultipleSelectedNotes
|
||||
application={this.application}
|
||||
filesController={this.viewControllerManager.filesController}
|
||||
selectionController={this.viewControllerManager.selectionController}
|
||||
featuresController={this.viewControllerManager.featuresController}
|
||||
filePreviewModalController={this.viewControllerManager.filePreviewModalController}
|
||||
navigationController={this.viewControllerManager.navigationController}
|
||||
notesController={this.viewControllerManager.notesController}
|
||||
noteTagsController={this.viewControllerManager.noteTagsController}
|
||||
/>
|
||||
)}
|
||||
|
||||
{this.state.showMultipleSelectedFiles && (
|
||||
<MultipleSelectedFiles
|
||||
application={this.application}
|
||||
filesController={this.viewControllerManager.filesController}
|
||||
selectionController={this.viewControllerManager.selectionController}
|
||||
featuresController={this.viewControllerManager.featuresController}
|
||||
filePreviewModalController={this.viewControllerManager.filePreviewModalController}
|
||||
navigationController={this.viewControllerManager.navigationController}
|
||||
notesController={this.viewControllerManager.notesController}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -950,6 +950,7 @@ class NoteView extends PureComponent<NoteViewProps, State> {
|
||||
filesController={this.viewControllerManager.filesController}
|
||||
navigationController={this.viewControllerManager.navigationController}
|
||||
notesController={this.viewControllerManager.notesController}
|
||||
selectionController={this.viewControllerManager.selectionController}
|
||||
/>
|
||||
</div>
|
||||
<div className="mr-3">
|
||||
@@ -961,13 +962,15 @@ class NoteView extends PureComponent<NoteViewProps, State> {
|
||||
</div>
|
||||
<div className="mr-3">
|
||||
<PinNoteButton
|
||||
viewControllerManager={this.viewControllerManager}
|
||||
notesController={this.viewControllerManager.notesController}
|
||||
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
|
||||
/>
|
||||
</div>
|
||||
<NotesOptionsPanel
|
||||
application={this.application}
|
||||
viewControllerManager={this.viewControllerManager}
|
||||
navigationController={this.viewControllerManager.navigationController}
|
||||
notesController={this.viewControllerManager.notesController}
|
||||
noteTagsController={this.viewControllerManager.noteTagsController}
|
||||
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
import { ViewControllerManager } from '@/Services/ViewControllerManager'
|
||||
import { useCloseOnBlur } from '@/Hooks/useCloseOnBlur'
|
||||
import { useCloseOnClickOutside } from '@/Hooks/useCloseOnClickOutside'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import NotesOptions from '@/Components/NotesOptions/NotesOptions'
|
||||
import { useCallback, useEffect, useRef } from 'react'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { NotesController } from '@/Controllers/NotesController'
|
||||
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
|
||||
import { NoteTagsController } from '@/Controllers/NoteTagsController'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
viewControllerManager: ViewControllerManager
|
||||
navigationController: NavigationController
|
||||
notesController: NotesController
|
||||
noteTagsController: NoteTagsController
|
||||
}
|
||||
|
||||
const NotesContextMenu = ({ application, viewControllerManager }: Props) => {
|
||||
const { contextMenuOpen, contextMenuPosition, contextMenuMaxHeight } = viewControllerManager.notesController
|
||||
const NotesContextMenu = ({ application, navigationController, notesController, noteTagsController }: Props) => {
|
||||
const { contextMenuOpen, contextMenuPosition, contextMenuMaxHeight } = notesController
|
||||
|
||||
const contextMenuRef = useRef<HTMLDivElement>(null)
|
||||
const [closeOnBlur] = useCloseOnBlur(contextMenuRef, (open: boolean) =>
|
||||
viewControllerManager.notesController.setContextMenuOpen(open),
|
||||
)
|
||||
const [closeOnBlur] = useCloseOnBlur(contextMenuRef, (open: boolean) => notesController.setContextMenuOpen(open))
|
||||
|
||||
useCloseOnClickOutside(contextMenuRef, () => viewControllerManager.notesController.setContextMenuOpen(false))
|
||||
useCloseOnClickOutside(contextMenuRef, () => notesController.setContextMenuOpen(false))
|
||||
|
||||
const reloadContextMenuLayout = useCallback(() => {
|
||||
viewControllerManager.notesController.reloadContextMenuLayout()
|
||||
}, [viewControllerManager])
|
||||
notesController.reloadContextMenuLayout()
|
||||
}, [notesController])
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', reloadContextMenuLayout)
|
||||
@@ -41,7 +43,13 @@ const NotesContextMenu = ({ application, viewControllerManager }: Props) => {
|
||||
maxHeight: contextMenuMaxHeight,
|
||||
}}
|
||||
>
|
||||
<NotesOptions application={application} viewControllerManager={viewControllerManager} closeOnBlur={closeOnBlur} />
|
||||
<NotesOptions
|
||||
application={application}
|
||||
closeOnBlur={closeOnBlur}
|
||||
navigationController={navigationController}
|
||||
notesController={notesController}
|
||||
noteTagsController={noteTagsController}
|
||||
/>
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import { ViewControllerManager } from '@/Services/ViewControllerManager'
|
||||
import { calculateSubmenuStyle, SubmenuStyle } from '@/Utils/CalculateSubmenuStyle'
|
||||
import { Disclosure, DisclosureButton, DisclosurePanel } from '@reach/disclosure'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import { useCloseOnBlur } from '@/Hooks/useCloseOnBlur'
|
||||
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
|
||||
import { NotesController } from '@/Controllers/NotesController'
|
||||
import { NoteTagsController } from '@/Controllers/NoteTagsController'
|
||||
|
||||
type Props = {
|
||||
viewControllerManager: ViewControllerManager
|
||||
navigationController: NavigationController
|
||||
notesController: NotesController
|
||||
noteTagsController: NoteTagsController
|
||||
}
|
||||
|
||||
const AddTagOption: FunctionComponent<Props> = ({ viewControllerManager }) => {
|
||||
const AddTagOption: FunctionComponent<Props> = ({ navigationController, notesController, noteTagsController }) => {
|
||||
const menuContainerRef = useRef<HTMLDivElement>(null)
|
||||
const menuRef = useRef<HTMLDivElement>(null)
|
||||
const menuButtonRef = useRef<HTMLButtonElement>(null)
|
||||
@@ -84,22 +88,22 @@ const AddTagOption: FunctionComponent<Props> = ({ viewControllerManager }) => {
|
||||
}}
|
||||
className="sn-dropdown min-w-80 flex flex-col py-2 max-h-120 max-w-xs fixed overflow-y-auto"
|
||||
>
|
||||
{viewControllerManager.navigationController.tags.map((tag) => (
|
||||
{navigationController.tags.map((tag) => (
|
||||
<button
|
||||
key={tag.uuid}
|
||||
className="sn-dropdown-item sn-dropdown-item--no-icon max-w-80"
|
||||
onBlur={closeOnBlur}
|
||||
onClick={() => {
|
||||
viewControllerManager.notesController.isTagInSelectedNotes(tag)
|
||||
? viewControllerManager.notesController.removeTagFromSelectedNotes(tag).catch(console.error)
|
||||
: viewControllerManager.notesController.addTagToSelectedNotes(tag).catch(console.error)
|
||||
notesController.isTagInSelectedNotes(tag)
|
||||
? notesController.removeTagFromSelectedNotes(tag).catch(console.error)
|
||||
: notesController.addTagToSelectedNotes(tag).catch(console.error)
|
||||
}}
|
||||
>
|
||||
<span
|
||||
className={`whitespace-nowrap overflow-hidden overflow-ellipsis
|
||||
${viewControllerManager.notesController.isTagInSelectedNotes(tag) ? 'font-bold' : ''}`}
|
||||
${notesController.isTagInSelectedNotes(tag) ? 'font-bold' : ''}`}
|
||||
>
|
||||
{viewControllerManager.noteTagsController.getLongTitle(tag)}
|
||||
{noteTagsController.getLongTitle(tag)}
|
||||
</span>
|
||||
</button>
|
||||
))}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { KeyboardKey } from '@/Services/IOService'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { ViewControllerManager } from '@/Services/ViewControllerManager'
|
||||
import { Disclosure, DisclosureButton, DisclosurePanel } from '@reach/disclosure'
|
||||
import { SNNote } from '@standardnotes/snjs'
|
||||
import { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react'
|
||||
@@ -10,7 +9,6 @@ import { calculateSubmenuStyle, SubmenuStyle } from '@/Utils/CalculateSubmenuSty
|
||||
import { useCloseOnBlur } from '@/Hooks/useCloseOnBlur'
|
||||
|
||||
type ChangeEditorOptionProps = {
|
||||
viewControllerManager: ViewControllerManager
|
||||
application: WebApplication
|
||||
note: SNNote
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { ViewControllerManager } from '@/Services/ViewControllerManager'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import Switch from '@/Components/Switch/Switch'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useState, useEffect, useMemo, useCallback, FunctionComponent } from 'react'
|
||||
import { SNApplication, SNNote } from '@standardnotes/snjs'
|
||||
import { SNApplication, SNComponent, SNNote } from '@standardnotes/snjs'
|
||||
import { KeyboardModifier } from '@/Services/IOService'
|
||||
import ChangeEditorOption from './ChangeEditorOption'
|
||||
import { BYTES_IN_ONE_MEGABYTE } from '@/Constants/Constants'
|
||||
@@ -11,6 +10,7 @@ import ListedActionsOption from './ListedActionsOption'
|
||||
import AddTagOption from './AddTagOption'
|
||||
import { addToast, dismissToast, ToastType } from '@standardnotes/stylekit'
|
||||
import { NotesOptionsProps } from './NotesOptionsProps'
|
||||
import { NotesController } from '@/Controllers/NotesController'
|
||||
|
||||
type DeletePermanentlyButtonProps = {
|
||||
closeOnBlur: NotesOptionsProps['closeOnBlur']
|
||||
@@ -121,15 +121,15 @@ const NoteAttributes: FunctionComponent<{
|
||||
}
|
||||
|
||||
const SpellcheckOptions: FunctionComponent<{
|
||||
viewControllerManager: ViewControllerManager
|
||||
editorForNote: SNComponent | undefined
|
||||
notesController: NotesController
|
||||
note: SNNote
|
||||
}> = ({ viewControllerManager, note }) => {
|
||||
const editor = viewControllerManager.application.componentManager.editorForNote(note)
|
||||
const spellcheckControllable = Boolean(!editor || editor.package_info.spellcheckControl)
|
||||
}> = ({ editorForNote, notesController, note }) => {
|
||||
const spellcheckControllable = Boolean(!editorForNote || editorForNote.package_info.spellcheckControl)
|
||||
const noteSpellcheck = !spellcheckControllable
|
||||
? true
|
||||
: note
|
||||
? viewControllerManager.notesController.getSpellcheckStateForNote(note)
|
||||
? notesController.getSpellcheckStateForNote(note)
|
||||
: undefined
|
||||
|
||||
return (
|
||||
@@ -137,7 +137,7 @@ const SpellcheckOptions: FunctionComponent<{
|
||||
<button
|
||||
className="sn-dropdown-item justify-between px-3 py-1"
|
||||
onClick={() => {
|
||||
viewControllerManager.notesController.toggleGlobalSpellcheckForNote(note).catch(console.error)
|
||||
notesController.toggleGlobalSpellcheckForNote(note).catch(console.error)
|
||||
}}
|
||||
disabled={!spellcheckControllable}
|
||||
>
|
||||
@@ -169,7 +169,13 @@ const NoteSizeWarning: FunctionComponent<{
|
||||
) : null
|
||||
}
|
||||
|
||||
const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: NotesOptionsProps) => {
|
||||
const NotesOptions = ({
|
||||
application,
|
||||
navigationController,
|
||||
notesController,
|
||||
noteTagsController,
|
||||
closeOnBlur,
|
||||
}: NotesOptionsProps) => {
|
||||
const [altKeyDown, setAltKeyDown] = useState(false)
|
||||
|
||||
const toggleOn = (condition: (note: SNNote) => boolean) => {
|
||||
@@ -178,7 +184,7 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
return notesMatchingAttribute.length > notesNotMatchingAttribute.length
|
||||
}
|
||||
|
||||
const notes = viewControllerManager.notesController.selectedNotes
|
||||
const notes = notesController.selectedNotes
|
||||
const hidePreviews = toggleOn((note) => note.hidePreview)
|
||||
const locked = toggleOn((note) => note.locked)
|
||||
const protect = toggleOn((note) => note.protected)
|
||||
@@ -189,6 +195,11 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
const pinned = notes.some((note) => note.pinned)
|
||||
const unpinned = notes.some((note) => !note.pinned)
|
||||
|
||||
const editorForNote = useMemo(
|
||||
() => application.componentManager.editorForNote(notes[0]),
|
||||
[application.componentManager, notes],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const removeAltKeyObserver = application.io.addKeyObserver({
|
||||
modifiers: [KeyboardModifier.Alt],
|
||||
@@ -248,8 +259,8 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
}, [application, notes])
|
||||
|
||||
const openRevisionHistoryModal = useCallback(() => {
|
||||
viewControllerManager.notesController.setShowRevisionHistoryModal(true)
|
||||
}, [viewControllerManager])
|
||||
notesController.setShowRevisionHistoryModal(true)
|
||||
}, [notesController])
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -265,7 +276,7 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
<button
|
||||
className="sn-dropdown-item justify-between"
|
||||
onClick={() => {
|
||||
viewControllerManager.notesController.setLockSelectedNotes(!locked)
|
||||
notesController.setLockSelectedNotes(!locked)
|
||||
}}
|
||||
onBlur={closeOnBlur}
|
||||
>
|
||||
@@ -278,7 +289,7 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
<button
|
||||
className="sn-dropdown-item justify-between"
|
||||
onClick={() => {
|
||||
viewControllerManager.notesController.setHideSelectedNotePreviews(!hidePreviews)
|
||||
notesController.setHideSelectedNotePreviews(!hidePreviews)
|
||||
}}
|
||||
onBlur={closeOnBlur}
|
||||
>
|
||||
@@ -291,7 +302,7 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
<button
|
||||
className="sn-dropdown-item justify-between"
|
||||
onClick={() => {
|
||||
viewControllerManager.notesController.setProtectSelectedNotes(!protect).catch(console.error)
|
||||
notesController.setProtectSelectedNotes(!protect).catch(console.error)
|
||||
}}
|
||||
onBlur={closeOnBlur}
|
||||
>
|
||||
@@ -304,19 +315,23 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
{notes.length === 1 && (
|
||||
<>
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
<ChangeEditorOption viewControllerManager={viewControllerManager} application={application} note={notes[0]} />
|
||||
<ChangeEditorOption application={application} note={notes[0]} />
|
||||
</>
|
||||
)}
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
{viewControllerManager.navigationController.tagsCount > 0 && (
|
||||
<AddTagOption viewControllerManager={viewControllerManager} />
|
||||
{navigationController.tagsCount > 0 && (
|
||||
<AddTagOption
|
||||
navigationController={navigationController}
|
||||
notesController={notesController}
|
||||
noteTagsController={noteTagsController}
|
||||
/>
|
||||
)}
|
||||
{unpinned && (
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={() => {
|
||||
viewControllerManager.notesController.setPinSelectedNotes(true)
|
||||
notesController.setPinSelectedNotes(true)
|
||||
}}
|
||||
>
|
||||
<Icon type="pin" className={iconClass} />
|
||||
@@ -328,7 +343,7 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={() => {
|
||||
viewControllerManager.notesController.setPinSelectedNotes(false)
|
||||
notesController.setPinSelectedNotes(false)
|
||||
}}
|
||||
>
|
||||
<Icon type="unpin" className={iconClass} />
|
||||
@@ -348,7 +363,7 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={() => {
|
||||
viewControllerManager.notesController.setArchiveSelectedNotes(true).catch(console.error)
|
||||
notesController.setArchiveSelectedNotes(true).catch(console.error)
|
||||
}}
|
||||
>
|
||||
<Icon type="archive" className={iconClassWarning} />
|
||||
@@ -360,7 +375,7 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={() => {
|
||||
viewControllerManager.notesController.setArchiveSelectedNotes(false).catch(console.error)
|
||||
notesController.setArchiveSelectedNotes(false).catch(console.error)
|
||||
}}
|
||||
>
|
||||
<Icon type="unarchive" className={iconClassWarning} />
|
||||
@@ -372,7 +387,7 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
<DeletePermanentlyButton
|
||||
closeOnBlur={closeOnBlur}
|
||||
onClick={async () => {
|
||||
await viewControllerManager.notesController.deleteNotesPermanently()
|
||||
await notesController.deleteNotesPermanently()
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
@@ -380,7 +395,7 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={async () => {
|
||||
await viewControllerManager.notesController.setTrashSelectedNotes(true)
|
||||
await notesController.setTrashSelectedNotes(true)
|
||||
}}
|
||||
>
|
||||
<Icon type="trash" className={iconClassDanger} />
|
||||
@@ -393,7 +408,7 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={async () => {
|
||||
await viewControllerManager.notesController.setTrashSelectedNotes(false)
|
||||
await notesController.setTrashSelectedNotes(false)
|
||||
}}
|
||||
>
|
||||
<Icon type="restore" className={iconClassSuccess} />
|
||||
@@ -402,21 +417,21 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
<DeletePermanentlyButton
|
||||
closeOnBlur={closeOnBlur}
|
||||
onClick={async () => {
|
||||
await viewControllerManager.notesController.deleteNotesPermanently()
|
||||
await notesController.deleteNotesPermanently()
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
onBlur={closeOnBlur}
|
||||
className="sn-dropdown-item"
|
||||
onClick={async () => {
|
||||
await viewControllerManager.notesController.emptyTrash()
|
||||
await notesController.emptyTrash()
|
||||
}}
|
||||
>
|
||||
<div className="flex items-start">
|
||||
<Icon type="trash-sweep" className="color-danger mr-2" />
|
||||
<div className="flex-row">
|
||||
<div className="color-danger">Empty Trash</div>
|
||||
<div className="text-xs">{viewControllerManager.notesController.trashedNotesCount} notes in Trash</div>
|
||||
<div className="text-xs">{notesController.trashedNotesCount} notes in Trash</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
@@ -427,7 +442,7 @@ const NotesOptions = ({ application, viewControllerManager, closeOnBlur }: Notes
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
<ListedActionsOption application={application} note={notes[0]} />
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
<SpellcheckOptions viewControllerManager={viewControllerManager} note={notes[0]} />
|
||||
<SpellcheckOptions editorForNote={editorForNote} notesController={notesController} note={notes[0]} />
|
||||
<div className="min-h-1px my-2 bg-border"></div>
|
||||
<NoteAttributes application={application} note={notes[0]} />
|
||||
<NoteSizeWarning note={notes[0]} />
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { ViewControllerManager } from '@/Services/ViewControllerManager'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import VisuallyHidden from '@reach/visually-hidden'
|
||||
import { useCloseOnBlur } from '@/Hooks/useCloseOnBlur'
|
||||
@@ -8,14 +7,25 @@ import { observer } from 'mobx-react-lite'
|
||||
import NotesOptions from './NotesOptions'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/Constants/Constants'
|
||||
import { NotesController } from '@/Controllers/NotesController'
|
||||
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
|
||||
import { NoteTagsController } from '@/Controllers/NoteTagsController'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
viewControllerManager: ViewControllerManager
|
||||
navigationController: NavigationController
|
||||
notesController: NotesController
|
||||
noteTagsController: NoteTagsController
|
||||
onClickPreprocessing?: () => Promise<void>
|
||||
}
|
||||
|
||||
const NotesOptionsPanel = ({ application, viewControllerManager, onClickPreprocessing }: Props) => {
|
||||
const NotesOptionsPanel = ({
|
||||
application,
|
||||
navigationController,
|
||||
notesController,
|
||||
noteTagsController,
|
||||
onClickPreprocessing,
|
||||
}: Props) => {
|
||||
const [open, setOpen] = useState(false)
|
||||
const [position, setPosition] = useState({
|
||||
top: 0,
|
||||
@@ -82,7 +92,9 @@ const NotesOptionsPanel = ({ application, viewControllerManager, onClickPreproce
|
||||
{open && (
|
||||
<NotesOptions
|
||||
application={application}
|
||||
viewControllerManager={viewControllerManager}
|
||||
navigationController={navigationController}
|
||||
notesController={notesController}
|
||||
noteTagsController={noteTagsController}
|
||||
closeOnBlur={closeOnBlur}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { ViewControllerManager } from '@/Services/ViewControllerManager'
|
||||
import { NavigationController } from '@/Controllers/Navigation/NavigationController'
|
||||
import { NotesController } from '@/Controllers/NotesController'
|
||||
import { NoteTagsController } from '@/Controllers/NoteTagsController'
|
||||
|
||||
export type NotesOptionsProps = {
|
||||
application: WebApplication
|
||||
viewControllerManager: ViewControllerManager
|
||||
navigationController: NavigationController
|
||||
notesController: NotesController
|
||||
noteTagsController: NoteTagsController
|
||||
closeOnBlur: (event: { relatedTarget: EventTarget | null }) => void
|
||||
}
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
import { ViewControllerManager } from '@/Services/ViewControllerManager'
|
||||
import VisuallyHidden from '@reach/visually-hidden'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { FunctionComponent, useCallback } from 'react'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import { NotesController } from '@/Controllers/NotesController'
|
||||
|
||||
type Props = {
|
||||
viewControllerManager: ViewControllerManager
|
||||
className?: string
|
||||
notesController: NotesController
|
||||
onClickPreprocessing?: () => Promise<void>
|
||||
}
|
||||
|
||||
const PinNoteButton: FunctionComponent<Props> = ({
|
||||
viewControllerManager,
|
||||
className = '',
|
||||
onClickPreprocessing,
|
||||
}: Props) => {
|
||||
const notes = viewControllerManager.notesController.selectedNotes
|
||||
const PinNoteButton: FunctionComponent<Props> = ({ className = '', notesController, onClickPreprocessing }: Props) => {
|
||||
const notes = notesController.selectedNotes
|
||||
const pinned = notes.some((note) => note.pinned)
|
||||
|
||||
const togglePinned = useCallback(async () => {
|
||||
@@ -23,11 +19,11 @@ const PinNoteButton: FunctionComponent<Props> = ({
|
||||
await onClickPreprocessing()
|
||||
}
|
||||
if (!pinned) {
|
||||
viewControllerManager.notesController.setPinSelectedNotes(true)
|
||||
notesController.setPinSelectedNotes(true)
|
||||
} else {
|
||||
viewControllerManager.notesController.setPinSelectedNotes(false)
|
||||
notesController.setPinSelectedNotes(false)
|
||||
}
|
||||
}, [viewControllerManager, onClickPreprocessing, pinned])
|
||||
}, [onClickPreprocessing, pinned, notesController])
|
||||
|
||||
return (
|
||||
<button className={`sn-icon-button border-contrast ${pinned ? 'toggled' : ''} ${className}`} onClick={togglePinned}>
|
||||
|
||||
Reference in New Issue
Block a user