2023-03-23 17:47:36 +00:00
|
|
|
import { createEffect } from 'solid-js'
|
2023-03-23 17:15:50 +00:00
|
|
|
import { createTiptapEditor, useEditorHTML } from 'solid-tiptap'
|
2023-03-08 16:35:13 +00:00
|
|
|
import { useLocalize } from '../../context/localize'
|
|
|
|
import { Blockquote } from '@tiptap/extension-blockquote'
|
|
|
|
import { Bold } from '@tiptap/extension-bold'
|
|
|
|
import { BubbleMenu } from '@tiptap/extension-bubble-menu'
|
|
|
|
import { Dropcursor } from '@tiptap/extension-dropcursor'
|
|
|
|
import { Italic } from '@tiptap/extension-italic'
|
|
|
|
import { Strike } from '@tiptap/extension-strike'
|
|
|
|
import { HorizontalRule } from '@tiptap/extension-horizontal-rule'
|
|
|
|
import { Underline } from '@tiptap/extension-underline'
|
|
|
|
import { FloatingMenu } from '@tiptap/extension-floating-menu'
|
|
|
|
import { BulletList } from '@tiptap/extension-bullet-list'
|
|
|
|
import { OrderedList } from '@tiptap/extension-ordered-list'
|
|
|
|
import { ListItem } from '@tiptap/extension-list-item'
|
|
|
|
import { CharacterCount } from '@tiptap/extension-character-count'
|
|
|
|
import { Placeholder } from '@tiptap/extension-placeholder'
|
|
|
|
import { Gapcursor } from '@tiptap/extension-gapcursor'
|
|
|
|
import { HardBreak } from '@tiptap/extension-hard-break'
|
|
|
|
import { Heading } from '@tiptap/extension-heading'
|
|
|
|
import { Highlight } from '@tiptap/extension-highlight'
|
|
|
|
import { Link } from '@tiptap/extension-link'
|
|
|
|
import { Youtube } from '@tiptap/extension-youtube'
|
|
|
|
import { Document } from '@tiptap/extension-document'
|
|
|
|
import { Text } from '@tiptap/extension-text'
|
|
|
|
import { Image } from '@tiptap/extension-image'
|
|
|
|
import { Paragraph } from '@tiptap/extension-paragraph'
|
|
|
|
import Focus from '@tiptap/extension-focus'
|
|
|
|
import { TrailingNode } from './extensions/TrailingNode'
|
2023-03-25 04:42:45 +00:00
|
|
|
import { EditorBubbleMenu } from './EditorBubbleMenu/EditorBubbleMenu'
|
2023-03-08 16:35:13 +00:00
|
|
|
import { EditorFloatingMenu } from './EditorFloatingMenu'
|
2023-03-29 08:51:27 +00:00
|
|
|
import * as Y from 'yjs'
|
|
|
|
import { WebrtcProvider } from 'y-webrtc'
|
|
|
|
import { CollaborationCursor } from '@tiptap/extension-collaboration-cursor'
|
|
|
|
import { Collaboration } from '@tiptap/extension-collaboration'
|
2023-03-22 07:47:51 +00:00
|
|
|
import './Prosemirror.scss'
|
2023-03-29 08:51:27 +00:00
|
|
|
import { IndexeddbPersistence } from 'y-indexeddb'
|
|
|
|
import { useSession } from '../../context/session'
|
2023-03-29 10:22:03 +00:00
|
|
|
import uniqolor from 'uniqolor'
|
2023-03-29 15:36:12 +00:00
|
|
|
import { HocuspocusProvider } from '@hocuspocus/provider'
|
2023-03-08 16:35:13 +00:00
|
|
|
|
|
|
|
type EditorProps = {
|
2023-03-29 08:51:27 +00:00
|
|
|
shoutId: number
|
2023-03-08 16:35:13 +00:00
|
|
|
initialContent?: string
|
2023-03-23 17:15:50 +00:00
|
|
|
onChange: (text: string) => void
|
2023-03-08 16:35:13 +00:00
|
|
|
}
|
|
|
|
|
2023-03-29 08:51:27 +00:00
|
|
|
const yDoc = new Y.Doc()
|
2023-03-29 10:14:39 +00:00
|
|
|
const persisters: Record<string, IndexeddbPersistence> = {}
|
2023-03-29 15:36:12 +00:00
|
|
|
const providers: Record<string, HocuspocusProvider> = {}
|
2023-03-08 16:35:13 +00:00
|
|
|
|
|
|
|
export const Editor = (props: EditorProps) => {
|
|
|
|
const { t } = useLocalize()
|
2023-03-29 08:51:27 +00:00
|
|
|
const { user } = useSession()
|
|
|
|
|
|
|
|
const docName = `shout-${props.shoutId}`
|
2023-03-29 15:36:12 +00:00
|
|
|
if (!persisters[docName]) {
|
|
|
|
persisters[docName] = new IndexeddbPersistence(docName, yDoc)
|
|
|
|
}
|
2023-03-29 08:51:27 +00:00
|
|
|
|
2023-03-29 10:14:39 +00:00
|
|
|
if (!providers[docName]) {
|
2023-03-29 15:36:12 +00:00
|
|
|
providers[docName] = new HocuspocusProvider({
|
2023-03-29 17:00:09 +00:00
|
|
|
url: 'wss://v2.discours.io:4242',
|
2023-03-29 15:36:12 +00:00
|
|
|
name: docName,
|
|
|
|
document: yDoc
|
|
|
|
})
|
2023-03-29 10:14:39 +00:00
|
|
|
}
|
2023-03-08 16:35:13 +00:00
|
|
|
|
|
|
|
const editorElRef: {
|
|
|
|
current: HTMLDivElement
|
|
|
|
} = {
|
|
|
|
current: null
|
|
|
|
}
|
|
|
|
|
|
|
|
const bubbleMenuRef: {
|
|
|
|
current: HTMLDivElement
|
|
|
|
} = {
|
|
|
|
current: null
|
|
|
|
}
|
|
|
|
|
|
|
|
const floatingMenuRef: {
|
|
|
|
current: HTMLDivElement
|
|
|
|
} = {
|
|
|
|
current: null
|
|
|
|
}
|
|
|
|
|
|
|
|
const editor = createTiptapEditor(() => ({
|
|
|
|
element: editorElRef.current,
|
|
|
|
extensions: [
|
|
|
|
Document,
|
|
|
|
Text,
|
|
|
|
Paragraph,
|
|
|
|
Dropcursor,
|
|
|
|
Blockquote,
|
|
|
|
Bold,
|
|
|
|
Italic,
|
|
|
|
Strike,
|
|
|
|
HorizontalRule,
|
|
|
|
Underline,
|
2023-03-20 09:19:14 +00:00
|
|
|
Link.configure({
|
|
|
|
openOnClick: false
|
|
|
|
}),
|
2023-03-22 07:47:51 +00:00
|
|
|
Heading.configure({
|
|
|
|
levels: [1, 2, 3]
|
|
|
|
}),
|
2023-03-08 16:35:13 +00:00
|
|
|
BubbleMenu.configure({
|
|
|
|
element: bubbleMenuRef.current
|
|
|
|
}),
|
|
|
|
FloatingMenu.configure({
|
|
|
|
tippyOptions: {
|
|
|
|
placement: 'left'
|
|
|
|
},
|
|
|
|
element: floatingMenuRef.current
|
|
|
|
}),
|
|
|
|
BulletList,
|
|
|
|
OrderedList,
|
|
|
|
ListItem,
|
|
|
|
CharacterCount,
|
2023-03-29 08:51:27 +00:00
|
|
|
Collaboration.configure({
|
|
|
|
document: yDoc
|
|
|
|
}),
|
2023-03-29 10:14:39 +00:00
|
|
|
CollaborationCursor.configure({
|
|
|
|
provider: providers[docName],
|
|
|
|
user: {
|
|
|
|
name: user().name,
|
2023-03-29 10:28:40 +00:00
|
|
|
color: uniqolor(user().slug).color
|
2023-03-29 10:14:39 +00:00
|
|
|
}
|
|
|
|
}),
|
2023-03-08 16:35:13 +00:00
|
|
|
Placeholder.configure({
|
|
|
|
placeholder: t('Short opening')
|
|
|
|
}),
|
|
|
|
Focus,
|
|
|
|
Gapcursor,
|
|
|
|
HardBreak,
|
|
|
|
Highlight,
|
|
|
|
Image,
|
|
|
|
Youtube,
|
|
|
|
TrailingNode
|
|
|
|
]
|
|
|
|
}))
|
|
|
|
|
2023-03-23 17:15:50 +00:00
|
|
|
const html = useEditorHTML(() => editor())
|
|
|
|
|
|
|
|
createEffect(() => {
|
|
|
|
props.onChange(html())
|
|
|
|
})
|
|
|
|
|
2023-03-08 16:35:13 +00:00
|
|
|
return (
|
2023-03-12 20:16:20 +00:00
|
|
|
<>
|
|
|
|
<div ref={(el) => (editorElRef.current = el)} />
|
2023-03-08 16:35:13 +00:00
|
|
|
<EditorBubbleMenu editor={editor()} ref={(el) => (bubbleMenuRef.current = el)} />
|
|
|
|
<EditorFloatingMenu editor={editor()} ref={(el) => (floatingMenuRef.current = el)} />
|
2023-03-12 20:16:20 +00:00
|
|
|
</>
|
2023-03-08 16:35:13 +00:00
|
|
|
)
|
|
|
|
}
|