Gwk-Cultural-Park/schemas/settings/OpenGraphPreview.tsx

70 lines
2.0 KiB
TypeScript
Raw Permalink Normal View History

2024-09-07 01:40:25 +00:00
import { Card } from '@sanity/ui'
import { height, OpenGraphImage, width } from 'components/OpenGraphImage'
import { createIntlSegmenterPolyfill } from 'intl-segmenter-polyfill'
import type { Settings } from 'lib/sanity.queries'
import satori, { type SatoriOptions } from 'satori'
import styled from 'styled-components'
import useSWR from 'swr/immutable'
async function init(): Promise<SatoriOptions['fonts']> {
if (!globalThis?.Intl?.Segmenter) {
console.debug('Polyfilling Intl.Segmenter')
//@ts-expect-error
globalThis.Intl = globalThis.Intl || {}
//@ts-expect-error
globalThis.Intl.Segmenter = await createIntlSegmenterPolyfill(
fetch(new URL('public/break_iterator.wasm', import.meta.url))
)
}
const fontData = await fetch(
new URL('public/fonts/Inter-Bold.woff', import.meta.url)
).then((res) => res.arrayBuffer())
return [{ name: 'Inter', data: fontData, style: 'normal', weight: 700 }]
}
// preload fonts and polyfill
const fontsPromise = init()
const OpenGraphSvg = styled(Card).attrs({
radius: 3,
shadow: 1,
overflow: 'hidden',
})`
display: flex;
align-items: center;
justify-content: center;
svg {
display: block;
object-fit: cover;
aspect-ratio: ${width} / ${height};
object-position: center;
height: 100%;
width: 100%;
}
`
export default function OpenGraphPreview(props: Settings['ogImage']) {
// we wrap the segmenter setup and font loading in SWR to enable caching
const { data: fonts } = useSWR('OpenGraphPreview.init', () => fontsPromise, {
suspense: true,
})
// Also handle the satori render call in SWR to enable caching and only re-render when the title changes or fonts hot reload
const { data: __html } = useSWR(
[props.title, fonts satisfies SatoriOptions['fonts']],
([title, fonts]) => {
return satori(<OpenGraphImage title={title || ''} />, {
width,
height,
fonts,
})
},
{ suspense: true }
)
return <OpenGraphSvg dangerouslySetInnerHTML={{ __html }} />
}