Experiment to rebuild Diffuse using web applets.
0
fork

Configure Feed

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

feat: Audio experiment

+176 -24
+1 -1
src/common/pages/manifest.ts
··· 1 1 export function manifest(obj: Record<string, unknown>) { 2 - return async function GET({}) { 2 + return function GET() { 3 3 return new Response( 4 4 JSON.stringify(obj), 5 5 );
+8
src/layouts/applet.astro
··· 7 7 <meta charset="UTF-8" /> 8 8 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 9 9 <link rel="manifest" href="manifest.json" /> 10 + 10 11 <title>{title}</title> 12 + 13 + <style> 14 + html, 15 + body { 16 + margin: 0; 17 + } 18 + </style> 11 19 </head> 12 20 <body> 13 21 <slot />
+15
src/layouts/page.astro
··· 1 + --- 2 + const { title } = Astro.props; 3 + --- 4 + 5 + <html lang="en"> 6 + <head> 7 + <meta charset="UTF-8" /> 8 + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 9 + 10 + <title>{title}</title> 11 + </head> 12 + <body> 13 + <slot /> 14 + </body> 15 + </html>
+23 -11
src/pages/engines/audio/index.astro
··· 3 3 --- 4 4 5 5 <Applet title="Diffuse engines/audio applet"> 6 - <div id="name"></div> 6 + <div id="container"> 7 + <audio 8 + src="https://archive.org/download/lp_moonlight-sonata_ludwig-van-beethoven-frdric-chopin-alexand/disc1%2F01.02.%20Moonlight%20Sonata%20Op.%2027%2C%20No.%202%20In%20C%20Sharp%20Minor%3A%20Allegretto.mp3?tunnel=1" 9 + ></audio> 10 + </div> 7 11 8 12 <script> 9 13 import { applets } from "@web-applets/sdk"; 10 14 11 15 const context = applets.register(); 16 + const container = document.querySelector("#container"); 17 + const audio = document.querySelector("audio"); 12 18 13 - // Define a 'set_name' action, and make it update the shared data object with the new name 14 - context.setActionHandler("set_name", (args: any) => { 15 - context.data = { name: args.name }; 19 + audio.ontimeupdate = (event) => { 20 + context.data = { 21 + progress: 22 + isNaN(audio.duration) || audio.duration === 0 ? 0 : audio.currentTime / audio.duration, 23 + }; 24 + }; 25 + 26 + context.setActionHandler("load", (src: string) => { 27 + audio.src = src; 16 28 }); 17 29 18 - // Whenever the data is updated, update the view 19 - context.ondata = () => { 20 - const nameElement = document.getElementById("name"); 21 - if (nameElement) { 22 - nameElement.innerText = context.data.name; 23 - } 24 - }; 30 + context.setActionHandler("play", () => { 31 + audio.play(); 32 + }); 33 + 34 + context.setActionHandler("pause", () => { 35 + audio.pause(); 36 + }); 25 37 </script> 26 38 </Applet>
+19 -11
src/pages/engines/audio/manifest.json.ts
··· 4 4 name: "diffuse/engines/audio", 5 5 entrypoint: "index.html", 6 6 actions: { 7 - set_name: { 8 - title: "Set name", 9 - description: "", 7 + load: { 8 + title: "Load", 9 + description: "Load a given audio src", 10 10 params_schema: { 11 - type: "object", 12 - properties: { 13 - name: { 14 - type: "string", 15 - description: "", 16 - }, 17 - }, 18 - required: ["name"], 11 + type: "string", 12 + description: "String to be used as the audio `src`", 13 + }, 14 + }, 15 + pause: { 16 + title: "Pause", 17 + description: "Indicate the active audio should be paused", 18 + params_schema: { 19 + type: "null", 20 + }, 21 + }, 22 + play: { 23 + title: "Play", 24 + description: "Indicate the active audio should be playing", 25 + params_schema: { 26 + type: "null", 19 27 }, 20 28 }, 21 29 },
+50 -1
src/pages/index.astro
··· 1 - <iframe src="engines/audio" frameborder="0" height="0" width="0"></iframe> 1 + --- 2 + import Page from "../layouts/page.astro"; 3 + --- 4 + 5 + <Page title="Diffuse Applets Usage Example"> 6 + <iframe src="engines/audio" frameborder="0" height="0" width="0"></iframe> 7 + <iframe src="interface/audio" frameborder="0" style="width: 100%"></iframe> 8 + </Page> 9 + 10 + <script> 11 + import { applets } from "@web-applets/sdk"; 12 + 13 + async function applet(src: string, opts: { setHeight?: boolean } = {}) { 14 + const frame: HTMLIFrameElement = document.querySelector(`[src="${src}"]`); 15 + 16 + if (opts.setHeight) { 17 + frame.addEventListener( 18 + "load", 19 + () => { 20 + frame.height = frame.contentWindow.document.body.scrollHeight + "px"; 21 + }, 22 + { once: true }, 23 + ); 24 + } 25 + 26 + return await applets.connect(frame.contentWindow); 27 + } 28 + 29 + const index = { 30 + engines: { 31 + audio: await applet("engines/audio"), 32 + }, 33 + interface: { 34 + audio: await applet("interface/audio", { setHeight: true }), 35 + }, 36 + }; 37 + 38 + // Connect the applets 39 + index.interface.audio.ondata = (event) => { 40 + if (event.data.isPlaying) { 41 + index.engines.audio.sendAction("play", null); 42 + } else { 43 + index.engines.audio.sendAction("pause", null); 44 + } 45 + }; 46 + 47 + index.engines.audio.ondata = (event) => { 48 + index.interface.audio.sendAction("set_progress", event.data.progress); 49 + }; 50 + </script>
+38
src/pages/interface/audio/index.astro
··· 1 + --- 2 + import Applet from "../../../layouts/applet.astro"; 3 + --- 4 + 5 + <Applet title="Diffuse interface/audio applet"> 6 + <div 7 + style="background: dimgray; color: white; height: 100px; line-height: 100px; text-align: center;" 8 + > 9 + <button>▶️</button> 10 + <progress max="100" value="0"></progress> 11 + </div> 12 + 13 + <script> 14 + import { applets } from "@web-applets/sdk"; 15 + 16 + interface State { 17 + isPlaying: boolean; 18 + } 19 + 20 + const context = applets.register<State>(); 21 + 22 + context.setActionHandler("set_is_playing", (isPlaying: boolean) => { 23 + context.data = { ...context.data, isPlaying }; 24 + }); 25 + 26 + context.setActionHandler("set_progress", (progress: number) => { 27 + document.body.querySelector("progress").value = Math.round(progress * 100); 28 + }); 29 + 30 + context.ondata = () => { 31 + document.body.querySelector("button").innerText = context.data.isPlaying ? "⏸️" : "▶️"; 32 + }; 33 + 34 + document.body.querySelector("button").onclick = () => { 35 + context.data = { isPlaying: !(context.data?.isPlaying ?? false) }; 36 + }; 37 + </script> 38 + </Applet>
+22
src/pages/interface/audio/manifest.json.ts
··· 1 + import { manifest } from "../../../common/pages/manifest.ts"; 2 + 3 + export const GET = manifest({ 4 + name: "diffuse/interface/audio", 5 + entrypoint: "index.html", 6 + actions: { 7 + set_is_playing: { 8 + title: "Set is-playing state", 9 + description: "Indicate if audio is playing or not.", 10 + params_schema: { 11 + type: "boolean", 12 + }, 13 + }, 14 + set_progress: { 15 + title: "Set progress", 16 + description: "Indicate how far the audio has progressed.", 17 + params_schema: { 18 + type: "number", 19 + }, 20 + }, 21 + }, 22 + });