Fixes #258
parent
9fbe78dadd
commit
a4c103e127
|
@ -5,7 +5,7 @@ dist_bundle
|
|||
dist
|
||||
*.js.map
|
||||
website_build
|
||||
data.db
|
||||
data.db*
|
||||
publish-data.db
|
||||
/index.json
|
||||
.idea
|
||||
|
|
|
@ -42,3 +42,11 @@ export type CompleteEvent = {
|
|||
linePrefix: string;
|
||||
pos: number;
|
||||
};
|
||||
|
||||
export type WidgetContent = {
|
||||
html?: string;
|
||||
script?: string;
|
||||
url?: string;
|
||||
height?: number;
|
||||
width?: number;
|
||||
};
|
||||
|
|
|
@ -409,6 +409,10 @@ functions:
|
|||
events:
|
||||
- unfurl:title-unfurl
|
||||
|
||||
embedWidget:
|
||||
path: ./embed.ts:embedWidget
|
||||
codeWidget: embed
|
||||
|
||||
# Random stuff
|
||||
statsCommand:
|
||||
path: ./stats.ts:statsCommand
|
||||
|
|
|
@ -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: "",
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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<WidgetContent> {
|
||||
const mdTree = await parseMarkdown(bodyText);
|
||||
|
||||
const html = renderMarkdownToHtml(mdTree, {
|
||||
|
|
|
@ -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 }) => {
|
||||
// Only run this code once
|
||||
iframe.onload = null;
|
||||
this.codeWidgetCallback(this.bodyText).then(
|
||||
(widgetContent: WidgetContent) => {
|
||||
if (widgetContent.html) {
|
||||
iframe.contentWindow!.postMessage({
|
||||
type: "html",
|
||||
html,
|
||||
script,
|
||||
});
|
||||
iframe.contentWindow!.onunload = () => {
|
||||
// Unsubscribing from events
|
||||
globalThis.removeEventListener("message", messageListener);
|
||||
};
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ function loadJsByUrl(url) {
|
|||
</script>
|
||||
</head>
|
||||
<body>
|
||||
Send me HTML
|
||||
Loading...
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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**
|
||||
```
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue