Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add inputs to balloon toolbar for new child note/snippet #426

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/components/toast/showOpenToasts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react'
import InteractiveToast from '@ui/components/InteractiveToast'
import toast from 'react-hot-toast'
import { useNavigation } from '@hooks/useNavigation'
import { NavigationType, ROUTE_PATHS, useRouting } from '@views/routes/urls'
import { useSnippetStore } from '@store/useSnippetStore'

export const useOpenToast = () => {
const { push } = useNavigation()
const { goTo } = useRouting()
const loadSnippet = useSnippetStore((store) => store.loadSnippet)

const openNoteToast = (nodeid: string, title: string) => {
toast.custom((t) => (
<InteractiveToast
tid={t.id}
message={`Created new note: ${title}`}
actionName="Open"
onClick={() => {
push(nodeid)
goTo(ROUTE_PATHS.node, NavigationType.push, nodeid)
// console.log('We are here')
}}
/>
))
}

const openSnippetToast = (snippetid: string, title: string) => {
toast.custom((t) => (
<InteractiveToast
tid={t.id}
message={`Created new snippet: ${title}`}
actionName="Open"
onClick={() => {
loadSnippet(snippetid)
goTo(ROUTE_PATHS.snippet, NavigationType.push, snippetid)
// console.log('We are here')
}}
/>
))
}

return { openNoteToast, openSnippetToast }
}
12 changes: 12 additions & 0 deletions src/editor/Components/BalloonToolbar/BalloonToolbar.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,15 @@ export const BalloonToolbarBase = styled(ToolbarBase)<BalloonToolbarProps>`
border-radius: ${({ theme }) => theme.borderRadius.tiny};
}
`

export const BalloonToolbarInputWrapper = styled.div`
display: flex;
align-items: center;
gap: ${({ theme }) => theme.spacing.small};
padding: ${({ theme }) => theme.spacing.tiny};

svg {
width: 1.2rem;
height: 1.2rem;
}
`
Original file line number Diff line number Diff line change
@@ -1,24 +1,76 @@
import { ToolbarButton, ToolbarButtonProps } from '@udecode/plate'
import { getPreventDefaultHandler, usePlateEditorState } from '@udecode/plate-core'
import React from 'react'
import React, { useEffect } from 'react'
import { useTransform } from './useTransform'
import fileList2Line from '@iconify/icons-ri/file-list-2-line'

import { BalloonToolbarInputWrapper, useBalloonToolbarStore } from '../../BalloonToolbar'
import quillPenLine from '@iconify/icons-ri/quill-pen-line'
import { Icon } from '@iconify/react'
import { Input } from '@style/Form'

/**
* Toolbar button to Create new note from editor selection
*/
export const SelectionToNode = ({ ...props }: ToolbarButtonProps) => {
const editor = usePlateEditorState()!
const { selectionToNode, isConvertable } = useTransform()
const { isConvertable } = useTransform()
const setToolbarState = useBalloonToolbarStore((s) => s.setToolbarState)

return (
<ToolbarButton
disabled={!!editor?.selection && isConvertable(editor)}
onMouseDown={
!!editor?.selection && isConvertable(editor) ? getPreventDefaultHandler(selectionToNode, editor) : undefined
!!editor?.selection && isConvertable(editor)
? getPreventDefaultHandler(() => setToolbarState('new-note'))
: undefined
}
// Fade out when sync is selected
styles={{ root: { opacity: !!editor?.selection && isConvertable(editor) ? 1 : 0.25 } }}
{...props}
/>
)
}

