Skip to content

Instantly share code, notes, and snippets.

@kmelve
Last active September 18, 2024 15:19
Show Gist options
  • Save kmelve/850b1b9408f967a4b99b7c3698287750 to your computer and use it in GitHub Desktop.
Save kmelve/850b1b9408f967a4b99b7c3698287750 to your computer and use it in GitHub Desktop.
LinkedIn Embed Input for Sanity Studio
import React, { useState } from "react"
import { TextInput, Stack } from "@sanity/ui"
import { set, unset } from "sanity"
interface LinkedInEmbed {
_key: string
_type: string
postUrl: string
height: number
}
export const LinkedInEmbedInput = React.forwardRef((props: any, ref) => {
const { onChange, value } = props
const [embedCode, setEmbedCode] = useState("")
const extractLinkedInData = (
html: string
): Omit<LinkedInEmbed, "_key" | "_type"> | null => {
const parser = new DOMParser()
const doc = parser.parseFromString(html, "text/html")
const iframe = doc.querySelector("iframe")
if (iframe) {
const src = iframe.getAttribute("src")
const height = iframe.getAttribute("height")
if (src && height) {
return {
postUrl: src,
height: parseInt(height, 10),
}
}
}
return null
}
const handleEmbedCodeChange = (
event: React.ChangeEvent<HTMLInputElement>
) => {
const newEmbedCode = event.target.value
setEmbedCode(newEmbedCode)
const data = extractLinkedInData(newEmbedCode)
if (data) {
const fullData: LinkedInEmbed = {
_key: value?._key,
_type: "linkedInEmbed",
...data,
}
onChange(set(fullData))
} else {
onChange(unset())
}
}
return (
<Stack space={3}>
{value.postUrl || value.height ? (
props.renderDefault(props)
) : (
<TextInput
value={embedCode}
onChange={handleEmbedCodeChange}
placeholder="Paste LinkedIn embed code here"
/>
)}
</Stack>
)
})
LinkedInEmbedInput.displayName = "LinkedInEmbedInput"
import styles from "./LinkedInEmbedPreview.module.css"
type LinkedInEmbedPreviewProps = {
postUrl: string
height: number
}
export const LinkedInEmbedPreview = ({
postUrl,
height,
}: LinkedInEmbedPreviewProps) => {
return postUrl ? (
<iframe
className={styles.iframe}
src={postUrl}
height={height || 500}
width="504"
frameborder="0"
allowfullscreen=""
title="Embedded post"
></iframe>
) : (
<div>🚨 LinkedIn Post URL missing</div>
)
}
import { CiLinkedin } from "react-icons/ci"
import { LinkedInEmbedInput } from "./LinkedInEmbedInput"
import { LinkedInEmbedPreview } from "./LinkedInEmbedPreview"
export const LinkedInEmbedType = {
title: "LinkedIn Embed",
icon: ciLinkedIn,
type: "object",
name: "linkedInEmbed",
description: `Paste the LinkedIn embed HTML code here. This field will automatically extract the URL.`,
fields: [
{
title: "Post URL",
type: "string",
name: "postUrl",
description: `URL from the LinkedIn embed code "src" attribute`,
validation: (Rule) =>
Rule.custom((value) => {
if (!value) return true
// Make sure the `src` attribute follows the LinkedIn URL format
const linkedinUrlRegex =
/^https:\/\/www\.linkedin\.com\/embed\/feed\/update\/urn:li:share:[\w\d-]+$/
if (!linkedinUrlRegex.test(value)) {
throw new Error(
"Invalid LinkedIn URL: The post URL does not match the LinkedIn embed URL format."
)
}
return true
}),
},
{
title: "Height",
type: "number",
name: "height",
description: `Height from the iframe’s "height" attribute LinkedIn gives you when you click on "Embed this post"`,
validation: (Rule) => Rule.required(),
},
],
preview: {
select: {
postUrl: "postUrl",
height: "height",
},
},
components: {
preview: LinkedInEmbedPreview,
input: LinkedInEmbedInput,
},
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment