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

Configure Feed

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

refactor: constituents presentation + loader

+231 -108
+2 -1
_config.ts
··· 123 123 124 124 // MISC 125 125 126 - site.add("/themes/loader/constituent/examples/"); 126 + site.add([".htm"]); 127 + site.add([".txt"]); 127 128 site.use(sourceMaps()); 128 129 129 130 site.script("copy-type-defs", () => {
+17
src/_components/constituents.vto
··· 1 + <ul> 2 + {{ for item of items }} 3 + <li> 4 + <span>{{item.title}}</span> 5 + <div class="list-description"> 6 + <div class="button-row"> 7 + <a href="constituents/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>--> 10 + </div> 11 + <div> 12 + {{item.desc |> md(true)}} 13 + </div> 14 + </div> 15 + </li> 16 + {{ /for }} 17 + </ul>
+9
src/constituents/l/index.vto
··· 1 + --- 2 + layout: layouts/constituent.vto 3 + base: ../../ 4 + 5 + scripts: 6 + - constituents/l/index.js 7 + --- 8 + 9 + <div id="container"></div>
-20
src/index.vto
··· 27 27 desc: > 28 28 **Winamp 2 + Windows 98**. Uses Webamp as the audio player connected to various Diffuse elements. Also features a desktop-like Windows 98 environment in which you can open "programs" that control the used Diffuse elements. 29 29 30 - # CONSTITUENTS 31 - 32 - constituents: 33 - - url: "themes/blur/artwork-controller/" 34 - title: "Blur / Artwork controller" 35 - desc: > 36 - Audio playback controller with artwork display. 37 - - url: "themes/loader/constituent/" 38 - title: "Loader" 39 - desc: > 40 - **Bring in other constituents!** Load a constituent from a code snippet, store it in your user data output, explore community creations, or generate one. 41 - - url: "themes/webamp/browser/" 42 - title: "Webamp / Browser" 43 - desc: > 44 - Collection browser + search in a retro, win98, look. 45 - - url: "themes/webamp/configurators/input/" 46 - title: "Webamp / Input Configurator" 47 - desc: > 48 - Windows 98 styled input configurator where you can add music sources. 49 - 50 30 # ELEMENTS 51 31 52 32 configurators:
+13 -1
src/styles/diffuse/page.css
··· 344 344 } 345 345 346 346 .list-description { 347 + color: oklch(from currentColor l c h / 0.6); 347 348 font-size: var(--fs-xs); 348 349 margin-bottom: var(--space-xs); 349 350 margin-top: var(--space-2xs); 350 - opacity: 0.6; 351 351 352 352 a { 353 353 text-underline-offset: 3px; 354 354 } 355 355 356 + button, 357 + .button { 358 + line-height: 1; 359 + padding: var(--space-3xs); 360 + border-radius: var(--radius-xs); 361 + } 362 + 356 363 code { 357 364 font-size: var(--fs-xs); 365 + } 366 + 367 + .button-row { 368 + gap: var(--space-3xs); 369 + margin: 0 0 var(--space-2xs); 358 370 } 359 371 } 360 372
+7
src/themes/blur/artwork-controller/constituent.html.txt
··· 1 + <style> 2 + @import "styles/vendor/phosphor/bold/style.css"; 3 + @import "styles/vendor/phosphor/fill/style.css"; 4 + @import "styles/base.css"; 5 + </style> 6 + 7 + <script type="module" src="themes/blur/artwork-controller/constituent.js"></script>
+24
src/themes/blur/artwork-controller/constituent.js
··· 1 + import foundation from "@common/constituents/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);
src/themes/index.js

This is a binary file and will not be displayed.

