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.

feat: better browser sorting + direction

+55 -42
+3 -1
src/components/orchestrator/scoped-tracks/element.js
··· 188 188 const tracks = this.#tracksSearch.value; 189 189 const playlistItems = this.#selectedPlaylistItems(); 190 190 const sortBy = this.#scope.value?.sortBy(); 191 + const sortDirection = this.#scope.value?.sortDirection(); 191 192 192 193 if ((await this.isLeader()) === false) return; 193 194 ··· 196 197 : tracks; 197 198 198 199 if (sortBy?.length) { 200 + const dir = sortDirection === "desc" ? -1 : 1; 199 201 final = [...final].sort((a, b) => { 200 202 for (const field of sortBy) { 201 203 let aVal = /** @type {any} */ (a); ··· 214 216 ? aVal.localeCompare(bVal) 215 217 : aVal < bVal ? -1 : aVal > bVal ? 1 : 0; 216 218 217 - if (cmp !== 0) return cmp; 219 + if (cmp !== 0) return cmp * dir; 218 220 } 219 221 220 222 return 0;
+52 -41
src/themes/webamp/browser/element.js
··· 16 16 const ROW_HEIGHT = 14; 17 17 const OVERSCAN = 20; 18 18 19 - const SORT_OPTIONS = [ 20 - { label: "Default", value: [] }, 21 - { label: "Added to collection", value: ["createdAt"] }, 22 - { label: "Title", value: ["tags.title"] }, 23 - { label: "Album", value: ["tags.album", "tags.disc.no", "tags.track.no"] }, 24 - { 25 - label: "Artist", 26 - value: ["tags.artist", "tags.album", "tags.disc.no", "tags.track.no"], 27 - }, 28 - { label: "Year", value: ["tags.year"] }, 29 - { label: "Date", value: ["tags.date"] }, 30 - ]; 19 + /** @type {Record<string, string[]>} */ 20 + const COLUMN_SORT = { 21 + title: ["tags.title"], 22 + artist: ["tags.artist", "tags.album", "tags.disc.no", "tags.track.no"], 23 + album: ["tags.album", "tags.disc.no", "tags.track.no"], 24 + }; 31 25 32 26 class Browser extends DiffuseElement { 33 27 constructor() { ··· 138 132 /** @type {HTMLSelectElement} */ (select).value = playlist ?? ""; 139 133 } 140 134 }); 141 - 142 - this.effect(() => { 143 - const sortBy = this.$scope.value?.sortBy(); 144 - const select = this.root().querySelector("#sort-by-select"); 145 - 146 - if (select) { 147 - /** @type {HTMLSelectElement} */ (select).value = JSON.stringify( 148 - sortBy ?? [], 149 - ); 150 - } 151 - }); 152 135 } 153 136 154 137 /** ··· 245 228 }; 246 229 247 230 /** 248 - * @param {Event} event 231 + * @param {string} column 249 232 */ 250 - setSortBy = (event) => { 251 - const value = /** @type {HTMLSelectElement} */ (event.currentTarget).value; 233 + sortByColumn = (column) => { 234 + const scope = this.$scope.value; 235 + if (!scope) return; 252 236 253 - this.$scope.value?.setSortBy(JSON.parse(value)); 237 + const isActive = JSON.stringify(COLUMN_SORT[column]) === 238 + JSON.stringify(scope.sortBy()); 239 + 240 + if (isActive) { 241 + scope.setSortDirection( 242 + scope.sortDirection() === "desc" ? undefined : "desc", 243 + ); 244 + } else { 245 + scope.setSortBy(COLUMN_SORT[column] ?? []); 246 + scope.setSortDirection(undefined); 247 + } 254 248 }; 255 249 256 250 // RENDER ··· 264 258 const tracks = this.$provider.value?.tracks() ?? []; 265 259 const playlist = this.$scope.value?.playlist(); 266 260 const searchTerm = this.$scope.value?.searchTerm() ?? ""; 267 - const sortByJson = JSON.stringify(this.$scope.value?.sortBy() ?? []); 261 + const sortBy = this.$scope.value?.sortBy() ?? []; 262 + const sortDirection = this.$scope.value?.sortDirection(); 263 + const sortedColumn = Object.entries(COLUMN_SORT).find( 264 + ([, v]) => JSON.stringify(v) === JSON.stringify(sortBy), 265 + )?.[0]; 266 + const ariaSort = /** @param {string} col */ (col) => 267 + sortedColumn === col 268 + ? (sortDirection === "desc" ? "descending" : "ascending") 269 + : "none"; 268 270 269 271 // Virtual list 270 272 const totalTracks = tracks.length; ··· 334 336 } 335 337 336 338 table th { 339 + cursor: pointer; 340 + user-select: none; 337 341 width: 30%; 338 342 339 343 &:first-child { 340 344 width: 40%; 341 345 } 346 + } 347 + 348 + table th[aria-sort="ascending"]::after { 349 + content: " ▲"; 350 + } 351 + 352 + table th[aria-sort="descending"]::after { 353 + content: " ▼"; 342 354 } 343 355 344 356 .virtual-scroll table { ··· 385 397 ` 386 398 )} 387 399 </select> 388 - <label for="sort-by-select">Sort by:</label> 389 - <select id="sort-by-select" @change="${this.setSortBy}"> 390 - ${SORT_OPTIONS.map((opt) => { 391 - const json = JSON.stringify(opt.value); 392 - return html` 393 - <option value="${json}" ?selected="${sortByJson === json}">${opt 394 - .label}</option> 395 - `; 396 - })} 397 - </select> 398 400 </search> 399 401 400 402 <div class="sunken-panel"> 401 403 <table class="virtual-header"> 402 404 <thead> 403 405 <tr> 404 - <th>Title</th> 405 - <th>Artist</th> 406 - <th>Album</th> 406 + <th 407 + aria-sort="${ariaSort(`title`)}" 408 + @click="${() => this.sortByColumn(`title`)}" 409 + >Title</th> 410 + <th 411 + aria-sort="${ariaSort(`artist`)}" 412 + @click="${() => this.sortByColumn(`artist`)}" 413 + >Artist</th> 414 + <th 415 + aria-sort="${ariaSort(`album`)}" 416 + @click="${() => this.sortByColumn(`album`)}" 417 + >Album</th> 407 418 </tr> 408 419 </thead> 409 420 </table>