Rebuilt frontmatter templates as template widgets
This commit is contained in:
+4
-1
@@ -315,7 +315,10 @@ export class Client {
|
||||
setTimeout(() => {
|
||||
this.editorView.dispatch({
|
||||
selection: { anchor: pos as number },
|
||||
effects: EditorView.scrollIntoView(pos as number, { y: "start" }),
|
||||
effects: EditorView.scrollIntoView(pos as number, {
|
||||
y: "start",
|
||||
yMargin: 5,
|
||||
}),
|
||||
});
|
||||
});
|
||||
} else if (!stateRestored) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from "./util.ts";
|
||||
import { MarkdownWidget } from "./markdown_widget.ts";
|
||||
import { IFrameWidget } from "./iframe_widget.ts";
|
||||
import { isTemplate } from "$sb/lib/cheap_yaml.ts";
|
||||
|
||||
export function fencedCodePlugin(editor: Client) {
|
||||
return decoratorStateField((state: EditorState) => {
|
||||
@@ -27,7 +28,8 @@ export function fencedCodePlugin(editor: Client) {
|
||||
const renderMode = editor.system.codeWidgetHook.codeWidgetModes.get(
|
||||
lang,
|
||||
);
|
||||
if (codeWidgetCallback) {
|
||||
// Only custom render when we have a custom renderer, and the current page is not a template
|
||||
if (codeWidgetCallback && !isTemplate(state.sliceDoc(0, from))) {
|
||||
// We got a custom renderer!
|
||||
const lineStrings = text.split("\n");
|
||||
|
||||
|
||||
@@ -35,14 +35,23 @@ export class IFrameWidget extends WidgetType {
|
||||
case "reload":
|
||||
this.codeWidgetCallback(this.bodyText, this.client.currentPage!)
|
||||
.then(
|
||||
(widgetContent: WidgetContent) => {
|
||||
iframe.contentWindow!.postMessage({
|
||||
type: "html",
|
||||
html: widgetContent.html,
|
||||
script: widgetContent.script,
|
||||
theme:
|
||||
document.getElementsByTagName("html")[0].dataset.theme,
|
||||
});
|
||||
(widgetContent: WidgetContent | null) => {
|
||||
if (widgetContent === null) {
|
||||
iframe.contentWindow!.postMessage({
|
||||
type: "html",
|
||||
html: "",
|
||||
theme:
|
||||
document.getElementsByTagName("html")[0].dataset.theme,
|
||||
});
|
||||
} else {
|
||||
iframe.contentWindow!.postMessage({
|
||||
type: "html",
|
||||
html: widgetContent.html,
|
||||
script: widgetContent.script,
|
||||
theme:
|
||||
document.getElementsByTagName("html")[0].dataset.theme,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
break;
|
||||
|
||||
@@ -27,12 +27,10 @@ export class MarkdownWidget extends WidgetType {
|
||||
div.className = this.className;
|
||||
const cacheItem = this.client.getWidgetCache(this.cacheKey);
|
||||
if (cacheItem) {
|
||||
div.innerHTML = this.wrapHtml(
|
||||
cacheItem.html,
|
||||
cacheItem.buttons || [],
|
||||
cacheItem.banner,
|
||||
);
|
||||
this.attachListeners(div, cacheItem.buttons);
|
||||
div.innerHTML = this.wrapHtml(cacheItem.html, cacheItem.buttons);
|
||||
if (cacheItem.html) {
|
||||
this.attachListeners(div, cacheItem.buttons);
|
||||
}
|
||||
}
|
||||
|
||||
// Async kick-off of content renderer
|
||||
@@ -90,6 +88,7 @@ export class MarkdownWidget extends WidgetType {
|
||||
},
|
||||
preserveAttributes: true,
|
||||
});
|
||||
// console.log("Got html", html);
|
||||
|
||||
if (cachedHtml === html) {
|
||||
// HTML still same as in cache, no need to re-render
|
||||
@@ -97,10 +96,11 @@ export class MarkdownWidget extends WidgetType {
|
||||
}
|
||||
div.innerHTML = this.wrapHtml(
|
||||
html,
|
||||
widgetContent.buttons || [],
|
||||
widgetContent.banner,
|
||||
widgetContent.buttons,
|
||||
);
|
||||
this.attachListeners(div, widgetContent.buttons);
|
||||
if (html) {
|
||||
this.attachListeners(div, widgetContent.buttons);
|
||||
}
|
||||
|
||||
// Let's give it a tick, then measure and cache
|
||||
setTimeout(() => {
|
||||
@@ -110,7 +110,6 @@ export class MarkdownWidget extends WidgetType {
|
||||
height: div.offsetHeight,
|
||||
html,
|
||||
buttons: widgetContent.buttons,
|
||||
banner: widgetContent.banner,
|
||||
},
|
||||
);
|
||||
// Because of the rejiggering of the DOM, we need to do a no-op cursor move to make sure it's positioned correctly
|
||||
@@ -124,8 +123,7 @@ export class MarkdownWidget extends WidgetType {
|
||||
|
||||
private wrapHtml(
|
||||
html: string,
|
||||
buttons: CodeWidgetButton[],
|
||||
banner?: string,
|
||||
buttons: CodeWidgetButton[] = [],
|
||||
) {
|
||||
if (!html) {
|
||||
return "";
|
||||
@@ -134,9 +132,7 @@ export class MarkdownWidget extends WidgetType {
|
||||
buttons.filter((button) => !button.widgetTarget).map((button, idx) =>
|
||||
`<button data-button="${idx}" title="${button.description}">${button.svg}</button> `
|
||||
).join("")
|
||||
}</div>${
|
||||
banner ? `<div class="sb-banner">${escapeHtml(banner)}</div>` : ""
|
||||
}${html}`;
|
||||
}</div>${html}`;
|
||||
}
|
||||
|
||||
private attachListeners(div: HTMLElement, buttons?: CodeWidgetButton[]) {
|
||||
@@ -255,10 +251,3 @@ function garbageCollectWidgets() {
|
||||
}
|
||||
|
||||
setInterval(garbageCollectWidgets, 5000);
|
||||
|
||||
function escapeHtml(text: string) {
|
||||
return text.replace(/&/g, "&").replace(/</g, "<").replace(
|
||||
/>/g,
|
||||
">",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ export function postScriptPrefacePlugin(
|
||||
undefined,
|
||||
editor,
|
||||
`top:${editor.currentPage}`,
|
||||
"",
|
||||
"top",
|
||||
topCallback,
|
||||
"sb-markdown-top-widget",
|
||||
),
|
||||
@@ -34,7 +34,7 @@ export function postScriptPrefacePlugin(
|
||||
undefined,
|
||||
editor,
|
||||
`bottom:${editor.currentPage}`,
|
||||
"",
|
||||
"bottom",
|
||||
bottomCallback,
|
||||
"sb-markdown-bottom-widget",
|
||||
),
|
||||
|
||||
@@ -104,7 +104,7 @@ export function mountIFrame(
|
||||
preloadedIFrame: PreloadedIFrame,
|
||||
client: Client,
|
||||
widgetHeightCacheKey: string | null,
|
||||
content: WidgetContent | Promise<WidgetContent>,
|
||||
content: WidgetContent | null | Promise<WidgetContent | null>,
|
||||
onMessage?: (message: any) => void,
|
||||
) {
|
||||
const iframe = preloadedIFrame.iframe;
|
||||
@@ -174,26 +174,28 @@ export function mountIFrame(
|
||||
console.warn("Iframe went away or content was not loaded");
|
||||
return;
|
||||
}
|
||||
if (resolvedContent.html) {
|
||||
iframe.contentWindow!.postMessage({
|
||||
type: "html",
|
||||
html: resolvedContent.html,
|
||||
script: resolvedContent.script,
|
||||
theme: document.getElementsByTagName("html")[0].dataset.theme,
|
||||
});
|
||||
} else if (resolvedContent.url) {
|
||||
iframe.contentWindow!.location.href = resolvedContent.url;
|
||||
if (resolvedContent.height) {
|
||||
iframe.height = resolvedContent.height + "px";
|
||||
if (widgetHeightCacheKey) {
|
||||
client.setCachedWidgetHeight(
|
||||
widgetHeightCacheKey!,
|
||||
resolvedContent.height,
|
||||
);
|
||||
if (resolvedContent) {
|
||||
if (resolvedContent.html) {
|
||||
iframe.contentWindow!.postMessage({
|
||||
type: "html",
|
||||
html: resolvedContent.html,
|
||||
script: resolvedContent.script,
|
||||
theme: document.getElementsByTagName("html")[0].dataset.theme,
|
||||
});
|
||||
} else if (resolvedContent.url) {
|
||||
iframe.contentWindow!.location.href = resolvedContent.url;
|
||||
if (resolvedContent.height) {
|
||||
iframe.height = resolvedContent.height + "px";
|
||||
if (widgetHeightCacheKey) {
|
||||
client.setCachedWidgetHeight(
|
||||
widgetHeightCacheKey!,
|
||||
resolvedContent.height,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (resolvedContent.width) {
|
||||
iframe.width = resolvedContent.width + "px";
|
||||
}
|
||||
}
|
||||
if (resolvedContent.width) {
|
||||
iframe.width = resolvedContent.width + "px";
|
||||
}
|
||||
}
|
||||
}).catch(console.error);
|
||||
@@ -202,7 +204,7 @@ export function mountIFrame(
|
||||
export function createWidgetSandboxIFrame(
|
||||
client: Client,
|
||||
widgetHeightCacheKey: string | null,
|
||||
content: WidgetContent | Promise<WidgetContent>,
|
||||
content: WidgetContent | null | Promise<WidgetContent | null>,
|
||||
onMessage?: (message: any) => void,
|
||||
) {
|
||||
// console.log("Claiming iframe");
|
||||
|
||||
@@ -48,7 +48,7 @@ export class PanelWidgetHook implements Hook<PanelWidgetT> {
|
||||
if (!functionDef.panelWidget) {
|
||||
continue;
|
||||
}
|
||||
if (!["top", "bottom", "frontmatter"].includes(functionDef.panelWidget)) {
|
||||
if (!["top", "bottom"].includes(functionDef.panelWidget)) {
|
||||
errors.push(
|
||||
`Panel widgets must be attached to either 'top' or 'bottom'.`,
|
||||
);
|
||||
|
||||
@@ -429,8 +429,6 @@
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.sb-markdown-widget,
|
||||
.sb-markdown-top-widget:has(*),
|
||||
.sb-markdown-bottom-widget:has(*) {
|
||||
|
||||
@@ -11,7 +11,7 @@ export function codeWidgetSyscalls(
|
||||
lang: string,
|
||||
body: string,
|
||||
pageName: string,
|
||||
): Promise<CodeWidgetContent> => {
|
||||
): Promise<CodeWidgetContent | null> => {
|
||||
const langCallback = codeWidgetHook.codeWidgetCallbacks.get(
|
||||
lang,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user