a simple web player for subsonic tinysub.devins.page
subsonic navidrome javascript
9
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: reorganize icons

also remove image wrappers, not needed

+66 -83
+3 -12
src/css/components.css
··· 120 120 opacity: 0.5; 121 121 } 122 122 123 - #sidebar #library .tree-cover { 123 + #sidebar #library .tree-toggle img, 124 + #sidebar #library .tree-name img { 124 125 width: var(--art-artist); 125 126 height: var(--art-artist); 126 - flex-shrink: 0; 127 - } 128 - 129 - #sidebar #library .tree-cover img { 130 - width: 100%; 131 - height: 100%; 132 127 aspect-ratio: 1 / 1; 133 128 object-fit: cover; 129 + flex-shrink: 0; 134 130 } 135 131 136 132 #sidebar #library ul.nested > li .tree-toggle img, 137 133 #sidebar #library ul.nested > li .tree-name img { 138 - width: var(--art-album); 139 - height: var(--art-album); 140 - } 141 - 142 - #sidebar #library ul.nested > li .tree-cover { 143 134 width: var(--art-album); 144 135 height: var(--art-album); 145 136 }
+22 -24
src/index.html
··· 13 13 <!-- icons cache --> 14 14 <!-- this serves as a lookup table for the build process, which inlines the imgs into a single html --> 15 15 <div id="icon-cache" style="display: none"> 16 - <img id="icon-play" src="static/famfamfam-silk/control_play_blue.png" /> 17 - <img id="icon-pause" src="static/famfamfam-silk/control_pause_blue.png" /> 16 + <img id="icon-add" src="static/famfamfam-silk/add.png" /> 17 + <img id="icon-arrow_down" src="static/famfamfam-silk/arrow_down.png" /> 18 + <img id="icon-arrow_up" src="static/famfamfam-silk/arrow_up.png" /> 19 + <img id="icon-cd" src="static/famfamfam-silk/cd.png" /> 20 + <img 21 + id="icon-control_fastforward" 22 + src="static/famfamfam-silk/control_fastforward.png" 23 + /> 24 + <img 25 + id="icon-control_pause" 26 + src="static/famfamfam-silk/control_pause.png" 27 + /> 18 28 <img 19 - id="icon-play-next" 20 - src="static/famfamfam-silk/control_fastforward_blue.png" 29 + id="icon-control_play" 30 + src="static/famfamfam-silk/control_play.png" 21 31 /> 22 - <img id="icon-add" src="static/famfamfam-silk/add.png" /> 23 - <img id="icon-favorite" src="static/famfamfam-silk/heart.png" /> 24 - <img id="icon-move-up" src="static/famfamfam-silk/arrow_up.png" /> 25 - <img id="icon-move-down" src="static/famfamfam-silk/arrow_down.png" /> 26 - <img id="icon-remove" src="static/famfamfam-silk/cross.png" /> 32 + <img id="icon-cross" src="static/famfamfam-silk/cross.png" /> 33 + <img id="icon-heart" src="static/famfamfam-silk/heart.png" /> 34 + <img id="icon-star" src="static/famfamfam-silk/star.png" /> 27 35 <img id="icon-tinysub" src="static/tinysub.svg" /> 36 + <img id="icon-user" src="static/famfamfam-silk/user.png" /> 28 37 </div> 29 38 <!-- auth modal --> 30 39 <div id="auth-modal" class="modal hidden"> ··· 193 202 <header id="playback"> 194 203 <audio id="player" crossorigin="anonymous"></audio> 195 204 <button id="prev-btn" aria-label="previous"> 196 - <img 197 - src="static/famfamfam-silk/control_rewind_blue.png" 198 - alt="previous" 199 - /> 205 + <img src="static/famfamfam-silk/control_rewind.png" alt="previous" /> 200 206 </button> 201 207 <button id="play-btn" aria-label="play"> 202 - <img src="static/famfamfam-silk/control_play_blue.png" alt="play" /> 208 + <img src="static/famfamfam-silk/control_play.png" alt="play" /> 203 209 </button> 204 210 <button id="next-btn" aria-label="next"> 205 - <img 206 - src="static/famfamfam-silk/control_fastforward_blue.png" 207 - alt="next" 208 - /> 211 + <img src="static/famfamfam-silk/control_fastforward.png" alt="next" /> 209 212 </button> 210 213 <button id="loop-btn" aria-label="loop"> 211 214 <img src="static/famfamfam-silk/control_repeat.png" alt="loop" /> ··· 226 229 <div id="playlists-tree"></div> 227 230 </div> 228 231 <div id="now-playing"> 229 - <img 230 - id="cover-art" 231 - src="static/tinysub.svg" 232 - alt="cover" 233 - loading="lazy" 234 - /> 232 + <img id="cover-art" src="static/tinysub.svg" alt="cover" /> 235 233 <div id="track-info"> 236 234 <div id="track-title">no track playing</div> 237 235 <div id="track-artist"></div>
+1
src/js/auth.js
··· 75 75 // clear all storage and reload to logout 76 76 async function handleLogout() { 77 77 try { 78 + await imageCache.clear(); 78 79 if (indexedDB.databases) { 79 80 const dbs = await indexedDB.databases(); 80 81 for (const db of dbs) {
+26 -19
src/js/constants.js
··· 59 59 }; 60 60 61 61 const ICONS = { 62 - PLAY: 63 - document.getElementById("icon-play")?.src || 64 - "static/famfamfam-silk/control_play_blue.png", 65 - PAUSE: 66 - document.getElementById("icon-pause")?.src || 67 - "static/famfamfam-silk/control_pause_blue.png", 68 - PLAY_NEXT: 69 - document.getElementById("icon-play-next")?.src || 70 - "static/famfamfam-silk/control_fastforward_blue.png", 71 62 ADD: 72 63 document.getElementById("icon-add")?.src || "static/famfamfam-silk/add.png", 73 - FAVORITE: 74 - document.getElementById("icon-favorite")?.src || 75 - "static/famfamfam-silk/heart.png", 76 - MOVE_UP: 77 - document.getElementById("icon-move-up")?.src || 64 + ARROW_DOWN: 65 + document.getElementById("icon-arrow_down")?.src || 66 + "static/famfamfam-silk/arrow_down.png", 67 + ARROW_UP: 68 + document.getElementById("icon-arrow_up")?.src || 78 69 "static/famfamfam-silk/arrow_up.png", 79 - MOVE_DOWN: 80 - document.getElementById("icon-move-down")?.src || 81 - "static/famfamfam-silk/arrow_down.png", 82 - REMOVE: 83 - document.getElementById("icon-remove")?.src || 70 + CD: document.getElementById("icon-cd")?.src || "static/famfamfam-silk/cd.png", 71 + CONTROL_FASTFORWARD: 72 + document.getElementById("icon-control_fastforward")?.src || 73 + "static/famfamfam-silk/control_fastforward.png", 74 + CONTROL_PAUSE: 75 + document.getElementById("icon-control_pause")?.src || 76 + "static/famfamfam-silk/control_pause.png", 77 + CONTROL_PLAY: 78 + document.getElementById("icon-control_play")?.src || 79 + "static/famfamfam-silk/control_play.png", 80 + CROSS: 81 + document.getElementById("icon-cross")?.src || 84 82 "static/famfamfam-silk/cross.png", 83 + HEART: 84 + document.getElementById("icon-heart")?.src || 85 + "static/famfamfam-silk/heart.png", 86 + STAR: 87 + document.getElementById("icon-star")?.src || 88 + "static/famfamfam-silk/star.png", 85 89 TINYSUB: document.getElementById("icon-tinysub")?.src || "static/tinysub.svg", 90 + USER: 91 + document.getElementById("icon-user")?.src || 92 + "static/famfamfam-silk/user.png", 86 93 };
+4 -16
src/js/library.js
··· 222 222 223 223 const linkChildren = []; 224 224 if (coverArtId) { 225 - const imgEl = createElement("img", { 226 - attributes: { 227 - alt: "cover", 228 - loading: "lazy", 229 - }, 230 - }); 225 + const imgEl = createElement("img"); 231 226 loadCachedImage(imgEl, coverArtId, artType); 232 - const wrapper = createElement("div", { 233 - className: "tree-cover", 234 - children: [imgEl], 235 - }); 236 - linkChildren.push(wrapper); 227 + linkChildren.push(imgEl); 237 228 } 238 229 linkChildren.push(createElement("span", { textContent: name })); 239 230 ··· 250 241 251 242 div.appendChild(linkEl); 252 243 if (onAdd) 253 - div.appendChild( 254 - createIconButton("tree-action", "add", ICONS.ADD, "add", onAdd), 255 - ); 244 + div.appendChild(createIconButton("tree-action", "add", ICONS.ADD, onAdd)); 256 245 if (onAddNext) 257 246 div.appendChild( 258 247 createIconButton( 259 248 "tree-action", 260 249 "add next", 261 - ICONS.PLAY_NEXT, 262 - "add next", 250 + ICONS.CONTROL_FASTFORWARD, 263 251 onAddNext, 264 252 ), 265 253 );
+1 -1
src/js/player.js
··· 57 57 // update play button icon based on playback state 58 58 const updatePlayIcon = () => { 59 59 const isPaused = ui.player.paused; 60 - const iconPath = isPaused ? ICONS.PLAY : ICONS.PAUSE; 60 + const iconPath = isPaused ? ICONS.CONTROL_PLAY : ICONS.CONTROL_PAUSE; 61 61 const label = isPaused ? "play" : "pause"; 62 62 ui.playBtn.innerHTML = `<img src="${iconPath}" alt="${label}" />`; 63 63 if (ui.player.src) {
+7 -7
src/js/queue.js
··· 362 362 { 363 363 className: CLASSES.QUEUE_PLAY, 364 364 label: "play", 365 - icon: ICONS.PLAY, 365 + icon: ICONS.CONTROL_PLAY, 366 366 }, 367 367 { 368 368 className: CLASSES.QUEUE_PLAY_NEXT, 369 369 label: "play next", 370 - icon: ICONS.PLAY_NEXT, 370 + icon: ICONS.CONTROL_FASTFORWARD, 371 371 }, 372 372 { 373 373 className: CLASSES.QUEUE_FAVORITE, 374 374 label: "favorite", 375 - icon: ICONS.FAVORITE, 375 + icon: ICONS.HEART, 376 376 }, 377 377 { 378 378 className: CLASSES.QUEUE_MOVE_UP, 379 379 label: "move up", 380 - icon: ICONS.MOVE_UP, 380 + icon: ICONS.ARROW_UP, 381 381 }, 382 382 { 383 383 className: CLASSES.QUEUE_MOVE_DOWN, 384 384 label: "move down", 385 - icon: ICONS.MOVE_DOWN, 385 + icon: ICONS.ARROW_DOWN, 386 386 }, 387 387 { 388 388 className: CLASSES.QUEUE_CLEAR, 389 389 label: "clear", 390 - icon: ICONS.REMOVE, 390 + icon: ICONS.CROSS, 391 391 }, 392 392 ]; 393 393 ··· 434 434 const actionsCell = document.createElement("td"); 435 435 const isFavorited = state.favorites.has(song.id); 436 436 ROW_BUTTON_CONFIG.forEach(({ className, label, icon }) => { 437 - const btn = createIconButton(className, label, icon, label); 437 + const btn = createIconButton(className, label, icon); 438 438 if (className === CLASSES.QUEUE_FAVORITE && isFavorited) { 439 439 btn.classList.add(CLASSES.FAVORITED); 440 440 }
+2 -4
src/js/ui.js
··· 25 25 } 26 26 27 27 // create a button with icon 28 - function createIconButton(className, ariaLabel, iconPath, iconAlt, onCallback) { 28 + function createIconButton(className, ariaLabel, iconPath, onCallback) { 29 29 const btn = createElement("button", { 30 30 className, 31 31 attributes: { "aria-label": ariaLabel }, 32 - children: [ 33 - createElement("img", { attributes: { src: iconPath, alt: iconAlt } }), 34 - ], 32 + children: [createElement("img", { attributes: { src: iconPath } })], 35 33 }); 36 34 37 35 if (onCallback) {