Update static/js/00-config.js

This commit is contained in:
admin 2026-10-08 00:38:02 +00:00
parent 627a08ced6
commit 0b45bd657c

View File

@ -1,8 +1,6 @@
// static/js/00-config.js // static/js/00-config.js
"use strict"; "use strict";
window.Glow = window.Glow || {}; window.Glow = window.Glow || {};
Glow.els = { Glow.els = {
chatBox: document.getElementById("chatBox"), chatBox: document.getElementById("chatBox"),
dmBox: document.getElementById("dmBox"), dmBox: document.getElementById("dmBox"),
@ -93,9 +91,9 @@ Glow.els = {
muteCallButton: document.getElementById("muteCallButton"), muteCallButton: document.getElementById("muteCallButton"),
hangupCallButton: document.getElementById("hangupCallButton"), hangupCallButton: document.getElementById("hangupCallButton"),
closeCallPanelButton: document.getElementById("closeCallPanelButton"), closeCallPanelButton: document.getElementById("closeCallPanelButton"),
remoteAudio: document.getElementById("remoteAudio") remoteAudio: document.getElementById("remoteAudio"),
emojiAutocomplete: document.getElementById("emojiAutocomplete")
}; };
Glow.state = { Glow.state = {
currentUser: null, currentUser: null,
csrfToken: "", csrfToken: "",
@ -150,6 +148,8 @@ Glow.state = {
originalTitle: document.title, originalTitle: document.title,
dialogResolver: null, dialogResolver: null,
lastFocusedElement: null, lastFocusedElement: null,
emojiSuggestions: [],
emojiActiveInput: null,
presence: { presence: {
roomOnlineCount: 0, roomOnlineCount: 0,
channelOnlineCount: 0, channelOnlineCount: 0,
@ -170,18 +170,34 @@ Glow.state = {
invitePollTimer: null invitePollTimer: null
} }
}; };
Glow.MAX_MESSAGE_LENGTH = 1000; Glow.MAX_MESSAGE_LENGTH = 1000;
Glow.MAX_ATTACHMENT_BYTES = 5 * 1024 * 1024; Glow.MAX_ATTACHMENT_BYTES = 5 * 1024 * 1024;
Glow.DEFAULT_ACCENT_COLOR = "#f7dce8"; Glow.DEFAULT_ACCENT_COLOR = "#f7dce8";
Glow.EMOJI_ALIASES = {
smile: "😄",
grin: "😁",
joy: "😂",
heart: "❤️",
thumbs_up: "👍",
fire: "🔥",
tada: "🎉",
clap: "👏",
eyes: "👀",
rocket: "🚀",
wave: "👋",
sparkles: "✨",
thinking: "🤔",
cry: "😢",
check: "✅",
bulb: "💡",
shrug: "¯\\_(ツ)_/¯"
};
Glow.normalizeAccentColor = value => { Glow.normalizeAccentColor = value => {
if (typeof value !== "string") return null; if (typeof value !== "string") return null;
const color = value.trim(); 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(); return color.toLowerCase();
}; };
Glow.normalizeNameColor = value => { Glow.normalizeNameColor = value => {
if (value == null || value === "") return null; if (value == null || value === "") return null;
if (typeof value !== "string") return null; if (typeof value !== "string") return null;
@ -189,7 +205,6 @@ Glow.normalizeNameColor = value => {
if (!/^#[0-9a-fA-F]{6}$/.test(color)) return null; if (!/^#[0-9a-fA-F]{6}$/.test(color)) return null;
return color.toLowerCase(); return color.toLowerCase();
}; };
Glow.hexToRgb = hex => { Glow.hexToRgb = hex => {
const normalized = Glow.normalizeAccentColor(hex); const normalized = Glow.normalizeAccentColor(hex);
if (!normalized) return null; if (!normalized) return null;
@ -199,7 +214,6 @@ Glow.hexToRgb = hex => {
b: parseInt(normalized.slice(5, 7), 16) b: parseInt(normalized.slice(5, 7), 16)
}; };
}; };
Glow.relativeLuminance = hex => { Glow.relativeLuminance = hex => {
const rgb = Glow.hexToRgb(hex); const rgb = Glow.hexToRgb(hex);
if (!rgb) return 0; if (!rgb) return 0;
@ -215,11 +229,9 @@ Glow.relativeLuminance = hex => {
0.0722 * channel(rgb.b) 0.0722 * channel(rgb.b)
); );
}; };
Glow.accentTextColor = hex => { Glow.accentTextColor = hex => {
return Glow.relativeLuminance(hex) >= 0.18 ? hex : "#f2f2f4"; return Glow.relativeLuminance(hex) >= 0.18 ? hex : "#f2f2f4";
}; };
Glow.applyAccentColor = value => { Glow.applyAccentColor = value => {
const accent = const accent =
Glow.normalizeAccentColor(value) || Glow.DEFAULT_ACCENT_COLOR; Glow.normalizeAccentColor(value) || Glow.DEFAULT_ACCENT_COLOR;
@ -239,12 +251,10 @@ Glow.applyAccentColor = value => {
localStorage.setItem("glow_accent_color", accent); localStorage.setItem("glow_accent_color", accent);
Glow.updateThemeButton?.(); Glow.updateThemeButton?.();
}; };
Glow.resetAccentColor = () => { Glow.resetAccentColor = () => {
localStorage.removeItem("glow_accent_color"); localStorage.removeItem("glow_accent_color");
Glow.applyAccentColor(Glow.DEFAULT_ACCENT_COLOR); Glow.applyAccentColor(Glow.DEFAULT_ACCENT_COLOR);
}; };
Glow.roleDefaultNameColor = role => { Glow.roleDefaultNameColor = role => {
switch (String(role || "").toLowerCase()) { switch (String(role || "").toLowerCase()) {
case "admin": case "admin":
@ -255,7 +265,6 @@ Glow.roleDefaultNameColor = role => {
return "#f5f5f7"; return "#f5f5f7";
} }
}; };
Glow.resolveUserNameColor = userish => { Glow.resolveUserNameColor = userish => {
const explicit = const explicit =
Glow.normalizeNameColor(userish?.name_color) || Glow.normalizeNameColor(userish?.name_color) ||
@ -263,22 +272,18 @@ Glow.resolveUserNameColor = userish => {
if (explicit) return explicit; if (explicit) return explicit;
return Glow.roleDefaultNameColor(userish?.role || userish?.user_role); return Glow.roleDefaultNameColor(userish?.role || userish?.user_role);
}; };
Glow.applyUserColor = (element, userish) => { Glow.applyUserColor = (element, userish) => {
if (!(element instanceof HTMLElement)) return; if (!(element instanceof HTMLElement)) return;
element.style.color = Glow.resolveUserNameColor(userish); element.style.color = Glow.resolveUserNameColor(userish);
}; };
Glow.canModerate = () => { Glow.canModerate = () => {
const user = Glow.state.currentUser; const user = Glow.state.currentUser;
return Boolean(user && ["moderator", "admin"].includes(user.role)); return Boolean(user && ["moderator", "admin"].includes(user.role));
}; };
Glow.isAdmin = () => { Glow.isAdmin = () => {
const user = Glow.state.currentUser; const user = Glow.state.currentUser;
return Boolean(user && user.role === "admin"); return Boolean(user && user.role === "admin");
}; };
Glow.showToast = (message, type = "") => { Glow.showToast = (message, type = "") => {
clearTimeout(Glow.state.toastTimer); clearTimeout(Glow.state.toastTimer);
Glow.els.statusToast.textContent = String(message); Glow.els.statusToast.textContent = String(message);
@ -287,17 +292,14 @@ Glow.showToast = (message, type = "") => {
Glow.els.statusToast.className = "status-toast"; Glow.els.statusToast.className = "status-toast";
}, 3500); }, 3500);
}; };
Glow.showAuthNotice = (message, type = "error") => { Glow.showAuthNotice = (message, type = "error") => {
Glow.els.authNotice.textContent = String(message); Glow.els.authNotice.textContent = String(message);
Glow.els.authNotice.className = `notice show ${type}`; Glow.els.authNotice.className = `notice show ${type}`;
}; };
Glow.clearAuthNotice = () => { Glow.clearAuthNotice = () => {
Glow.els.authNotice.textContent = ""; Glow.els.authNotice.textContent = "";
Glow.els.authNotice.className = "notice"; Glow.els.authNotice.className = "notice";
}; };
Glow.showBlocked = message => { Glow.showBlocked = message => {
Glow.els.blockedMessage.textContent = message || "Access has been blocked."; Glow.els.blockedMessage.textContent = message || "Access has been blocked.";
Glow.els.blockedOverlay.classList.remove("hidden"); Glow.els.blockedOverlay.classList.remove("hidden");
@ -309,7 +311,6 @@ Glow.showBlocked = message => {
Glow.els.attachmentButton.classList.add("disabled"); Glow.els.attachmentButton.classList.add("disabled");
clearTimeout(Glow.state.pollTimer); clearTimeout(Glow.state.pollTimer);
}; };
Glow.relativeTime = iso => { Glow.relativeTime = iso => {
const seconds = Math.max( const seconds = Math.max(
0, 0,
@ -323,7 +324,6 @@ Glow.relativeTime = iso => {
if (hours < 24) return `${hours}h`; if (hours < 24) return `${hours}h`;
return `${Math.floor(hours / 24)}d`; return `${Math.floor(hours / 24)}d`;
}; };
Glow.formatDateLabel = iso => { Glow.formatDateLabel = iso => {
const date = new Date(iso); const date = new Date(iso);
const now = new Date(); const now = new Date();
@ -339,7 +339,6 @@ Glow.formatDateLabel = iso => {
day: "numeric" day: "numeric"
}); });
}; };
Glow.dateKey = iso => { Glow.dateKey = iso => {
const date = new Date(iso); const date = new Date(iso);
return [ return [
@ -348,7 +347,6 @@ Glow.dateKey = iso => {
String(date.getDate()).padStart(2, "0") String(date.getDate()).padStart(2, "0")
].join("-"); ].join("-");
}; };
Glow.isNearBottom = () => { Glow.isNearBottom = () => {
const activeBox = const activeBox =
Glow.state.activeView === "feed" Glow.state.activeView === "feed"
@ -361,41 +359,34 @@ Glow.isNearBottom = () => {
if (!activeBox) return true; if (!activeBox) return true;
return activeBox.scrollHeight - activeBox.scrollTop - activeBox.clientHeight < 100; return activeBox.scrollHeight - activeBox.scrollTop - activeBox.clientHeight < 100;
}; };
Glow.autoResizeComposer = () => { Glow.autoResizeComposer = () => {
const input = Glow.els.messageInput; const input = Glow.els.messageInput;
input.style.height = "auto"; input.style.height = "auto";
input.style.height = `${Math.min(input.scrollHeight, 150)}px`; input.style.height = `${Math.min(input.scrollHeight, 150)}px`;
}; };
Glow.updateMessageCount = () => { Glow.updateMessageCount = () => {
const count = Glow.els.messageInput.value.length; const count = Glow.els.messageInput.value.length;
Glow.els.messageCount.textContent = `${count} / ${Glow.MAX_MESSAGE_LENGTH}`; Glow.els.messageCount.textContent = `${count} / ${Glow.MAX_MESSAGE_LENGTH}`;
}; };
Glow.updateDocumentTitle = () => { Glow.updateDocumentTitle = () => {
if (!Glow.state.unreadMessages) { if (!Glow.state.unreadMessages) {
document.title = Glow.state.originalTitle; document.title = Glow.state.originalTitle;
return; return;
} }
document.title = `(${Glow.state.unreadMessages})` + Glow.state.originalTitle; document.title = `(${Glow.state.unreadMessages}) ${Glow.state.originalTitle}`;
}; };
Glow.resetUnreadMessages = () => { Glow.resetUnreadMessages = () => {
Glow.state.unreadMessages = 0; Glow.state.unreadMessages = 0;
Glow.updateDocumentTitle(); Glow.updateDocumentTitle();
Glow.els.newMessagesBar.classList.add("hidden"); Glow.els.newMessagesBar.classList.add("hidden");
}; };
Glow.showNewMessages = () => { Glow.showNewMessages = () => {
Glow.els.newMessagesBar.classList.remove("hidden"); Glow.els.newMessagesBar.classList.remove("hidden");
}; };
Glow.normalizeSelectedFiles = fileList => { Glow.normalizeSelectedFiles = fileList => {
if (!fileList) return []; if (!fileList) return [];
return [...fileList].filter(Boolean); return [...fileList].filter(Boolean);
}; };
Glow.openDialog = ({ Glow.openDialog = ({
title, title,
body, body,
@ -407,12 +398,10 @@ Glow.openDialog = ({
if (Glow.state.dialogResolver) { if (Glow.state.dialogResolver) {
Glow.closeDialog(null); Glow.closeDialog(null);
} }
Glow.state.lastFocusedElement = document.activeElement; Glow.state.lastFocusedElement = document.activeElement;
Glow.els.dialogTitle.textContent = title; Glow.els.dialogTitle.textContent = title;
Glow.els.dialogBody.replaceChildren(); Glow.els.dialogBody.replaceChildren();
Glow.els.dialogActions.replaceChildren(); Glow.els.dialogActions.replaceChildren();
if (typeof body === "string") { if (typeof body === "string") {
const paragraph = document.createElement("p"); const paragraph = document.createElement("p");
paragraph.textContent = body; paragraph.textContent = body;
@ -420,20 +409,17 @@ Glow.openDialog = ({
} else if (body instanceof Node) { } else if (body instanceof Node) {
Glow.els.dialogBody.append(body); Glow.els.dialogBody.append(body);
} }
const fieldElements = {}; const fieldElements = {};
for (const field of fields) { for (const field of fields) {
const label = document.createElement("label"); const label = document.createElement("label");
label.className = "dialog-label"; label.className = "dialog-label";
label.textContent = field.label; label.textContent = field.label;
const isMultiline = Boolean(field.multiline); const isMultiline = Boolean(field.multiline);
const input = document.createElement(isMultiline ? "textarea" : "input"); const input = document.createElement(isMultiline ? "textarea" : "input");
input.className = "field"; input.className = "field";
input.name = field.name; input.name = field.name;
input.value = field.value || ""; input.value = field.value || "";
input.placeholder = field.placeholder || ""; input.placeholder = field.placeholder || "";
if (isMultiline) { if (isMultiline) {
input.rows = field.rows || 3; input.rows = field.rows || 3;
input.maxLength = field.maxLength || 300; input.maxLength = field.maxLength || 300;
@ -446,26 +432,20 @@ Glow.openDialog = ({
input.step = field.step || "1"; input.step = field.step || "1";
} }
} }
label.append(input); label.append(input);
Glow.els.dialogBody.append(label); Glow.els.dialogBody.append(label);
fieldElements[field.name] = input; fieldElements[field.name] = input;
} }
const cancel = document.createElement("button"); const cancel = document.createElement("button");
cancel.className = "button secondary"; cancel.className = "button secondary";
cancel.type = "button"; cancel.type = "button";
cancel.textContent = cancelText; cancel.textContent = cancelText;
const confirmButton = document.createElement("button"); const confirmButton = document.createElement("button");
confirmButton.className = danger ? "danger-button" : "button"; confirmButton.className = danger ? "danger-button" : "button";
confirmButton.type = "button"; confirmButton.type = "button";
confirmButton.textContent = confirmText; confirmButton.textContent = confirmText;
Glow.els.dialogActions.append(cancel, confirmButton); Glow.els.dialogActions.append(cancel, confirmButton);
Glow.els.dialogOverlay.classList.remove("hidden"); Glow.els.dialogOverlay.classList.remove("hidden");
return new Promise(resolve => { return new Promise(resolve => {
Glow.state.dialogResolver = resolve; Glow.state.dialogResolver = resolve;
cancel.addEventListener("click", () => Glow.closeDialog(null), { once: true }); cancel.addEventListener("click", () => Glow.closeDialog(null), { once: true });
@ -486,7 +466,6 @@ Glow.openDialog = ({
}, 0); }, 0);
}); });
}; };
Glow.closeDialog = (result = null) => { Glow.closeDialog = (result = null) => {
Glow.els.dialogOverlay.classList.add("hidden"); Glow.els.dialogOverlay.classList.add("hidden");
const resolve = Glow.state.dialogResolver; const resolve = Glow.state.dialogResolver;