A music player that connects to your cloud/distributed storage.
5
fork

Configure Feed

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

feat: save or fork facets

+371 -157
+1
deno.jsonc
··· 13 13 "@codemirror/lang-css": "npm:@codemirror/lang-css@^6.3.1", 14 14 "@codemirror/lang-html": "npm:@codemirror/lang-html@^6.4.11", 15 15 "@codemirror/lang-javascript": "npm:@codemirror/lang-javascript@^6.2.4", 16 + "@fcrozatier/htmlcrunch": "jsr:@fcrozatier/htmlcrunch@^1.5.1", 16 17 "@fry69/deep-diff": "jsr:@fry69/deep-diff@^0.1.10", 17 18 "@js-temporal/polyfill": "npm:@js-temporal/polyfill@^0.5.1", 18 19 "@kunkun/kkrpc": "jsr:@kunkun/kkrpc@^0.6.0",
+4 -4
src/_components/facets.vto
··· 1 1 <ul> 2 2 {{ for item of items }} 3 - <li> 3 + <li data-url="{{item.url}}" data-name="{{item.title}}"> 4 4 <span>{{item.title}}</span> 5 5 <div class="list-description"> 6 6 <div class="button-row"> 7 - <a href="facets/l/?url={{encodeURIComponent(item.url)}}" class="button">Try</a> 8 - <!--<button style="background-color: var(--accent-twist-1);">Save</button>--> 9 - <!--<button style="background-color: var(--accent-twist-2);">Fork</button>--> 7 + <a href="facets/l/?url={{encodeURIComponent(item.url)}}" class="button button--bg-twist-1">Try</a> 8 + <button rel="save" class="button--bg-twist-2">Save</button> 9 + <button rel="fork" class="button--bg-twist-4">Fork</button> 10 10 </div> 11 11 <div> 12 12 {{item.desc |> md(true)}}
+80
src/common/facets/utils.js
··· 1 + // import { fragments, serializeFragments } from "@fcrozatier/htmlcrunch"; 2 + 3 + import * as CID from "@atcute/cid"; 4 + import { Temporal } from "@js-temporal/polyfill"; 5 + 6 + /** 7 + * @import {Facet} from "@definitions/types.d.ts" 8 + */ 9 + 10 + /** 11 + * @param {{ name: string; url: string }} _args 12 + * @param {{ fetchHTML: boolean }} options 13 + */ 14 + export async function facetFromUrl({ name, url }, { fetchHTML }) { 15 + const html = fetchHTML 16 + ? await fetch(url).then((res) => res.text()) 17 + : undefined; 18 + const cid = html 19 + ? await CID.create(0x55, new TextEncoder().encode(html)) 20 + : undefined; 21 + const timestamp = Temporal.Now.zonedDateTimeISO().toString(); 22 + 23 + /** @type {Facet} */ 24 + const facet = { 25 + $type: "sh.diffuse.output.facet", 26 + createdAt: timestamp, 27 + id: crypto.randomUUID(), 28 + cid: cid ? CID.toString(cid) : undefined, 29 + html, 30 + name, 31 + updatedAt: timestamp, 32 + url, 33 + }; 34 + 35 + return facet; 36 + } 37 + 38 + // /** 39 + // * @param {string} html 40 + // */ 41 + // export async function inlineModuleScripts(html) { 42 + // const docPromises = fragments.parseOrThrow(html).map(async (frag) => { 43 + // if ("tagName" in frag && frag.tagName === "script") { 44 + // const isModScript = frag.attributes.find((a) => 45 + // a[0] === "type" 46 + // )?.[1] === "module"; 47 + // if (!isModScript) return frag; 48 + // 49 + // const src = frag.attributes.find((a) => a[0] === "src")?.[1]; 50 + // if (!src) return frag; 51 + // 52 + // const scriptContents = await fetch(src).then((r) => r.text()).catch(() => 53 + // null 54 + // ); 55 + // 56 + // if (!scriptContents) return frag; 57 + // 58 + // /** 59 + // * @type {import("@fcrozatier/htmlcrunch").MTextNode} 60 + // */ 61 + // const child = { 62 + // kind: "TEXT", 63 + // text: "\n" + scriptContents.split("\n").map((l) => 64 + // ` ${l}` 65 + // ).join("\n") + "\n", 66 + // }; 67 + // 68 + // return { 69 + // ...frag, 70 + // attributes: frag.attributes.filter((a) => a[0] !== "src"), 71 + // children: [child], 72 + // }; 73 + // } 74 + // 75 + // return frag; 76 + // }); 77 + // 78 + // const doc = await Promise.all(docPromises); 79 + // return serializeFragments(doc); 80 + // }
+7 -1
src/definitions/output/facet.json
··· 6 6 "type": "record", 7 7 "record": { 8 8 "type": "object", 9 - "required": ["cid", "html", "name"], 9 + "required": ["id", "name"], 10 10 "properties": { 11 + "id": { 12 + "type": "string", 13 + "description": "A unique identifier" 14 + }, 11 15 "cid": { 12 16 "type": "string", 13 17 "description": "A DASL CID representing the UTF8 encoded HTML (raw 0x55 codec)" 14 18 }, 19 + "createdAt": { "type": "string", "format": "datetime" }, 15 20 "description": { "type": "string" }, 16 21 "html": { 17 22 "type": "string", 18 23 "description": "The UTF8 HTML string that makes up the facet" 19 24 }, 20 25 "name": { "type": "string" }, 26 + "updatedAt": { "type": "string", "format": "datetime" }, 21 27 "url": { 22 28 "type": "string", 23 29 "description": "An optional URL that points at the facet; can be used to update this artifact"
+7 -1
src/definitions/output/theme.json
··· 6 6 "type": "record", 7 7 "record": { 8 8 "type": "object", 9 - "required": ["cid", "html", "name"], 9 + "required": ["id", "name"], 10 10 "properties": { 11 + "id": { 12 + "type": "string", 13 + "description": "A unique identifier" 14 + }, 11 15 "cid": { 12 16 "type": "string", 13 17 "description": "A DASL CID representing the UTF8 encoded HTML (raw 0x55 codec)" 14 18 }, 19 + "createdAt": { "type": "string", "format": "datetime" }, 15 20 "description": { "type": "string" }, 16 21 "html": { 17 22 "type": "string", 18 23 "description": "The UTF8 HTML string that makes up the theme" 19 24 }, 20 25 "name": { "type": "string" }, 26 + "updatedAt": { "type": "string", "format": "datetime" }, 21 27 "url": { 22 28 "type": "string", 23 29 "description": "An optional URL that points at the theme; can be used to update this artifact"
+123 -34
src/facets/index.js
··· 1 1 import * as CID from "@atcute/cid"; 2 + import { Temporal } from "@js-temporal/polyfill"; 2 3 import { html, render } from "lit-html"; 3 4 4 5 import { basicSetup, EditorView } from "codemirror"; ··· 8 9 import { autocompletion } from "@codemirror/autocomplete"; 9 10 10 11 import foundation from "@common/facets/foundation.js"; 11 - import { effect } from "@common/signal.js"; 12 + import { effect, signal } from "@common/signal.js"; 13 + import { facetFromUrl } from "@common/facets/utils.js"; 12 14 13 15 /** 14 16 * @import {Facet} from "@definitions/types.d.ts" 15 17 */ 16 18 17 19 //////////////////////////////////////////// 18 - // LIST 20 + // SAVE & FORK 21 + //////////////////////////////////////////// 22 + 23 + document.body.addEventListener( 24 + "click", 25 + /** 26 + * @param {MouseEvent} event 27 + */ 28 + async (event) => { 29 + const target = /** @type {HTMLElement} */ (event.target); 30 + const rel = target.getAttribute("rel"); 31 + if (!rel) return; 32 + 33 + const url = target.closest("li")?.getAttribute("data-url"); 34 + if (!url) return; 35 + 36 + const name = target.closest("li")?.getAttribute("data-name"); 37 + if (!name) return; 38 + 39 + switch (rel) { 40 + case "fork": { 41 + const facet = await facetFromUrl({ name, url }, { fetchHTML: true }); 42 + editFacet(facet); 43 + document.querySelector("#build")?.scrollIntoView(); 44 + break; 45 + } 46 + case "save": { 47 + const facet = await facetFromUrl({ name, url }, { fetchHTML: false }); 48 + const out = foundation.orchestrator.output(); 49 + 50 + out.facets.save([ 51 + ...out.facets.collection(), 52 + facet, 53 + ]); 54 + break; 55 + } 56 + } 57 + }, 58 + ); 59 + 60 + //////////////////////////////////////////// 61 + // YOUR COLLECTION 19 62 //////////////////////////////////////////// 20 63 21 64 /** @type {HTMLElement | null} */ ··· 37 80 <li style="margin-bottom: var(--space-2xs)"> 38 81 <span>${c.name}</span> 39 82 <div class="list-description"> 83 + <div style="margin-bottom: var(--space-2xs)"> 84 + ${c.url && !c.html 85 + ? html` 86 + <span class="with-icon"> 87 + <i class="ph-fill ph-binoculars"></i> 88 + <span>Tracking the original <a href="${c 89 + .url}">URL</a></span> 90 + </span> 91 + ` 92 + : html` 93 + <span class="with-icon"> 94 + <i class="ph-fill ph-code"></i> 95 + <span>Custom code</span> 96 + </span> 97 + `} 98 + </div> 40 99 <div class="button-row"> 41 - <a href="facets/l/?cid=${c.cid}" class="button">Open</a> 100 + <a href="facets/l/?id=${c.id}" class="button">Open</a> 101 + <button 102 + style="background-color: var(--accent-twist-4);" 103 + @click="${() => editFacet(c)}" 104 + > 105 + Edit 106 + </button> 42 107 <button 43 108 style="background-color: var(--accent-twist-2);" 44 109 @click="${deleteFacet({ 45 - cid: c.cid, 46 - name: c.name, 110 + id: c.id, 47 111 })}" 48 112 > 49 113 Delete 50 114 </button> 51 - <!--<button style="background-color: var(--accent-twist-1);">Save</button>--> 52 - <!--<button style="background-color: var(--accent-twist-2);">Fork</button>--> 53 115 </div> 54 116 </div> 55 117 </li> ··· 73 135 `; 74 136 75 137 /** 76 - * @param {{ cid: string; name: string }} _ 138 + * @param {{ id: string }} _ 77 139 */ 78 - function deleteFacet({ cid, name }) { 140 + function deleteFacet({ id }) { 79 141 return () => { 80 142 const c = confirm("Are you sure you want to delete this facet?"); 81 143 if (!c) return; 82 144 83 145 output.facets.save( 84 - output.facets.collection().filter((c) => 85 - !(c.name === name && c.cid === cid) 86 - ), 146 + output.facets.collection().filter((c) => !(c.id === id)), 87 147 ); 88 148 }; 89 149 } ··· 91 151 //////////////////////////////////////////// 92 152 // BUILD 93 153 //////////////////////////////////////////// 154 + 155 + const $editingFacet = signal(/** @type {Facet | null} */ (null)); 94 156 95 157 // Code editor 96 158 const editorContainer = document.body.querySelector("#html-input-container"); ··· 155 217 const name = nameEl?.value ?? "nameless"; 156 218 157 219 /** @type {Facet} */ 158 - const facet = { 159 - $type: "sh.diffuse.output.facet", 160 - cid: CID.toString(cid), 161 - html, 162 - name, 163 - }; 220 + const facet = $editingFacet.value 221 + ? { 222 + ...$editingFacet.value, 223 + cid: CID.toString(cid), 224 + html, 225 + name, 226 + } 227 + : { 228 + $type: "sh.diffuse.output.facet", 229 + id: crypto.randomUUID(), 230 + cid: CID.toString(cid), 231 + html, 232 + name, 233 + }; 164 234 165 235 switch (/** @type {any} */ (event).submitter.name) { 166 - case "load-example": { 167 - /** @type {HTMLSelectElement | null} */ 168 - const selected = document.body.querySelector("#example-select"); 169 - 170 - if (selected?.value) { 171 - const text = await fetch(selected.value).then((r) => r.text()); 172 - 173 - editor.dispatch({ 174 - changes: { from: 0, to: editor.state.doc.length, insert: text }, 175 - }); 176 - } 177 - break; 178 - } 179 236 case "save": 180 237 await saveFacet(facet); 181 238 break; 182 239 case "save+open": 183 240 await saveFacet(facet); 184 - window.open(`./facets/l/?cid=${facet.cid}`, "blank"); 241 + globalThis.open(`./facets/l/?cid=${facet.cid}`, "blank"); 185 242 break; 186 243 } 187 244 } 188 245 189 246 /** 247 + * @param {Facet} ogFacet 248 + */ 249 + async function editFacet(ogFacet) { 250 + const facet = { ...ogFacet }; 251 + const nameEl = /** @type {HTMLInputElement | null} */ (document.querySelector( 252 + "#name-input", 253 + )); 254 + 255 + if (!nameEl) return; 256 + 257 + // Make sure HTML is loaded 258 + if (!facet.html && facet.url) { 259 + const html = await fetch(facet.url).then((res) => res.text()); 260 + const cid = await CID.create(0x55, new TextEncoder().encode(html)); 261 + 262 + facet.html = html; 263 + facet.cid = CID.toString(cid); 264 + } 265 + 266 + $editingFacet.value = facet; 267 + nameEl.value = facet.name; 268 + 269 + editor.dispatch({ 270 + changes: { from: 0, to: editor.state.doc.length, insert: facet.html }, 271 + }); 272 + } 273 + 274 + /** 190 275 * @param {Facet} facet 191 276 */ 192 277 async function saveFacet(facet) { 193 278 const col = output.facets.collection(); 194 - const colWithoutName = col.filter((c) => c.name !== facet.name); 279 + const colWithoutId = col.filter((c) => c.id !== facet.id); 280 + const timestamp = Temporal.Now.zonedDateTimeISO().toString(); 195 281 196 - await output.facets.save([...colWithoutName, facet]); 282 + await output.facets.save([...colWithoutId, { 283 + ...facet, 284 + updatedAt: timestamp, 285 + }]); 197 286 }
+19 -24
src/facets/index.vto
··· 5 5 styles: 6 6 - styles/base.css 7 7 - styles/diffuse/page.css 8 - - styles/vendor/phosphor/bold/style.css 9 8 - styles/vendor/phosphor/fill/style.css 10 9 11 10 scripts: ··· 13 12 14 13 # FACETS 15 14 16 - facets: 15 + builtIn: 17 16 - url: "themes/blur/artwork-controller/facet.html.txt" 18 17 title: "Blur / Artwork controller" 19 18 desc: > ··· 26 25 title: "Webamp / Input Configurator" 27 26 desc: > 28 27 Windows 98 styled input configurator where you can add music sources. 28 + 29 + examples: 30 + - url: "facets/examples/now-playing.html.txt" 31 + title: "Now playing" 32 + desc: > 33 + Shows what's currently set to "now playing" in the queue, along with a button to shift the queue to the next track. 34 + - url: "facets/examples/generate-playlist.html.txt" 35 + title: "Generate playlist" 36 + desc: > 37 + Make a list of what previously played in the queue. 29 38 --- 30 39 31 40 <header> ··· 59 68 <section class="flex"> 60 69 <h2 id="built-in">Built-in</h2> 61 70 62 - <div style="margin-top: var(--space-lg);"> 63 - {{ await comp.facets({ items: facets }) }} 64 - </div> 71 + {{ await comp.facets({ items: builtIn }) }} 65 72 </section> 66 73 67 74 <section class="flex"> ··· 84 91 85 92 <section class="flex"> 86 93 <h2 id="examples">Examples</h2> 94 + 95 + <p> 96 + Some simple examples to help you understand how to build your own facet. Fork them to load them into the code editor below (or save → edit). 97 + </p> 98 + 99 + {{ await comp.facets({ items: examples }) }} 87 100 </section> 88 101 </div> 89 102 ··· 108 121 <p style="margin-top: 0"> 109 122 Your code here builds on the <a href="facets/#foundation">foundation</a> listed below, it'll be injected into a <code>&lt;div id="container"&gt;</code> element in the body. 110 123 </p> 111 - <input id="name-input" type="text" placeholder="Unique name" name="name" value="Unique name" required /> 124 + <input id="name-input" type="text" placeholder="Name" name="name" required /> 112 125 <p> 113 126 <span class="button-row"> 114 127 <button name="save">Save</button> 115 128 <button name="save+open">Save &amp; Open</button> 116 - </span> 117 - </p> 118 - <p> 119 - Browse examples: 120 - </p> 121 - <div> 122 - <select id="example-select"> 123 - <button> 124 - <selectedcontent></selectedcontent> 125 - </button> 126 - 127 - <option value="facets/examples/now-playing.html.txt" selected>Now playing & next queue item</option> 128 - <option value="facets/examples/generate-playlist.html.txt">Generate playlist from queue</option> 129 - </select> 130 - </div> 131 - <p> 132 - <span class="button-row"> 133 - <button name="load-example">Load example</button> 134 129 </span> 135 130 </p> 136 131 </div>
+17 -9
src/facets/l/index.js
··· 19 19 20 20 const docUrl = new URL(document.location.href); 21 21 22 + const id = docUrl.searchParams.get("id"); 22 23 const cid = docUrl.searchParams.get("cid"); 23 24 const name = docUrl.searchParams.get("name"); 24 25 const url = docUrl.searchParams.get("url"); ··· 38 39 39 40 let facet; 40 41 41 - if (cid) { 42 + if (id) { 43 + facet = collection.find((c) => c.id === id); 44 + } else if (cid) { 42 45 facet = collection.find((c) => c.cid === cid); 43 46 } else if (name) { 44 47 facet = collection.find((c) => c.name === name); 45 48 } else if (url) { 46 - const html = await fetch(url).then((res) => res.text()); 47 - const cid = await CID.create(0x55, new TextEncoder().encode(html)); 48 - const name = "tryout"; 49 - 50 49 /** @type {Facet} */ 51 50 const c = { 52 51 $type: "sh.diffuse.output.facet", 53 - cid: CID.toString(cid), 54 - html, 55 - name, 52 + id: crypto.randomUUID(), 53 + name: "tryout", 54 + url, 56 55 }; 57 56 58 57 facet = c; ··· 61 60 // TODO: Message that facet was not found 62 61 if (!facet) return; 63 62 63 + // Make sure HTML is loaded 64 + if (!facet.html && facet.url) { 65 + const html = await fetch(facet.url).then((res) => res.text()); 66 + const cid = await CID.create(0x55, new TextEncoder().encode(html)); 67 + 68 + facet.html = html; 69 + facet.cid = CID.toString(cid); 70 + } 71 + 64 72 loadIntoContainer(facet); 65 73 }); 66 74 ··· 72 80 73 81 const range = document.createRange(); 74 82 range.selectNode(container); 75 - const documentFragment = range.createContextualFragment(facet.html); 83 + const documentFragment = range.createContextualFragment(facet.html ?? ""); 76 84 77 85 container.innerHTML = ""; 78 86 container.append(documentFragment);
+29 -3
src/styles/diffuse/page.css
··· 277 277 278 278 button, 279 279 a.button { 280 - background: var(--accent); 280 + --button-bg-opacity: 0.6; 281 + background: oklch(from var(--accent) l c h / var(--button-bg-opacity)); 281 282 border: 0; 282 283 border-radius: var(--radius-md); 283 284 color: var(--bg-color); ··· 288 289 line-height: var(--leading-tight); 289 290 padding: var(--space-2xs) var(--space-xs); 290 291 transition-duration: 500ms; 291 - transition-property: opacity; 292 + transition-property: background-color opacity; 292 293 293 294 &[disabled] { 295 + --button-bg-opacity: 0.4; 294 296 cursor: not-allowed; 295 - opacity: 0.5; 297 + } 298 + 299 + &:hover:not([disabled]), 300 + &:focus:not([disabled]) { 301 + --button-bg-opacity: 1; 302 + } 303 + 304 + &.button--bg-twist-1 { 305 + background-color: oklch(from var(--accent-twist-1) l c h / var(--button-bg-opacity)); 306 + } 307 + 308 + &.button--bg-twist-2 { 309 + background-color: oklch(from var(--accent-twist-2) l c h / var(--button-bg-opacity)); 310 + } 311 + 312 + &.button--bg-twist-3 { 313 + background-color: oklch(from var(--accent-twist-3) l c h / var(--button-bg-opacity)); 314 + } 315 + 316 + &.button--bg-twist-4 { 317 + background-color: oklch(from var(--accent-twist-4) l c h / var(--button-bg-opacity)); 318 + } 319 + 320 + &.button--bg-twist-5 { 321 + background-color: oklch(from var(--accent-twist-5) l c h / var(--button-bg-opacity)); 296 322 } 297 323 298 324 & > span {
+29 -4
src/themes/blur/artwork-controller/facet.html.txt
··· 1 1 <style> 2 - @import "styles/vendor/phosphor/bold/style.css"; 3 - @import "styles/vendor/phosphor/fill/style.css"; 4 - @import "styles/base.css"; 2 + @import "./styles/vendor/phosphor/bold/style.css"; 3 + @import "./styles/vendor/phosphor/fill/style.css"; 4 + @import "./styles/base.css"; 5 5 </style> 6 6 7 - <script type="module" src="themes/blur/artwork-controller/facet.js"></script> 7 + <script type="module"> 8 + import foundation from "./common/facets/foundation.js"; 9 + import ArtworkController from "./themes/blur/artwork-controller/element.js"; 10 + 11 + // Setup the prerequisite elements 12 + foundation.features.fillQueueAutomatically(); 13 + foundation.features.playAudioFromQueue(); 14 + foundation.features.processInputs(); 15 + 16 + const aud = foundation.engine.audio(); 17 + const art = foundation.processor.artwork(); 18 + const inp = foundation.orchestrator.input(); 19 + const que = foundation.engine.queue(); 20 + const rse = foundation.engine.repeatShuffle(); 21 + 22 + // Controller 23 + const dac = new ArtworkController(); 24 + dac.setAttribute("artwork-processor-selector", art.selector); 25 + dac.setAttribute("audio-engine-selector", aud.selector); 26 + dac.setAttribute("input-selector", inp.selector); 27 + dac.setAttribute("queue-engine-selector", que.selector); 28 + dac.setAttribute("repeat-shuffle-engine-selector", rse.selector); 29 + 30 + // Add to DOM 31 + document.body.append(dac); 32 + </script>
-24
src/themes/blur/artwork-controller/facet.js
··· 1 - import foundation from "@common/facets/foundation.js"; 2 - import ArtworkController from "@themes/blur/artwork-controller/element.js"; 3 - 4 - // Setup the prerequisite elements 5 - foundation.features.fillQueueAutomatically(); 6 - foundation.features.playAudioFromQueue(); 7 - foundation.features.processInputs(); 8 - 9 - const aud = foundation.engine.audio(); 10 - const art = foundation.processor.artwork(); 11 - const inp = foundation.orchestrator.input(); 12 - const que = foundation.engine.queue(); 13 - const rse = foundation.engine.repeatShuffle(); 14 - 15 - // Controller 16 - const dac = new ArtworkController(); 17 - dac.setAttribute("artwork-processor-selector", art.selector); 18 - dac.setAttribute("audio-engine-selector", aud.selector); 19 - dac.setAttribute("input-selector", inp.selector); 20 - dac.setAttribute("queue-engine-selector", que.selector); 21 - dac.setAttribute("repeat-shuffle-engine-selector", rse.selector); 22 - 23 - // Add to DOM 24 - document.body.append(dac);
+24 -4
src/themes/webamp/browser/facet.html.txt
··· 18 18 </div> 19 19 20 20 <style> 21 - @import "styles/vendor/98.css"; 22 - @import "themes/webamp/fonts.css"; 23 - @import "themes/webamp/facet.css"; 21 + @import "./styles/vendor/98.css"; 22 + @import "./themes/webamp/fonts.css"; 23 + @import "./themes/webamp/facet.css"; 24 24 </style> 25 25 26 - <script type="module" src="themes/webamp/browser/facet.js"></script> 26 + <script type="module"> 27 + import foundation from "./common/facets/foundation.js"; 28 + import BrowserElement from "./themes/webamp/browser/element.js"; 29 + 30 + foundation.features.fillQueueAutomatically(); 31 + foundation.features.processInputs(); 32 + foundation.features.searchThroughCollection(); 33 + 34 + const inp = foundation.orchestrator.input(); 35 + const out = foundation.orchestrator.output(); 36 + const que = foundation.engine.queue(); 37 + const sea = foundation.processor.search(); 38 + 39 + const el = new BrowserElement(); 40 + el.setAttribute("input-selector", inp.selector); 41 + el.setAttribute("output-selector", out.selector); 42 + el.setAttribute("queue-engine-selector", que.selector); 43 + el.setAttribute("search-processor-selector", sea.selector); 44 + 45 + document.querySelector("#placeholder")?.replaceWith(el); 46 + </script>
-19
src/themes/webamp/browser/facet.js
··· 1 - import foundation from "@common/facets/foundation.js"; 2 - import BrowserElement from "@themes/webamp/browser/element.js"; 3 - 4 - foundation.features.fillQueueAutomatically(); 5 - foundation.features.processInputs(); 6 - foundation.features.searchThroughCollection(); 7 - 8 - const inp = foundation.orchestrator.input(); 9 - const out = foundation.orchestrator.output(); 10 - const que = foundation.engine.queue(); 11 - const sea = foundation.processor.search(); 12 - 13 - const el = new BrowserElement(); 14 - el.setAttribute("input-selector", inp.selector); 15 - el.setAttribute("output-selector", out.selector); 16 - el.setAttribute("queue-engine-selector", que.selector); 17 - el.setAttribute("search-processor-selector", sea.selector); 18 - 19 - document.querySelector("#placeholder")?.replaceWith(el);
+31 -4
src/themes/webamp/configurators/input/facet.html.txt
··· 18 18 </div> 19 19 20 20 <style> 21 - @import "styles/vendor/98.css"; 22 - @import "themes/webamp/fonts.css"; 23 - @import "themes/webamp/facet.css"; 21 + @import "./styles/vendor/98.css"; 22 + @import "./themes/webamp/fonts.css"; 23 + @import "./themes/webamp/facet.css"; 24 24 </style> 25 25 26 - <script type="module" src="themes/webamp/configurators/input/facet.js"></script> 26 + <script type="module"> 27 + import foundation from "./common/facets/foundation.js"; 28 + import InputConfigElement from "./themes/webamp/configurators/input/element.js"; 29 + import { effect } from "./common/signal.js"; 30 + 31 + const inp = foundation.orchestrator.input(); 32 + const out = foundation.orchestrator.output(); 33 + const pro = foundation.orchestrator.processTracks({ disableWhenReady: true }); 34 + const sou = foundation.orchestrator.sources(); 35 + 36 + const el = new InputConfigElement(); 37 + el.setAttribute("input-selector", inp.selector); 38 + el.setAttribute("output-selector", out.selector); 39 + el.setAttribute("sources-orchestrator-selector", sou.selector); 40 + 41 + document.querySelector("#placeholder")?.replaceWith(el); 42 + 43 + // EFFECTS 44 + 45 + let initEffect = false; 46 + 47 + effect(() => { 48 + const _trigger = sou.sources(); 49 + if (out.tracks.state() !== "loaded") return; 50 + if (initEffect) pro.process(); 51 + initEffect = true; 52 + }); 53 + </script>
-26
src/themes/webamp/configurators/input/facet.js
··· 1 - import foundation from "@common/facets/foundation.js"; 2 - import InputConfigElement from "@themes/webamp/configurators/input/element.js"; 3 - import { effect } from "@common/signal.js"; 4 - 5 - const inp = foundation.orchestrator.input(); 6 - const out = foundation.orchestrator.output(); 7 - const pro = foundation.orchestrator.processTracks({ disableWhenReady: true }); 8 - const sou = foundation.orchestrator.sources(); 9 - 10 - const el = new InputConfigElement(); 11 - el.setAttribute("input-selector", inp.selector); 12 - el.setAttribute("output-selector", out.selector); 13 - el.setAttribute("sources-orchestrator-selector", sou.selector); 14 - 15 - document.querySelector("#placeholder")?.replaceWith(el); 16 - 17 - // EFFECTS 18 - 19 - let initEffect = false; 20 - 21 - effect(() => { 22 - const _trigger = sou.sources(); 23 - if (out.tracks.state() !== "loaded") return; 24 - if (initEffect) pro.process(); 25 - initEffect = true; 26 - });