+43
src/themes/index.vto
··· 1 + --- 2 + layout: layouts/constituent.vto 3 + base: ../ 4 + 5 + styles: 6 + - styles/base.css 7 + - styles/diffuse/page.css 8 + - styles/vendor/phosphor/bold/style.css 9 + - styles/vendor/phosphor/fill/style.css 10 + 11 + scripts: 12 + - themes/index.js 13 + --- 14 + 15 + <header> 16 + <div> 17 + <div> 18 + <a class="diffuse-logo" href="./" style="display: inline-block;"> 19 + {{ await comp.diffuse.logo() }} 20 + </a> 21 + </div> 22 + <p class="construct dither-mask" style="margin-top: 0"> 23 + Themes 24 + </p> 25 + <p> 26 + Themes are element compositions and provide a traditional browser web application way of 27 + using them. In other words, pretty much the whole thing, besides your data, lives inside a single browser tab. 28 + </p> 29 + 30 + <p> 31 + <small> 32 + <strong><i class="ph-fill ph-info"></i></strong> 33 + Each theme is unique, not just a skin; each one might have a totally different feature set. 34 + </small> 35 + </p> 36 + </div> 37 + <div class="dither-mask filler"></div> 38 + </header> 39 + <main> 40 + <p> 41 + TODO 42 + </p> 43 + </main>
src/themes/loader/constituent/examples/generate-playlist.txt src/constituents/examples/generate-playlist.html.txt
src/themes/loader/constituent/examples/now-playing.txt src/constituents/examples/now-playing.html.txt
+23 -18
src/themes/loader/constituent/index.js src/constituents/index.js
··· 35 35 ${col.map((c) => 36 36 html` 37 37 <li style="margin-bottom: var(--space-2xs)"> 38 - <a href="themes/loader/constituent/s/?cid=${c.cid}"> 39 - ${c.name} 40 - </a> 41 - <br /> 42 - <small> 43 - <span @click="${deleteConstituent({ 44 - cid: c.cid, 45 - name: c.name, 46 - })}" style="cursor: pointer;"> 47 - Delete 48 - </span> 49 - </small> 38 + <span>${c.name}</span> 39 + <div class="list-description"> 40 + <div class="button-row"> 41 + <a href="constituents/l/?cid=${c.cid}" class="button">Open</a> 42 + <button 43 + style="background-color: var(--accent-twist-2);" 44 + @click="${deleteConstituent({ 45 + cid: c.cid, 46 + name: c.name, 47 + })}" 48 + > 49 + Delete 50 + </button> 51 + <!--<button style="background-color: var(--accent-twist-1);">Save</button>--> 52 + <!--<button style="background-color: var(--accent-twist-2);">Fork</button>--> 53 + </div> 54 + </div> 50 55 </li> 51 56 ` 52 57 )} ··· 63 68 64 69 const emptyConstituentsList = html` 65 70 <p style="margin-bottom: 0;"> 66 - <i class="ph-fill ph-info"></i> You have not added any constituents yet. Add 67 - or create some using the tools below. 71 + <i class="ph-fill ph-info"></i> You have not saved any constituents yet. 68 72 </p> 69 73 `; 70 74 ··· 73 77 */ 74 78 function deleteConstituent({ cid, name }) { 75 79 return () => { 80 + const c = confirm("Are you sure you want to delete this constituent?"); 81 + if (!c) return; 82 + 76 83 output.constituents.save( 77 84 output.constituents.collection().filter((c) => 78 85 !(c.name === name && c.cid === cid) ··· 161 168 const selected = document.body.querySelector("#example-select"); 162 169 163 170 if (selected?.value) { 164 - const text = await fetch( 165 - `themes/loader/constituent/examples/${selected.value}`, 166 - ).then((r) => r.text()); 171 + const text = await fetch(selected.value).then((r) => r.text()); 167 172 168 173 editor.dispatch({ 169 174 changes: { from: 0, to: editor.state.doc.length, insert: text }, ··· 176 181 break; 177 182 case "save+open": 178 183 await saveConstituent(constituent); 179 - window.open(`${location.href}s/?cid=${constituent.cid}`, "blank"); 184 + window.open(`./constituents/l/?cid=${constituent.cid}`, "blank"); 180 185 break; 181 186 } 182 187 }
+56 -25
src/themes/loader/constituent/index.vto src/constituents/index.vto
··· 1 1 --- 2 2 layout: layouts/constituent.vto 3 - base: ../../../ 3 + base: ../ 4 4 5 5 styles: 6 6 - styles/base.css ··· 9 9 - styles/vendor/phosphor/fill/style.css 10 10 11 11 scripts: 12 - - themes/loader/constituent/index.js 12 + - constituents/index.js 13 + 14 + # CONSTITUENTS 15 + 16 + constituents: 17 + - url: "themes/blur/artwork-controller/constituent.html.txt" 18 + title: "Blur / Artwork controller" 19 + desc: > 20 + Audio playback controller with an artwork display. 21 + - url: "themes/webamp/browser/constituent.html.txt" 22 + title: "Webamp / Browser" 23 + desc: > 24 + Collection browser + search in a retro, win98, look. 25 + - url: "themes/webamp/configurators/input/constituent.html.txt" 26 + title: "Webamp / Input Configurator" 27 + desc: > 28 + Windows 98 styled input configurator where you can add music sources. 13 29 --- 14 30 15 31 <header> ··· 19 35 {{ await comp.diffuse.logo() }} 20 36 </a> 21 37 </div> 22 - <p class="construct dither-mask" style="margin-top: 0;"> 23 - Constituent loader ❈ 38 + <p class="construct dither-mask" style="margin-top: 0; max-width: none;"> 39 + Constituents 24 40 </p> 25 41 <p> 26 - <strong>Missing a feature, or prefer a different user interface that is not part of Diffuse? Add it here.</strong> This tool allows you to load a custom <a href="#constituents">constituent</a> besides the <a href="#constituents">existing ones</a>. 42 + Constituents are various interface components each loaded in their own web page. Every used component is configured so that it operates in broadcast mode, making all the pages communicate with each other. 27 43 </p> 44 + 45 + <ul class="table-of-contents"> 46 + <li><a href="constituents/#built-in">Built-in</a></li> 47 + <li><a href="constituents/#community">Community</a></li> 48 + <li><a href="constituents/#saved">Your collection</a></li> 49 + <li><a href="constituents/#examples">Examples</a></li> 50 + <li><a href="constituents/#build">Build</a></li> 51 + <li><a href="constituents/#foundation">Foundation</a></li> 52 + </ul> 28 53 </div> 29 54 <div class="dither-mask filler"></div> 30 55 </header> 31 56 <main> 32 - <!-- LIST --> 33 - <div class="columns" style="margin-top: var(--space-2xl);"> 34 - <div class="dither-mask filler flex"></div> 57 + <!-- BUILT-IN --> 58 + <div class="columns"> 59 + <section class="flex"> 60 + <h2 id="built-in">Built-in</h2> 61 + 62 + <div style="margin-top: var(--space-lg);"> 63 + {{ await comp.constituents({ items: constituents }) }} 64 + </div> 65 + </section> 35 66 36 67 <section class="flex"> 37 - <h2 id="yours" style="margin-top: 0;">Yours</h2> 38 - <div id="list"></div> 68 + <h2 id="community">Community</h2> 69 + <p> 70 + Check out some constituents from the community and load them here. 71 + </p> 72 + <p> 73 + <small><i class="ph-fill ph-info"></i> Nothing here yet, too early.</small> 74 + </p> 39 75 </section> 40 76 </div> 41 77 42 - <!-- GENERATE + COMMUNITY --> 78 + <!-- LIST + EXAMPLES --> 43 79 <div class="columns"> 44 80 <section class="flex"> 45 - <h2 id="generate">Generate</h2> 46 - <p> 47 - <small><i class="ph-fill ph-check-square"></i> On the todo list, the idea is to have AI generate a piece of UI for you; building on the logical blocks provided by Diffuse.</small> 48 - </p> 81 + <h2 id="saved">Your collection</h2> 82 + <div id="list"></div> 49 83 </section> 50 84 51 85 <section class="flex"> 52 - <h2 id="community">Community</h2> 53 - <!--<p> 54 - Check out some constituents from the community and load them here. 55 - </p>--> 56 - <p> 57 - <small><i class="ph-fill ph-info"></i> Nothing here yet, too early.</small> 58 - </p> 86 + <h2 id="examples">Examples</h2> 59 87 </section> 60 88 </div> 89 + 90 + <!-- / --> 91 + <div class="dither-mask filler" style="height: var(--space-2xl); margin-top: var(--space-2xl);"></div> 61 92 62 93 <!-- BUILD --> 63 94 <section> ··· 75 106 76 107 <div class="flex"> 77 108 <p style="margin-top: 0"> 78 - Your code here builds on the <a href="themes/loader/constituent/#foundation">foundation</a> listed below, it'll be injected into a <code>&lt;div id="container"&gt;</code> element in the body. 109 + Your code here builds on the <a href="constituents/#foundation">foundation</a> listed below, it'll be injected into a <code>&lt;div id="container"&gt;</code> element in the body. 79 110 </p> 80 111 <input id="name-input" type="text" placeholder="Unique name" name="name" value="Unique name" required /> 81 112 <p> ··· 93 124 <selectedcontent></selectedcontent> 94 125 </button> 95 126 96 - <option value="now-playing.txt" selected>Now playing & next queue item</option> 97 - <option value="generate-playlist.txt">Generate playlist from queue</option> 127 + <option value="constituents/examples/now-playing.html.txt" selected>Now playing & next queue item</option> 128 + <option value="constituents/examples/generate-playlist.html.txt">Generate playlist from queue</option> 98 129 </select> 99 130 </div> 100 131 <p>
+21 -4
src/themes/loader/constituent/s/index.js src/constituents/l/index.js
··· 1 + import * as CID from "@atcute/cid"; 2 + 1 3 import foundation from "@common/constituents/foundation.js"; 2 4 import { effect } from "@common/signal.js"; 3 5 ··· 15 17 // URL PARAMS 16 18 //////////////////////////////////////////// 17 19 18 - const url = new URL(document.location.href); 20 + const docUrl = new URL(document.location.href); 19 21 20 - const cid = url.searchParams.get("cid"); 21 - const name = url.searchParams.get("name"); 22 + const cid = docUrl.searchParams.get("cid"); 23 + const name = docUrl.searchParams.get("name"); 24 + const url = docUrl.searchParams.get("url"); 22 25 23 26 //////////////////////////////////////////// 24 27 // LOAD ··· 29 32 30 33 const container = /** @type {HTMLDivElement} */ (containerNull); 31 34 32 - effect(() => { 35 + effect(async () => { 33 36 const collection = output.constituents.collection(); 34 37 if (output.constituents.state() !== "loaded") return; 35 38 ··· 39 42 constituent = collection.find((c) => c.cid === cid); 40 43 } else if (name) { 41 44 constituent = collection.find((c) => c.name === name); 45 + } 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 + /** @type {Constituent} */ 51 + const c = { 52 + $type: "sh.diffuse.output.constituent", 53 + cid: CID.toString(cid), 54 + html, 55 + name, 56 + }; 57 + 58 + constituent = c; 42 59 } 43 60 44 61 // TODO: Message that constituent was not found
-9
src/themes/loader/constituent/s/index.vto
··· 1 - --- 2 - layout: layouts/constituent.vto 3 - base: ../../../../ 4 - 5 - scripts: 6 - - themes/loader/constituent/s/index.js 7 - --- 8 - 9 - <div id="container"></div>
src/themes/webamp/browser/index.js src/themes/webamp/browser/constituent.js
+8 -15
src/themes/webamp/browser/index.vto src/themes/webamp/browser/constituent.html.txt
··· 1 - --- 2 - layout: layouts/constituent.vto 3 - base: ../../../ 4 - 5 - styles: 6 - - styles/vendor/98.css 7 - - themes/webamp/fonts.css 8 - - themes/webamp/constituent.css 9 - 10 - scripts: 11 - - themes/webamp/browser/index.js 12 - --- 13 - 14 - <!-- ELEMENTS --> 15 - 16 1 <div class="window"> 17 2 <div 18 3 class="title-bar" ··· 31 16 <div id="placeholder"></div> 32 17 </div> 33 18 </div> 19 + 20 + <style> 21 + @import "styles/vendor/98.css"; 22 + @import "themes/webamp/fonts.css"; 23 + @import "themes/webamp/constituent.css"; 24 + </style> 25 + 26 + <script type="module" src="themes/webamp/browser/constituent.js"></script>
src/themes/webamp/configurators/input/index.js src/themes/webamp/configurators/input/constituent.js
+8 -15
src/themes/webamp/configurators/input/index.vto src/themes/webamp/configurators/input/constituent.html.txt
··· 1 - --- 2 - layout: layouts/constituent.vto 3 - base: ../../../../ 4 - 5 - styles: 6 - - styles/vendor/98.css 7 - - themes/webamp/fonts.css 8 - - themes/webamp/constituent.css 9 - 10 - scripts: 11 - - themes/webamp/configurators/input/index.js 12 - --- 13 - 14 - <!-- ELEMENTS --> 15 - 16 1 <div class="window"> 17 2 <div 18 3 class="title-bar" ··· 31 16 <div id="placeholder"></div> 32 17 </div> 33 18 </div> 19 + 20 + <style> 21 + @import "styles/vendor/98.css"; 22 + @import "themes/webamp/fonts.css"; 23 + @import "themes/webamp/constituent.css"; 24 + </style> 25 + 26 + <script type="module" src="themes/webamp/configurators/input/constituent.js"></script>