feat: parse youtube, simplecast and custom iframe embeds on server-side
This commit is contained in:
parent
77e4369176
commit
bd0406eac5
|
@ -4,7 +4,6 @@ import {
|
|||
extractIdFromFirstTag,
|
||||
extractInnerHtml,
|
||||
} from '@/utils/html.utils'
|
||||
import { convertToIframe } from '@/utils/string.utils'
|
||||
import { HeadingElementsRef } from '@/utils/ui.utils'
|
||||
import { Typography } from '@acid-info/lsd-react'
|
||||
import styled from '@emotion/styled'
|
||||
|
@ -40,31 +39,18 @@ export const RenderArticleBlock = ({
|
|||
)
|
||||
}
|
||||
case 'p': {
|
||||
const isIframeRegex = /<iframe[^>]*>(?:<\/iframe>|[^]*?<\/iframe>)/
|
||||
const isIframe = isIframeRegex.test(block.text)
|
||||
const isIframe = block.embed && block.labels.includes('embed')
|
||||
|
||||
const isYoutubeRegex =
|
||||
/^(https?\:\/\/)?((www\.)?youtube\.com|youtu\.?be)\/.+$/
|
||||
|
||||
const isYoutube = isYoutubeRegex.test(block.text)
|
||||
const youtubeLink = block.text.match(isYoutubeRegex) ?? []
|
||||
|
||||
const isSimplecastRegex =
|
||||
/^https?:\/\/([a-zA-Z0-9-]+\.)*simplecast\.com\/[^?\s]+(\?[\s\S]*)?$/
|
||||
|
||||
const isSimplecast = isSimplecastRegex.test(block.text)
|
||||
const simplecastLink = block.text.match(isSimplecastRegex) ?? []
|
||||
|
||||
return isIframe ? (
|
||||
<IframeContainer dangerouslySetInnerHTML={{ __html: block.text }} />
|
||||
) : isYoutube ? (
|
||||
<ReactPlayer url={youtubeLink[0]} />
|
||||
) : isSimplecast ? (
|
||||
return block.embed && isIframe ? (
|
||||
block.labels.includes('youtube_embed') ? (
|
||||
<ReactPlayer url={block.embed.src} />
|
||||
) : (
|
||||
<IframeContainer
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: convertToIframe(simplecastLink[0] ?? ''),
|
||||
__html: block.embed.html,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<Paragraph
|
||||
variant="body1"
|
||||
|
|
|
@ -17,7 +17,12 @@ const ArticleBlocks = ({ data }: Props) => {
|
|||
const headingElementsRef = useIntersectionObserver(setTocId)
|
||||
|
||||
const blocks = useMemo(
|
||||
() => data.content.filter((b) => b.labels.length === 0),
|
||||
() =>
|
||||
data.content.filter(
|
||||
(b) =>
|
||||
b.labels.length === 0 ||
|
||||
b.labels.includes(LPE.Post.ContentBlockLabels.Embed),
|
||||
),
|
||||
[data.content],
|
||||
)
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ const ArticlePage = ({ data, errors, why }: ArticleProps) => {
|
|||
|
||||
if (!data) return null
|
||||
if (errors) return <div>{errors}</div>
|
||||
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { LPE } from '../../../types/lpe.types'
|
||||
import { convertToIframe } from '../../../utils/string.utils'
|
||||
import { UnbodyResGoogleDocData, UnbodyResTextBlockData } from '../unbody.types'
|
||||
import { UnbodyDataTypeConfig } from './types'
|
||||
|
||||
|
@ -15,6 +16,55 @@ export const TextBlockDataType: UnbodyDataTypeConfig<
|
|||
isMatch: (helpers, data, original, root) => data.__typename === 'TextBlock',
|
||||
|
||||
transform: (helpers, data, original, root) => {
|
||||
const { text = '', html = '' } = data
|
||||
const labels: LPE.Post.ContentBlockLabel[] = []
|
||||
let embed: LPE.Post.TextBlockEmbed | null = null
|
||||
|
||||
if (text.length > 0 || html.length > 0) {
|
||||
const isLink =
|
||||
/^<p[^>]*><span[^>]*><a[^>]*href="(https):\/\/[^ "]+"[^>]*>.*<\/a><\/span><\/p>$/.test(
|
||||
html,
|
||||
)
|
||||
const isIframe = /<iframe[^>]*>(?:<\/iframe>|[^]*?<\/iframe>)/.test(text)
|
||||
|
||||
if (isLink) {
|
||||
const youtube = html.match(
|
||||
/(https?\:\/\/)?((www\.)?youtube\.com|youtu\.?be)\/[^ "]+/gi,
|
||||
)
|
||||
|
||||
const simplecast = html.match(
|
||||
/(https?\:\/\/)?((player\.)?simplecast\.com)\/[^ "]+/gi,
|
||||
)
|
||||
|
||||
const label = youtube?.[0]
|
||||
? LPE.Post.ContentBlockLabels.YoutubeEmbed
|
||||
: LPE.Post.ContentBlockLabels.SimplecastEmbed
|
||||
const src = youtube?.[0] || simplecast?.[0]
|
||||
if (src && src.length > 0) {
|
||||
labels.push(label)
|
||||
labels.push(LPE.Post.ContentBlockLabels.Embed)
|
||||
|
||||
embed = {
|
||||
src,
|
||||
html: convertToIframe(src),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isIframe) {
|
||||
const src = text.match(/(?<=src=").*?(?=[\?"])/g)?.[0]
|
||||
|
||||
if (src) {
|
||||
labels.push(LPE.Post.ContentBlockLabels.Embed)
|
||||
|
||||
embed = {
|
||||
html: text,
|
||||
src,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: data?._additional?.id || `${data.order}`,
|
||||
type: 'text',
|
||||
|
@ -24,7 +74,8 @@ export const TextBlockDataType: UnbodyDataTypeConfig<
|
|||
footnotes: data.footnotesObj,
|
||||
order: data.order,
|
||||
tagName: data.tagName,
|
||||
labels: [],
|
||||
labels,
|
||||
...(embed ? { embed } : {}),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -61,6 +61,9 @@ export namespace LPE {
|
|||
Footnote: 'footnote',
|
||||
Paragraph: 'paragraph',
|
||||
CoverImage: 'cover_image',
|
||||
Embed: 'embed',
|
||||
YoutubeEmbed: 'youtube_embed',
|
||||
SimplecastEmbed: 'simplecast_embed',
|
||||
} as const
|
||||
|
||||
export type ContentBlockLabel = DictValues<typeof ContentBlockLabels>
|
||||
|
@ -72,6 +75,11 @@ export namespace LPE {
|
|||
document?: D
|
||||
}
|
||||
|
||||
export type TextBlockEmbed = {
|
||||
src: string
|
||||
html: string
|
||||
}
|
||||
|
||||
export type TextBlock<D = any> = ContentBlockCommon<D> & {
|
||||
text: string
|
||||
html: string
|
||||
|
@ -79,6 +87,7 @@ export namespace LPE {
|
|||
classNames: string[]
|
||||
type: Extract<ContentBlockType, 'text'>
|
||||
footnotes: Post.Footnotes
|
||||
embed?: TextBlockEmbed
|
||||
}
|
||||
|
||||
export type ImageBlock<D = any> = ContentBlockCommon<D> &
|
||||
|
|
Loading…
Reference in New Issue