A music player that connects to your cloud/distributed storage.

chore: dashboard nav loading anim

+42 -9
+9 -9
src/_components/nav.vto
··· 4 4 <div class="nav-container"> 5 5 <nav id="diffuse-nav"> 6 6 <a href="dashboard/" class="button {{ colorClass("dashboard/") }} button--border"> 7 - <span class="with-icon"> 7 + <span> 8 8 <i class="ph-fill ph-person"></i> 9 9 Your Diffuse 10 10 </span> 11 11 </a> 12 12 13 13 <a href="guide/" class="button {{ colorClass("guide/") }} button--border"> 14 - <span class="with-icon"> 14 + <span> 15 15 <i class="ph-fill ph-book-open-text"></i> 16 16 Guide 17 17 </span> 18 18 </a> 19 19 20 20 <a href="featured/" class="button {{ colorClass("featured/") }} button--border"> 21 - <span class="with-icon"> 21 + <span> 22 22 <i class="ph-fill ph-sparkle"></i> 23 23 Featured 24 24 </span> 25 25 </a> 26 26 27 27 <a href="build/" class="button {{ colorClass("build/") }} button--border"> 28 - <span class="with-icon"> 28 + <span> 29 29 <i class="ph-fill ph-hammer"></i> 30 30 Build 31 31 </span> ··· 34 34 <div class="divider"></div> 35 35 36 36 <a href="data/" class="button {{ colorClass("data/") }} button--border"> 37 - Input & Output 37 + <span>Input & Output</span> 38 38 </a> 39 39 40 40 <a href="playback/" class="button {{ colorClass("playback/") }} button--border"> 41 - Playback 41 + <span>Playback</span> 42 42 </a> 43 43 44 44 <a href="browsing/" class="button {{ colorClass("browsing/") }} button--border"> 45 - Browsing 45 + <span>Browsing</span> 46 46 </a> 47 47 48 48 <a href="themes/" class="button {{ colorClass("themes/") }} button--border"> 49 - Themes 49 + <span>Themes</span> 50 50 </a> 51 51 52 52 <a href="misc/" class="button {{ colorClass("misc/") }} button--border"> 53 - <span class="with-icon"> 53 + <span> 54 54 <i class="ph-fill ph-treasure-chest"></i> 55 55 </span> 56 56 </a>
+33
src/common/pages/ppr.js
··· 86 86 event.intercept({ 87 87 scroll: "manual", 88 88 async handler() { 89 + const navLinks = /** @type {HTMLAnchorElement[]} */ ([ 90 + ...document.querySelectorAll("#diffuse-nav a, #nav-overflow-menu a"), 91 + ]); 92 + const stripSlash = (/** @type {string} */ p) => p.replace(/^\//, ""); 93 + const navLink = navLinks.find( 94 + (a) => 95 + stripSlash(new URL(a.href).pathname) === stripSlash(url.pathname), 96 + ); 97 + 98 + const icon = navLink?.querySelector("i"); 99 + const originalIconClass = icon?.className; 100 + let addedSpinner = /** @type {HTMLElement | undefined} */ (undefined); 101 + 102 + const loadingTimer = navLink 103 + ? setTimeout(() => { 104 + if (icon) { 105 + icon.className = "ph-bold ph-spinner animate-spin"; 106 + } else { 107 + addedSpinner = document.createElement("i"); 108 + addedSpinner.className = "ph-bold ph-spinner animate-spin"; 109 + const span = navLink.querySelector("span"); 110 + (span ?? navLink).prepend(addedSpinner); 111 + } 112 + }, 250) 113 + : undefined; 114 + 89 115 let html; 90 116 91 117 try { ··· 93 119 if (!response.ok) throw new Error(`${response.status}`); 94 120 html = await response.text(); 95 121 } catch { 122 + clearTimeout(loadingTimer); 123 + if (icon && originalIconClass !== undefined) icon.className = originalIconClass; 124 + addedSpinner?.remove(); 96 125 location.href = url.href; 97 126 return; 127 + } finally { 128 + clearTimeout(loadingTimer); 129 + if (icon && originalIconClass !== undefined) icon.className = originalIconClass; 130 + addedSpinner?.remove(); 98 131 } 99 132 100 133 const parser = new DOMParser();