(function () { const { CSS_CLASSES, GLOBAL_ENV, IS_MOBILE } = window; const BUTTON_ID = "rscord-settings-btn"; const CONTENT_CONTAINER_ID = "custom-content"; const SWITCH_CONTAINER_ID = "switch-container"; const CUSTOM_CSS_ID = "custom-css"; const CUSTOM_CSS_INPUT_ID = "custom-css-input"; const STATUS_COLOR_MAP = { "hsl(38, calc(var(--saturation-factor, 1) * 95.7%), 54.1%)": "#FAA61A", // Idle (yellow) "hsl(0, calc(var(--saturation-factor, 1) * 100%), 71.4%)": "#F04747", // DND (red) "hsl(235, calc(var(--saturation-factor, 1) * 85.6%), 64.7%)": "#7289DA", // Away (blue) "hsl(0, calc(var(--saturation-factor, 1) * 0%), 47.5%)": "#747F8D", // Offline (gray) "hsl(139, calc(var(--saturation-factor, 1) * 47.3%), 43.9%)": "#43B581", // Online (green) }; const TAB_CONTENT = `

RSCord Settings

Options
Custom CSS
`; function addJoinDates() { if (document.querySelector("[data-join-date]")) return; const nitroBadge = document.querySelector(CSS_CLASSES.nitroBadge); if (!nitroBadge) return; const date = nitroBadge.getAttribute("aria-label"); if (date) { const formattedDate = date.replace("Subscriber since ", ""); if (!formattedDate) return; } const isCompact = !!document.querySelector("h3.bodyTitle-2Az3VQ"); const h3Elements = document.querySelectorAll("h3"); let anchor = null; for (let i = 0; i < h3Elements.length; i++) { const h = h3Elements[i]; if ((h.className.indexOf("bodyTitle") > -1 && h.textContent.indexOf("Role") > -1) || h.textContent.trim() === "Note") { anchor = h; break; } } if (!anchor) return; const infoText = document.createElement("div"); infoText.className = isCompact ? CSS_CLASSES.userInfoTitle : CSS_CLASSES.userInfoSectionHeader; infoText.textContent = "Member since"; infoText.style.color = "var(--header-secondary)"; infoText.dataset.joinDate = "title"; const dateText = document.createElement("div"); dateText.className = isCompact ? CSS_CLASSES.userInfoBody : CSS_CLASSES.userInfoText; dateText.textContent = formattedDate; dateText.dataset.joinDate = "value"; if (isCompact) { let infoSection = anchor.previousElementSibling; const isNewSection = !infoSection; if (isNewSection) { infoSection = document.createElement("div"); infoSection.className = CSS_CLASSES.userInfoSection; anchor.parentNode.insertBefore(infoSection, anchor); } infoText.style.marginTop = isNewSection ? "0px" : "10px"; infoSection.appendChild(infoText); infoSection.appendChild(dateText); } else { anchor.parentNode.insertBefore(infoText, anchor); anchor.parentNode.insertBefore(dateText, anchor); } } async function addSwitches(container) { const config = loadConfig(); const pushRegistered = await isPushRegistered(); container.appendChild(createSwitch( "Push Notifications", "Sends you notifications even when you close the app", "push-notifications", pushRegistered, async (checked) => { const publicKey = GLOBAL_ENV.VAPID_KEY; if (!publicKey) return false; try { await (checked ? registerPush(publicKey) : unregisterPush()); return true; } catch(error) { alert("Failed to register notifications: ", error.message) return false; } } )); container.appendChild(createSwitch( "Revert Status Icons", "Revert the colorblind status icons added in 2019", "revert-status", config.revertStatusIcons, (checked) => saveConfig({ revertStatusIcons: checked }) )); } function revertStatusIcons() { const statusRects = document.querySelectorAll("rect[fill^='hsl']"); for (const rect of statusRects) { const fill = rect.getAttribute("fill"); if (STATUS_COLOR_MAP[fill]) { rect.setAttribute("fill", STATUS_COLOR_MAP[fill]); } const maskRef = rect.getAttribute("mask"); if (!maskRef) continue; const maskMatch = maskRef.match(/#([^)]+)/); const maskId = maskMatch ? maskMatch[1] : null; if (!maskId) continue; const mask = document.getElementById(maskId); if (!mask) continue; mask.querySelectorAll("[fill='black']").forEach(el => el.remove()); } } function applyCustomCss() { const { customCss } = loadConfig(); let style = document.getElementById(CUSTOM_CSS_ID); if (!style) { style = document.createElement("style"); style.id = CUSTOM_CSS_ID; document.head.appendChild(style); } style.textContent = customCss; } function setupCssInput(textarea) { if (!textarea) return; const config = loadConfig(); textarea.value = config.customCss; const style = document.getElementById(CUSTOM_CSS_ID); if (!style) return; textarea.addEventListener("input", () => { style.textContent = textarea.value; saveConfig({ customCss: textarea.value }); }); } function addSettingsTab() { const advancedTab = document.querySelector(`.${CSS_CLASSES.tabItem}[aria-controls="advanced-tab"]`); if (!advancedTab) return; if (document.getElementById(BUTTON_ID)) return; const settingsBtn = document.createElement("div"); settingsBtn.id = BUTTON_ID; settingsBtn.className = advancedTab.className; settingsBtn.role = "tab"; settingsBtn.tabIndex = -1; settingsBtn.ariaSelected = "false"; settingsBtn.textContent = "RSCord Settings"; settingsBtn.addEventListener("click", () => { const tabs = settingsBtn.parentElement.querySelectorAll("[role='tab']"); tabs.forEach(tab => tab.classList.remove(CSS_CLASSES.selected)); tabs.forEach(tab => tab.setAttribute("aria-selected", "false")); settingsBtn.classList.add(CSS_CLASSES.selected); settingsBtn.setAttribute("aria-selected", "true"); let customContent = document.getElementById(CONTENT_CONTAINER_ID); if (!customContent) { customContent = document.createElement("div"); customContent.id = CONTENT_CONTAINER_ID; customContent.innerHTML = TAB_CONTENT; const switchContainer = customContent.querySelector(`#${SWITCH_CONTAINER_ID}`); addSwitches(switchContainer); document.querySelector(`.${CSS_CLASSES.contentColumn}`).appendChild(customContent); const cssInput = document.getElementById(CUSTOM_CSS_INPUT_ID); setupCssInput(cssInput); } const contentColumn = document.querySelector(`.${CSS_CLASSES.contentColumn}`); Array.from(contentColumn.children).forEach(child => { if (child.id !== CONTENT_CONTAINER_ID) child.style.display = "none"; }); customContent.style.display = "block"; }); advancedTab.insertAdjacentElement("afterend", settingsBtn); return true; } const observer = new MutationObserver(() => { if (document.querySelector(`.${CSS_CLASSES.settingsSidebar}`)) addSettingsTab(); if (loadConfig().revertStatusIcons) revertStatusIcons(); addJoinDates(); }); observer.observe(document.body, { childList: true, subtree: true }); applyCustomCss(); document.body.addEventListener("click", (e) => { const clickedHamburger = e.target.closest(`.${CSS_CLASSES.hamburger}`) if (clickedHamburger && IS_MOBILE) { const settingsRegion = document.querySelector(`.${CSS_CLASSES.settingsRegion}`) settingsRegion.classList.remove(CSS_CLASSES.hidden); const contentRegion = document.querySelector(`.${CSS_CLASSES.contentRegion}`) contentRegion.classList.add(CSS_CLASSES.hidden); } const clickedTab = e.target.closest("[role='tab']"); if (!clickedTab) return; const allTabs = document.querySelectorAll("[role='tab']"); allTabs.forEach(tab => tab.classList.remove(CSS_CLASSES.selected)); allTabs.forEach(tab => tab.setAttribute("aria-selected", "false")); clickedTab.classList.add(CSS_CLASSES.selected); clickedTab.setAttribute("aria-selected", "true"); const contentColumn = document.querySelector(`.${CSS_CLASSES.contentColumn}`); if (!contentColumn) return; if (clickedTab.id === BUTTON_ID) { Array.from(contentColumn.children).forEach(child => { if (child.id === CONTENT_CONTAINER_ID) { child.style.display = "block"; } else { child.style.display = "none"; } if (IS_MOBILE) { const settingsRegion = document.querySelector(`.${CSS_CLASSES.settingsRegion}`) settingsRegion.classList.add(CSS_CLASSES.hidden); const contentRegion = document.querySelector(`.${CSS_CLASSES.contentRegion}`) contentRegion.classList.remove(CSS_CLASSES.hidden); } }); } else { Array.from(contentColumn.children).forEach(child => { if (child.id !== CONTENT_CONTAINER_ID) child.style.display = ""; else child.style.display = "none"; }); } }); })();