feat: Added "Find in note" option to note options/context menu for Super notes
This commit is contained in:
@@ -8,7 +8,6 @@ import {
|
|||||||
PIN_NOTE_COMMAND,
|
PIN_NOTE_COMMAND,
|
||||||
SHOW_HIDDEN_OPTIONS_KEYBOARD_COMMAND,
|
SHOW_HIDDEN_OPTIONS_KEYBOARD_COMMAND,
|
||||||
STAR_NOTE_COMMAND,
|
STAR_NOTE_COMMAND,
|
||||||
SUPER_SHOW_MARKDOWN_PREVIEW,
|
|
||||||
} from '@standardnotes/ui-services'
|
} from '@standardnotes/ui-services'
|
||||||
import ChangeEditorOption from './ChangeEditorOption'
|
import ChangeEditorOption from './ChangeEditorOption'
|
||||||
import ListedActionsOption from './Listed/ListedActionsOption'
|
import ListedActionsOption from './Listed/ListedActionsOption'
|
||||||
@@ -24,7 +23,6 @@ import { KeyboardShortcutIndicator } from '../KeyboardShortcutIndicator/Keyboard
|
|||||||
import { NoteAttributes } from './NoteAttributes'
|
import { NoteAttributes } from './NoteAttributes'
|
||||||
import { SpellcheckOptions } from './SpellcheckOptions'
|
import { SpellcheckOptions } from './SpellcheckOptions'
|
||||||
import { NoteSizeWarning } from './NoteSizeWarning'
|
import { NoteSizeWarning } from './NoteSizeWarning'
|
||||||
import { useCommandService } from '../CommandProvider'
|
|
||||||
import { iconClass } from './ClassNames'
|
import { iconClass } from './ClassNames'
|
||||||
import SuperNoteOptions from './SuperNoteOptions'
|
import SuperNoteOptions from './SuperNoteOptions'
|
||||||
import MenuSwitchButtonItem from '../Menu/MenuSwitchButtonItem'
|
import MenuSwitchButtonItem from '../Menu/MenuSwitchButtonItem'
|
||||||
@@ -48,12 +46,6 @@ const NotesOptions = ({ notes, closeMenu }: NotesOptionsProps) => {
|
|||||||
|
|
||||||
const [altKeyDown, setAltKeyDown] = useState(false)
|
const [altKeyDown, setAltKeyDown] = useState(false)
|
||||||
const { toggleAppPane } = useResponsiveAppPane()
|
const { toggleAppPane } = useResponsiveAppPane()
|
||||||
const commandService = useCommandService()
|
|
||||||
|
|
||||||
const markdownShortcut = useMemo(
|
|
||||||
() => commandService.keyboardShortcutForCommand(SUPER_SHOW_MARKDOWN_PREVIEW),
|
|
||||||
[commandService],
|
|
||||||
)
|
|
||||||
|
|
||||||
const toggleOn = (condition: (note: SNNote) => boolean) => {
|
const toggleOn = (condition: (note: SNNote) => boolean) => {
|
||||||
const notesMatchingAttribute = notes.filter(condition)
|
const notesMatchingAttribute = notes.filter(condition)
|
||||||
@@ -213,10 +205,6 @@ const NotesOptions = ({ notes, closeMenu }: NotesOptionsProps) => {
|
|||||||
[application],
|
[application],
|
||||||
)
|
)
|
||||||
|
|
||||||
const enableSuperMarkdownPreview = useCallback(() => {
|
|
||||||
commandService.triggerCommand(SUPER_SHOW_MARKDOWN_PREVIEW)
|
|
||||||
}, [commandService])
|
|
||||||
|
|
||||||
const toggleLineWidthModal = useCallback(() => {
|
const toggleLineWidthModal = useCallback(() => {
|
||||||
application.keyboardService.triggerCommand(CHANGE_EDITOR_WIDTH_COMMAND)
|
application.keyboardService.triggerCommand(CHANGE_EDITOR_WIDTH_COMMAND)
|
||||||
}, [application.keyboardService])
|
}, [application.keyboardService])
|
||||||
@@ -468,13 +456,7 @@ const NotesOptions = ({ notes, closeMenu }: NotesOptionsProps) => {
|
|||||||
|
|
||||||
{notes.length === 1 && (
|
{notes.length === 1 && (
|
||||||
<>
|
<>
|
||||||
{notes[0].noteType === NoteType.Super && (
|
{notes[0].noteType === NoteType.Super && <SuperNoteOptions closeMenu={closeMenu} />}
|
||||||
<SuperNoteOptions
|
|
||||||
note={notes[0]}
|
|
||||||
markdownShortcut={markdownShortcut}
|
|
||||||
enableSuperMarkdownPreview={enableSuperMarkdownPreview}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!areSomeNotesInSharedVault && (
|
{!areSomeNotesInSharedVault && (
|
||||||
<MenuSection>
|
<MenuSection>
|
||||||
|
|||||||
@@ -1,20 +1,42 @@
|
|||||||
import { SNNote } from '@standardnotes/snjs'
|
|
||||||
import { PlatformedKeyboardShortcut } from '@standardnotes/ui-services'
|
|
||||||
import Icon from '../Icon/Icon'
|
import Icon from '../Icon/Icon'
|
||||||
import { KeyboardShortcutIndicator } from '../KeyboardShortcutIndicator/KeyboardShortcutIndicator'
|
import { KeyboardShortcutIndicator } from '../KeyboardShortcutIndicator/KeyboardShortcutIndicator'
|
||||||
import MenuItem from '../Menu/MenuItem'
|
import MenuItem from '../Menu/MenuItem'
|
||||||
import { iconClass } from './ClassNames'
|
import { iconClass } from './ClassNames'
|
||||||
import MenuSection from '../Menu/MenuSection'
|
import MenuSection from '../Menu/MenuSection'
|
||||||
|
import { SUPER_SHOW_MARKDOWN_PREVIEW, SUPER_TOGGLE_SEARCH } from '@standardnotes/ui-services'
|
||||||
|
import { useMemo, useCallback } from 'react'
|
||||||
|
import { useCommandService } from '../CommandProvider'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
note: SNNote
|
closeMenu: () => void
|
||||||
markdownShortcut?: PlatformedKeyboardShortcut
|
|
||||||
enableSuperMarkdownPreview: () => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SuperNoteOptions = ({ markdownShortcut, enableSuperMarkdownPreview }: Props) => {
|
const SuperNoteOptions = ({ closeMenu }: Props) => {
|
||||||
|
const commandService = useCommandService()
|
||||||
|
|
||||||
|
const markdownShortcut = useMemo(
|
||||||
|
() => commandService.keyboardShortcutForCommand(SUPER_SHOW_MARKDOWN_PREVIEW),
|
||||||
|
[commandService],
|
||||||
|
)
|
||||||
|
|
||||||
|
const findShortcut = useMemo(() => commandService.keyboardShortcutForCommand(SUPER_TOGGLE_SEARCH), [commandService])
|
||||||
|
|
||||||
|
const enableSuperMarkdownPreview = useCallback(() => {
|
||||||
|
commandService.triggerCommand(SUPER_SHOW_MARKDOWN_PREVIEW)
|
||||||
|
}, [commandService])
|
||||||
|
|
||||||
|
const findInNote = useCallback(() => {
|
||||||
|
commandService.triggerCommand(SUPER_TOGGLE_SEARCH)
|
||||||
|
closeMenu()
|
||||||
|
}, [closeMenu, commandService])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuSection>
|
<MenuSection>
|
||||||
|
<MenuItem onClick={findInNote}>
|
||||||
|
<Icon type="search" className={iconClass} />
|
||||||
|
Find in note
|
||||||
|
{findShortcut && <KeyboardShortcutIndicator className="ml-auto" shortcut={findShortcut} />}
|
||||||
|
</MenuItem>
|
||||||
<MenuItem onClick={enableSuperMarkdownPreview}>
|
<MenuItem onClick={enableSuperMarkdownPreview}>
|
||||||
<Icon type="markdown" className={iconClass} />
|
<Icon type="markdown" className={iconClass} />
|
||||||
Show Markdown
|
Show Markdown
|
||||||
|
|||||||
@@ -14,8 +14,11 @@ import {
|
|||||||
import { classNames } from '@standardnotes/utils'
|
import { classNames } from '@standardnotes/utils'
|
||||||
import { useCallback, useMemo, useState } from 'react'
|
import { useCallback, useMemo, useState } from 'react'
|
||||||
import { useSuperSearchContext } from './Context'
|
import { useSuperSearchContext } from './Context'
|
||||||
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||||
|
|
||||||
export const SearchDialog = ({ open, closeDialog }: { open: boolean; closeDialog: () => void }) => {
|
export const SearchDialog = ({ open, closeDialog }: { open: boolean; closeDialog: () => void }) => {
|
||||||
|
const [editor] = useLexicalComposerContext()
|
||||||
|
|
||||||
const { query, results, currentResultIndex, isCaseSensitive, isReplaceMode, dispatch, dispatchReplaceEvent } =
|
const { query, results, currentResultIndex, isCaseSensitive, isReplaceMode, dispatch, dispatchReplaceEvent } =
|
||||||
useSuperSearchContext()
|
useSuperSearchContext()
|
||||||
|
|
||||||
@@ -53,22 +56,27 @@ export const SearchDialog = ({ open, closeDialog }: { open: boolean; closeDialog
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="absolute right-6 top-13 z-10 flex select-none rounded border border-border bg-default"
|
className={classNames(
|
||||||
|
'absolute left-2 right-6 top-2 z-10 flex select-none rounded border border-border bg-default md:left-auto',
|
||||||
|
editor.isEditable() ? 'md:top-13' : 'md:top-3',
|
||||||
|
)}
|
||||||
ref={setElement}
|
ref={setElement}
|
||||||
>
|
>
|
||||||
<button
|
{editor.isEditable() && (
|
||||||
className="focus:ring-none border-r border-border px-1 hover:bg-contrast focus:shadow-inner focus:shadow-info"
|
<button
|
||||||
onClick={() => {
|
className="focus:ring-none border-r border-border px-1 hover:bg-contrast focus:shadow-inner focus:shadow-info"
|
||||||
dispatch({ type: 'toggle-replace-mode' })
|
onClick={() => {
|
||||||
}}
|
dispatch({ type: 'toggle-replace-mode' })
|
||||||
title={`Toggle Replace Mode (${toggleReplaceShortcut})`}
|
}}
|
||||||
>
|
title={`Toggle Replace Mode (${toggleReplaceShortcut})`}
|
||||||
{isReplaceMode ? (
|
>
|
||||||
<ArrowDownIcon className="h-4 w-4 fill-text" />
|
{isReplaceMode ? (
|
||||||
) : (
|
<ArrowDownIcon className="h-4 w-4 fill-text" />
|
||||||
<ArrowRightIcon className="h-4 w-4 fill-text" />
|
) : (
|
||||||
)}
|
<ArrowRightIcon className="h-4 w-4 fill-text" />
|
||||||
</button>
|
)}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
className="flex flex-col gap-2 px-2 py-2"
|
className="flex flex-col gap-2 px-2 py-2"
|
||||||
onKeyDown={(event) => {
|
onKeyDown={(event) => {
|
||||||
@@ -171,7 +179,7 @@ export const SearchDialog = ({ open, closeDialog }: { open: boolean; closeDialog
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{isReplaceMode && (
|
{isReplaceMode && (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2 md:flex-nowrap">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Replace"
|
placeholder="Replace"
|
||||||
|
|||||||
@@ -28,26 +28,15 @@ export const SearchPlugin = () => {
|
|||||||
const resultsRef = useStateRef(results)
|
const resultsRef = useStateRef(results)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const isFocusInEditor = () => {
|
|
||||||
if (!document.activeElement || !document.activeElement.closest('.blocks-editor')) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return application.keyboardService.addCommandHandlers([
|
return application.keyboardService.addCommandHandlers([
|
||||||
{
|
{
|
||||||
command: SUPER_TOGGLE_SEARCH,
|
command: SUPER_TOGGLE_SEARCH,
|
||||||
category: 'Super notes',
|
category: 'Super notes',
|
||||||
description: 'Search in current note',
|
description: 'Search in current note',
|
||||||
onKeyDown: (event) => {
|
onKeyDown: (event) => {
|
||||||
if (!isFocusInEditor()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
dispatch({ type: 'toggle-search' })
|
dispatch({ type: 'toggle-search' })
|
||||||
editor.focus()
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -55,7 +44,7 @@ export const SearchPlugin = () => {
|
|||||||
category: 'Super notes',
|
category: 'Super notes',
|
||||||
description: 'Search and replace in current note',
|
description: 'Search and replace in current note',
|
||||||
onKeyDown: (event) => {
|
onKeyDown: (event) => {
|
||||||
if (!isFocusInEditor()) {
|
if (!editor.isEditable()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
@@ -66,9 +55,6 @@ export const SearchPlugin = () => {
|
|||||||
{
|
{
|
||||||
command: SUPER_SEARCH_TOGGLE_CASE_SENSITIVE,
|
command: SUPER_SEARCH_TOGGLE_CASE_SENSITIVE,
|
||||||
onKeyDown() {
|
onKeyDown() {
|
||||||
if (!isFocusInEditor()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'toggle-case-sensitive',
|
type: 'toggle-case-sensitive',
|
||||||
})
|
})
|
||||||
@@ -79,9 +65,6 @@ export const SearchPlugin = () => {
|
|||||||
category: 'Super notes',
|
category: 'Super notes',
|
||||||
description: 'Go to next search result',
|
description: 'Go to next search result',
|
||||||
onKeyDown(event) {
|
onKeyDown(event) {
|
||||||
if (!isFocusInEditor()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
dispatch({
|
dispatch({
|
||||||
@@ -94,9 +77,6 @@ export const SearchPlugin = () => {
|
|||||||
category: 'Super notes',
|
category: 'Super notes',
|
||||||
description: 'Go to previous search result',
|
description: 'Go to previous search result',
|
||||||
onKeyDown(event) {
|
onKeyDown(event) {
|
||||||
if (!isFocusInEditor()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|||||||
Reference in New Issue
Block a user