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