Skip to content

Instantly share code, notes, and snippets.

@GreenFootballs
Last active May 23, 2024 18:13
Show Gist options
  • Save GreenFootballs/d61d33b411fb0f2c519c79a1783ab297 to your computer and use it in GitHub Desktop.
Save GreenFootballs/d61d33b411fb0f2c519c79a1783ab297 to your computer and use it in GitHub Desktop.
Render Bluesky embedded posts dynamically, with callback when complete
/**
* bluesky-embed.js
*
* @author Charles Johnson
* @url https://github.com/GreenFootballs
*
* Adds an object named "_bluesky" to the window element, with an "embed" method.
*
* Runs automatically at window.onload, searches the page for blockquotes with a
* "data-bluesky-uri" attribute, converts them to iframes, and resizes them to fit the content.
*
* To resize dynamically added Bluesky posts, call "_bluesky.embed(div, callback)"
* where "container" is the enclosing element for the dynamic content.
*
* The "container" parameter can be a string with a CSS selector, a reference to a DOM element,
* or left undefined to search the entire document.
*
* The "callback" parameter is an optional function called after all iframes
* in the container are resized.
*/
window.addEventListener('load', () => {
const EMBED_URL = 'https://embed.bsky.app'
window._bluesky = window._bluesky || {
iframes: new Map(),
onRender: null,
embed: (container = document, callback = null) => {
window._bluesky.iframes.clear()
window._bluesky.onRender = null
if (typeof container === 'string') {
container = document.querySelector(container)
if (!container) return
}
Array.from(container.querySelectorAll('[data-bluesky-uri]')).forEach( (quote, index, arr) => {
if (index === arr.length - 1 && callback !== null) window._bluesky.onRender = callback
const id = crypto.randomUUID()
const atUri = quote.getAttribute('data-bluesky-uri').substring('at://'.length)
const searchParams = new URLSearchParams()
searchParams.set('id', id)
const ref_url = location.origin + location.pathname
if (ref_url.startsWith('http')) searchParams.set('ref_url', encodeURIComponent(ref_url))
const iframe = document.createElement('iframe')
window._bluesky.iframes.set(id, iframe)
iframe.style.cssText = 'width: 100%; border: none; display: block; flex-grow: 1; overflow: hidden;'
iframe.setAttribute('frameBorder', '0')
iframe.setAttribute('scrolling', 'no')
iframe.src = `${ EMBED_URL }/embed/${ atUri }?${ searchParams.toString() }`
const div = document.createElement('div')
div.style.cssText = 'max-width: 600px; width: 100%; margin: 10px auto; display: flex;'
div.className = 'bluesky-embed'
div.appendChild(iframe)
quote.replaceWith(div)
})
}
}
// When the iframe loads, it sends a message with its ID and content height
window.addEventListener('message', e => {
if (e.origin !== EMBED_URL || !e.data.id || !e.data.height) return
const embed = window._bluesky.iframes.get(e.data.id)
if (!embed) return
embed.style.height = `${e.data.height}px`
if (window._bluesky.onRender !== null) {
window._bluesky.onRender()
window._bluesky.onRender = null
}
})
window._bluesky.embed()
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment