import type { WebrtcProvider } from "y-webrtc"; export function StatusBar(provider: WebrtcProvider, user_provider: WebrtcProvider, onLoginLogout: (event: Event) => Promise, onCreateUser: (event: Event) => Promise): HTMLElement { const el = document.createElement("div"); el.className = "status-bar"; const statusPanel=document.createElement("div"); statusPanel.className = "status-bar"; const divider = document.createElement("span"); divider.className = "status-divider"; divider.textContent = "\u00b7"; function getProviderStatus(){ const dot = document.createElement("span"); dot.className = "status-dot connecting"; const statusText = document.createElement("span"); statusText.className = "status-text"; statusText.textContent = "Connecting"; const peerText = document.createElement("span"); peerText.className = "status-peers"; return { dot: dot, statusText: statusText, peerText: peerText} } const providerStatusPanel=document.createElement("div"); providerStatusPanel.className = "provider-status-container"; const pollProviderText = document.createElement("span"); pollProviderText.className = "status-text"; pollProviderText.textContent = "Polls: "; const pollProviderElements = getProviderStatus() const pollProviderStatusPanel=document.createElement("div"); pollProviderStatusPanel.className = "status-bar"; pollProviderStatusPanel.append(pollProviderText,pollProviderElements.dot, pollProviderElements.statusText, divider, pollProviderElements.peerText); const userProviderText = document.createElement("span"); userProviderText.className = "status-text"; userProviderText.textContent = "Users: "; const userProviderElements = getProviderStatus() const userProviderStatusPanel=document.createElement("div"); userProviderStatusPanel.className = "status-bar"; userProviderStatusPanel.append(userProviderText,userProviderElements.dot, userProviderElements.statusText, divider, userProviderElements.peerText); providerStatusPanel.append(userProviderStatusPanel,pollProviderStatusPanel) const userButtons = document.createElement("div"); userButtons.className = "status-bar"; const loginLabel = document.createElement("label"); loginLabel.setAttribute("title", "Select Key File"); const loginSpan = document.createElement("span"); loginSpan.className = "add-option-btn" loginSpan.textContent = "Login"; const loginInput = document.createElement("input"); loginInput.type = "file" loginInput.accept = ".pem" loginInput.hidden = true loginLabel.append(loginSpan,loginInput) const logoutButton = document.createElement("button"); logoutButton.className = "add-option-btn"; logoutButton.setAttribute("aria-label", "Logout"); logoutButton.innerHTML="Logout" logoutButton.style.display = "none"; const createUserButton = document.createElement("button"); createUserButton.className = "add-option-btn"; createUserButton.setAttribute("aria-label", "Create User"); createUserButton.innerHTML="Create User" async function onLoginLogoutResult(event: Event, loginLogout: (event: Event) => Promise){ if(await loginLogout(event)){ console.log('created / logged in') loginLabel.style.display = "none"; logoutButton.style.display = "block"; createUserButton.style.display = "none"; } else { console.log('logged out') loginLabel.style.display = "block"; logoutButton.style.display = "none"; createUserButton.hidden = false; createUserButton.style.display = "block"; } } loginLabel.addEventListener("change", (e) => onLoginLogoutResult(e,onLoginLogout)); logoutButton.addEventListener("click", (e) => onLoginLogoutResult(e,onLoginLogout)); createUserButton.addEventListener("click", (e) => onLoginLogoutResult(e,onCreateUser)); userButtons.append(loginLabel,logoutButton,createUserButton) el.append(providerStatusPanel, divider, userButtons); // --- Connection state --- let syncTimeout: ReturnType | undefined = setTimeout(() => { pollProviderElements.statusText.textContent = "Ready"; pollProviderElements.dot.className = "status-dot ready"; }, 3000); provider.on("synced", ({ synced }: { synced: boolean }) => { if (syncTimeout) { clearTimeout(syncTimeout); syncTimeout = undefined; } pollProviderElements.dot.className = `status-dot ${synced ? "connected" : "connecting"}`; pollProviderElements.statusText.textContent = synced ? "Connected" : "Connecting"; }); let syncTimeout2: ReturnType | undefined = setTimeout(() => { userProviderElements.statusText.textContent = "Ready"; userProviderElements.dot.className = "status-dot ready"; }, 3000); user_provider.on("synced", ({ synced }: { synced: boolean }) => { if (syncTimeout2) { clearTimeout(syncTimeout2); syncTimeout2 = undefined; } userProviderElements.dot.className = `status-dot ${synced ? "connected" : "connecting"}`; userProviderElements.statusText.textContent = synced ? "Connected" : "Connecting"; }); // Online/offline awareness const handleOffline = () => { pollProviderElements.dot.className = "status-dot connecting"; pollProviderElements.statusText.textContent = "Offline"; userProviderElements.dot.className = "status-dot connecting"; userProviderElements.statusText.textContent = "Offline"; }; const handleOnline = () => { pollProviderElements.dot.className = "status-dot connecting"; pollProviderElements.statusText.textContent = "Reconnecting"; userProviderElements.dot.className = "status-dot connecting"; userProviderElements.statusText.textContent = "Reconnecting"; }; window.addEventListener("offline", handleOffline); window.addEventListener("online", handleOnline); // --- Peer count --- function updatePeerCount() { const total = provider.awareness.getStates().size; const others = total - 1; pollProviderElements.peerText.textContent = others === 0 ? "Only you" : `${others} other${others !== 1 ? "s" : ""}`; const total2 = user_provider.awareness.getStates().size; const others2 = total2 - 1; userProviderElements.peerText.textContent = others2 === 0 ? "Only you" : `${others2} other${others2 !== 1 ? "s" : ""}`; } provider.awareness.on("change", updatePeerCount); updatePeerCount(); return el; }