From f0d7f26c63eac16c804ebcd73ce10f92552c9989 Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 8 Oct 2026 00:45:06 +0000 Subject: [PATCH] Update static/js/08-settings.js --- static/js/08-settings.js | 190 ++++++++++++++++++++++++++------------- 1 file changed, 128 insertions(+), 62 deletions(-) diff --git a/static/js/08-settings.js b/static/js/08-settings.js index e6e5c70..83b6aa6 100644 --- a/static/js/08-settings.js +++ b/static/js/08-settings.js @@ -1,8 +1,6 @@ // static/js/08-settings.js "use strict"; - window.Glow = window.Glow || {}; - Glow.state = Glow.state || {}; Glow.state.settings = Glow.state.settings || null; @@ -14,13 +12,11 @@ Glow.applyThemeMode = mode => { Glow.applyCustomCss = cssText => { let style = document.getElementById("glowCustomCss"); - if (!style) { style = document.createElement("style"); style.id = "glowCustomCss"; document.head.append(style); } - style.textContent = typeof cssText === "string" ? cssText : ""; }; @@ -28,15 +24,12 @@ Glow.loadMySettings = async () => { try { const data = await Glow.apiGetMySettings(); Glow.state.settings = data.settings || {}; - const accent = Glow.state.settings.accent_color || Glow.state.accentColor; Glow.applyAccentColor(accent); - const mode = Glow.state.settings.theme_mode || localStorage.getItem("glow_theme_mode") || "dark"; - Glow.applyThemeMode(mode); Glow.applyCustomCss(Glow.state.settings.custom_css || ""); } catch (_) { @@ -48,44 +41,34 @@ Glow.loadMySettings = async () => { Glow.renderHeaderMenu = () => { const list = Glow.els.headerMenuList; if (!list) return; - list.replaceChildren(); - const addItem = ({ label, hint = "", onClick, hidden = false }) => { if (hidden) return; - const button = document.createElement("button"); button.className = "header-menu-item"; button.type = "button"; - const left = document.createElement("span"); left.textContent = label; - const right = document.createElement("small"); right.textContent = hint; - button.append(left, right); button.addEventListener("click", () => { Glow.closeHeaderMenu?.(); onClick?.(); }); - list.append(button); }; - addItem({ label: "My profile", hint: Glow.state.currentUser ? `@${Glow.state.currentUser.username}` : "", onClick: () => Glow.openMyProfile?.(), hidden: !Glow.state.currentUser }); - addItem({ label: "Settings", hint: "Theme, CSS, profile", onClick: () => Glow.openSettings?.() }); - addItem({ label: "Direct messages", hint: Glow.state.currentUser ? "Private chat" : "", @@ -97,28 +80,24 @@ Glow.renderHeaderMenu = () => { }, hidden: !Glow.state.currentUser }); - addItem({ label: "Create team", hint: "Up to 3 max", onClick: () => Glow.openCreateTeamDialog?.(), hidden: !Glow.state.currentUser }); - addItem({ label: "Edit current team", hint: Glow.state.activeTeam?.can_manage ? "Manage" : "", onClick: () => Glow.openEditTeamDialog?.(Glow.state.activeTeam), hidden: !Glow.state.activeTeam || !Glow.state.activeTeam.can_manage }); - addItem({ label: "Add channel", hint: Glow.state.activeTeam?.name || "", onClick: () => Glow.openCreateChannelDialog?.(Glow.state.activeTeam), hidden: !Glow.state.activeTeam || !Glow.state.activeTeam.can_manage }); - addItem({ label: "Edit current channel", hint: Glow.state.activeChannel?.name || Glow.state.activeRoom?.name || "", @@ -132,21 +111,18 @@ Glow.renderHeaderMenu = () => { !(Glow.state.activeChannel || Glow.state.activeRoom) || Glow.state.activeView === "dm" }); - addItem({ label: "Manage team members", hint: Glow.state.activeTeam?.can_manage ? "Members" : "", onClick: () => Glow.manageTeamMembers?.(Glow.state.activeTeam), hidden: !Glow.state.activeTeam || !Glow.state.activeTeam.can_manage }); - addItem({ label: "Create team invite", hint: Glow.state.activeTeam?.can_manage ? "Share" : "", onClick: () => Glow.createTeamInviteLink?.(Glow.state.activeTeam), hidden: !Glow.state.activeTeam || !Glow.state.activeTeam.can_manage }); - addItem({ label: "Delete current channel", hint: Glow.state.activeChannel?.name || "", @@ -179,22 +155,18 @@ Glow.toggleHeaderMenu = () => { Glow.openSettings = async () => { Glow.state.activeView = "settings"; Glow.updateViewUI(); - if (!Glow.state.settings && Glow.state.currentUser) { await Glow.loadMySettings(); } - Glow.renderSettingsView(); }; Glow.renderNameColorPreview = value => { const wrap = document.createElement("div"); wrap.className = "settings-row"; - const label = document.createElement("div"); label.className = "header-subtitle"; label.textContent = "Preview"; - const preview = document.createElement("div"); preview.className = "name-color-preview"; preview.textContent = @@ -202,7 +174,6 @@ Glow.renderNameColorPreview = value => { preview.style.color = Glow.normalizeNameColor(value) || Glow.roleDefaultNameColor(Glow.state.currentUser?.role); - wrap.append(label, preview); return wrap; }; @@ -216,16 +187,13 @@ Glow.renderSettingsView = () => { const appearance = document.createElement("section"); appearance.className = "settings-section"; - const aTitle = document.createElement("h2"); aTitle.textContent = "Appearance"; - const aText = document.createElement("p"); - aText.textContent = "Set your theme mode, accent color, username color, and custom CSS."; + aText.textContent = "Set your theme mode, accent color, username color, profile background, and banner color."; const themeRow = document.createElement("div"); themeRow.className = "settings-theme-row"; - const currentTheme = Glow.state.settings?.theme_mode || localStorage.getItem("glow_theme_mode") || @@ -235,7 +203,6 @@ Glow.renderSettingsView = () => { darkButton.className = `theme-pill${currentTheme !== "light" ? " active" : ""}`; darkButton.type = "button"; darkButton.textContent = "Dark"; - const lightButton = document.createElement("button"); lightButton.className = `theme-pill${currentTheme === "light" ? " active" : ""}`; lightButton.type = "button"; @@ -247,23 +214,19 @@ Glow.renderSettingsView = () => { Glow.state.settings.theme_mode = "dark"; Glow.renderSettingsView(); }); - lightButton.addEventListener("click", () => { Glow.applyThemeMode("light"); Glow.state.settings ||= {}; Glow.state.settings.theme_mode = "light"; Glow.renderSettingsView(); }); - themeRow.append(darkButton, lightButton); const accentWrap = document.createElement("div"); accentWrap.className = "settings-row"; - const accentLabel = document.createElement("label"); accentLabel.className = "dialog-label"; accentLabel.textContent = "Accent color"; - const accentInput = document.createElement("input"); accentInput.type = "color"; accentInput.className = "accent-color-input"; @@ -271,23 +234,53 @@ Glow.renderSettingsView = () => { Glow.normalizeAccentColor( Glow.state.settings?.accent_color || Glow.state.accentColor ) || Glow.DEFAULT_ACCENT_COLOR; - accentInput.addEventListener("input", () => { Glow.applyAccentColor(accentInput.value); Glow.state.settings ||= {}; Glow.state.settings.accent_color = accentInput.value; }); - accentLabel.append(accentInput); accentWrap.append(accentLabel); + const backgroundWrap = document.createElement("div"); + backgroundWrap.className = "settings-row"; + const backgroundLabel = document.createElement("label"); + backgroundLabel.className = "dialog-label"; + backgroundLabel.textContent = "Profile background color"; + const backgroundInput = document.createElement("input"); + backgroundInput.type = "color"; + backgroundInput.className = "accent-color-input"; + backgroundInput.value = + Glow.normalizeAccentColor(Glow.state.settings?.profile_background_color) || "#121214"; + backgroundInput.addEventListener("input", () => { + Glow.state.settings ||= {}; + Glow.state.settings.profile_background_color = backgroundInput.value; + }); + backgroundLabel.append(backgroundInput); + backgroundWrap.append(backgroundLabel); + + const bannerWrap = document.createElement("div"); + bannerWrap.className = "settings-row"; + const bannerLabel = document.createElement("label"); + bannerLabel.className = "dialog-label"; + bannerLabel.textContent = "Profile banner color"; + const bannerInput = document.createElement("input"); + bannerInput.type = "color"; + bannerInput.className = "accent-color-input"; + bannerInput.value = + Glow.normalizeAccentColor(Glow.state.settings?.profile_banner_color) || "#3a3140"; + bannerInput.addEventListener("input", () => { + Glow.state.settings ||= {}; + Glow.state.settings.profile_banner_color = bannerInput.value; + }); + bannerLabel.append(bannerInput); + bannerWrap.append(bannerLabel); + const nameColorWrap = document.createElement("div"); nameColorWrap.className = "settings-row"; - const nameColorLabel = document.createElement("label"); nameColorLabel.className = "dialog-label"; nameColorLabel.textContent = "Username color"; - const nameColorInput = document.createElement("input"); nameColorInput.type = "color"; nameColorInput.className = "accent-color-input"; @@ -300,13 +293,11 @@ Glow.renderSettingsView = () => { nameColorText.type = "text"; nameColorText.maxLength = 7; nameColorText.value = - Glow.normalizeNameColor(Glow.state.settings?.name_color) || - ""; + Glow.normalizeNameColor(Glow.state.settings?.name_color) || ""; nameColorText.placeholder = "#7dd3fc"; const nameRow = document.createElement("div"); nameRow.className = "accent-picker-row"; - const previewSwatch = document.createElement("span"); previewSwatch.className = "accent-preview"; previewSwatch.style.background = @@ -322,7 +313,6 @@ Glow.renderSettingsView = () => { const normalized = Glow.normalizeNameColor(value); const finalColor = normalized || Glow.roleDefaultNameColor(Glow.state.currentUser?.role); - previewSwatch.style.background = finalColor; return finalColor; }; @@ -354,44 +344,108 @@ Glow.renderSettingsView = () => { nameRow.append(nameColorInput, nameColorText, previewSwatch); nameColorLabel.append(nameRow); - nameColorWrap.append(nameColorLabel, help, Glow.renderNameColorPreview( - Glow.state.settings?.name_color - ), resetNameColor); + nameColorWrap.append( + nameColorLabel, + help, + Glow.renderNameColorPreview(Glow.state.settings?.name_color), + resetNameColor + ); - appearance.append(aTitle, aText, themeRow, accentWrap, nameColorWrap); + appearance.append( + aTitle, + aText, + themeRow, + accentWrap, + backgroundWrap, + bannerWrap, + nameColorWrap + ); + + const presenceSection = document.createElement("section"); + presenceSection.className = "settings-section"; + const pTitle = document.createElement("h2"); + pTitle.textContent = "Presence & privacy"; + const pText = document.createElement("p"); + pText.textContent = "Control who can view your profile and last active time, and set your presence mode."; + + const profileVisibility = document.createElement("input"); + profileVisibility.className = "field"; + profileVisibility.value = Glow.state.settings?.profile_visibility || "public"; + profileVisibility.placeholder = "public | members | private"; + + const lastActiveVisibility = document.createElement("input"); + lastActiveVisibility.className = "field"; + lastActiveVisibility.value = Glow.state.settings?.last_active_visibility || "everyone"; + lastActiveVisibility.placeholder = "everyone | members | nobody"; + + const presenceMode = document.createElement("input"); + presenceMode.className = "field"; + presenceMode.value = Glow.state.settings?.presence_mode || Glow.state.currentUser?.presence_mode || "online"; + presenceMode.placeholder = "online | silent | focus | dnd"; + + profileVisibility.addEventListener("input", () => { + Glow.state.settings ||= {}; + Glow.state.settings.profile_visibility = profileVisibility.value.trim().toLowerCase(); + }); + lastActiveVisibility.addEventListener("input", () => { + Glow.state.settings ||= {}; + Glow.state.settings.last_active_visibility = lastActiveVisibility.value.trim().toLowerCase(); + }); + presenceMode.addEventListener("input", () => { + Glow.state.settings ||= {}; + Glow.state.settings.presence_mode = presenceMode.value.trim().toLowerCase(); + }); + + presenceSection.append( + pTitle, + pText, + (() => { + const label = document.createElement("label"); + label.className = "dialog-label"; + label.textContent = "Profile visibility"; + label.append(profileVisibility); + return label; + })(), + (() => { + const label = document.createElement("label"); + label.className = "dialog-label"; + label.textContent = "Last active visibility"; + label.append(lastActiveVisibility); + return label; + })(), + (() => { + const label = document.createElement("label"); + label.className = "dialog-label"; + label.textContent = "Presence mode"; + label.append(presenceMode); + return label; + })() + ); const cssSection = document.createElement("section"); cssSection.className = "settings-section"; - const cTitle = document.createElement("h2"); cTitle.textContent = "Custom CSS"; - const cText = document.createElement("p"); cText.textContent = "Optional CSS applied only for your account in this browser session and saved to your settings. \n ex: *,html,body{font-size:95%;text-transform:lowercase;}"; - const cssInput = document.createElement("textarea"); cssInput.className = "field settings-custom-css"; cssInput.placeholder = "/* Custom CSS */"; cssInput.value = Glow.state.settings?.custom_css || ""; - cssInput.addEventListener("input", () => { Glow.applyCustomCss(cssInput.value); Glow.state.settings ||= {}; Glow.state.settings.custom_css = cssInput.value; }); - cssSection.append(cTitle, cText, cssInput); const accountSection = document.createElement("section"); accountSection.className = "settings-section"; - const accountTitle = document.createElement("h2"); accountTitle.textContent = "Account"; - const accountText = document.createElement("p"); accountText.textContent = "Update your public profile and application preferences."; - const actions = document.createElement("div"); actions.className = "settings-actions"; @@ -420,11 +474,23 @@ Glow.renderSettingsView = () => { theme_mode: Glow.state.settings?.theme_mode || localStorage.getItem("glow_theme_mode") || - "dark" + "dark", + profile_background_color: + Glow.normalizeAccentColor(Glow.state.settings?.profile_background_color) || null, + profile_banner_color: + Glow.normalizeAccentColor(Glow.state.settings?.profile_banner_color) || null, + profile_visibility: + Glow.state.settings?.profile_visibility || "public", + last_active_visibility: + Glow.state.settings?.last_active_visibility || "everyone", + presence_mode: + Glow.state.settings?.presence_mode || "online" }; - const data = await Glow.apiUpdateMySettings(payload); Glow.state.settings = data.settings || payload; + if (Glow.state.currentUser) { + Glow.state.currentUser.presence_mode = Glow.state.settings.presence_mode || "online"; + } Glow.showToast("Settings saved."); Glow.renderSettingsView(); } catch (error) { @@ -446,6 +512,6 @@ Glow.renderSettingsView = () => { actions.append(editProfile, saveSettings, resetAccent); accountSection.append(accountTitle, accountText, actions); - card.append(appearance, cssSection, accountSection); + card.append(appearance, presenceSection, cssSection, accountSection); box.append(card); -}; +}; \ No newline at end of file