forked from
tokono.ma/diffuse
A music player that connects to your cloud/distributed storage.
1import { BroadcastableDiffuseElement, query } from "~/common/element.js";
2import { computed, signal } from "~/common/signal.js";
3
4/**
5 * @import { OutputElement, OutputManagerDeputy } from "../../output/types.d.ts"
6 */
7
8/**
9 * @template [T=null]
10 */
11export class OutputTransformer extends BroadcastableDiffuseElement {
12 // SIGNALS
13
14 #output = signal(/** @type {OutputElement<T> | undefined} */ (undefined));
15 #outputWhenDefined = Promise.withResolvers();
16
17 output = {
18 whenDefined: this.#outputWhenDefined.promise,
19 signal: this.#output.get,
20 };
21
22 // LIFECYCLE
23
24 /**
25 * @override
26 */
27 connectedCallback() {
28 super.connectedCallback();
29
30 /** @type {OutputElement<T>} */
31 const output = query(this, "output-selector");
32
33 // When defined
34 customElements.whenDefined(output.localName).then(() => {
35 this.#output.value = output;
36 this.#outputWhenDefined.resolve(null);
37 });
38 }
39
40 // MANAGER
41
42 base() {
43 /** @type {OutputManagerDeputy<T>} */
44 const m = {
45 facets: {
46 collection: computed(() => {
47 return this.output.signal()?.facets?.collection() ??
48 { state: "loading" };
49 }),
50 reload: () => {
51 return this.output.signal()?.facets?.reload() ??
52 Promise.resolve();
53 },
54 save: async (newFacets) => {
55 await this.output.whenDefined;
56 await this.output.signal()?.facets.save(newFacets);
57 },
58 },
59 playlistItems: {
60 collection: computed(() => {
61 return this.output.signal()?.playlistItems?.collection() ??
62 { state: "loading" };
63 }),
64 reload: () => {
65 return this.output.signal()?.playlistItems?.reload() ??
66 Promise.resolve();
67 },
68 save: async (newPlaylistItems) => {
69 await this.output.whenDefined;
70 await this.output.signal()?.playlistItems.save(newPlaylistItems);
71 },
72 },
73 settings: {
74 collection: computed(() => {
75 return this.output.signal()?.settings?.collection() ??
76 { state: "loading" };
77 }),
78 reload: () => {
79 return this.output.signal()?.settings?.reload() ??
80 Promise.resolve();
81 },
82 save: async (newSettings) => {
83 await this.output.whenDefined;
84 await this.output.signal()?.settings.save(newSettings);
85 },
86 },
87 tracks: {
88 collection: computed(() => {
89 return this.output.signal()?.tracks?.collection() ??
90 { state: "loading" };
91 }),
92 reload: () => {
93 return this.output.signal()?.tracks?.reload() ?? Promise.resolve();
94 },
95 save: async (newTracks) => {
96 await this.output.whenDefined;
97 await this.output.signal()?.tracks.save(newTracks);
98 },
99 },
100
101 // Other non-data related state
102 ready: computed(() => this.output.signal()?.ready() ?? false),
103 };
104
105 return m;
106 }
107}