mirror of
https://github.com/ueberdosis/tiptap.git
synced 2025-06-07 17:43:49 +08:00
137 lines
3.8 KiB
JavaScript
137 lines
3.8 KiB
JavaScript
import React, {
|
|
useState, useCallback, useEffect,
|
|
} from 'react'
|
|
import * as Y from 'yjs'
|
|
import { WebsocketProvider } from 'y-websocket'
|
|
import { IndexeddbPersistence } from 'y-indexeddb'
|
|
import { useEditor, EditorContent } from '@tiptap/react'
|
|
import StarterKit from '@tiptap/starter-kit'
|
|
import TaskList from '@tiptap/extension-task-list'
|
|
import TaskItem from '@tiptap/extension-task-item'
|
|
import Highlight from '@tiptap/extension-highlight'
|
|
import CharacterCount from '@tiptap/extension-character-count'
|
|
import Collaboration from '@tiptap/extension-collaboration'
|
|
import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
|
|
import MenuBar from './MenuBar'
|
|
import './styles.scss'
|
|
|
|
const colors = ['#958DF1', '#F98181', '#FBBC88', '#FAF594', '#70CFF8', '#94FADB', '#B9F18D']
|
|
const rooms = ['rooms.10', 'rooms.11', 'rooms.12']
|
|
const names = [
|
|
'Lea Thompson',
|
|
'Cyndi Lauper',
|
|
'Tom Cruise',
|
|
'Madonna',
|
|
'Jerry Hall',
|
|
'Joan Collins',
|
|
'Winona Ryder',
|
|
'Christina Applegate',
|
|
'Alyssa Milano',
|
|
'Molly Ringwald',
|
|
'Ally Sheedy',
|
|
'Debbie Harry',
|
|
'Olivia Newton-John',
|
|
'Elton John',
|
|
'Michael J. Fox',
|
|
'Axl Rose',
|
|
'Emilio Estevez',
|
|
'Ralph Macchio',
|
|
'Rob Lowe',
|
|
'Jennifer Grey',
|
|
'Mickey Rourke',
|
|
'John Cusack',
|
|
'Matthew Broderick',
|
|
'Justine Bateman',
|
|
'Lisa Bonet',
|
|
]
|
|
|
|
const getRandomElement = list => list[Math.floor(Math.random() * list.length)]
|
|
|
|
const getRandomRoom = () => getRandomElement(rooms)
|
|
const getRandomColor = () => getRandomElement(colors)
|
|
const getRandomName = () => getRandomElement(names)
|
|
|
|
const room = getRandomRoom()
|
|
|
|
const ydoc = new Y.Doc()
|
|
const websocketProvider = new WebsocketProvider('wss://connect.tiptap.dev', room, ydoc)
|
|
|
|
const getInitialUser = () => {
|
|
return JSON.parse(localStorage.getItem('currentUser')) || {
|
|
name: getRandomName(),
|
|
color: getRandomColor(),
|
|
}
|
|
}
|
|
|
|
export default () => {
|
|
const [status, setStatus] = useState('connecting')
|
|
const [currentUser, setCurrentUser] = useState(getInitialUser)
|
|
|
|
const editor = useEditor({
|
|
extensions: [
|
|
StarterKit.configure({
|
|
history: false,
|
|
}),
|
|
Highlight,
|
|
TaskList,
|
|
TaskItem,
|
|
CharacterCount.configure({
|
|
limit: 10000,
|
|
}),
|
|
Collaboration.configure({
|
|
document: ydoc,
|
|
}),
|
|
CollaborationCursor.configure({
|
|
provider: websocketProvider,
|
|
}),
|
|
],
|
|
})
|
|
|
|
useEffect(() => {
|
|
// Store shared data persistently in browser to make offline editing possible
|
|
const indexeddbProvider = new IndexeddbPersistence(room, ydoc)
|
|
|
|
indexeddbProvider.on('synced', () => {
|
|
console.log('Loaded content from database …')
|
|
})
|
|
|
|
// Update status changes
|
|
websocketProvider.on('status', event => {
|
|
setStatus(event.status)
|
|
})
|
|
}, [])
|
|
|
|
// Save current user to localStorage and emit to editor
|
|
useEffect(() => {
|
|
if (editor && currentUser) {
|
|
localStorage.setItem('currentUser', JSON.stringify(currentUser))
|
|
editor.chain().focus().updateUser(currentUser).run()
|
|
}
|
|
}, [editor, currentUser])
|
|
|
|
const setName = useCallback(() => {
|
|
const name = (window.prompt('Name') || '').trim().substring(0, 32)
|
|
|
|
if (name) {
|
|
return setCurrentUser({ ...currentUser, name })
|
|
}
|
|
}, [currentUser])
|
|
|
|
return (
|
|
<div className="editor">
|
|
{editor && <MenuBar editor={editor} />}
|
|
<EditorContent className="editor__content" editor={editor} />
|
|
<div className="editor__footer">
|
|
<div className={`editor__status editor__status--${status}`}>
|
|
{status === 'connected'
|
|
? `${editor.storage.collaborationCursor.users.length} user${editor.storage.collaborationCursor.users.length === 1 ? '' : 's'} online in ${room}`
|
|
: 'offline'}
|
|
</div>
|
|
<div className="editor__name">
|
|
<button onClick={setName}>{currentUser.name}</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|