Experiment to rebuild Diffuse using web applets.
0
fork

Configure Feed

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

fix: Apparently this behaves totally different on HTTPS 🤷‍♂️

+38 -19
+1
.gitignore
··· 1 1 .astro 2 + .dprc 2 3 dist 3 4 node_modules
+1
deno.json
··· 6 6 "spellcaster": "npm:spellcaster@^5.0.2" 7 7 }, 8 8 "tasks": { 9 + "astro": "astro", 9 10 "build": "astro build", 10 11 "dev": "astro dev" 11 12 },
+18 -1
src/applets/engine/audio/applet.astro
··· 1 1 <div id="container"> 2 2 <audio 3 + crossorigin="anonymous" 3 4 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" 4 - ></audio> 5 + preload="auto" 6 + controls></audio> 5 7 </div> 6 8 7 9 <script> ··· 36 38 audio.onpause = () => (context.data = { ...context.data, isPlaying: false }); 37 39 audio.onplay = () => (context.data = { ...context.data, isPlaying: true }); 38 40 41 + // TODO: 42 + // audio.oncanplay = (event) => console.log("canplay", event); 43 + // audio.onemptied = (event) => console.log("emptied", event); 44 + // audio.onended = (event) => console.log("ended", event); 45 + // audio.onloadeddata = (event) => console.log("loadeddata", event); 46 + // audio.onloadedmetadata = (event) => console.log("loadedmetadata", event); 47 + // audio.onloadstart = (event) => console.log("loadstart", event); 48 + // audio.onplaying = (event) => console.log("playing", event); 49 + // audio.onstalled = (event) => console.log("stalled", event); 50 + // audio.onsuspend = (event) => console.log("suspend", event); 51 + // audio.onwaiting = (event) => console.log("waiting", event); 52 + 53 + audio.onerror = (err) => console.error(err); 54 + 39 55 //////////////////////////////////////////// 40 56 // Actions 41 57 //////////////////////////////////////////// 42 58 context.setActionHandler("load", (src: string) => { 43 59 audio.src = src; 60 + audio.load(); 44 61 }); 45 62 46 63 context.setActionHandler("play", () => {
+5 -3
src/applets/themes/pilot/ui/audio/applet.astro
··· 34 34 background: transparent; 35 35 border: 0; 36 36 color: inherit; 37 + cursor: pointer; 37 38 display: inline-block; 38 39 line-height: 0; 39 40 } ··· 113 114 }); 114 115 115 116 context.setActionHandler("set_progress", (progress: number) => { 116 - document.body.querySelector("progress").value = Math.round(progress * 100); 117 + const p = isNaN(progress) || !isFinite(progress) ? 0 : Math.min(Math.max(progress, 0), 1); 118 + document.body.querySelector("progress").value = p * 100; 117 119 }); 118 120 119 121 //////////////////////////////////////////// 120 122 // DOM 121 123 //////////////////////////////////////////// 122 - document.body.querySelector("button").onclick = () => { 124 + document.body.querySelector(".controls__playpause").addEventListener("click", () => { 123 125 context.data = { isPlaying: !(context.data?.isPlaying ?? false) }; 124 - }; 126 + }); 125 127 126 128 function render() { 127 129 document.body.querySelector("button").innerHTML = context.data.isPlaying
+1 -1
src/pages/themes/pilot/index.astro
··· 9 9 <iframe id="applet__ui__audio" src="ui/audio/" frameborder="0"></iframe> 10 10 11 11 <!-- Other applets --> 12 - <iframe id="applet__engine__audio" src="../../engine/audio/" frameborder="0" height="0" width="0" 12 + <iframe id="applet__engine__audio" src="../../engine/audio/" frameborder="0" height="1" width="1" 13 13 ></iframe> 14 14 </Page>
+7 -10
src/scripts/themes/pilot/index.ts
··· 19 19 //////////////////////////////////////////// 20 20 reactive( 21 21 ui.audio, 22 - (isPlaying: boolean) => 23 - engine.audio.sendAction(isPlaying ? "play" : "pause", null), 22 + "isPlaying", 23 + (isPlaying: boolean) => engine.audio.sendAction(isPlaying ? "play" : "pause", null), 24 24 ); 25 25 26 26 reactive( 27 27 engine.audio, 28 + "isPlaying", 28 29 (isPlaying: boolean) => ui.audio.sendAction("set_is_playing", isPlaying), 29 30 ); 30 31 31 32 reactive( 32 33 engine.audio, 34 + "progress", 33 35 (progress: number) => ui.audio.sendAction("set_progress", progress), 34 36 ); 35 37 ··· 58 60 // 🔮 Reactive state management 59 61 //////////////////////////////////////////// 60 62 // TODO: Applet should have a subtype 61 - function reactive<T>(applet: Applet, effectFn: (t: T) => void) { 62 - const property = effectFn 63 - .toString() 64 - .slice(1) 65 - .match(/([^(\)|,|\s)]+)/); 66 - 63 + function reactive<T>(applet: Applet, property: string, effectFn: (t: T) => void) { 67 64 const [getter, setter] = signal( 68 - (applet.data as any)[property ? property[1] : "ignore"] as T, 65 + (applet.data as any)[property] as T, 69 66 ); 70 67 71 68 effect(() => effectFn(getter())); 72 69 73 70 applet.addEventListener("data", (event: AppletEvent) => { 74 - setter(event.data[property ? property[1] : "ignore"]); 71 + setter(event.data[property]); 75 72 }); 76 73 }
+5 -4
src/styles/themes/pilot/index.css
··· 36 36 37 37 /*********************************** 38 38 * Applets (No UI) 39 - * --------------- 40 - * Position engines outside the viewframe 41 39 ***********************************/ 40 + 41 + /* Audio is special case, iframe needs to be "visible" in order to play the audio. */ 42 42 #applet__engine__audio { 43 - left: 110vw; 43 + left: 0; 44 + pointer-events: none; 44 45 position: absolute; 45 - top: 110vh; 46 + top: 0; 46 47 }