Last active
May 23, 2024 18:13
-
-
Save GreenFootballs/d61d33b411fb0f2c519c79a1783ab297 to your computer and use it in GitHub Desktop.
Render Bluesky embedded posts dynamically, with callback when complete
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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