diff --git a/static/js/00-config.js b/static/js/00-config.js index 0f63722..0b5ca1b 100644 --- a/static/js/00-config.js +++ b/static/js/00-config.js @@ -36,9 +36,7 @@ Glow.els = { clearMessagesButton: document.getElementById("clearMessagesButton"), createRoomButton: document.getElementById("createRoomButton"), typingToggleButton: document.getElementById("typingToggleButton"), - notificationsToggleButton: document.getElementById( - "notificationsToggleButton" - ), + notificationsToggleButton: document.getElementById("notificationsToggleButton"), themeButton: document.getElementById("themeButton"), adminUsers: document.getElementById("adminUsers"), adminRooms: document.getElementById("adminRooms"), @@ -52,7 +50,6 @@ Glow.els = { dialogTitle: document.getElementById("dialogTitle"), dialogBody: document.getElementById("dialogBody"), dialogActions: document.getElementById("dialogActions"), - teamSelect: document.getElementById("teamSelect"), pagesButton: document.getElementById("pagesButton"), backButton: document.getElementById("backButton"), @@ -67,22 +64,16 @@ Glow.els = { threadAttachmentName: document.getElementById("threadAttachmentName"), pagesBox: document.getElementById("pagesBox"), pageDetailBox: document.getElementById("pageDetailBox"), - settingsButton: document.getElementById("settingsButton"), profileBox: document.getElementById("profileBox"), - headerMenuOverlay: document.getElementById("headerMenuOverlay"), headerMenuList: document.getElementById("headerMenuList"), - reactionPopupOverlay: document.getElementById("reactionPopupOverlay"), reactionPopupGrid: document.getElementById("reactionPopupGrid"), reactionPopupList: document.getElementById("reactionPopupList"), reactionCustomInput: document.getElementById("reactionCustomInput"), reactionCustomButton: document.getElementById("reactionCustomButton"), - closeReactionPopupButton: document.getElementById( - "closeReactionPopupButton" - ), - + closeReactionPopupButton: document.getElementById("closeReactionPopupButton"), mediaOverlay: document.getElementById("mediaOverlay"), mediaTitle: document.getElementById("mediaTitle"), mediaImage: document.getElementById("mediaImage"), @@ -92,12 +83,12 @@ Glow.els = { mediaFallbackLink: document.getElementById("mediaFallbackLink"), mediaDownloadLink: document.getElementById("mediaDownloadLink"), closeMediaButton: document.getElementById("closeMediaButton"), - callOverlay: document.getElementById("callOverlay"), callStatus: document.getElementById("callStatus"), callPeerLabel: document.getElementById("callPeerLabel"), startCallButton: document.getElementById("startCallButton"), answerCallButton: document.getElementById("answerCallButton"), + addToCallButton: document.getElementById("addToCallButton"), muteCallButton: document.getElementById("muteCallButton"), hangupCallButton: document.getElementById("hangupCallButton"), closeCallPanelButton: document.getElementById("closeCallPanelButton"), @@ -107,20 +98,15 @@ Glow.els = { Glow.state = { currentUser: null, csrfToken: "", - rooms: [], activeRoom: null, - teams: [], activeTeam: null, channels: [], activeChannel: null, - dms: [], activeDm: null, - activeView: "feed", - lastSeenId: 0, knownMessageIds: new Set(), renderedMessages: [], @@ -130,68 +116,57 @@ Glow.state = { pollInFlight: false, channelPollInFlight: false, dmPollInFlight: false, - feedLastSeenId: 0, feedKnownMessageIds: new Set(), feedEntries: [], feedRequestId: 0, feedPollInFlight: false, - activeThread: null, threadReplies: [], threadRequestId: 0, threadPollInFlight: false, - pages: [], activePage: null, pageTypeFilter: "", - activeProfile: null, settings: null, - pollTimer: null, initialized: false, - toastTimer: null, - selectedAttachment: [], selectedThreadAttachment: [], - typingTimer: null, typingLastSent: 0, typingUsers: [], dmTypingUsers: [], - typingIndicatorsEnabled: localStorage.getItem("glow_typing_enabled") !== "false", - notificationsEnabled: localStorage.getItem("glow_notifications_enabled") === "true", - accentColor: localStorage.getItem("glow_accent_color") || "#f7dce8", - unreadMessages: 0, originalTitle: document.title, - dialogResolver: null, lastFocusedElement: null, - presence: { roomOnlineCount: 0, channelOnlineCount: 0, dmOnlineCount: 0 }, - calls: { activeCall: null, - peerConnection: null, + ws: null, + session: null, localStream: null, muted: false, - signalLastSeenId: 0, - pollTimer: null, - incomingCall: null, - pendingOffer: null + selfPeerId: null, + peerConnections: new Map(), + remoteStreams: new Map(), + peers: [], + reconnectTimer: null, + invites: [], + invitePollTimer: null } }; @@ -200,43 +175,23 @@ Glow.MAX_ATTACHMENT_BYTES = 5 * 1024 * 1024; Glow.DEFAULT_ACCENT_COLOR = "#f7dce8"; Glow.normalizeAccentColor = value => { - if (typeof value !== "string") { - return null; - } - + if (typeof value !== "string") return null; const color = value.trim(); - - if (!/^#[0-9a-fA-F]{6}$/.test(color)) { - return null; - } - + if (!/^#[0-9a-fA-F]{6}$/.test(color)) return null; return color.toLowerCase(); }; Glow.normalizeNameColor = value => { - if (value == null || value === "") { - return null; - } - - if (typeof value !== "string") { - return null; - } - + if (value == null || value === "") return null; + if (typeof value !== "string") return null; const color = value.trim(); - if (!/^#[0-9a-fA-F]{6}$/.test(color)) { - return null; - } - + if (!/^#[0-9a-fA-F]{6}$/.test(color)) return null; return color.toLowerCase(); }; Glow.hexToRgb = hex => { const normalized = Glow.normalizeAccentColor(hex); - - if (!normalized) { - return null; - } - + if (!normalized) return null; return { r: parseInt(normalized.slice(1, 3), 16), g: parseInt(normalized.slice(3, 5), 16), @@ -246,19 +201,13 @@ Glow.hexToRgb = hex => { Glow.relativeLuminance = hex => { const rgb = Glow.hexToRgb(hex); - - if (!rgb) { - return 0; - } - + if (!rgb) return 0; const channel = value => { const normalized = value / 255; - return normalized <= 0.03928 ? normalized / 12.92 : Math.pow((normalized + 0.055) / 1.055, 2.4); }; - return ( 0.2126 * channel(rgb.r) + 0.7152 * channel(rgb.g) + @@ -273,12 +222,9 @@ Glow.accentTextColor = hex => { Glow.applyAccentColor = value => { const accent = Glow.normalizeAccentColor(value) || Glow.DEFAULT_ACCENT_COLOR; - const rgb = Glow.hexToRgb(accent); const root = document.documentElement; - Glow.state.accentColor = accent; - root.style.setProperty("--accent", accent); root.style.setProperty("--accent-active", Glow.accentTextColor(accent)); root.style.setProperty( @@ -289,9 +235,7 @@ Glow.applyAccentColor = value => { "--accent-hover", `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.28)` ); - localStorage.setItem("glow_accent_color", accent); - Glow.updateThemeButton?.(); }; @@ -315,19 +259,12 @@ Glow.resolveUserNameColor = userish => { const explicit = Glow.normalizeNameColor(userish?.name_color) || Glow.normalizeNameColor(userish?.user_name_color); - - if (explicit) { - return explicit; - } - + if (explicit) return explicit; return Glow.roleDefaultNameColor(userish?.role || userish?.user_role); }; Glow.applyUserColor = (element, userish) => { - if (!(element instanceof HTMLElement)) { - return; - } - + if (!(element instanceof HTMLElement)) return; element.style.color = Glow.resolveUserNameColor(userish); }; @@ -343,10 +280,8 @@ Glow.isAdmin = () => { Glow.showToast = (message, type = "") => { clearTimeout(Glow.state.toastTimer); - Glow.els.statusToast.textContent = String(message); Glow.els.statusToast.className = `status-toast show ${type}`.trim(); - Glow.state.toastTimer = setTimeout(() => { Glow.els.statusToast.className = "status-toast"; }, 3500); @@ -364,17 +299,13 @@ Glow.clearAuthNotice = () => { Glow.showBlocked = message => { Glow.els.blockedMessage.textContent = message || "Access has been blocked."; - Glow.els.blockedOverlay.classList.remove("hidden"); Glow.els.authOverlay.classList.add("hidden"); - Glow.els.messageInput.disabled = true; Glow.els.sendButton.disabled = true; Glow.els.roomSelect.disabled = true; Glow.els.attachmentInput.disabled = true; - Glow.els.attachmentButton.classList.add("disabled"); - clearTimeout(Glow.state.pollTimer); }; @@ -383,52 +314,23 @@ Glow.relativeTime = iso => { 0, Math.floor((Date.now() - new Date(iso).getTime()) / 1000) ); - - if (seconds < 5) { - return "now"; - } - - if (seconds < 60) { - return `${seconds}s`; - } - + if (seconds < 5) return "now"; + if (seconds < 60) return `${seconds}s`; const minutes = Math.floor(seconds / 60); - - if (minutes < 60) { - return `${minutes}m`; - } - + if (minutes < 60) return `${minutes}m`; const hours = Math.floor(minutes / 60); - - if (hours < 24) { - return `${hours}h`; - } - + if (hours < 24) return `${hours}h`; return `${Math.floor(hours / 24)}d`; }; Glow.formatDateLabel = iso => { const date = new Date(iso); const now = new Date(); - const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); - - const target = new Date( - date.getFullYear(), - date.getMonth(), - date.getDate() - ); - + const target = new Date(date.getFullYear(), date.getMonth(), date.getDate()); const diff = Math.round((today - target) / 86400000); - - if (diff === 0) { - return "Today"; - } - - if (diff === 1) { - return "Yesterday"; - } - + if (diff === 0) return "Today"; + if (diff === 1) return "Yesterday"; return date.toLocaleDateString(undefined, { weekday: "long", year: "numeric", @@ -439,7 +341,6 @@ Glow.formatDateLabel = iso => { Glow.dateKey = iso => { const date = new Date(iso); - return [ date.getFullYear(), String(date.getMonth() + 1).padStart(2, "0"), @@ -456,11 +357,7 @@ Glow.isNearBottom = () => { : Glow.state.activeView === "dms" ? Glow.els.dmBox : Glow.els.chatBox; - - if (!activeBox) { - return true; - } - + if (!activeBox) return true; return activeBox.scrollHeight - activeBox.scrollTop - activeBox.clientHeight < 100; }; @@ -480,8 +377,7 @@ Glow.updateDocumentTitle = () => { document.title = Glow.state.originalTitle; return; } - - document.title = `(${Glow.state.unreadMessages}) ` + Glow.state.originalTitle; + document.title = `(${Glow.state.unreadMessages})` + Glow.state.originalTitle; }; Glow.resetUnreadMessages = () => { @@ -495,10 +391,7 @@ Glow.showNewMessages = () => { }; Glow.normalizeSelectedFiles = fileList => { - if (!fileList) { - return []; - } - + if (!fileList) return []; return [...fileList].filter(Boolean); }; @@ -515,7 +408,6 @@ Glow.openDialog = ({ } Glow.state.lastFocusedElement = document.activeElement; - Glow.els.dialogTitle.textContent = title; Glow.els.dialogBody.replaceChildren(); Glow.els.dialogActions.replaceChildren(); @@ -529,7 +421,6 @@ Glow.openDialog = ({ } const fieldElements = {}; - for (const field of fields) { const label = document.createElement("label"); label.className = "dialog-label"; @@ -537,7 +428,6 @@ Glow.openDialog = ({ const isMultiline = Boolean(field.multiline); const input = document.createElement(isMultiline ? "textarea" : "input"); - input.className = "field"; input.name = field.name; input.value = field.value || ""; @@ -549,7 +439,6 @@ Glow.openDialog = ({ } else { input.type = field.type || "text"; input.maxLength = field.maxLength || 300; - if (field.type === "number") { input.min = field.min || "1"; input.max = field.max || "43200"; @@ -573,31 +462,23 @@ Glow.openDialog = ({ confirmButton.textContent = confirmText; Glow.els.dialogActions.append(cancel, confirmButton); + Glow.els.dialogOverlay.classList.remove("hidden"); return new Promise(resolve => { Glow.state.dialogResolver = resolve; - - cancel.addEventListener( - "click", - () => Glow.closeDialog(null), - { once: true } - ); - + cancel.addEventListener("click", () => Glow.closeDialog(null), { once: true }); confirmButton.addEventListener( "click", () => { const values = {}; - for (const [name, input] of Object.entries(fieldElements)) { values[name] = input.value.trim(); } - Glow.closeDialog(values); }, { once: true } ); - setTimeout(() => { const first = Object.values(fieldElements)[0] || confirmButton; first.focus(); @@ -607,15 +488,10 @@ Glow.openDialog = ({ Glow.closeDialog = (result = null) => { Glow.els.dialogOverlay.classList.add("hidden"); - const resolve = Glow.state.dialogResolver; Glow.state.dialogResolver = null; - - if (resolve) { - resolve(result); - } - + if (resolve) resolve(result); if (Glow.state.lastFocusedElement instanceof HTMLElement) { Glow.state.lastFocusedElement.focus(); } -}; +}; \ No newline at end of file