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.

chore: rename constituents to facets

+201 -209
+2 -2
README.md
··· 4 4 5 5 Diffuse provides a range of custom elements: audio input, data output, metadata & artwork processing, audio playback, a queue system, and much more. 6 6 7 - It is also aimed at consumers, providing themes and constituents, preconfigured component compositions; while simultaneously trying to be [malleable software](https://www.inkandswitch.com/essay/malleable-software/). 7 + It is also aimed at consumers, providing themes and facets, preconfigured component compositions; while simultaneously trying to be [malleable software](https://www.inkandswitch.com/essay/malleable-software/). 8 8 9 9 More information on the [website](https://elements.diffuse.sh/latest/). 10 10 ··· 25 25 import QueueEngine from "@toko/diffuse/components/engine/queue/element.js" 26 26 27 27 const queue = new QueueEngine() 28 - queue.setAttribute("group", "constituents") 28 + queue.setAttribute("group", "facets") 29 29 30 30 document.body.append(queue) 31 31 ````
+2 -2
deno.jsonc
··· 68 68 }, 69 69 "exports": { 70 70 // .js 71 - "./common/constituents/foundation.js": "./src/common/constituents/foundation.js", 71 + "./common/facets/foundation.js": "./src/common/facets/foundation.js", 72 72 "./common/element.js": "./src/common/element.js", 73 73 "./common/signal.js": "./src/common/signal.js", 74 74 "./common/worker.js": "./src/common/worker.js", ··· 137 137 "./definitions/types.d.ts": "./src/definitions/types.d.ts", 138 138 139 139 // .ts 140 - "./definitions/types/sh/diffuse/output/constituent.ts": "./src/definitions/types/sh/diffuse/output/constituent.ts", 140 + "./definitions/types/sh/diffuse/output/facet.ts": "./src/definitions/types/sh/diffuse/output/facet.ts", 141 141 "./definitions/types/sh/diffuse/output/playlist.ts": "./src/definitions/types/sh/diffuse/output/playlist.ts", 142 142 "./definitions/types/sh/diffuse/output/theme.ts": "./src/definitions/types/sh/diffuse/output/theme.ts", 143 143 "./definitions/types/sh/diffuse/output/track.ts": "./src/definitions/types/sh/diffuse/output/track.ts",
+1 -1
docs/ARCHITECTURE.md
··· 33 33 ## Other directories 34 34 35 35 - `src/common`: Common Javascript code shared by various components and/or themes. 36 - - `src/styles`: Common CSS shared by themes, the index page or constituents (part of themes). 36 + - `src/styles`: Common CSS shared by themes, the index page or facets. 37 37 - `src/favicons`, `src/fonts`, `src/images` are binary assets for themes and the index page (`src/index.vto`) 38 38 - `src/_components` and `src/_includes` are templates used in `.vto` templates, again themes and index page.
+1 -1
src/_components/constituents.vto src/_components/facets.vto
··· 4 4 <span>{{item.title}}</span> 5 5 <div class="list-description"> 6 6 <div class="button-row"> 7 - <a href="constituents/l/?url={{encodeURIComponent(item.url)}}" class="button">Try</a> 7 + <a href="facets/l/?url={{encodeURIComponent(item.url)}}" class="button">Try</a> 8 8 <!--<button style="background-color: var(--accent-twist-1);">Save</button>--> 9 9 <!--<button style="background-color: var(--accent-twist-2);">Fork</button>--> 10 10 </div>
src/_includes/layouts/constituent.vto src/_includes/layouts/facet.vto
+2 -2
src/common/constituents/foundation.js src/common/facets/foundation.js
··· 18 18 */ 19 19 20 20 const url = new URL(document.location.href); 21 - export const GROUP = url.searchParams.get("group") ?? "constituents"; 21 + export const GROUP = url.searchParams.get("group") ?? "facets"; 22 22 23 23 /** 24 - * Default config for constituents. 24 + * Default config for facets. 25 25 */ 26 26 export const config = { 27 27 GROUP,
+15 -15
src/components/configurator/output/element.js
··· 2 2 import { batch, computed, signal } from "@common/signal.js"; 3 3 4 4 /** 5 - * @import {Constituent, Track} from "@definitions/types.d.ts" 5 + * @import {Facet, Track} from "@definitions/types.d.ts" 6 6 * @import {OutputManagerDeputy, OutputElement} from "@components/output/types.d.ts" 7 7 */ 8 8 ··· 27 27 28 28 /** @type {OutputManagerDeputy} */ 29 29 const manager = { 30 - constituents: { 30 + facets: { 31 31 collection: computed(() => { 32 32 const out = this.#selectedOutput.value; 33 - if (out) return out.constituents.collection(); 33 + if (out) return out.facets.collection(); 34 34 35 35 const def = this.#defaultOutput.value; 36 - if (def) return def.constituents.collection(); 36 + if (def) return def.facets.collection(); 37 37 38 - return this.#memory.constituents.value; 38 + return this.#memory.facets.value; 39 39 }), 40 40 reload: () => { 41 41 const def = this.#defaultOutput.value; 42 - if (def) def.constituents.reload(); 42 + if (def) def.facets.reload(); 43 43 44 44 const out = this.#selectedOutput.value; 45 - if (out) return out.constituents.reload(); 45 + if (out) return out.facets.reload(); 46 46 47 47 return Promise.resolve(); 48 48 }, 49 - save: async (newConstituents) => { 49 + save: async (newFacets) => { 50 50 const def = this.#defaultOutput.value; 51 - if (def) await def.constituents.save(newConstituents); 51 + if (def) await def.facets.save(newFacets); 52 52 53 53 const out = this.#selectedOutput.value; 54 - if (out) return await out.constituents.save(newConstituents); 54 + if (out) return await out.facets.save(newFacets); 55 55 56 - this.#memory.constituents.value = newConstituents; 56 + this.#memory.facets.value = newFacets; 57 57 }, 58 58 state: computed(() => { 59 59 const out = this.#selectedOutput.value; 60 - if (out) return out.constituents.state(); 60 + if (out) return out.facets.state(); 61 61 62 62 const def = this.#defaultOutput.value; 63 - if (def) return def.constituents.state(); 63 + if (def) return def.facets.state(); 64 64 65 65 return this.#setupFinished.value ? "loaded" : "sleeping"; 66 66 }), ··· 106 106 }; 107 107 108 108 // Assign manager properties to class 109 - this.constituents = manager.constituents; 109 + this.facets = manager.facets; 110 110 this.tracks = manager.tracks; 111 111 } 112 112 ··· 117 117 ); 118 118 119 119 #memory = { 120 - constituents: signal(/** @type {Constituent[]} */ ([])), 120 + facets: signal(/** @type {Facet[]} */ ([])), 121 121 tracks: signal(/** @type {Track[]} */ ([])), 122 122 }; 123 123
+2 -2
src/components/orchestrator/output/element.js
··· 35 35 36 36 // PROXY OUTPUT ACTIONS 37 37 38 - get constituents() { 39 - return this.output.constituents; 38 + get facets() { 39 + return this.output.facets; 40 40 } 41 41 42 42 get tracks() {
+13 -13
src/components/output/common.js
··· 1 1 import { computed, signal, untracked } from "@common/signal.js"; 2 2 3 3 /** 4 - * @import {Constituent, Track} from "@definitions/types.d.ts" 4 + * @import {Facet, Track} from "@definitions/types.d.ts" 5 5 * @import {OutputManager, OutputManagerProperties} from "./types.d.ts" 6 6 */ 7 7 ··· 10 10 * @param {OutputManagerProperties<Encoding>} _ 11 11 * @returns {OutputManager<Encoding>} 12 12 */ 13 - export function outputManager({ init, constituents, tracks }) { 13 + export function outputManager({ init, facets, tracks }) { 14 14 const c = signal( 15 - /** @type {Encoding extends null ? Constituent[] : Encoding} */ (constituents 15 + /** @type {Encoding extends null ? Facet[] : Encoding} */ (facets 16 16 .empty()), 17 17 ); 18 18 const cs = signal( ··· 26 26 /** @type {"loading" | "loaded" | "sleeping"} */ ("sleeping"), 27 27 ); 28 28 29 - async function loadConstituents() { 29 + async function loadFacets() { 30 30 if (init && (await init()) === false) return; 31 31 cs.value = "loading"; 32 - c.value = await constituents.get(); 32 + c.value = await facets.get(); 33 33 cs.value = "loaded"; 34 34 } 35 35 ··· 41 41 } 42 42 43 43 return { 44 - constituents: { 44 + facets: { 45 45 collection: computed(() => { 46 - if (untracked(() => cs.value === "sleeping")) loadConstituents(); 46 + if (untracked(() => cs.value === "sleeping")) loadFacets(); 47 47 return c.value; 48 48 }), 49 - reload: loadConstituents, 50 - save: async (newConstituents) => { 51 - if (untracked(() => cs.value === "sleeping")) loadConstituents(); 52 - c.value = newConstituents; 53 - await constituents.put(newConstituents); 49 + reload: loadFacets, 50 + save: async (newFacets) => { 51 + if (untracked(() => cs.value === "sleeping")) loadFacets(); 52 + c.value = newFacets; 53 + await facets.put(newFacets); 54 54 }, 55 55 state: cs.get, 56 56 }, ··· 68 68 state: ts.get, 69 69 }, 70 70 signals: { 71 - constituents: c, 71 + facets: c, 72 72 tracks: t, 73 73 }, 74 74 };
+4 -4
src/components/output/polymorphic/indexed-db/element.js
··· 28 28 29 29 /** @type {OutputManager<SupportedDataTypes>} */ 30 30 this.#manager = outputManager({ 31 - constituents: { 31 + facets: { 32 32 empty: () => undefined, 33 - get: () => this.#get("constituents"), 34 - put: (data) => this.#put("constituents", data), 33 + get: () => this.#get("facets"), 34 + put: (data) => this.#put("facets", data), 35 35 }, 36 36 init: () => this.whenConnected(), 37 37 tracks: { ··· 41 41 }, 42 42 }); 43 43 44 - this.constituents = this.#manager.constituents; 44 + this.facets = this.#manager.facets; 45 45 this.tracks = this.#manager.tracks; 46 46 } 47 47
+9 -9
src/components/output/types.d.ts
··· 1 1 import type { Signal, SignalReader } from "@common/signal.d.ts"; 2 2 import type { DiffuseElement } from "@common/element.js"; 3 - import type { Constituent, Track } from "@definitions/types.d.ts"; 3 + import type { Facet, Track } from "@definitions/types.d.ts"; 4 4 5 5 export type OutputElement<Encoding = null> = 6 6 & DiffuseElement ··· 12 12 >; 13 13 14 14 export type OutputManager<Encoding = null> = { 15 - constituents: { 16 - collection: SignalReader<Encoding extends null ? Constituent[] : Encoding>; 15 + facets: { 16 + collection: SignalReader<Encoding extends null ? Facet[] : Encoding>; 17 17 reload: () => Promise<void>; 18 18 save: ( 19 - constituents: Encoding extends null ? Constituent[] : Encoding, 19 + facets: Encoding extends null ? Facet[] : Encoding, 20 20 ) => Promise<void>; 21 21 state: SignalReader<"loading" | "loaded" | "sleeping">; 22 22 }; 23 23 signals: { 24 - constituents: Signal<Encoding extends null ? Constituent[] : Encoding>; 24 + facets: Signal<Encoding extends null ? Facet[] : Encoding>; 25 25 tracks: Signal<Encoding extends null ? Track[] : Encoding>; 26 26 }; 27 27 tracks: { ··· 33 33 }; 34 34 35 35 export type OutputManagerProperties<Encoding = null> = { 36 - constituents: { 37 - empty(): Encoding extends null ? Constituent[] : Encoding; 38 - get(): Promise<Encoding extends null ? Constituent[] : Encoding>; 36 + facets: { 37 + empty(): Encoding extends null ? Facet[] : Encoding; 38 + get(): Promise<Encoding extends null ? Facet[] : Encoding>; 39 39 put( 40 - constituents: Encoding extends null ? Constituent[] : Encoding, 40 + facets: Encoding extends null ? Facet[] : Encoding, 41 41 ): Promise<void>; 42 42 }; 43 43 init?: () => Promise<boolean>;
+7 -7
src/components/transformer/output/base.js
··· 42 42 base() { 43 43 /** @type {OutputManagerDeputy<T | undefined>} */ 44 44 const m = { 45 - constituents: { 45 + facets: { 46 46 collection: computed(() => { 47 - return this.output.signal()?.constituents?.collection(); 47 + return this.output.signal()?.facets?.collection(); 48 48 }), 49 49 reload: () => { 50 - return this.output.signal()?.constituents?.reload() ?? 50 + return this.output.signal()?.facets?.reload() ?? 51 51 Promise.resolve(); 52 52 }, 53 - save: async (newConstituents) => { 54 - if (newConstituents === undefined) return; 53 + save: async (newFacets) => { 54 + if (newFacets === undefined) return; 55 55 await this.output.whenDefined; 56 - await this.output.signal()?.constituents.save(newConstituents); 56 + await this.output.signal()?.facets.save(newFacets); 57 57 }, 58 58 state: computed(() => { 59 - return this.output.signal()?.constituents.state() ?? "sleeping"; 59 + return this.output.signal()?.facets.state() ?? "sleeping"; 60 60 }), 61 61 }, 62 62 tracks: {
+3 -3
src/components/transformer/output/bytes/automerge/constants.js
··· 2 2 import { base64 } from "iso-base/rfc4648"; 3 3 4 4 /** 5 - * @import { ConstituentsDocument, PlaylistsDocument, ThemesDocument, TracksDocument } from "./types.d.ts"; 5 + * @import { FacetsDocument, PlaylistsDocument, ThemesDocument, TracksDocument } from "./types.d.ts"; 6 6 */ 7 7 8 - /** @type {Automerge.Doc<ConstituentsDocument>} */ 9 - export const INITIAL_CONSTITUENTS_DOCUMENT = Automerge.load( 8 + /** @type {Automerge.Doc<FacetsDocument>} */ 9 + export const INITIAL_FACETS_DOCUMENT = Automerge.load( 10 10 base64.decode( 11 11 "hW9Kg1fmLLcAeAEQZ2dnbV0O8AUftAeEXT1QVQHsmc9lhGh1ysz4ECa3pEUgzSZG2aF8hob78u7FqeybBQYBAgMCEwIjBkACVgIHFQwhAiMCNAFCAlYCgAECfwB/AX8Bf8KTqcwGfwB/B38KY29sbGVjdGlvbn8AfwEBfwJ/AH8AAA", 12 12 ),
+14 -14
src/components/transformer/output/bytes/automerge/element.js
··· 5 5 import { recursivelyCloneRecords } from "@common/utils.js"; 6 6 import { OutputTransformer } from "../../base.js"; 7 7 import { 8 - INITIAL_CONSTITUENTS_DOCUMENT, 8 + INITIAL_FACETS_DOCUMENT, 9 9 INITIAL_TRACKS_DOCUMENT, 10 10 } from "./constants.js"; 11 11 12 12 /** 13 13 * @import { SignalReader } from "@common/signal.d.ts"; 14 14 * @import { OutputManagerDeputy } from "@components/output/types.d.ts" 15 - * @import { ConstituentsDocument, PlaylistsDocument, ThemesDocument, TracksDocument } from "./types.d.ts" 15 + * @import { FacetsDocument, PlaylistsDocument, ThemesDocument, TracksDocument } from "./types.d.ts" 16 16 */ 17 17 18 18 /** ··· 24 24 25 25 const base = this.base(); 26 26 27 - /** @type {SignalReader<Automerge.Doc<ConstituentsDocument>>} */ 28 - const constituentsDocument = computed(() => { 29 - const value = base.constituents.collection(); 27 + /** @type {SignalReader<Automerge.Doc<FacetsDocument>>} */ 28 + const facetsDocument = computed(() => { 29 + const value = base.facets.collection(); 30 30 31 31 if (isUint8Array(value)) { 32 32 return Automerge.load(value); 33 33 } else if (value == undefined) { 34 - return INITIAL_CONSTITUENTS_DOCUMENT; 34 + return INITIAL_FACETS_DOCUMENT; 35 35 } else { 36 36 // TODO: Better error 37 37 throw new Error("Invalid data type"); ··· 54 54 55 55 /** @type {OutputManagerDeputy} */ 56 56 const manager = { 57 - constituents: { 58 - ...base.constituents, 59 - collection: computed(() => constituentsDocument().collection), 60 - save: async (newConstituents) => { 61 - const doc = Automerge.change(constituentsDocument(), (d) => { 62 - const clonedCollection = newConstituents.map((constituent) => { 63 - return recursivelyCloneRecords(constituent); 57 + facets: { 58 + ...base.facets, 59 + collection: computed(() => facetsDocument().collection), 60 + save: async (newFacets) => { 61 + const doc = Automerge.change(facetsDocument(), (d) => { 62 + const clonedCollection = newFacets.map((facet) => { 63 + return recursivelyCloneRecords(facet); 64 64 }); 65 65 66 66 d.collection = clonedCollection; 67 67 }); 68 68 69 69 const bytes = Automerge.save(doc); 70 - await base.constituents.save(bytes); 70 + await base.facets.save(bytes); 71 71 }, 72 72 }, 73 73 tracks: {
+2 -7
src/components/transformer/output/bytes/automerge/types.d.ts
··· 1 - import type { 2 - Constituent, 3 - Playlist, 4 - Theme, 5 - Track, 6 - } from "@definitions/types.d.ts"; 1 + import type { Facet, Playlist, Theme, Track } from "@definitions/types.d.ts"; 7 2 8 - export type ConstituentsDocument = { collection: Constituent[] }; 3 + export type FacetsDocument = { collection: Facet[] }; 9 4 export type PlaylistsDocument = { collection: Playlist[] }; 10 5 export type ThemesDocument = { collection: Theme[] }; 11 6 export type TracksDocument = { collection: Track[] };
+8 -8
src/components/transformer/output/bytes/json/element.js
··· 3 3 4 4 /** 5 5 * @import { OutputManagerDeputy } from "@components/output/types.d.ts" 6 - * @import { Constituent, Track } from "@definitions/types.d.ts" 6 + * @import { Facet, Track } from "@definitions/types.d.ts" 7 7 */ 8 8 9 9 /** ··· 17 17 18 18 /** @type {OutputManagerDeputy} */ 19 19 const manager = { 20 - constituents: { 21 - ...base.constituents, 20 + facets: { 21 + ...base.facets, 22 22 collection: computed(() => { 23 - const data = base.constituents.collection(); 24 - /** @type {Constituent[]} */ 23 + const data = base.facets.collection(); 24 + /** @type {Facet[]} */ 25 25 const c = parseArray(data); 26 26 return c; 27 27 }), 28 - save: async (newConstituents) => { 29 - const json = JSON.stringify(newConstituents); 28 + save: async (newFacets) => { 29 + const json = JSON.stringify(newFacets); 30 30 const encoder = new TextEncoder(); 31 31 const bytes = encoder.encode(json); 32 - await base.constituents.save(bytes); 32 + await base.facets.save(bytes); 33 33 }, 34 34 }, 35 35 tracks: {
+4 -4
src/components/transformer/output/refiner/default/element.js
··· 16 16 17 17 /** @type {OutputManagerDeputy} */ 18 18 const manager = { 19 - constituents: { 20 - ...base.constituents, 19 + facets: { 20 + ...base.facets, 21 21 collection: computed(() => { 22 - return base.constituents.collection() ?? []; 22 + return base.facets.collection() ?? []; 23 23 }), 24 24 }, 25 25 tracks: { ··· 35 35 }; 36 36 37 37 // Assign manager properties to class 38 - this.constituents = manager.constituents; 38 + this.facets = manager.facets; 39 39 this.tracks = manager.tracks; 40 40 } 41 41 }
+7 -8
src/components/transformer/output/string/json/element.js
··· 3 3 4 4 /** 5 5 * @import { OutputManagerDeputy } from "@components/output/types.d.ts" 6 - * @import { Track } from "@definitions/types.d.ts" 7 6 */ 8 7 9 8 /** ··· 17 16 18 17 /** @type {OutputManagerDeputy} */ 19 18 const manager = { 20 - constituents: { 21 - ...base.constituents, 19 + facets: { 20 + ...base.facets, 22 21 collection: computed(() => { 23 - const json = base.constituents.collection(); 22 + const json = base.facets.collection(); 24 23 return typeof json === "string" ? parseArray(json) : []; 25 24 }), 26 - save: async (newConstituents) => { 27 - const json = JSON.stringify(newConstituents); 28 - await base.constituents.save(json); 25 + save: async (newFacets) => { 26 + const json = JSON.stringify(newFacets); 27 + await base.facets.save(json); 29 28 }, 30 29 }, 31 30 tracks: { ··· 42 41 }; 43 42 44 43 // Assign manager properties to class 45 - this.constituents = manager.constituents; 44 + this.facets = manager.facets; 46 45 this.tracks = manager.tracks; 47 46 } 48 47 }
+1 -1
src/constituents/examples/generate-playlist.html.txt src/facets/examples/generate-playlist.html.txt
··· 10 10 </style> 11 11 12 12 <script type="module"> 13 - import foundation from "./common/constituents/foundation.js"; 13 + import foundation from "./common/facets/foundation.js"; 14 14 15 15 const queue = foundation.engine.queue(); 16 16
+1 -1
src/constituents/examples/now-playing.html.txt src/facets/examples/now-playing.html.txt
··· 9 9 </style> 10 10 11 11 <script type="module"> 12 - import foundation from "./common/constituents/foundation.js"; 12 + import foundation from "./common/facets/foundation.js"; 13 13 import { computed, effect } from "./common/signal.js"; 14 14 15 15 foundation.features.processInputs();
+25 -25
src/constituents/index.js src/facets/index.js
··· 7 7 import { javascript as langJs } from "@codemirror/lang-javascript"; 8 8 import { autocompletion } from "@codemirror/autocomplete"; 9 9 10 - import foundation from "@common/constituents/foundation.js"; 10 + import foundation from "@common/facets/foundation.js"; 11 11 import { effect } from "@common/signal.js"; 12 12 13 13 /** 14 - * @import {Constituent} from "@definitions/types.d.ts" 14 + * @import {Facet} from "@definitions/types.d.ts" 15 15 */ 16 16 17 17 //////////////////////////////////////////// ··· 25 25 const output = foundation.orchestrator.output(); 26 26 27 27 effect(() => { 28 - const col = output.constituents.collection().sort((a, b) => { 28 + const col = output.facets.collection().sort((a, b) => { 29 29 return a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase()); 30 30 }); 31 31 ··· 38 38 <span>${c.name}</span> 39 39 <div class="list-description"> 40 40 <div class="button-row"> 41 - <a href="constituents/l/?cid=${c.cid}" class="button">Open</a> 41 + <a href="facets/l/?cid=${c.cid}" class="button">Open</a> 42 42 <button 43 43 style="background-color: var(--accent-twist-2);" 44 - @click="${deleteConstituent({ 44 + @click="${deleteFacet({ 45 45 cid: c.cid, 46 46 name: c.name, 47 47 })}" ··· 57 57 )} 58 58 </ul> 59 59 ` 60 - : output.constituents.state() === "loaded" 61 - ? emptyConstituentsList 60 + : output.facets.state() === "loaded" 61 + ? emptyFacetsList 62 62 : html` 63 63 <i class="ph-bold ph-spinner-gap"></i> 64 64 `; ··· 66 66 render(h, listEl); 67 67 }); 68 68 69 - const emptyConstituentsList = html` 69 + const emptyFacetsList = html` 70 70 <p style="margin-bottom: 0;"> 71 - <i class="ph-fill ph-info"></i> You have not saved any constituents yet. 71 + <i class="ph-fill ph-info"></i> You have not saved any facets yet. 72 72 </p> 73 73 `; 74 74 75 75 /** 76 76 * @param {{ cid: string; name: string }} _ 77 77 */ 78 - function deleteConstituent({ cid, name }) { 78 + function deleteFacet({ cid, name }) { 79 79 return () => { 80 - const c = confirm("Are you sure you want to delete this constituent?"); 80 + const c = confirm("Are you sure you want to delete this facet?"); 81 81 if (!c) return; 82 82 83 - output.constituents.save( 84 - output.constituents.collection().filter((c) => 83 + output.facets.save( 84 + output.facets.collection().filter((c) => 85 85 !(c.name === name && c.cid === cid) 86 86 ), 87 87 ); ··· 111 111 </style> 112 112 113 113 <script type="module"> 114 - import foundation from "./common/constituents/foundation.js"; 114 + import foundation from "./common/facets/foundation.js"; 115 115 import { effect } from "./common/signal.js"; 116 116 117 117 const components = foundation.features.fillQueueAutomatically(); ··· 154 154 const cid = await CID.create(0x55, new TextEncoder().encode(html)); 155 155 const name = nameEl?.value ?? "nameless"; 156 156 157 - /** @type {Constituent} */ 158 - const constituent = { 159 - $type: "sh.diffuse.output.constituent", 157 + /** @type {Facet} */ 158 + const facet = { 159 + $type: "sh.diffuse.output.facet", 160 160 cid: CID.toString(cid), 161 161 html, 162 162 name, ··· 177 177 break; 178 178 } 179 179 case "save": 180 - await saveConstituent(constituent); 180 + await saveFacet(facet); 181 181 break; 182 182 case "save+open": 183 - await saveConstituent(constituent); 184 - window.open(`./constituents/l/?cid=${constituent.cid}`, "blank"); 183 + await saveFacet(facet); 184 + window.open(`./facets/l/?cid=${facet.cid}`, "blank"); 185 185 break; 186 186 } 187 187 } 188 188 189 189 /** 190 - * @param {Constituent} constituent 190 + * @param {Facet} facet 191 191 */ 192 - async function saveConstituent(constituent) { 193 - const col = output.constituents.collection(); 194 - const colWithoutName = col.filter((c) => c.name !== constituent.name); 192 + async function saveFacet(facet) { 193 + const col = output.facets.collection(); 194 + const colWithoutName = col.filter((c) => c.name !== facet.name); 195 195 196 - await output.constituents.save([...colWithoutName, constituent]); 196 + await output.facets.save([...colWithoutName, facet]); 197 197 }
+22 -22
src/constituents/index.vto src/facets/index.vto
··· 1 1 --- 2 - layout: layouts/constituent.vto 2 + layout: layouts/facet.vto 3 3 base: ../ 4 4 5 5 styles: ··· 9 9 - styles/vendor/phosphor/fill/style.css 10 10 11 11 scripts: 12 - - constituents/index.js 12 + - facets/index.js 13 13 14 - # CONSTITUENTS 14 + # FACETS 15 15 16 - constituents: 17 - - url: "themes/blur/artwork-controller/constituent.html.txt" 16 + facets: 17 + - url: "themes/blur/artwork-controller/facet.html.txt" 18 18 title: "Blur / Artwork controller" 19 19 desc: > 20 20 Audio playback controller with an artwork display. 21 - - url: "themes/webamp/browser/constituent.html.txt" 21 + - url: "themes/webamp/browser/facet.html.txt" 22 22 title: "Webamp / Browser" 23 23 desc: > 24 24 Collection browser + search in a retro, win98, look. 25 - - url: "themes/webamp/configurators/input/constituent.html.txt" 25 + - url: "themes/webamp/configurators/input/facet.html.txt" 26 26 title: "Webamp / Input Configurator" 27 27 desc: > 28 28 Windows 98 styled input configurator where you can add music sources. ··· 36 36 </a> 37 37 </div> 38 38 <p class="construct dither-mask" style="margin-top: 0; max-width: none;"> 39 - Constituents 39 + Facets 40 40 </p> 41 41 <p> 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. 42 + Facets 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. 43 43 </p> 44 44 45 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> 46 + <li><a href="facets/#built-in">Built-in</a></li> 47 + <li><a href="facets/#community">Community</a></li> 48 + <li><a href="facets/#saved">Your collection</a></li> 49 + <li><a href="facets/#examples">Examples</a></li> 50 + <li><a href="facets/#build">Build</a></li> 51 + <li><a href="facets/#foundation">Foundation</a></li> 52 52 </ul> 53 53 </div> 54 54 <div class="dither-mask filler"></div> ··· 60 60 <h2 id="built-in">Built-in</h2> 61 61 62 62 <div style="margin-top: var(--space-lg);"> 63 - {{ await comp.constituents({ items: constituents }) }} 63 + {{ await comp.facets({ items: facets }) }} 64 64 </div> 65 65 </section> 66 66 67 67 <section class="flex"> 68 68 <h2 id="community">Community</h2> 69 69 <p> 70 - Check out some constituents from the community and load them here. 70 + Check out some facets from the community and load them here. 71 71 </p> 72 72 <p> 73 73 <small><i class="ph-fill ph-info"></i> Nothing here yet, too early.</small> ··· 106 106 107 107 <div class="flex"> 108 108 <p style="margin-top: 0"> 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. 109 + 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 110 </p> 111 111 <input id="name-input" type="text" placeholder="Unique name" name="name" value="Unique name" required /> 112 112 <p> ··· 124 124 <selectedcontent></selectedcontent> 125 125 </button> 126 126 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> 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 129 </select> 130 130 </div> 131 131 <p> ··· 151 151 <div class="code-block"> 152 152 <code> 153 153 {{- echo -}} 154 - import foundation from "common/constituents/foundation.js" 154 + import foundation from "common/facets/foundation.js" 155 155 {{ /echo }} 156 156 {{ echo -}}foundation.engine.audio(){{- /echo }} 157 157 {{ echo -}}foundation.engine.queue(){{- /echo }} ··· 203 203 </ul> 204 204 <h3>Notes</h3> 205 205 <p> 206 - While you have the ability to do whatever you want in a custom constituent, the existing constituents are designed to work a certain way; so here's some things to keep in mind: 206 + While you have the ability to do whatever you want in a custom facet, the existing facets are designed to work a certain way; so here's some things to keep in mind: 207 207 </p> 208 208 <ul> 209 209 <li><span>In most cases you'll want to call <code>foundation.features.processInputs()</code> so that your audio files and streams actually show up.</span></li>
+16 -16
src/constituents/l/index.js src/facets/l/index.js
··· 1 1 import * as CID from "@atcute/cid"; 2 2 3 - import foundation from "@common/constituents/foundation.js"; 3 + import foundation from "@common/facets/foundation.js"; 4 4 import { effect } from "@common/signal.js"; 5 5 6 6 /** 7 - * @import {Constituent} from "@definitions/types.d.ts" 7 + * @import {Facet} from "@definitions/types.d.ts" 8 8 */ 9 9 10 10 //////////////////////////////////////////// ··· 33 33 const container = /** @type {HTMLDivElement} */ (containerNull); 34 34 35 35 effect(async () => { 36 - const collection = output.constituents.collection(); 37 - if (output.constituents.state() !== "loaded") return; 36 + const collection = output.facets.collection(); 37 + if (output.facets.state() !== "loaded") return; 38 38 39 - let constituent; 39 + let facet; 40 40 41 41 if (cid) { 42 - constituent = collection.find((c) => c.cid === cid); 42 + facet = collection.find((c) => c.cid === cid); 43 43 } else if (name) { 44 - constituent = collection.find((c) => c.name === name); 44 + facet = collection.find((c) => c.name === name); 45 45 } else if (url) { 46 46 const html = await fetch(url).then((res) => res.text()); 47 47 const cid = await CID.create(0x55, new TextEncoder().encode(html)); 48 48 const name = "tryout"; 49 49 50 - /** @type {Constituent} */ 50 + /** @type {Facet} */ 51 51 const c = { 52 - $type: "sh.diffuse.output.constituent", 52 + $type: "sh.diffuse.output.facet", 53 53 cid: CID.toString(cid), 54 54 html, 55 55 name, 56 56 }; 57 57 58 - constituent = c; 58 + facet = c; 59 59 } 60 60 61 - // TODO: Message that constituent was not found 62 - if (!constituent) return; 61 + // TODO: Message that facet was not found 62 + if (!facet) return; 63 63 64 - loadIntoContainer(constituent); 64 + loadIntoContainer(facet); 65 65 }); 66 66 67 67 /** 68 - * @param {Constituent} constituent 68 + * @param {Facet} facet 69 69 */ 70 - function loadIntoContainer(constituent) { 70 + function loadIntoContainer(facet) { 71 71 // TODO: Validate if CID matches HTML 72 72 73 73 const range = document.createRange(); 74 74 range.selectNode(container); 75 - const documentFragment = range.createContextualFragment(constituent.html); 75 + const documentFragment = range.createContextualFragment(facet.html); 76 76 77 77 container.innerHTML = ""; 78 78 container.append(documentFragment);
-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>
+1 -1
src/definitions/index.ts
··· 1 - export * as ShDiffuseOutputConstituent from "./types/sh/diffuse/output/constituent.ts"; 1 + export * as ShDiffuseOutputFacet from "./types/sh/diffuse/output/facet.ts"; 2 2 export * as ShDiffuseOutputPlaylist from "./types/sh/diffuse/output/playlist.ts"; 3 3 export * as ShDiffuseOutputTheme from "./types/sh/diffuse/output/theme.ts"; 4 4 export * as ShDiffuseOutputTrack from "./types/sh/diffuse/output/track.ts";
+3 -3
src/definitions/output/constituent.json src/definitions/output/facet.json
··· 1 1 { 2 2 "lexicon": 1, 3 - "id": "sh.diffuse.output.constituent", 3 + "id": "sh.diffuse.output.facet", 4 4 "defs": { 5 5 "main": { 6 6 "type": "record", ··· 15 15 "description": { "type": "string" }, 16 16 "html": { 17 17 "type": "string", 18 - "description": "The UTF8 HTML string that makes up the constituent" 18 + "description": "The UTF8 HTML string that makes up the facet" 19 19 }, 20 20 "name": { "type": "string" }, 21 21 "url": { 22 22 "type": "string", 23 - "description": "An optional URL that points at the constituent; can be used to update this artifact" 23 + "description": "An optional URL that points at the facet; can be used to update this artifact" 24 24 } 25 25 } 26 26 }
+1 -3
src/definitions/types.d.ts
··· 1 - export type { 2 - Main as Constituent, 3 - } from "./types/sh/diffuse/output/constituent.ts"; 1 + export type { Main as Facet } from "./types/sh/diffuse/output/facet.ts"; 4 2 5 3 export type { 6 4 AutoGenerate as PlaylistAutoGeneration,
+9
src/facets/l/index.vto
··· 1 + --- 2 + layout: layouts/facet.vto 3 + base: ../../ 4 + 5 + scripts: 6 + - facets/l/index.js 7 + --- 8 + 9 + <div id="container"></div>
+1 -1
src/index.js
··· 1 - import { GROUP } from "@common/constituents/foundation.js"; 1 + import { GROUP } from "@common/facets/foundation.js"; 2 2 3 3 import InputConfigurator from "@components/configurator/input/element.js"; 4 4 import MetadataProcessor from "@components/processor/metadata/element.js";
+16 -16
src/index.vto
··· 21 21 - title: "Loader" 22 22 todo: true 23 23 desc: > 24 - **A theme that loads other themes!** _If you're taking the first steps to customize, checkout the [constituents loader](#constituents) first!_ 24 + **A theme that loads other themes!** _If you're taking the first steps to customize, checkout the [facets loader](#facets) first!_ 25 25 - url: "themes/webamp/" 26 26 title: "Webamp" 27 27 desc: > ··· 163 163 # DEFINITIONS 164 164 165 165 definitions: 166 - - title: "Output / Constituent" 166 + - title: "Output / Facet" 167 167 desc: > 168 - Constituent pointer or HTML snippet. 169 - url: "definitions/output/constituent.json" 168 + Facet pointer or HTML snippet. 169 + url: "definitions/output/facet.json" 170 170 - title: "Output / Playlist" 171 171 desc: > 172 172 Represents a collection of tracks, which may be ordered or unordered. Tracks are matched based on the given criteria. ··· 212 212 <ul class="table-of-contents"> 213 213 <li><a href="#usage">Usage</a></li> 214 214 <li><a href="#themes">Themes</a></li> 215 - <li><a href="#constituents">Constituents</a></li> 215 + <li><a href="#facets">Facets</a></li> 216 216 <li><a href="#agency">Agency</a></li> 217 217 <li><a href="#elements">Elements</a></li> 218 218 <li><a href="#definitions">Definitions</a></li> ··· 235 235 </p> 236 236 237 237 <p> 238 - Alternatively, there's <a href="constituents/">constituents</a> which allows you to use any component from any theme interchange&shy;ably, among pieces that are not in themes; each in a separate browser tab. Each tab talks to each other, so you can for example browse audio in one tab and play it in another. 238 + Alternatively, there's <a href="facets/">facets</a> which allows you to use any component from any theme interchange&shy;ably, among pieces that are not in themes; each in a separate browser tab. Each tab talks to each other, so you can for example browse audio in one tab and play it in another. 239 239 </p> 240 240 </div> 241 241 242 242 <div class="element"> 243 243 <p> 244 - <strong style="color: var(--accent); font-weight: 700;">Diffuse is not your typical streaming service though, you have to add sources of audio.</strong> To start you can try out the demo by clicking the button below, or, go to a <a href="themes/">theme</a> or <a href="constituents/">constituent</a> that lets you add your audio input. 244 + <strong style="color: var(--accent); font-weight: 700;">Diffuse is not your typical streaming service though, you have to add sources of audio.</strong> To start you can try out the demo by clicking the button below, or, go to a <a href="themes/">theme</a> or <a href="facets/">facet</a> that lets you add your audio input. 245 245 </p> 246 246 247 247 <p> ··· 253 253 </div> 254 254 </section> 255 255 256 - <!-- THEMES & CONSTITUENTS --> 256 + <!-- THEMES & FACETS --> 257 257 <div class="columns"> 258 258 <section> 259 259 <h2 id="themes">Themes</h2> ··· 269 269 </section> 270 270 271 271 <section> 272 - <h2 id="constituents">Constituents</h2> 272 + <h2 id="facets">Facets</h2> 273 273 274 274 <p> 275 - 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. 275 + Facets 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. 276 276 </p> 277 277 278 278 <p> 279 - <a class="button button--alt" href="constituents/">Explore</a> 279 + <a class="button button--alt" href="facets/">Explore</a> 280 280 </p> 281 281 </section> 282 282 </div> ··· 302 302 <!-- 2 --> 303 303 <li> 304 304 <p> 305 - <i class="ph-fill ph-basket"></i> <strong>Level 2</strong>: Take out food from various places, eg. cheese shop + bakery. You choose how you combine the foods and from where you order them. That's <a href="constituents/">constituents</a>. 305 + <i class="ph-fill ph-basket"></i> <strong>Level 2</strong>: Take out food from various places, eg. cheese shop + bakery. You choose how you combine the foods and from where you order them. That's <a href="facets/">facets</a>. 306 306 </p> 307 307 </li> 308 308 <!-- 3 --> ··· 311 311 <i class="ph-fill ph-pepper"></i> <strong>Level 3</strong>: Now that you know which food is good and how to make combinations, you might make a slight customization, add a little something of your own (eg. add some spice). However, you're not quite confident enough which spice to pick, so you hire some help. 312 312 </p> 313 313 <p> 314 - This can be done using the <a href="constituents/#builder">constituents builder</a> which allows you to build on top of a familiar preconfigured foundation and load custom constituents. People might share their own, or maybe you use an LLM to generate something for you (eg. an album art gallery). 314 + This can be done using the <a href="facets/#builder">facets builder</a> which allows you to build on top of a familiar preconfigured foundation and load custom facets. People might share their own, or maybe you use an LLM to generate something for you (eg. an album art gallery). 315 315 </p> 316 316 </li> 317 317 <!-- 4 --> ··· 320 320 <i class="ph-fill ph-knife"></i> <strong>Level 4</strong>: You learned a bit from watching and talking to the help you hired, so you decide to take things in your own hands. 321 321 </p> 322 322 <p> 323 - You continue to use the <a href="constituents/#builder">constituents builder</a> but learn a bit of <a href="https://htmlforpeople.com">HTML</a>, <a href="https://javascript.info">Javascript</a> and <a href="https://htmlforpeople.com/css-basics/">CSS</a>; so you're able to write your own constituent. 323 + You continue to use the <a href="facets/#builder">facets builder</a> but learn a bit of <a href="https://htmlforpeople.com">HTML</a>, <a href="https://javascript.info">Javascript</a> and <a href="https://htmlforpeople.com/css-basics/">CSS</a>; so you're able to write your own facet. 324 324 </p> 325 325 </li> 326 326 </div> ··· 331 331 <i class="ph-fill ph-cooking-pot"></i> <strong>Level 5</strong>: At this point you're confident enough to make a meal from scratch. You can start very simple, eg. just throwing a steak in the pan with some butter and some salt to it. Then later add some baked potatoes and go from there. 332 332 </p> 333 333 <p> 334 - A similar tool comes into play here, the <a href="themes/#builder">themes builder</a>. Same concept as the constituents builder, but now you need to specify the foundation yourself. You can use the <a href="#elements">elements</a> listed below to do so. The code for these is available from this website or through the <a href="https://jsr.io/@toko/diffuse">Javascript package</a>. 334 + A similar tool comes into play here, the <a href="themes/#builder">themes builder</a>. Same concept as the facets builder, but now you need to specify the foundation yourself. You can use the <a href="#elements">elements</a> listed below to do so. The code for these is available from this website or through the <a href="https://jsr.io/@toko/diffuse">Javascript package</a>. 335 335 </p> 336 336 </li> 337 337 <!-- 6 --> ··· 365 365 </p> 366 366 367 367 <p> 368 - Consume these using the constituents <a href="constituents/#builder">builder</a>, the Javascript <a href="https://jsr.io/@toko/diffuse">package</a>, or the linked Javascript files down below. 368 + Consume these using the facets <a href="facets/#builder">builder</a>, the Javascript <a href="https://jsr.io/@toko/diffuse">package</a>, or the linked Javascript files down below. 369 369 </p> 370 370 371 371 <div class="columns">
+1 -1
src/themes/blur/artwork-controller/constituent.html.txt src/themes/blur/artwork-controller/facet.html.txt
··· 4 4 @import "styles/base.css"; 5 5 </style> 6 6 7 - <script type="module" src="themes/blur/artwork-controller/constituent.js"></script> 7 + <script type="module" src="themes/blur/artwork-controller/facet.js"></script>
+1 -1
src/themes/blur/artwork-controller/constituent.js src/themes/blur/artwork-controller/facet.js
··· 1 - import foundation from "@common/constituents/foundation.js"; 1 + import foundation from "@common/facets/foundation.js"; 2 2 import ArtworkController from "@themes/blur/artwork-controller/element.js"; 3 3 4 4 // Setup the prerequisite elements
+1 -1
src/themes/index.vto
··· 1 1 --- 2 - layout: layouts/constituent.vto 2 + layout: layouts/facet.vto 3 3 base: ../ 4 4 5 5 styles:
+2 -2
src/themes/webamp/browser/constituent.html.txt src/themes/webamp/browser/facet.html.txt
··· 20 20 <style> 21 21 @import "styles/vendor/98.css"; 22 22 @import "themes/webamp/fonts.css"; 23 - @import "themes/webamp/constituent.css"; 23 + @import "themes/webamp/facet.css"; 24 24 </style> 25 25 26 - <script type="module" src="themes/webamp/browser/constituent.js"></script> 26 + <script type="module" src="themes/webamp/browser/facet.js"></script>
+1 -1
src/themes/webamp/browser/constituent.js src/themes/webamp/browser/facet.js
··· 1 - import foundation from "@common/constituents/foundation.js"; 1 + import foundation from "@common/facets/foundation.js"; 2 2 import BrowserElement from "@themes/webamp/browser/element.js"; 3 3 4 4 foundation.features.fillQueueAutomatically();
+2 -2
src/themes/webamp/configurators/input/constituent.html.txt src/themes/webamp/configurators/input/facet.html.txt
··· 20 20 <style> 21 21 @import "styles/vendor/98.css"; 22 22 @import "themes/webamp/fonts.css"; 23 - @import "themes/webamp/constituent.css"; 23 + @import "themes/webamp/facet.css"; 24 24 </style> 25 25 26 - <script type="module" src="themes/webamp/configurators/input/constituent.js"></script> 26 + <script type="module" src="themes/webamp/configurators/input/facet.js"></script>
+1 -1
src/themes/webamp/configurators/input/constituent.js src/themes/webamp/configurators/input/facet.js
··· 1 - import foundation from "@common/constituents/foundation.js"; 1 + import foundation from "@common/facets/foundation.js"; 2 2 import InputConfigElement from "@themes/webamp/configurators/input/element.js"; 3 3 import { effect } from "@common/signal.js"; 4 4
src/themes/webamp/constituent.css src/themes/webamp/facet.css