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.

at a0924e204985facf3a9eb44f5f0f8a4e53e1ee83 98 lines 3.6 kB view raw
1/** 2 * Updates the active state of nav links based on the current URL. 3 * Required because the nav now lives in <header> and is not replaced by PPR. 4 */ 5export function updateActiveLinks() { 6 const nav = document.getElementById("diffuse-nav"); 7 const menu = document.getElementById("nav-overflow-menu"); 8 9 for (const container of [nav, menu]) { 10 if (!container) continue; 11 for (const link of container.querySelectorAll("a[href]")) { 12 const a = /** @type {HTMLAnchorElement} */ (link); 13 const isActive = new URL(a.href).pathname === location.pathname; 14 a.classList.toggle("button--transparent", !isActive); 15 } 16 } 17} 18 19export function update() { 20 const nav = document.getElementById("diffuse-nav"); 21 const btn = document.getElementById("nav-overflow-btn"); 22 const menu = document.getElementById("nav-overflow-menu"); 23 24 if (!nav || !btn || !menu) return; 25 26 const items = /** @type {HTMLElement[]} */ ([...nav.children]); 27 28 // Reset: show all items, hide button, restore default icon 29 for (const item of items) item.style.display = ""; 30 btn.style.display = "none"; 31 const span = btn.querySelector("span"); 32 if (span) span.innerHTML = `<i class="ph-fill ph-dots-three-outline"></i>`; 33 34 // Available width is the nav-container's width (nav may be content-sized in column layouts) 35 const availableWidth = (nav.parentElement ?? nav).clientWidth; 36 37 // Measure total content width directly — scrollWidth is unreliable with 38 // justify-content: flex-end because overflow spills left (negative direction) 39 // and isn't reflected in scrollWidth. 40 const gap = parseFloat(getComputedStyle(nav).columnGap) || 0; 41 const contentWidth = () => { 42 const visible = items.filter((el) => el.style.display !== "none"); 43 return visible.reduce((acc, el) => acc + el.offsetWidth, 0) + 44 gap * Math.max(0, visible.length - 1); 45 }; 46 47 // No overflow — nothing to do 48 if (contentWidth() <= availableWidth) return; 49 50 // Show button (takes up space; subtract its width + container gap from available) 51 btn.style.display = ""; 52 const containerGap = parseFloat(getComputedStyle(nav.parentElement ?? nav).columnGap) || 0; 53 54 // Hide items from right until content fits 55 const hidden = []; 56 for (let i = items.length - 1; i >= 0; i--) { 57 if (contentWidth() <= availableWidth - btn.offsetWidth - containerGap) break; 58 items[i].style.display = "none"; 59 hidden.unshift(items[i]); 60 } 61 62 // Update button label: show "Menu" when all items are hidden 63 const allHidden = hidden.length === items.length; 64 if (span) { 65 span.innerHTML = allHidden 66 ? `<i class="ph-bold ph-list"></i> Menu` 67 : `<i class="ph-fill ph-dots-three-outline"></i>`; 68 } 69 70 // Populate dropdown with clones (stripped of button styling) 71 menu.innerHTML = ""; 72 for (const el of hidden) { 73 if (el.classList.contains("divider")) continue; 74 75 const clone = /** @type {HTMLElement} */ (el.cloneNode(true)); 76 clone.style.display = ""; 77 clone.classList.remove( 78 "button", 79 "button--transparent", 80 "button--border", 81 "button--bg-twist-2", 82 ); 83 84 menu.appendChild(clone); 85 } 86} 87 88let _observer = /** @type {ResizeObserver | undefined} */ (undefined); 89 90export function watchResize() { 91 const nav = document.getElementById("diffuse-nav"); 92 if (!nav) return; 93 _observer?.disconnect(); 94 _observer = new ResizeObserver(update); 95 // Observe the container — in column layouts the nav is content-sized and 96 // won't resize, but the container does as the header width changes. 97 _observer.observe(nav.parentElement ?? nav); 98}