From a4c103e127fab8e9ad250bcedfa2c5ff03c3d1ab Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Sat, 21 Jan 2023 13:37:55 +0100 Subject: [PATCH] Fixes #258 --- .gitignore | 2 +- plug-api/app_event.ts | 8 ++++++ plugs/core/core.plug.yaml | 4 +++ plugs/core/embed.ts | 47 ++++++++++++++++++++++++++++++++ plugs/markdown/widget.ts | 3 +- web/cm_plugins/fenced_code.ts | 38 ++++++++++++++++++-------- web/components/panel.tsx | 2 +- website/CHANGELOG.md | 1 + website/Markdown.md | 1 + website/Markdown/Code Widgets.md | 40 +++++++++++++++++++++++++++ website/SilverBullet.md | 7 +++-- 11 files changed, 137 insertions(+), 16 deletions(-) create mode 100644 plugs/core/embed.ts create mode 100644 website/Markdown/Code Widgets.md diff --git a/.gitignore b/.gitignore index 479c8469..0e5d25a7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ dist_bundle dist *.js.map website_build -data.db +data.db* publish-data.db /index.json .idea diff --git a/plug-api/app_event.ts b/plug-api/app_event.ts index c735ae85..7a105b91 100644 --- a/plug-api/app_event.ts +++ b/plug-api/app_event.ts @@ -42,3 +42,11 @@ export type CompleteEvent = { linePrefix: string; pos: number; }; + +export type WidgetContent = { + html?: string; + script?: string; + url?: string; + height?: number; + width?: number; +}; diff --git a/plugs/core/core.plug.yaml b/plugs/core/core.plug.yaml index 04f7c6f1..1063946f 100644 --- a/plugs/core/core.plug.yaml +++ b/plugs/core/core.plug.yaml @@ -409,6 +409,10 @@ functions: events: - unfurl:title-unfurl + embedWidget: + path: ./embed.ts:embedWidget + codeWidget: embed + # Random stuff statsCommand: path: ./stats.ts:statsCommand diff --git a/plugs/core/embed.ts b/plugs/core/embed.ts new file mode 100644 index 00000000..1173ff27 --- /dev/null +++ b/plugs/core/embed.ts @@ -0,0 +1,47 @@ +import * as YAML from "yaml"; +import type { WidgetContent } from "$sb/app_event.ts"; + +type EmbedConfig = { + url: string; + height?: number; + width?: number; +}; + +function extractYoutubeVideoId(url: string) { + let match = url.match(/youtube\.com\/watch\?v=([^&]+)/); + if (match) { + return match[1]; + } + match = url.match(/youtu.be\/([^&]+)/); + if (match) { + return match[1]; + } + + return null; +} + +export function embedWidget( + bodyText: string, +): WidgetContent { + try { + const data: EmbedConfig = YAML.parse(bodyText) as any; + let url = data.url; + const youtubeVideoId = extractYoutubeVideoId(url); + if (youtubeVideoId) { + url = `https://www.youtube.com/embed/${youtubeVideoId}`; + // Sensible video defaults + data.width = data.width || 560; + data.height = data.height || 315; + } + return { + url, + height: data.height, + width: data.width, + }; + } catch (e: any) { + return { + html: `ERROR: Could not parse body as YAML: ${e.message}`, + script: "", + }; + } +} diff --git a/plugs/markdown/widget.ts b/plugs/markdown/widget.ts index 10117756..9efe10f4 100644 --- a/plugs/markdown/widget.ts +++ b/plugs/markdown/widget.ts @@ -1,9 +1,10 @@ import { parseMarkdown } from "$sb/silverbullet-syscall/markdown.ts"; +import type { WidgetContent } from "$sb/app_event.ts"; import { renderMarkdownToHtml } from "./markdown_render.ts"; export async function markdownWidget( bodyText: string, -): Promise<{ html: string; script: string }> { +): Promise { const mdTree = await parseMarkdown(bodyText); const html = renderMarkdownToHtml(mdTree, { diff --git a/web/cm_plugins/fenced_code.ts b/web/cm_plugins/fenced_code.ts index ba7bceae..500618bf 100644 --- a/web/cm_plugins/fenced_code.ts +++ b/web/cm_plugins/fenced_code.ts @@ -1,3 +1,4 @@ +import { WidgetContent } from "../../plug-api/app_event.ts"; import { panelHtml } from "../components/panel.tsx"; import { Decoration, EditorState, syntaxTree, WidgetType } from "../deps.ts"; import type { Editor } from "../editor.tsx"; @@ -20,6 +21,7 @@ class IFrameWidget extends WidgetType { } toDOM(): HTMLElement { + console.log("toDOM"); const iframe = document.createElement("iframe"); iframe.srcdoc = panelHtml; // iframe.style.height = "0"; @@ -60,17 +62,31 @@ class IFrameWidget extends WidgetType { iframe.onload = () => { // Subscribe to message event on global object (to receive messages from iframe) globalThis.addEventListener("message", messageListener); - this.codeWidgetCallback(this.bodyText).then(({ html, script }) => { - iframe.contentWindow!.postMessage({ - type: "html", - html, - script, - }); - iframe.contentWindow!.onunload = () => { - // Unsubscribing from events - globalThis.removeEventListener("message", messageListener); - }; - }); + // Only run this code once + iframe.onload = null; + this.codeWidgetCallback(this.bodyText).then( + (widgetContent: WidgetContent) => { + if (widgetContent.html) { + iframe.contentWindow!.postMessage({ + type: "html", + html: widgetContent.html, + script: widgetContent.script, + }); + // iframe.contentWindow!.onunload = () => { + // // Unsubscribing from events + // globalThis.removeEventListener("message", messageListener); + // }; + } else if (widgetContent.url) { + iframe.contentWindow!.location.href = widgetContent.url; + if (widgetContent.height) { + iframe.style.height = widgetContent.height + "px"; + } + if (widgetContent.width) { + iframe.style.width = widgetContent.width + "px"; + } + } + }, + ); }; return iframe; } diff --git a/web/components/panel.tsx b/web/components/panel.tsx index 11932560..9c9cd7e0 100644 --- a/web/components/panel.tsx +++ b/web/components/panel.tsx @@ -89,7 +89,7 @@ function loadJsByUrl(url) { -Send me HTML +Loading... `; diff --git a/website/CHANGELOG.md b/website/CHANGELOG.md index edf53e41..d618851f 100644 --- a/website/CHANGELOG.md +++ b/website/CHANGELOG.md @@ -6,6 +6,7 @@ release. ## Next * Fixed copy & paste, drag & drop of attachments in the [[Desktop]] app * Continuous [[Sync]] +* Support for embedding [[Markdown/Code Widgets]]. --- ## 0.2.8 diff --git a/website/Markdown.md b/website/Markdown.md index 5728a496..11d36d76 100644 --- a/website/Markdown.md +++ b/website/Markdown.md @@ -8,6 +8,7 @@ We mentioned markdown _extensions_, here are the ones currently supported: * Double-bracketed wiki links: `[[link to page]]`, optionally with aliases `[[link to page|alias]]`. * Hashtags, e.g. `#mytag`. * Command link syntax: `{[Stats: Show]}` rendered into a clickable button {[Stats: Show]}. +* [[Markdown/Code Widgets]] * [Tables](https://www.markdownguide.org/extended-syntax/#tables) * [Fenced code blocks](https://www.markdownguide.org/extended-syntax/#fenced-code-blocks) * [Task lists](https://www.markdownguide.org/extended-syntax/#task-lists) diff --git a/website/Markdown/Code Widgets.md b/website/Markdown/Code Widgets.md new file mode 100644 index 00000000..8e595915 --- /dev/null +++ b/website/Markdown/Code Widgets.md @@ -0,0 +1,40 @@ +Code widgets are a SilverBullet specific “extensions” to [[Markdown]]. Technically, it’s not an extension — it just gives new semantics to markdown’s native fenced code blocks — code blocks that start with a triple backtick, specifying a programming language. + +Currently, SilverBullet provides two code widgets as part of its built in [[🔌 Plugs]]: + +* `embed` +* `markdown` + +In addition, plugs like [[🔌 KaTeX]] and [[🔌 Mermaid]] add additional ones. + +## Embed +This allows you to embed internet content into your page inside of an iframe. This is useful to, for instance, embed youtube videos. In fact, there is specific support for those. + +Two examples. + +First, embedding the silverbullet.md website into the silverbullet.md website (inception!): + +```embed +url: https://silverbullet.md +``` + +and a Youtube video: + +```embed +url: https://www.youtube.com/watch?v=VemS-cqAD5k +``` + +Note, there is specific support for youtube videos — it automatically will set width, height and replace the URL with an embed URL. + +The body of an `embed` block is written in [[YAML]] and supports the following attributes: + +* `url` (mandatory): the URL of the content to embed +* `height` (optional): the height of the embedded page in pixels +* `width` (optional): the width of the embedded page in pixels + +## Markdown +You can embed markdown inside of markdown and live preview it. Is this useful? 🤷 not really, it’s more of a demo of how this works. Nevertheless, to each their own, here’s an example: + +```markdown +This is going to be **bold** +``` \ No newline at end of file diff --git a/website/SilverBullet.md b/website/SilverBullet.md index 8c58b754..f86f19cc 100644 --- a/website/SilverBullet.md +++ b/website/SilverBullet.md @@ -20,8 +20,11 @@ Now that we got that out of the way, let’s have a look at some of SilverBullet * **Self-hosted**: you own your data. All content is stored as plain files in a folder on disk. Back up, sync, edit, publish, script with any additional tools you like. * SilverBullet is [open source, MIT licensed](https://github.com/silverbulletmd/silverbullet) software. -![Screencast screenshot](demo-video-screenshot.png) -To get a good feel of what SilverBullet is capable of, [have a look at this introduction video](https://youtu.be/VemS-cqAD5k). +To get a good feel of what SilverBullet is capable of, have a look at this introduction video. + +```embed +url: https://youtu.be/VemS-cqAD5k +``` ## Try it Here’s the kicker: