notes upgrade
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import { useEditor, EditorContent } from '@tiptap/react'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
interface NoteCardProps {
|
||||
anchorLabel: string
|
||||
html: string
|
||||
autoSaveMsg?: string
|
||||
onChange: (html: string) => void
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
export function NoteCard({ anchorLabel, html, autoSaveMsg, onChange, onClose }: NoteCardProps) {
|
||||
const editor = useEditor({
|
||||
extensions: [StarterKit],
|
||||
content: html || '<p></p>',
|
||||
onUpdate({ editor }) {
|
||||
const next = editor.getHTML()
|
||||
onChange(next === '<p></p>' ? '' : next)
|
||||
},
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (!editor || editor.isDestroyed) return
|
||||
if (editor.getHTML() !== html) {
|
||||
editor.commands.setContent(html || '<p></p>', false)
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [html])
|
||||
|
||||
useEffect(() => () => { editor?.destroy() }, [editor])
|
||||
|
||||
if (!editor) return null
|
||||
|
||||
return (
|
||||
<div className="note-card">
|
||||
<div className="note-card-header">
|
||||
<span className="note-card-label">✎ {anchorLabel}</span>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
|
||||
{autoSaveMsg && <span className="note-card-autosave">{autoSaveMsg}</span>}
|
||||
<button type="button" className="note-card-close" onClick={onClose} aria-label="Close note">×</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="note-card-toolbar" role="toolbar" aria-label="Text formatting">
|
||||
<button
|
||||
type="button"
|
||||
className={`note-tool${editor.isActive('bold') ? ' note-tool--active' : ''}`}
|
||||
onMouseDown={e => { e.preventDefault(); editor.chain().focus().toggleBold().run() }}
|
||||
aria-label="Bold"
|
||||
title="Bold (Ctrl+B)"
|
||||
><strong>B</strong></button>
|
||||
<button
|
||||
type="button"
|
||||
className={`note-tool${editor.isActive('italic') ? ' note-tool--active' : ''}`}
|
||||
onMouseDown={e => { e.preventDefault(); editor.chain().focus().toggleItalic().run() }}
|
||||
aria-label="Italic"
|
||||
title="Italic (Ctrl+I)"
|
||||
><em>I</em></button>
|
||||
<button
|
||||
type="button"
|
||||
className={`note-tool${editor.isActive('bulletList') ? ' note-tool--active' : ''}`}
|
||||
onMouseDown={e => { e.preventDefault(); editor.chain().focus().toggleBulletList().run() }}
|
||||
aria-label="Bullet list"
|
||||
title="Bullet list"
|
||||
>•—</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`note-tool${editor.isActive('orderedList') ? ' note-tool--active' : ''}`}
|
||||
onMouseDown={e => { e.preventDefault(); editor.chain().focus().toggleOrderedList().run() }}
|
||||
aria-label="Numbered list"
|
||||
title="Numbered list"
|
||||
>1.</button>
|
||||
<div className="note-tool-divider" />
|
||||
<button
|
||||
type="button"
|
||||
className="note-tool"
|
||||
onMouseDown={e => { e.preventDefault(); editor.chain().focus().undo().run() }}
|
||||
disabled={!editor.can().undo()}
|
||||
aria-label="Undo"
|
||||
title="Undo (Ctrl+Z)"
|
||||
>↩</button>
|
||||
<button
|
||||
type="button"
|
||||
className="note-tool"
|
||||
onMouseDown={e => { e.preventDefault(); editor.chain().focus().redo().run() }}
|
||||
disabled={!editor.can().redo()}
|
||||
aria-label="Redo"
|
||||
title="Redo (Ctrl+Y)"
|
||||
>↪</button>
|
||||
</div>
|
||||
|
||||
<EditorContent editor={editor} className="note-card-editor" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user