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: add source connection status to sources facet

+75 -9
+22
src/facets/data/sources/index.html
··· 53 53 } 54 54 55 55 .sources-item__detail { 56 + align-items: center; 56 57 color: oklch(from var(--text-color) l c h / 0.6); 58 + display: flex; 57 59 font-size: var(--fs-xs); 60 + gap: var(--space-3xs); 58 61 overflow: hidden; 59 62 text-overflow: ellipsis; 60 63 white-space: nowrap; 64 + } 65 + 66 + .sources-item__status { 67 + border-radius: 50%; 68 + flex-shrink: 0; 69 + height: 6px; 70 + width: 6px; 71 + } 72 + 73 + .sources-item__status--online { 74 + background-color: var(--accent); 75 + } 76 + 77 + .sources-item__status--offline { 78 + background-color: var(--accent-twist-4); 79 + } 80 + 81 + .sources-item__status--unknown { 82 + background-color: oklch(from var(--text-color) l c h / 0.2); 61 83 } 62 84 </style> 63 85
+53 -9
src/facets/data/sources/index.inline.js
··· 2 2 3 3 import * as Output from "~/common/output.js"; 4 4 import foundation from "~/common/foundation.js"; 5 - import { effect } from "~/common/signal.js"; 5 + import { effect, signal } from "~/common/signal.js"; 6 6 7 7 import { SCHEME as SCHEME_DROPBOX } from "~/components/input/dropbox/constants.js"; 8 8 import { SCHEME as SCHEME_EPHEMERAL_CACHE } from "~/components/input/ephemeral-cache/constants.js"; ··· 93 93 return q === -1 ? uri : uri.slice(0, q); 94 94 }; 95 95 96 + //////////////////////////////////////////// 97 + // ONLINE STATUS 98 + //////////////////////////////////////////// 99 + 100 + 101 + const onlineMap = signal(/** @type {Record<string, boolean | null>} */ ({})); 102 + 103 + /** @param {{ [scheme: string]: import("~/components/input/types.d.ts").Source[] }} sourcesRecord */ 104 + async function checkOnlineStatus(sourcesRecord) { 105 + const sources = Object.values(sourcesRecord).flat(); 106 + const entries = await Promise.all( 107 + sources.map(async ({ uri }) => { 108 + const result = await inputConfigurator.consult(uri); 109 + const online = 110 + result.supported && result.consult !== "undetermined" 111 + ? result.consult 112 + : null; 113 + return /** @type {[string, boolean | null]} */ ([trackPrefix(uri), online]); 114 + }), 115 + ); 116 + onlineMap.value = Object.fromEntries(entries); 117 + } 118 + 119 + effect(() => { 120 + checkOnlineStatus(sourcesOrchestrator.sources()); 121 + }); 122 + 96 123 effect(() => { 97 124 const sourcesRecord = sourcesOrchestrator.sources(); 125 + const statusMap = onlineMap.get(); 98 126 99 127 const tracksCol = outputOrchestrator.tracks.collection(); 100 128 const tracks = tracksCol.state === "loaded" ? tracksCol.data : []; 101 129 130 + /** @param {string} uri */ 131 + const statusClass = (uri) => { 132 + const status = statusMap[trackPrefix(uri)]; 133 + if (status === true) return "sources-item__status--online"; 134 + if (status === false) return "sources-item__status--offline"; 135 + return "sources-item__status--unknown"; 136 + }; 137 + 138 + /** @param {string} uri */ 139 + const statusTitle = (uri) => { 140 + const status = statusMap[trackPrefix(uri)]; 141 + if (status === true) return "Online"; 142 + if (status === false) return "Offline"; 143 + return "Status unknown"; 144 + }; 145 + 102 146 const entries = Object.entries(sourcesRecord).filter( 103 147 ([, sources]) => sources.length > 0, 104 148 ); ··· 120 164 : ""}"> 121 165 <div class="sources-item__info"> 122 166 <span class="sources-item__name">Files stored in the browser</span> 123 - <span class="sources-item__detail">${trackCount} track${trackCount === 124 - 1 125 - ? "" 126 - : "s"}</span> 167 + <span class="sources-item__detail"> 168 + <span class="sources-item__status ${statusClass(uri)}" title="${statusTitle(uri)}"></span> 169 + ${trackCount} track${trackCount === 1 ? "" : "s"} 170 + </span> 127 171 </div> 128 172 <button 129 173 class="button--plain" ··· 158 202 : ""}"> 159 203 <div class="sources-item__info"> 160 204 <span class="sources-item__name">${label}</span> 161 - <span class="sources-item__detail">${trackCount} track${trackCount === 162 - 1 163 - ? "" 164 - : "s"}</span> 205 + <span class="sources-item__detail"> 206 + <span class="sources-item__status ${statusClass(uri)}" title="${statusTitle(uri)}"></span> 207 + ${trackCount} track${trackCount === 1 ? "" : "s"} 208 + </span> 165 209 </div> 166 210 <button 167 211 class="button--plain button--icon"