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: show where your userdata is coming from on the dashboard

+80 -1
+5
src/_components/grid.vto
··· 4 4 <button class="button--border button--tiny" data-filter="all">All</button> 5 5 <button class="button--border button--tiny button--bg-accent button--tr-accent button--transparent" data-filter="prelude">Features</button> 6 6 <button class="button--border button--tiny button--bg-twist-2 button--tr-twist-2 button--transparent" data-filter="interface">Interfaces</button> 7 + 8 + <div style="flex: 1"></div> 9 + 10 + <span class="grid-filter--label grid-filter--label-output">Userdata from</span> 11 + <span class="grid-filter--output"></span> 7 12 </div> 8 13 9 14 <ul class="grid" style="margin-top: var(--space-xs);">
+25 -1
src/common/pages/dashboard.js
··· 10 10 11 11 import { deleteFacet, saveFacet } from "./crud.js"; 12 12 import { output } from "./output.js"; 13 + import OutputOrchestrator from "@toko/diffuse/components/orchestrator/output/element.js"; 13 14 14 15 // Signals 15 16 const activeFilter = signal("all"); ··· 206 207 } 207 208 208 209 /** 209 - * @param {OutputElement} output 210 + * @param {OutputOrchestrator} output 210 211 * @param {HTMLElement} listEl 211 212 */ 212 213 function _renderList(output, listEl) { ··· 238 239 ); 239 240 }) 240 241 : []; 242 + 243 + const selected = output.selected(); 244 + const outputLabel = selected?.label ?? selected?.getAttribute?.("label") ?? 245 + "Local"; 241 246 242 247 const filterBar = html` 243 248 <div class="grid-filter"> ··· 268 273 > 269 274 Interfaces 270 275 </button> 276 + 277 + <div style="flex: 1"></div> 278 + 279 + <span class="grid-filter--label grid-filter--label-output" 280 + >Userdata from</span> 281 + <span class="grid-filter--output">${outputLabel}</span> 271 282 </div> 272 283 `; 273 284 ··· 363 374 `; 364 375 365 376 render(h, listEl); 377 + 378 + setTimeout(() => { 379 + /** @type {HTMLElement | null} */ 380 + const l = listEl.querySelector(".grid-filter--label-output"); 381 + 382 + /** @type {HTMLElement | null} */ 383 + const o = listEl.querySelector(".grid-filter--output"); 384 + 385 + if (o && l) { 386 + l.style.opacity = "0.4"; 387 + o.style.opacity = "1"; 388 + } 389 + }, 250); 366 390 }
+36
src/common/pages/grid.js
··· 37 37 } 38 38 39 39 //////////////////////////////////////////// 40 + // OUTPUT INDICATOR 41 + //////////////////////////////////////////// 42 + 43 + /** @type {() => void | undefined} */ 44 + let stopOutputIndicator; 45 + 46 + export async function setupOutputIndicator() { 47 + if (stopOutputIndicator) stopOutputIndicator(); 48 + 49 + const filterEl = document.querySelector(".grid-filter"); 50 + if (!filterEl) return; 51 + 52 + const out = await output(); 53 + 54 + /** @type {HTMLElement | null} */ 55 + const indicator = filterEl.querySelector(".grid-filter--output"); 56 + if (!indicator) return; 57 + 58 + /** @type {HTMLElement | null} */ 59 + const label = filterEl.querySelector(".grid-filter--label-output"); 60 + if (!label) return; 61 + 62 + setTimeout(() => { 63 + indicator.style.opacity = "1"; 64 + label.style.opacity = "0.4"; 65 + }, 250); 66 + 67 + stopOutputIndicator = effect(() => { 68 + const selected = out.selected(); 69 + const label = selected?.label ?? selected?.getAttribute?.("label") ?? 70 + "Local"; 71 + indicator.textContent = label; 72 + }); 73 + } 74 + 75 + //////////////////////////////////////////// 40 76 // TOGGLE BUTTONS 41 77 //////////////////////////////////////////// 42 78
+1
src/common/pages/ppr.js
··· 33 33 Grid.setupFilter(); 34 34 Grid.insertToggleButtons(); 35 35 await Grid.monitorToggleButtonStates(); 36 + await Grid.setupOutputIndicator(); 36 37 37 38 switch (path) { 38 39 case "/build":
+1
src/facets/connect/atproto/index.inline.js
··· 219 219 } 220 220 221 221 async function disconnect() { 222 + await outputOrchestrator.deselect(); 222 223 await atprotoEl?.logout(); 223 224 } 224 225
+1
src/facets/connect/s3/index.inline.js
··· 184 184 } 185 185 186 186 if (isOutput) { 187 + await outputOrchestrator.deselect(); 187 188 await s3El?.unsetBucket(); 188 189 } 189 190 } catch (err) {
+11
src/styles/diffuse/page.css
··· 350 350 margin-right: var(--space-2xs); 351 351 opacity: 0.4; 352 352 } 353 + 354 + .grid-filter--output { 355 + font-size: var(--fs-xs); 356 + font-weight: 700; 357 + } 358 + 359 + .grid-filter--label-output, 360 + .grid-filter--output { 361 + opacity: 0; 362 + transition: opacity 250ms; 363 + } 353 364 } 354 365 355 366 /**