Try embedding iframes in tiptap
This commit is contained in:
parent
f7151f131d
commit
3a8968bdf1
98
common/util/iframe.ts
Normal file
98
common/util/iframe.ts
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
// Adopted from https://github.com/ueberdosis/tiptap/blob/main/demos/src/Experiments/Embeds/Vue/iframe.ts
|
||||||
|
|
||||||
|
import { Node } from '@tiptap/core'
|
||||||
|
import clsx from 'clsx'
|
||||||
|
|
||||||
|
export interface IframeOptions {
|
||||||
|
allowFullscreen: boolean
|
||||||
|
HTMLAttributes: {
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@tiptap/core' {
|
||||||
|
interface Commands<ReturnType> {
|
||||||
|
iframe: {
|
||||||
|
/**
|
||||||
|
* Add an iframe
|
||||||
|
*/
|
||||||
|
setIframe: (options: { src: string }) => ReturnType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrapperClasses = 'relative h-auto w-full overflow-hidden'
|
||||||
|
const iframeClasses = 'absolute top-0 left-0 h-full w-full'
|
||||||
|
|
||||||
|
export default Node.create<IframeOptions>({
|
||||||
|
name: 'iframe',
|
||||||
|
|
||||||
|
group: 'block',
|
||||||
|
|
||||||
|
atom: true,
|
||||||
|
|
||||||
|
addOptions() {
|
||||||
|
return {
|
||||||
|
allowFullscreen: true,
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: clsx('iframe-wrapper', wrapperClasses),
|
||||||
|
// Tailwind JIT doesn't seem to pick up `pb-[20rem]`, so we hack this in:
|
||||||
|
style: 'padding-bottom: 20rem;',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addAttributes() {
|
||||||
|
return {
|
||||||
|
src: {
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
frameborder: {
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
allowfullscreen: {
|
||||||
|
default: this.options.allowFullscreen,
|
||||||
|
parseHTML: () => this.options.allowFullscreen,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
parseHTML() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
tag: 'iframe',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
renderHTML({ HTMLAttributes }) {
|
||||||
|
return [
|
||||||
|
'div',
|
||||||
|
this.options.HTMLAttributes,
|
||||||
|
[
|
||||||
|
'iframe',
|
||||||
|
{
|
||||||
|
...HTMLAttributes,
|
||||||
|
class: clsx(HTMLAttributes.class, iframeClasses),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
setIframe:
|
||||||
|
(options: { src: string }) =>
|
||||||
|
({ tr, dispatch }) => {
|
||||||
|
const { selection } = tr
|
||||||
|
const node = this.type.create(options)
|
||||||
|
|
||||||
|
if (dispatch) {
|
||||||
|
tr.replaceRangeWith(selection.from, selection.to, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
|
@ -20,6 +20,7 @@ import { Text } from '@tiptap/extension-text'
|
||||||
// other tiptap extensions
|
// other tiptap extensions
|
||||||
import { Image } from '@tiptap/extension-image'
|
import { Image } from '@tiptap/extension-image'
|
||||||
import { Link } from '@tiptap/extension-link'
|
import { Link } from '@tiptap/extension-link'
|
||||||
|
import Iframe from './iframe'
|
||||||
|
|
||||||
export function parseTags(text: string) {
|
export function parseTags(text: string) {
|
||||||
const regex = /(?:^|\s)(?:[#][a-z0-9_]+)/gi
|
const regex = /(?:^|\s)(?:[#][a-z0-9_]+)/gi
|
||||||
|
@ -80,6 +81,7 @@ export const exhibitExts = [
|
||||||
|
|
||||||
Image,
|
Image,
|
||||||
Link,
|
Link,
|
||||||
|
Iframe,
|
||||||
]
|
]
|
||||||
// export const exhibitExts = [StarterKit as unknown as Extension, Image]
|
// export const exhibitExts = [StarterKit as unknown as Extension, Image]
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,9 @@ function RichEditContract(props: { contract: Contract; isAdmin?: boolean }) {
|
||||||
.setContent(contract.description)
|
.setContent(contract.description)
|
||||||
.focus('end')
|
.focus('end')
|
||||||
.insertContent(`<p>${editTimestamp()}</p>`)
|
.insertContent(`<p>${editTimestamp()}</p>`)
|
||||||
|
.insertContent(
|
||||||
|
`<iframe src="https://manifold.markets/embed/Austin/how-many-upvotes-will-the-new-versi" frameborder="0"></iframe>`
|
||||||
|
)
|
||||||
.run()
|
.run()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { useMutation } from 'react-query'
|
||||||
import { exhibitExts } from 'common/util/parse'
|
import { exhibitExts } from 'common/util/parse'
|
||||||
import { FileUploadButton } from './file-upload-button'
|
import { FileUploadButton } from './file-upload-button'
|
||||||
import { linkClass } from './site-link'
|
import { linkClass } from './site-link'
|
||||||
|
import Iframe from 'common/util/iframe'
|
||||||
|
|
||||||
const proseClass = clsx(
|
const proseClass = clsx(
|
||||||
'prose prose-p:my-0 prose-li:my-0 prose-blockquote:not-italic max-w-none prose-quoteless leading-relaxed',
|
'prose prose-p:my-0 prose-li:my-0 prose-blockquote:not-italic max-w-none prose-quoteless leading-relaxed',
|
||||||
|
@ -56,6 +57,7 @@ export function useTextEditor(props: {
|
||||||
class: clsx('no-underline !text-indigo-700', linkClass),
|
class: clsx('no-underline !text-indigo-700', linkClass),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
Iframe,
|
||||||
],
|
],
|
||||||
content: defaultValue,
|
content: defaultValue,
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue
Block a user