export const SelectionToNodeInput = () => {
const editor = usePlateEditorState()!
const setOpen = useBalloonToolbarStore((s) => s.setOpen)
const { selectionToNode, isConvertable } = useTransform()

const inputRef = React.useRef<HTMLInputElement>(null)

useEffect(() => {
const timeoutId = setTimeout(() => {
if (inputRef.current) {
inputRef.current.focus()
}
}, 1)
return () => clearTimeout(timeoutId)
}, [inputRef])

return (
<BalloonToolbarInputWrapper>
<Icon icon={fileList2Line} />
<Input
ref={inputRef}
placeholder="Child Note title"
onKeyDown={(e) => {
if (e.key === 'Enter') {
if (!!editor?.selection && isConvertable(editor)) {
const inputVal = e.currentTarget?.value
// console.log('We got that val', { inputVal })
if (inputVal !== '') {
selectionToNode(editor, inputVal ?? undefined)
} else selectionToNode(editor)
}
setOpen(false)
}
if (e.key === 'Escape') {
setOpen(false)
// setToolbarState('normal')
}
}}
/>
</BalloonToolbarInputWrapper>
)
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,74 @@
import { Input } from '@style/Form'
import quillPenLine from '@iconify/icons-ri/quill-pen-line'
import { BalloonToolbarInputWrapper, useBalloonToolbarStore } from '../../BalloonToolbar'
import { ToolbarButton, ToolbarButtonProps } from '@udecode/plate'
import { getPreventDefaultHandler, usePlateEditorState } from '@udecode/plate-core'
import React from 'react'
import React, { useEffect } from 'react'
import { useTransform } from './useTransform'
import { Icon } from '@iconify/react'

/**
* Toolbar button to Create new note from editor selection
*/
export const SelectionToSnippet = ({ ...props }: ToolbarButtonProps) => {
const editor = usePlateEditorState()!
const { selectionToSnippet, isConvertable } = useTransform()
const { isConvertable } = useTransform()
const setToolbarState = useBalloonToolbarStore((s) => s.setToolbarState)

return (
<ToolbarButton
disabled={!!editor?.selection && isConvertable(editor)}
onMouseDown={
!!editor?.selection && isConvertable(editor) ? getPreventDefaultHandler(selectionToSnippet, editor) : undefined
!!editor?.selection && isConvertable(editor)
? getPreventDefaultHandler(() => setToolbarState('new-snippet'))
: undefined
}
// Fade out when sync is selected
styles={{ root: { opacity: !!editor?.selection && isConvertable(editor) ? 1 : 0.25 } }}
{...props}
/>
)
}

export const SelectionToSnippetInput = () => {
const editor = usePlateEditorState()!
const setOpen = useBalloonToolbarStore((s) => s.setOpen)
const { selectionToSnippet, isConvertable } = useTransform()

const inputRef = React.useRef<HTMLInputElement>(null)

useEffect(() => {
const timeoutId = setTimeout(() => {
if (inputRef.current) {
inputRef.current.focus()
}
}, 1)
return () => clearTimeout(timeoutId)
}, [inputRef])

return (
<BalloonToolbarInputWrapper>
<Icon icon={quillPenLine} />
<Input
ref={inputRef}
placeholder="Snippet title"
onKeyDown={(e) => {
if (e.key === 'Enter') {
if (!!editor?.selection && isConvertable(editor)) {
const inputVal = e.currentTarget?.value
// console.log('We got that val', { inputVal })
if (inputVal !== '') {
selectionToSnippet(editor, inputVal ?? undefined)
} else selectionToSnippet(editor)
}
setOpen(false)
}
if (e.key === 'Escape') {
setOpen(false)
// setToolbarState('normal')
}
}}
/>
</BalloonToolbarInputWrapper>
)
}
44 changes: 23 additions & 21 deletions src/editor/Components/BalloonToolbar/components/useTransform.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
import { useOpenToast } from '@components/toast/showOpenToasts'
import { useCreateNewNote } from '@hooks/useCreateNewNote'
import { useSnippets } from '@hooks/useSnippets'
import { useToast } from '@hooks/useToast'
import { useUpdater } from '@hooks/useUpdater'
import {
getSelectionText,
insertNodes,
TEditor,
getNodeEntries,
removeNodes,
deleteText,
getPath,
withoutNormalizing
deleteText, getNodeEntries, getPath, getSelectionText,
insertNodes, removeNodes, TEditor, withoutNormalizing
} from '@udecode/plate'
import { convertValueToTasks } from '@utils/lib/contentConvertTask'
import genereateName from 'project-name-generator'
import { SEPARATOR } from '../../../../components/mex/Sidebar/treeUtils'
import { defaultContent } from '../../../../data/Defaults/baseData'
import { generateSnippetId, generateTempId } from '../../../../data/Defaults/idPrefixes'
import { useEditorStore } from '../../../../store/useEditorStore'
import { useSnippetStore } from '../../../../store/useSnippetStore'
import { NodeEditorContent } from '../../../../types/Types'
import { getSlug, NODE_PATH_CHAR_LENGTH, NODE_PATH_SPACER } from '../../../../utils/lib/strings'
import { convertContentToRawText } from '../../../../utils/search/parseData'
Expand All @@ -28,12 +21,13 @@ import { ELEMENT_QA_BLOCK } from '../../QABlock/createQAPlugin'
import { ELEMENT_SYNC_BLOCK } from '../../SyncBlock'

export const useTransform = () => {
const addSnippet = useSnippetStore((s) => s.addSnippet)
const node = useEditorStore((s) => s.node)
// const addSnippet = useSnippetStore((s) => s.addSnippet)
// const node = useEditorStore((s) => s.node)
const { openNoteToast, openSnippetToast } = useOpenToast()
const { updateSnippet } = useSnippets()
const { createNewNote } = useCreateNewNote()
const { updater } = useUpdater()
const { toast } = useToast()
// const { toast } = useToast()

// Checks whether a node is a flowblock
const isFlowBlock = (node: any): boolean => {
Expand Down Expand Up @@ -159,7 +153,7 @@ export const useTransform = () => {
* Inserts the link of new node in place of the selection
* @param editor
*/
const selectionToNode = (editor: TEditor) => {
const selectionToNode = (editor: TEditor, title?: string) => {
if (!editor.selection) return
if (!isConvertable(editor)) return

Expand All @@ -186,20 +180,27 @@ export const useTransform = () => {
return node
})
const isInline = lowest.length === 1
const putContent = selText.length > NODE_PATH_CHAR_LENGTH
const putContent = selText.length > NODE_PATH_CHAR_LENGTH && title !== undefined

const text = convertContentToRawText(value, NODE_PATH_SPACER)
const parentPath = useEditorStore.getState().node.title
const path = parentPath + SEPARATOR + (isInline ? getSlug(selText) : getSlug(text))
const parentPath = useEditorStore.getState().node.path
const namespace = useEditorStore.getState().node.namespace
const childTitle = title ?? (isInline ? getSlug(selText) : getSlug(text))
const path = parentPath + SEPARATOR + childTitle

const note = createNewNote({
path,
noteContent: putContent ? value : defaultContent.content,
namespace: node?.namespace,
namespace: namespace,
noRedirect: true
})

replaceSelectionWithLink(editor, note?.nodeid, isInline)

if (note) {
openNoteToast(note.nodeid, note.path)
}

// mog('Replace Selection with node We are here', {
// lowest,
// selText,
Expand Down Expand Up @@ -247,7 +248,7 @@ export const useTransform = () => {
* Shows notification of snippet creation
* @param editor
*/
const selectionToSnippet = (editor: TEditor) => {
const selectionToSnippet = (editor: TEditor, title?: string) => {
if (!editor.selection) return
if (!isConvertable(editor)) return

Expand All @@ -266,7 +267,7 @@ export const useTransform = () => {
})

const snippetId = generateSnippetId()
const snippetTitle = genereateName().dashed
const snippetTitle = title ?? genereateName().dashed
const newSnippet = {
id: snippetId,
title: snippetTitle,
Expand All @@ -278,8 +279,9 @@ export const useTransform = () => {
// addSnippet()

// mog('We are here', { esl: editor.selection, selectionPath, nodes, value })
//
openSnippetToast(snippetId, snippetTitle)

toast(`Snippet created [[${snippetTitle}]]`)
// setContent(nodeid, value)
// saveData()
// mog('We are here', { esl: editor.selection, selectionPath, nodes, value, text, path })
Expand Down
Loading