import { DiffuseElement, query, whenElementsDefined } from "@common/element.js"; import { signal } from "@common/signal.js"; import { highlightTableEntry } from "../common/ui.js"; /** * @import {RenderArg} from "@common/element.d.ts" * @import {Track} from "@definitions/types.d.ts" * @import {InputElement} from "@components/input/types.d.ts" * @import {OutputElement} from "@components/output/types.d.ts" */ class Browser extends DiffuseElement { constructor() { super(); this.attachShadow({ mode: "open" }); this.performSearch = this.performSearch.bind(this); } // SIGNALS #searchResults = signal(/** @type {Track[]} */ ([])); $input = signal( /** @type {InputElement | undefined} */ (undefined), ); $output = signal( /** @type {OutputElement | undefined} */ (undefined), ); $queue = signal( /** @type {import("@components/engine/queue/element.js").CLASS | undefined} */ (undefined), ); $search = signal( /** @type {import("@components/processor/search/element.js").CLASS | undefined} */ (undefined), ); // LIFECYCLE /** * @override */ connectedCallback() { super.connectedCallback(); /** @type {InputElement} */ const input = query(this, "input-selector"); /** @type {OutputElement} */ const output = query(this, "output-selector"); /** @type {import("@components/engine/queue/element.js").CLASS} */ const queue = query(this, "queue-engine-selector"); /** @type {import("@components/processor/search/element.js").CLASS} */ const search = query(this, "search-processor-selector"); this.$input.value = input; this.$output.value = output; this.$queue.value = queue; this.$search.value = search; // Wait for the above dependencies to be defined, then render again. whenElementsDefined({ input, output, search }).then(() => { this.effect(() => { const _cacheId = search.cacheId(); this.performSearch(); }); this.effect(() => { this.forceRender(); }); }); // Effects this.effect(() => { const _results = this.#searchResults.value; this.root().querySelector(".sunken-panel")?.scrollTo(0, 0); }); } // EVENTS /** * @param {Track} track */ playTrack(track) { this.$queue.value?.add({ inFront: true, tracks: [track], }); this.$queue.value?.shift(); } async performSearch() { /** @type {HTMLInputElement | null} */ const input = this.root().querySelector("#search-input"); const term = input?.value?.trim(); this.#searchResults.value = await this.$search.value?.search({ term: term, }) ?? []; } // RENDER /** * @param {RenderArg} _ */ render({ html }) { const isLoading = this.$output.value?.tracks?.state() !== "loaded" || (this.$output.value?.tracks?.collection()?.length && this.$search.value?.cacheId() === undefined); const tracks = this.#searchResults.value; return html`
${isLoading ? html` ` : tracks.map((track) => { return html` `; })}
Title Artist Album
Loading ...
${track.tags?.title} ${track.tags?.artist} ${track.tags?.album}
`; } } export default Browser; //////////////////////////////////////////// // REGISTER //////////////////////////////////////////// export const CLASS = Browser; export const NAME = "dtw-browser"; customElements.define(NAME, CLASS);