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.

chore: webamp output configurator overview messages

+174 -70
+8 -2
src/components/configurator/output/element.js
··· 4 4 /** 5 5 * @import {Facet, Playlist, Theme, Track} from "@definitions/types.d.ts" 6 6 * @import {OutputManagerDeputy, OutputElement} from "@components/output/types.d.ts" 7 + * 8 + * @import {OutputConfiguratorElement} from "./types.d.ts" 7 9 */ 8 10 9 11 /** ··· 17 19 //////////////////////////////////////////// 18 20 19 21 /** 20 - * @implements {OutputElement} 22 + * @implements {OutputConfiguratorElement} 21 23 */ 22 24 class OutputConfigurator extends DiffuseElement { 23 25 static NAME = "diffuse/configurator/output"; ··· 207 209 208 210 #setupFinished = signal(false); 209 211 212 + // STATE 213 + 214 + selectedOutput = computed(() => this.#selectedOutput.value ?? null); 215 + 210 216 // LIFECYCLE 211 217 212 218 /** ··· 298 304 return { 299 305 id: k, 300 306 label: v.label, 301 - element: v, 307 + element: /** @type {OutputElement} */ (v), 302 308 }; 303 309 }); 304 310 }
+15
src/components/configurator/output/types.d.ts
··· 1 + import type { OutputElement } from "@components/output/types.d.ts"; 2 + import type { SignalReader } from "@common/signal.d.ts"; 3 + 4 + export type OutputConfiguratorElement = OutputElement & { 5 + deselect: () => Promise<void>; 6 + options: () => Promise< 7 + Array<{ 8 + id: string; 9 + label: string; 10 + element: OutputElement; 11 + }> 12 + >; 13 + select: (id: string) => Promise<void>; 14 + selectedOutput: SignalReader<OutputElement | null>; 15 + };
+32
src/components/orchestrator/output/element.js
··· 12 12 /** 13 13 * @import {RenderArg} from "@common/element.d.ts" 14 14 * @import {OutputElement} from "@components/output/types.d.ts" 15 + * @import {OutputConfiguratorElement} from "@components/configurator/output/types.d.ts" 15 16 */ 16 17 17 18 //////////////////////////////////////////// ··· 20 21 21 22 /** 22 23 * A default setup for managing output. 24 + * 25 + * @implements {OutputConfiguratorElement} 23 26 */ 24 27 class OutputOrchestrator extends DiffuseElement { 25 28 static NAME = "diffuse/orchestrator/output"; ··· 35 38 return output; 36 39 } 37 40 41 + /** 42 + * @returns {OutputConfiguratorElement} 43 + */ 44 + get outputConfigurator() { 45 + /** @type {OutputConfiguratorElement | null} */ 46 + const outputConfigurator = this.root().querySelector("#do-output__dc-output"); 47 + 48 + if (!outputConfigurator) throw new Error("Output orchestrator did not render yet."); 49 + return outputConfigurator; 50 + } 51 + 38 52 // PROXY OUTPUT ACTIONS 39 53 40 54 get facets() { ··· 51 65 52 66 get tracks() { 53 67 return this.output.tracks; 68 + } 69 + 70 + // PROXY ADDITIONAL OUTPUT CONFIGURATOR ACTIONS 71 + 72 + get deselect() { 73 + return this.outputConfigurator.deselect 74 + } 75 + 76 + get options() { 77 + return this.outputConfigurator.options 78 + } 79 + 80 + get select() { 81 + return this.outputConfigurator.select 82 + } 83 + 84 + get selectedOutput() { 85 + return this.outputConfigurator.selectedOutput 54 86 } 55 87 56 88 // RENDER
+114 -68
src/themes/webamp/configurators/output/element.js
··· 1 - import { DiffuseElement } from "@common/element.js"; 1 + import { DiffuseElement, query } from "@common/element.js"; 2 2 import { signal } from "@common/signal.js"; 3 + import { NAME as ATPROTO_NAME } from "@components/output/raw/atproto/element.js"; 3 4 4 5 /** 5 - * @import {RenderArg} from "@common/element.d.ts" 6 6 * @import {ATProtoOutputElement} from "@components/output/raw/atproto/types.d.ts" 7 + * @import {OutputElement} from "@components/output/types.d.ts" 8 + * @import {OutputConfiguratorElement} from "@components/configurator/output/element.js" 9 + * @import {RenderArg} from "@common/element.d.ts" 7 10 */ 8 11 9 12 class OutputConfig extends DiffuseElement { ··· 14 17 15 18 // SIGNALS 16 19 17 - #atproto = signal(/** @type {ATProtoOutputElement | null} */ (null)); 20 + $output = signal( 21 + /** @type {OutputElement | OutputConfiguratorElement | undefined} */ (undefined), 22 + ); 23 + 24 + $atproto = signal(/** @type {ATProtoOutputElement | null} */ (null)); 18 25 19 26 // LIFECYCLE 20 27 ··· 22 29 async connectedCallback() { 23 30 super.connectedCallback(); 24 31 25 - await customElements.whenDefined("dor-atproto"); 32 + /** @type {OutputElement} */ 33 + const output = query(this, "output-selector"); 26 34 27 - // TODO: Remove? 28 - // The dor-atproto element is rendered by the do-output orchestrator, 29 - // which may connect after this element. Wait for it to appear. 30 - // await new Promise((resolve) => requestAnimationFrame(resolve)); 35 + await customElements.whenDefined(output.localName); 36 + 37 + this.$output.value = output; 38 + 39 + // Try setting up ATProto output 40 + await customElements.whenDefined(ATPROTO_NAME); 31 41 32 42 /** @type {ATProtoOutputElement | null} */ 33 - const atproto = document.querySelector("dor-atproto"); 34 - if (atproto) this.#atproto.value = atproto; 43 + const atproto = output.querySelector(ATPROTO_NAME); 44 + if (atproto) this.$atproto.value = atproto; 35 45 } 36 46 37 47 // EVENTS ··· 45 55 const handle = input?.value?.trim(); 46 56 if (!handle) return; 47 57 48 - const atproto = this.#atproto.value; 58 + const atproto = this.$atproto.value; 49 59 if (!atproto) return; 50 60 51 61 /** @type {HTMLButtonElement | null} */ ··· 56 66 }; 57 67 58 68 #handleAtprotoLogout = async () => { 59 - const atproto = this.#atproto.value; 69 + const atproto = this.$atproto.value; 60 70 if (!atproto) return; 61 71 62 72 await atproto.logout(); ··· 68 78 * @param {RenderArg} _ 69 79 */ 70 80 render({ html }) { 71 - const did = this.#atproto.value?.did() ?? null; 81 + const did = this.$atproto.value?.did() ?? null; 82 + const selectedOutput = this.$output.value?.selectedOutput(); 72 83 73 84 return html` 74 85 <link rel="stylesheet" href="styles/vendor/98.css" /> ··· 156 167 /> 157 168 <span>Here you can configure where to keep your user data.<br />Each 158 169 storage method comes with its pros and cons.<br />By default your 159 - data is only kept locally here in the browser.</span> 170 + data is only kept locally here in the browser. 171 + </span> 172 + </span> 173 + </fieldset> 174 + 175 + <fieldset style="margin-top: var(--grouped-element-spacing);"> 176 + <span class="with-icon with-icon--large"> 177 + <img 178 + src="images/icons/windows_98/msg_information-0.png" 179 + width="24" 180 + /> 181 + <span> 182 + Data does not transfer across storage methods!<br />You can however 183 + merge data between them though, if you wish to do so. 184 + </span> 185 + </span> 186 + </fieldset> 187 + 188 + <fieldset style="margin-top: var(--grouped-element-spacing);"> 189 + <legend>Active storage method</legend> 190 + <span class="with-icon with-icon--large"> 191 + <img 192 + src="images/icons/windows_98/msg_warning-0.png" 193 + width="24" 194 + /> 195 + <span> 196 + ${ 197 + this.$output.value && "selectedOutput" in this.$output.value 198 + ? selectedOutput 199 + ? `Selected output: ${selectedOutput.name}` 200 + : this.#defaultOutputMessage 201 + : this.#defaultOutputMessage 202 + } 160 203 </span> 161 - </fieldset> 162 - </div> 204 + </span> 205 + </fieldset> 206 + </div> 163 207 164 - <!-- AT Protocol --> 165 - <div class="window-body" id="atproto-contents"> 166 - ${did 167 - ? html` 168 - <fieldset> 169 - <span class="with-icon with-icon--large"> 170 - <img src="images/icons/windows_98/computer_user_pencil-0.png" width="24" /> 171 - <span>Signed in as <strong>${did}</strong></span> 208 + <!-- AT Protocol --> 209 + <div class="window-body" id="atproto-contents"> 210 + ${did 211 + ? html` 212 + <fieldset> 213 + <span class="with-icon with-icon--large"> 214 + <img src="images/icons/windows_98/computer_user_pencil-0.png" width="24" /> 215 + <span>Signed in as <strong>${did}</strong></span> 216 + </span> 217 + </fieldset> 218 + 219 + <p> 220 + <button @click="${this 221 + .#handleAtprotoLogout}">Sign out</button> 222 + </p> 223 + ` 224 + : html` 225 + <fieldset> 226 + <span class="with-icon with-icon--large"> 227 + <img src="images/icons/windows_98/computer_user_pencil-0.png" width="24" /> 228 + <span>Store your user data on the storage associated with your AT Protocol 229 + identity. WORK IN PROGRESS!</span> 172 230 </span> 173 231 </fieldset> 174 232 175 - <p> 176 - <button @click="${this 177 - .#handleAtprotoLogout}">Sign out</button> 178 - </p> 179 - ` 180 - : html` 181 - <fieldset> 182 - <span class="with-icon with-icon--large"> 183 - <img src="images/icons/windows_98/computer_user_pencil-0.png" width="24" /> 184 - <span>Store your user data on the storage associated with your AT Protocol 185 - identity. WORK IN PROGRESS!</span> 186 - </span> 233 + <form @submit="${this.#handleAtprotoLogin}"> 234 + <fieldset> 235 + <div class="field-row"> 236 + <label for="atproto-handle">Your internet handle:</label> 237 + <input 238 + id="atproto-handle" 239 + type="text" 240 + required 241 + placeholder="you.bsky.social" 242 + /> 243 + </div> 187 244 </fieldset> 188 245 189 - <form @submit="${this.#handleAtprotoLogin}"> 190 - <fieldset> 191 - <div class="field-row"> 192 - <label for="atproto-handle">Your internet handle:</label> 193 - <input 194 - id="atproto-handle" 195 - type="text" 196 - required 197 - placeholder="you.bsky.social" 198 - /> 199 - </div> 200 - </fieldset> 246 + <p> 247 + <button type="submit" id="atproto-submit">Sign in</button> 248 + </p> 249 + </form> 250 + `} 251 + </div> 201 252 202 - <p> 203 - <button type="submit" id="atproto-submit">Sign in</button> 204 - </p> 205 - </form> 206 - `} 207 - </div> 208 - 209 - <!-- S3 --> 210 - <div class="window-body" id="s3-contents"> 211 - <p>TODO</p> 212 - </div> 253 + <!-- S3 --> 254 + <div class="window-body" id="s3-contents"> 255 + <p>TODO</p> 213 256 </div> 214 257 </div> 215 - `; 216 - } 258 + </div> 259 + `; 217 260 } 218 261 219 - export default OutputConfig; 262 + #defaultOutputMessage = "Storing data locally in the browser without any backup or syncing enabled." 263 + } 220 264 221 - //////////////////////////////////////////// 222 - // REGISTER 223 - //////////////////////////////////////////// 265 + export default OutputConfig; 224 266 225 - export const CLASS = OutputConfig; 226 - export const NAME = "dtw-output-config"; 267 + //////////////////////////////////////////// 268 + // REGISTER 269 + //////////////////////////////////////////// 270 + 271 + export const CLASS = OutputConfig; 272 + export const NAME = "dtw-output-config"; 227 273 228 - customElements.define(NAME, CLASS); 274 + customElements.define(NAME, CLASS);
+5
src/themes/webamp/facet.css
··· 1 1 @import "../../styles/variables.css"; 2 + @import "./98-vars.css"; 2 3 3 4 body { 4 5 background: #3a6ea5; 5 6 margin: 0; 7 + } 8 + 9 + p { 10 + margin: var(--grouped-element-spacing) 0; 6 11 } 7 12 8 13 #container {