Central tiptap block definitions
This commit is contained in:
parent
3dd17ef692
commit
2d4e47af33
4 changed files with 46 additions and 82 deletions
|
|
@ -11,18 +11,7 @@
|
|||
|
||||
import { useEditor, EditorContent } from '@tiptap/vue-3'
|
||||
import type { Editor } from '@tiptap/core'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import Image from '@tiptap/extension-image'
|
||||
import TextAlign from '@tiptap/extension-text-align'
|
||||
import { TextStyle } from '@tiptap/extension-text-style'
|
||||
import Color from '@tiptap/extension-color'
|
||||
import Highlight from '@tiptap/extension-highlight'
|
||||
import Typography from '@tiptap/extension-typography'
|
||||
import Subscript from '@tiptap/extension-subscript'
|
||||
import Superscript from '@tiptap/extension-superscript'
|
||||
import Youtube from '@tiptap/extension-youtube'
|
||||
import { Div } from '~/utils/tiptapDiv'
|
||||
import { UupgsListNode } from '~/utils/tiptapUupgsList'
|
||||
import { buildTiptapExtensions } from '~/utils/tiptapExtensions'
|
||||
import { uploadImage } from '~/composables/useImageUpload'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
|
|
@ -41,20 +30,7 @@ const uploading = ref(false)
|
|||
|
||||
const editor = useEditor({
|
||||
content: props.modelValue,
|
||||
extensions: [
|
||||
StarterKit.configure({ link: { openOnClick: false, autolink: true } }),
|
||||
Image,
|
||||
TextAlign.configure({ types: ['heading', 'paragraph'] }),
|
||||
TextStyle,
|
||||
Color,
|
||||
Highlight,
|
||||
Typography,
|
||||
Subscript,
|
||||
Superscript,
|
||||
Youtube,
|
||||
Div,
|
||||
UupgsListNode
|
||||
],
|
||||
extensions: buildTiptapExtensions(),
|
||||
onUpdate({ editor: e }) {
|
||||
emit('update:modelValue', e.getJSON())
|
||||
}
|
||||
|
|
|
|||
36
app/utils/tiptapExtensions.ts
Normal file
36
app/utils/tiptapExtensions.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// Shared Tiptap extension set — used by both the editor
|
||||
// (app/components/admin/RichTextEditor.vue) and the server-side HTML
|
||||
// renderer (server/utils/renderTiptap.ts) so authored content round-trips
|
||||
// cleanly to the public page. Keep all extensions framework-agnostic here
|
||||
// (@tiptap/core + @tiptap/extension-*): no @tiptap/vue-3 imports, or the
|
||||
// server renderer will drag the Vue runtime into the Nitro bundle.
|
||||
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import Image from '@tiptap/extension-image'
|
||||
import TextAlign from '@tiptap/extension-text-align'
|
||||
import { TextStyle } from '@tiptap/extension-text-style'
|
||||
import Color from '@tiptap/extension-color'
|
||||
import Highlight from '@tiptap/extension-highlight'
|
||||
import Typography from '@tiptap/extension-typography'
|
||||
import Subscript from '@tiptap/extension-subscript'
|
||||
import Superscript from '@tiptap/extension-superscript'
|
||||
import Youtube from '@tiptap/extension-youtube'
|
||||
import { Div } from './tiptapDiv'
|
||||
import { UupgsListNode } from './tiptapUupgsList'
|
||||
|
||||
export function buildTiptapExtensions() {
|
||||
return [
|
||||
StarterKit.configure({ link: { openOnClick: false, autolink: true } }),
|
||||
Image,
|
||||
TextAlign.configure({ types: ['heading', 'paragraph'] }),
|
||||
TextStyle,
|
||||
Color,
|
||||
Highlight,
|
||||
Typography,
|
||||
Subscript,
|
||||
Superscript,
|
||||
Youtube,
|
||||
Div,
|
||||
UupgsListNode
|
||||
]
|
||||
}
|
||||
|
|
@ -11,33 +11,9 @@ import { JSDOM } from 'jsdom'
|
|||
// same logic @tiptap/html runs, just with a DOM we control.
|
||||
import { getSchema } from '@tiptap/core'
|
||||
import { DOMParser as ProseMirrorDOMParser } from 'prosemirror-model'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import Image from '@tiptap/extension-image'
|
||||
import TextAlign from '@tiptap/extension-text-align'
|
||||
import { TextStyle } from '@tiptap/extension-text-style'
|
||||
import Color from '@tiptap/extension-color'
|
||||
import Highlight from '@tiptap/extension-highlight'
|
||||
import Typography from '@tiptap/extension-typography'
|
||||
import Subscript from '@tiptap/extension-subscript'
|
||||
import Superscript from '@tiptap/extension-superscript'
|
||||
import Youtube from '@tiptap/extension-youtube'
|
||||
import { Div } from '../../app/utils/tiptapDiv'
|
||||
import { UupgsListNode } from '../../app/utils/tiptapUupgsList'
|
||||
import { buildTiptapExtensions } from '../../app/utils/tiptapExtensions'
|
||||
|
||||
const EXTENSIONS = [
|
||||
StarterKit.configure({ link: { openOnClick: false, autolink: true } }),
|
||||
Image,
|
||||
TextAlign.configure({ types: ['heading', 'paragraph'] }),
|
||||
TextStyle,
|
||||
Color,
|
||||
Highlight,
|
||||
Typography,
|
||||
Subscript,
|
||||
Superscript,
|
||||
Youtube,
|
||||
Div,
|
||||
UupgsListNode
|
||||
]
|
||||
const EXTENSIONS = buildTiptapExtensions()
|
||||
|
||||
// @tiptap/html ultimately calls prosemirror-model's DOMParser which
|
||||
// expects a global `window`/`document`. In Bun/Node we provide one via
|
||||
|
|
|
|||
|
|
@ -1,39 +1,15 @@
|
|||
// Server-side Tiptap JSON → HTML renderer. The extension set here must
|
||||
// stay aligned with app/components/admin/RichTextEditor.vue (built in
|
||||
// Phase 6) so content authored in the editor round-trips back out to
|
||||
// the public page with the same tags/attributes.
|
||||
// Server-side Tiptap JSON → HTML renderer. The extension set comes from
|
||||
// app/utils/tiptapExtensions.ts, shared with the editor component so
|
||||
// authored content round-trips back out to the public page with the
|
||||
// same tags/attributes.
|
||||
//
|
||||
// Keeping this on the server keeps the public bundle free of Tiptap
|
||||
// runtime code — the renderer serializes once and we send HTML.
|
||||
|
||||
import { generateHTML } from '@tiptap/html'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import Image from '@tiptap/extension-image'
|
||||
import TextAlign from '@tiptap/extension-text-align'
|
||||
import { TextStyle } from '@tiptap/extension-text-style'
|
||||
import Color from '@tiptap/extension-color'
|
||||
import Highlight from '@tiptap/extension-highlight'
|
||||
import Typography from '@tiptap/extension-typography'
|
||||
import Subscript from '@tiptap/extension-subscript'
|
||||
import Superscript from '@tiptap/extension-superscript'
|
||||
import Youtube from '@tiptap/extension-youtube'
|
||||
import { Div } from '~~/app/utils/tiptapDiv'
|
||||
import { UupgsListNode } from '~~/app/utils/tiptapUupgsList'
|
||||
import { buildTiptapExtensions } from '~~/app/utils/tiptapExtensions'
|
||||
|
||||
const EXTENSIONS = [
|
||||
StarterKit.configure({ link: { openOnClick: false, autolink: true } }),
|
||||
Image,
|
||||
TextAlign.configure({ types: ['heading', 'paragraph'] }),
|
||||
TextStyle,
|
||||
Color,
|
||||
Highlight,
|
||||
Typography,
|
||||
Subscript,
|
||||
Superscript,
|
||||
Youtube,
|
||||
Div,
|
||||
UupgsListNode
|
||||
]
|
||||
const EXTENSIONS = buildTiptapExtensions()
|
||||
|
||||
function isEmptyDoc(doc: unknown): boolean {
|
||||
if (!doc || typeof doc !== 'object') return true
|
||||
|
|
|
|||
Loading…
Reference in a new issue