Experiment to rebuild Diffuse using web applets.
0

Configure Feed

Select the types of activity you want to include in your feed.

1import type { Applet, AppletEvent } from "@web-applets/sdk"; 2 3import { applets } from "@web-applets/sdk"; 4import { type ElementConfigurator, h } from "spellcaster/hyperscript.js"; 5import { effect, isSignal, sample, Signal, signal } from "spellcaster/spellcaster.js"; 6import { xxh32 } from "xxh32"; 7 8//////////////////////////////////////////// 9// 🪟 Applet initialiser 10//////////////////////////////////////////// 11export async function applet<D>( 12 src: string, 13 opts: { 14 addSlashSuffix?: boolean; 15 context?: Window; 16 container?: HTMLElement; 17 id?: string; 18 setHeight?: boolean; 19 } = {}, 20): Promise<Applet<D>> { 21 src = `${src}${ 22 src.endsWith("/") 23 ? "" 24 : opts.addSlashSuffix === undefined || opts.addSlashSuffix === true 25 ? "/" 26 : "" 27 }`; 28 29 const existingFrame: HTMLIFrameElement | null = (opts.context || window).document.querySelector( 30 `[src="${src}"]`, 31 ); 32 33 let frame; 34 35 if (existingFrame) { 36 frame = existingFrame; 37 } else { 38 frame = document.createElement("iframe"); 39 frame.src = src; 40 if (opts.id) frame.id = opts.id; 41 42 if (opts.container) { 43 opts.container.appendChild(frame); 44 } else { 45 (opts.context || window).document.body.appendChild(frame); 46 } 47 } 48 49 if (frame.contentWindow === null) { 50 throw new Error("iframe does not have a contentWindow"); 51 } 52 53 const applet = await applets.connect<D>(frame.contentWindow, { context: opts.context }); 54 55 if (opts.setHeight) { 56 applet.onresize = () => { 57 frame.height = `${applet.height}px`; 58 frame.classList.add("has-loaded"); 59 }; 60 } else { 61 if (frame.contentDocument?.readyState === "complete") { 62 frame.classList.add("has-loaded"); 63 } 64 65 frame.addEventListener("load", () => { 66 frame.classList.add("has-loaded"); 67 }); 68 } 69 70 return applet; 71} 72 73//////////////////////////////////////////// 74// 🔮 Reactive state management 75//////////////////////////////////////////// 76export function reactive<D, T>( 77 applet: Applet<D>, 78 dataFn: (data: D) => T, 79 effectFn: (t: T) => void, 80) { 81 const [getter, setter] = signal(dataFn(applet.data)); 82 83 effect(() => effectFn(getter())); 84 85 applet.addEventListener("data", (event: AppletEvent) => { 86 setter(dataFn(event.data)); 87 }); 88} 89 90//////////////////////////////////////////// 91// 🛠️ 92//////////////////////////////////////////// 93export function addScope<O extends Object>(astroScope: string, object: O): O { 94 return { 95 ...object, 96 attrs: { ...((object as any).attrs || {}), [`data-astro-cid-${astroScope}`]: "" }, 97 }; 98} 99 100export function comparable(value: unknown) { 101 return xxh32(JSON.stringify(value)); 102} 103 104export function hs( 105 tag: string, 106 astroScope: string, 107 props?: Record<string, unknown> | Signal<Record<string, unknown>>, 108 configure?: ElementConfigurator, 109) { 110 const propsWithScope = 111 props && isSignal(props) 112 ? () => addScope(astroScope, props()) 113 : addScope(astroScope, props || {}); 114 115 return h(tag, propsWithScope, configure); 116} 117 118export function isPrimitive(test: unknown) { 119 return test !== Object(test); 120}