From 62b1f4761ac28b36d8a939625bb0a264f89798f3 Mon Sep 17 00:00:00 2001 From: Ed Date: Sat, 25 Jan 2025 16:45:26 -0300 Subject: [PATCH 1/2] chore: refactor replacement --- content/fennifith/posts/example/index.md | 4 ++++ src/utils/markdown/createHtmlPlugins.ts | 11 ++++++---- .../markdown/iframes/rehype-transform.ts | 22 +++++++++++++++---- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/content/fennifith/posts/example/index.md b/content/fennifith/posts/example/index.md index 7ca76361c..b12bd2121 100644 --- a/content/fennifith/posts/example/index.md +++ b/content/fennifith/posts/example/index.md @@ -156,3 +156,7 @@ This is regular text. # Heading `with a code snippet` inside of it # Heading [with a link](https://example.com) inside of it + +# COOL EMBED FEATURE FOR THE YOUTUBEZZZ + + diff --git a/src/utils/markdown/createHtmlPlugins.ts b/src/utils/markdown/createHtmlPlugins.ts index af76e0ac2..3c3d87c8b 100644 --- a/src/utils/markdown/createHtmlPlugins.ts +++ b/src/utils/markdown/createHtmlPlugins.ts @@ -81,10 +81,11 @@ export function createHtmlPlugins(unified: Processor) { .use(rehypeTooltips) .use(rehypeAstroImageMd) .use(rehypeUnicornIFrameClickToRun, { - srcReplacements: [ + replacements: [ + // PFP code (val: string, file: VFile) => { const iFrameUrl = new URL(val); - if (!iFrameUrl.protocol.startsWith("pfp-code:")) return val; + if (!iFrameUrl.protocol.startsWith("pfp-code:")) return {}; const contentDir = dirname(file.path); const fullPath = resolve(contentDir, iFrameUrl.pathname); @@ -101,9 +102,11 @@ export function createHtmlPlugins(unified: Processor) { const q = iFrameUrl.search; const repoPath = siteMetadata.repoPath; const provider = `stackblitz.com/github`; - return ` + return { + src: ` https://${provider}/${repoPath}/tree/${currentBranch}/${urlRelativePath}${q} - `.trim(); + `.trim(), + }; }, ], }) diff --git a/src/utils/markdown/iframes/rehype-transform.ts b/src/utils/markdown/iframes/rehype-transform.ts index fb5673f0c..be6b5ba7b 100644 --- a/src/utils/markdown/iframes/rehype-transform.ts +++ b/src/utils/markdown/iframes/rehype-transform.ts @@ -17,7 +17,17 @@ import { fetchPageHtml, getPageTitle } from "utils/fetch-page-html"; import { LRUCache } from "lru-cache"; interface RehypeUnicornIFrameClickToRunProps { - srcReplacements?: Array<(val: string, root: VFile) => string>; + replacements?: Array< + ( + val: string, + root: VFile, + ) => { + src?: string; + bgImg?: string; + btnColor?: string; + btnIconColor?: string; + } + >; } // default icon, used if a frame's favicon cannot be resolved @@ -175,7 +185,7 @@ export async function fetchPageInfo(src: string): Promise { export const rehypeUnicornIFrameClickToRun: Plugin< [RehypeUnicornIFrameClickToRunProps | never], Root -> = ({ srcReplacements = [], ...props }) => { +> = ({ replacements = [], ...props }) => { return async (tree, file) => { const iframeNodes: Element[] = []; visit(tree, "element", (node: Element) => { @@ -196,8 +206,12 @@ export const rehypeUnicornIFrameClickToRun: Plugin< ...propsToPreserve } = iframeNode.properties; - for (const replacement of srcReplacements) { - src = replacement(src!.toString(), file); + for (const replacement of replacements) { + const replacementData = replacement(src!.toString(), file); + + if (replacementData.src) { + src = replacementData.src; + } } width = width ?? EMBED_SIZE.w; From 4a58cf74612365f8de4805005db69ec6d1672b9b Mon Sep 17 00:00:00 2001 From: Ed Date: Sat, 25 Jan 2025 18:19:30 -0300 Subject: [PATCH 2/2] chore: aspect-ratio fix --- src/styles/markdown/embed.scss | 3 ++ src/utils/markdown/createHtmlPlugins.ts | 45 ++++++++++++++++++- .../markdown/iframes/iframe-placeholder.tsx | 10 ++++- src/utils/markdown/iframes/iframe-script.ts | 1 + .../markdown/iframes/rehype-transform.ts | 18 ++++++-- 5 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/styles/markdown/embed.scss b/src/styles/markdown/embed.scss index 9b404e9ff..5edfb5c35 100644 --- a/src/styles/markdown/embed.scss +++ b/src/styles/markdown/embed.scss @@ -98,6 +98,9 @@ &__placeholder { background-color: var(--embed_iframe_background-color); + background-size: cover; + background-position: center; + background-repeat: no-repeat; border: var(--embed-iframe_border-width) solid var(--embed_iframe_border_color); border-radius: var(--embed-iframe_corner-radius); diff --git a/src/utils/markdown/createHtmlPlugins.ts b/src/utils/markdown/createHtmlPlugins.ts index 3c3d87c8b..6f5be6e6f 100644 --- a/src/utils/markdown/createHtmlPlugins.ts +++ b/src/utils/markdown/createHtmlPlugins.ts @@ -83,7 +83,7 @@ export function createHtmlPlugins(unified: Processor) { .use(rehypeUnicornIFrameClickToRun, { replacements: [ // PFP code - (val: string, file: VFile) => { + async (val: string, file: VFile) => { const iFrameUrl = new URL(val); if (!iFrameUrl.protocol.startsWith("pfp-code:")) return {}; @@ -108,6 +108,49 @@ export function createHtmlPlugins(unified: Processor) { `.trim(), }; }, + + // Youtube embed + async (val) => { + const iFrameUrl = new URL(val); + if ( + iFrameUrl.hostname !== "youtube.com" && + iFrameUrl.hostname !== "www.youtube.com" && + iFrameUrl.hostname !== "youtu.be" + ) { + return {}; + } + + interface YouTubeLookup { + url: string; + version: string; + thumbnail_height: number; + provider_name: "YouTube"; + thumbnail_width: number; + width: number; + title: string; + author_name: string; + thumbnail_url: string; + author_url: string; + html: string; + type: "video"; + height: number; + provider_url: string; + } + + const json = await fetch( + `https://noembed.com/embed?dataType=json&url=${encodeURIComponent(val)}`, + ) + .then((r) => { + if (r.status !== 200) return null; + return r.json() as Promise; + }) + .catch(() => null); + if (!json) { + return {}; + } + + return { src: val, bgImg: json.thumbnail_url, aspectRatio: 16 / 9 }; + }, ], }) .use(rehypeTransformComponents, { diff --git a/src/utils/markdown/iframes/iframe-placeholder.tsx b/src/utils/markdown/iframes/iframe-placeholder.tsx index 5672f884a..5632b1393 100644 --- a/src/utils/markdown/iframes/iframe-placeholder.tsx +++ b/src/utils/markdown/iframes/iframe-placeholder.tsx @@ -9,6 +9,8 @@ const play = await fs.readFile("src/icons/play.svg", "utf8"); export interface IFramePlaceholderProps { width: string; height: string; + background: string | null; + aspectRatio : number | null; src: string; propsToPreserve: string; pageTitle: string; @@ -20,6 +22,8 @@ export interface IFramePlaceholderProps { export function IFramePlaceholder({ height, width, + background, + aspectRatio, propsToPreserve, ...props }: IFramePlaceholderProps): Element { @@ -70,7 +74,11 @@ export function IFramePlaceholder({ class="embed__placeholder" data-iframeurl={props.src} data-iframeprops={propsToPreserve} - style={`height: ${Number(height) ? `${height}px` : height};`} + style={` + ${!aspectRatio && height ? "height: " + (Number(height) ? height + 'px' : height) + ";" : ""} + ${background ? 'background-image: url("' + background + '");' : ""} + ${aspectRatio ? 'aspect-ratio:' + aspectRatio + ';' : ""} + `} >