2026-08-26 16:04:48 -04:00
|
|
|
(function () {
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
|
|
var popoverEl = null;
|
|
|
|
|
var currentSubreddit = null;
|
|
|
|
|
var currentAnchor = null;
|
|
|
|
|
var editState = { light: null, dark: null };
|
|
|
|
|
var selectedMode = "light";
|
2026-08-26 16:11:24 -04:00
|
|
|
var dirtyModes = { light: false, dark: false };
|
|
|
|
|
var hadOverride = { light: false, dark: false };
|
2026-08-26 17:14:02 -04:00
|
|
|
var picker = null;
|
|
|
|
|
var activeProp = null;
|
2026-08-26 16:04:48 -04:00
|
|
|
|
|
|
|
|
var els = {};
|
|
|
|
|
|
|
|
|
|
function getHelpers() {
|
|
|
|
|
return {
|
|
|
|
|
isDarkMode: window.RedditTweaks.badgeTweak.isDarkMode,
|
|
|
|
|
getColorPrefix: window.RedditTweaks.badgeTweak.getColorPrefix,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function hexValid(val) {
|
|
|
|
|
return /^#[0-9a-f]{6}$/i.test(val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function colorToHex(val) {
|
|
|
|
|
if (!val) return "#ffffff";
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createPopover() {
|
|
|
|
|
var el = document.createElement("div");
|
|
|
|
|
el.className = "rt-color-popover";
|
|
|
|
|
|
|
|
|
|
el.innerHTML = [
|
|
|
|
|
'<div class="rt-popover-header">',
|
|
|
|
|
' <span class="rt-popover-title"></span>',
|
|
|
|
|
' <button class="rt-popover-close" type="button">\u00d7</button>',
|
|
|
|
|
"</div>",
|
|
|
|
|
'<div class="rt-popover-mode">',
|
|
|
|
|
' <select class="rt-popover-mode-select">',
|
|
|
|
|
' <option value="light">Light</option>',
|
|
|
|
|
' <option value="dark">Dark</option>',
|
|
|
|
|
" </select>",
|
|
|
|
|
"</div>",
|
|
|
|
|
'<div class="rt-popover-body">',
|
|
|
|
|
' <div class="rt-popover-row" data-prop="bg">',
|
|
|
|
|
' <span class="rt-popover-row-label">Background</span>',
|
|
|
|
|
' <div class="rt-popover-row-inputs">',
|
2026-08-26 17:14:02 -04:00
|
|
|
' <div class="rt-color-swatch"></div>',
|
2026-08-26 16:04:48 -04:00
|
|
|
' <input type="text" class="rt-color-hex" maxlength="7">',
|
|
|
|
|
" </div>",
|
|
|
|
|
" </div>",
|
|
|
|
|
' <div class="rt-popover-row" data-prop="border">',
|
|
|
|
|
' <span class="rt-popover-row-label">Border</span>',
|
|
|
|
|
' <div class="rt-popover-row-inputs">',
|
2026-08-26 17:14:02 -04:00
|
|
|
' <div class="rt-color-swatch"></div>',
|
2026-08-26 16:04:48 -04:00
|
|
|
' <input type="text" class="rt-color-hex" maxlength="7">',
|
|
|
|
|
" </div>",
|
|
|
|
|
" </div>",
|
|
|
|
|
' <div class="rt-popover-row" data-prop="text">',
|
|
|
|
|
' <span class="rt-popover-row-label">Text</span>',
|
|
|
|
|
' <div class="rt-popover-row-inputs">',
|
2026-08-26 17:14:02 -04:00
|
|
|
' <div class="rt-color-swatch"></div>',
|
2026-08-26 16:04:48 -04:00
|
|
|
' <input type="text" class="rt-color-hex" maxlength="7">',
|
|
|
|
|
" </div>",
|
|
|
|
|
" </div>",
|
|
|
|
|
"</div>",
|
|
|
|
|
'<div class="rt-popover-preview">',
|
|
|
|
|
' <span class="rt-badge rt-badge--subreddit rt-popover-preview-badge" style="padding-right:6px"></span>',
|
|
|
|
|
"</div>",
|
|
|
|
|
'<div class="rt-popover-footer">',
|
|
|
|
|
' <button class="rt-btn-reset" type="button">Reset Default</button>',
|
|
|
|
|
' <div class="rt-popover-footer-right">',
|
|
|
|
|
' <button class="rt-btn-cancel" type="button">Cancel</button>',
|
|
|
|
|
' <button class="rt-btn-save" type="button">Save</button>',
|
|
|
|
|
" </div>",
|
|
|
|
|
"</div>",
|
|
|
|
|
].join("\n");
|
|
|
|
|
|
|
|
|
|
document.body.appendChild(el);
|
|
|
|
|
popoverEl = el;
|
|
|
|
|
|
|
|
|
|
els.title = el.querySelector(".rt-popover-title");
|
|
|
|
|
els.closeBtn = el.querySelector(".rt-popover-close");
|
|
|
|
|
els.modeSelect = el.querySelector(".rt-popover-mode-select");
|
|
|
|
|
els.preview = el.querySelector(".rt-popover-preview-badge");
|
|
|
|
|
els.saveBtn = el.querySelector(".rt-btn-save");
|
|
|
|
|
els.cancelBtn = el.querySelector(".rt-btn-cancel");
|
|
|
|
|
els.resetBtn = el.querySelector(".rt-btn-reset");
|
|
|
|
|
|
|
|
|
|
els.rows = {};
|
|
|
|
|
var rows = el.querySelectorAll(".rt-popover-row");
|
|
|
|
|
for (var i = 0; i < rows.length; i++) {
|
|
|
|
|
var row = rows[i];
|
|
|
|
|
var prop = row.getAttribute("data-prop");
|
|
|
|
|
els.rows[prop] = {
|
|
|
|
|
swatch: row.querySelector(".rt-color-swatch"),
|
|
|
|
|
hex: row.querySelector(".rt-color-hex"),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 17:14:02 -04:00
|
|
|
picker = window.RedditTweaks.colorPicker.create();
|
|
|
|
|
var previewSection = el.querySelector(".rt-popover-preview");
|
|
|
|
|
el.insertBefore(picker.el, previewSection);
|
|
|
|
|
|
2026-08-26 16:04:48 -04:00
|
|
|
els.closeBtn.addEventListener("click", close);
|
|
|
|
|
els.cancelBtn.addEventListener("click", close);
|
|
|
|
|
els.saveBtn.addEventListener("click", save);
|
|
|
|
|
els.resetBtn.addEventListener("click", resetToDefault);
|
|
|
|
|
|
|
|
|
|
els.modeSelect.addEventListener("change", function () {
|
2026-08-26 16:11:24 -04:00
|
|
|
markModeDirty(selectedMode);
|
2026-08-26 16:04:48 -04:00
|
|
|
storeCurrentEdits();
|
|
|
|
|
selectedMode = els.modeSelect.value;
|
2026-08-26 17:14:02 -04:00
|
|
|
closePicker();
|
2026-08-26 16:04:48 -04:00
|
|
|
loadModeIntoInputs();
|
|
|
|
|
updatePreview();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var props = ["bg", "border", "text"];
|
|
|
|
|
for (var p = 0; p < props.length; p++) {
|
|
|
|
|
(function (prop) {
|
|
|
|
|
var row = els.rows[prop];
|
2026-08-26 17:14:02 -04:00
|
|
|
row.swatch.addEventListener("click", function () {
|
|
|
|
|
onSwatchClick(prop);
|
2026-08-26 16:04:48 -04:00
|
|
|
});
|
|
|
|
|
row.hex.addEventListener("input", function () {
|
2026-08-26 16:11:24 -04:00
|
|
|
markModeDirty(selectedMode);
|
2026-08-26 16:04:48 -04:00
|
|
|
if (hexValid(row.hex.value)) {
|
2026-08-26 17:14:02 -04:00
|
|
|
row.swatch.style.backgroundColor = row.hex.value;
|
2026-08-26 16:04:48 -04:00
|
|
|
row.hex.classList.remove("rt-input-error");
|
2026-08-26 17:14:02 -04:00
|
|
|
if (picker.isOpen() && activeProp === prop) {
|
|
|
|
|
picker.setColor(row.hex.value);
|
|
|
|
|
}
|
2026-08-26 16:04:48 -04:00
|
|
|
updatePreview();
|
|
|
|
|
} else {
|
|
|
|
|
row.hex.classList.add("rt-input-error");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
})(props[p]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
document.addEventListener("mousedown", onDocumentMouseDown, true);
|
|
|
|
|
document.addEventListener("keydown", onDocumentKeyDown, true);
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 17:14:02 -04:00
|
|
|
function onSwatchClick(prop) {
|
|
|
|
|
if (picker.isOpen() && activeProp === prop) {
|
|
|
|
|
closePicker();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
closePicker();
|
|
|
|
|
activeProp = prop;
|
|
|
|
|
var row = els.rows[prop];
|
|
|
|
|
picker.open(row.hex.value, function (hex) {
|
|
|
|
|
markModeDirty(selectedMode);
|
|
|
|
|
row.swatch.style.backgroundColor = hex;
|
|
|
|
|
row.hex.value = hex;
|
|
|
|
|
row.hex.classList.remove("rt-input-error");
|
|
|
|
|
updatePreview();
|
|
|
|
|
});
|
2026-08-26 17:20:37 -04:00
|
|
|
if (currentAnchor) positionPopover(currentAnchor);
|
2026-08-26 17:14:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function closePicker() {
|
|
|
|
|
if (picker && picker.isOpen()) picker.close();
|
|
|
|
|
activeProp = null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 16:04:48 -04:00
|
|
|
function onDocumentMouseDown(e) {
|
|
|
|
|
if (!popoverEl || !popoverEl.classList.contains("rt-popover-visible")) return;
|
|
|
|
|
if (popoverEl.contains(e.target)) return;
|
|
|
|
|
close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onDocumentKeyDown(e) {
|
|
|
|
|
if (e.key === "Escape" && popoverEl && popoverEl.classList.contains("rt-popover-visible")) {
|
|
|
|
|
close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getDefaultsForMode(settings, mode) {
|
|
|
|
|
return {
|
|
|
|
|
bg: settings[mode + ".subredditBgColor"],
|
|
|
|
|
border: settings[mode + ".subredditBorderColor"],
|
|
|
|
|
text: settings[mode + ".subredditTextColor"],
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getColorsForMode(settings, subredditName, mode) {
|
|
|
|
|
var entry = settings.subredditColors[subredditName];
|
|
|
|
|
if (entry && entry[mode]) {
|
|
|
|
|
return { bg: entry[mode].bg, border: entry[mode].border, text: entry[mode].text };
|
|
|
|
|
}
|
|
|
|
|
return getDefaultsForMode(settings, mode);
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 16:11:24 -04:00
|
|
|
function markModeDirty(mode) {
|
|
|
|
|
dirtyModes[mode] = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resetTracking() {
|
|
|
|
|
dirtyModes = { light: false, dark: false };
|
|
|
|
|
hadOverride = { light: false, dark: false };
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 16:04:48 -04:00
|
|
|
function storeCurrentEdits() {
|
|
|
|
|
editState[selectedMode] = {
|
2026-08-26 17:14:02 -04:00
|
|
|
bg: els.rows.bg.hex.value,
|
|
|
|
|
border: els.rows.border.hex.value,
|
|
|
|
|
text: els.rows.text.hex.value,
|
2026-08-26 16:04:48 -04:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadModeIntoInputs() {
|
|
|
|
|
var colors = editState[selectedMode];
|
|
|
|
|
var props = ["bg", "border", "text"];
|
|
|
|
|
for (var i = 0; i < props.length; i++) {
|
|
|
|
|
var prop = props[i];
|
|
|
|
|
var val = colorToHex(colors[prop]);
|
2026-08-26 17:14:02 -04:00
|
|
|
els.rows[prop].swatch.style.backgroundColor = val;
|
2026-08-26 16:04:48 -04:00
|
|
|
els.rows[prop].hex.value = val;
|
|
|
|
|
els.rows[prop].hex.classList.remove("rt-input-error");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updatePreview() {
|
2026-08-26 17:14:02 -04:00
|
|
|
var bg = els.rows.bg.hex.value;
|
|
|
|
|
var border = els.rows.border.hex.value;
|
|
|
|
|
var text = els.rows.text.hex.value;
|
2026-08-26 16:04:48 -04:00
|
|
|
els.preview.style.background = bg;
|
|
|
|
|
els.preview.style.borderColor = border;
|
|
|
|
|
els.preview.style.color = text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function positionPopover(anchorEl) {
|
|
|
|
|
var rect = anchorEl.getBoundingClientRect();
|
|
|
|
|
var gap = 6;
|
|
|
|
|
|
|
|
|
|
popoverEl.style.visibility = "hidden";
|
|
|
|
|
popoverEl.classList.add("rt-popover-visible");
|
|
|
|
|
|
|
|
|
|
var popRect = popoverEl.getBoundingClientRect();
|
|
|
|
|
var top = rect.bottom + window.scrollY + gap;
|
|
|
|
|
var left = rect.left + window.scrollX;
|
|
|
|
|
|
|
|
|
|
if (rect.bottom + gap + popRect.height > window.innerHeight) {
|
|
|
|
|
top = rect.top + window.scrollY - popRect.height - gap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var maxLeft = document.documentElement.scrollWidth - popRect.width - 8;
|
|
|
|
|
if (left > maxLeft) left = maxLeft;
|
|
|
|
|
if (left < 8) left = 8;
|
|
|
|
|
|
|
|
|
|
popoverEl.style.top = top + "px";
|
|
|
|
|
popoverEl.style.left = left + "px";
|
|
|
|
|
popoverEl.style.visibility = "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function applyDarkModeToPopover(settings) {
|
|
|
|
|
var helpers = getHelpers();
|
|
|
|
|
if (helpers.isDarkMode(settings)) {
|
|
|
|
|
popoverEl.classList.add("rt-dark");
|
|
|
|
|
} else {
|
|
|
|
|
popoverEl.classList.remove("rt-dark");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function open(badgeEl, subredditName, settings) {
|
|
|
|
|
if (!popoverEl) createPopover();
|
|
|
|
|
|
|
|
|
|
if (currentSubreddit === subredditName && popoverEl.classList.contains("rt-popover-visible")) {
|
|
|
|
|
close();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
currentSubreddit = subredditName;
|
|
|
|
|
currentAnchor = badgeEl;
|
|
|
|
|
|
2026-08-26 16:11:24 -04:00
|
|
|
resetTracking();
|
|
|
|
|
var existingEntry = settings.subredditColors[subredditName];
|
|
|
|
|
hadOverride.light = !!(existingEntry && existingEntry.light);
|
|
|
|
|
hadOverride.dark = !!(existingEntry && existingEntry.dark);
|
|
|
|
|
|
2026-08-26 16:04:48 -04:00
|
|
|
var helpers = getHelpers();
|
|
|
|
|
selectedMode = helpers.getColorPrefix(settings);
|
|
|
|
|
|
|
|
|
|
editState.light = getColorsForMode(settings, subredditName, "light");
|
|
|
|
|
editState.dark = getColorsForMode(settings, subredditName, "dark");
|
|
|
|
|
|
|
|
|
|
els.title.textContent = "r/" + subredditName;
|
|
|
|
|
els.modeSelect.value = selectedMode;
|
|
|
|
|
els.preview.textContent = "r/" + subredditName;
|
|
|
|
|
|
2026-08-26 17:14:02 -04:00
|
|
|
closePicker();
|
2026-08-26 16:04:48 -04:00
|
|
|
applyDarkModeToPopover(settings);
|
|
|
|
|
loadModeIntoInputs();
|
|
|
|
|
updatePreview();
|
|
|
|
|
positionPopover(badgeEl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function close() {
|
|
|
|
|
if (!popoverEl) return;
|
2026-08-26 17:14:02 -04:00
|
|
|
closePicker();
|
2026-08-26 16:04:48 -04:00
|
|
|
popoverEl.classList.remove("rt-popover-visible");
|
|
|
|
|
currentSubreddit = null;
|
|
|
|
|
currentAnchor = null;
|
|
|
|
|
editState = { light: null, dark: null };
|
2026-08-26 16:11:24 -04:00
|
|
|
resetTracking();
|
2026-08-26 16:04:48 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function save() {
|
|
|
|
|
if (!currentSubreddit) return;
|
|
|
|
|
|
|
|
|
|
storeCurrentEdits();
|
|
|
|
|
|
|
|
|
|
var settings = await window.RedditTweaks.loadSettings();
|
|
|
|
|
var entry = settings.subredditColors[currentSubreddit] || {};
|
|
|
|
|
|
2026-08-26 16:11:24 -04:00
|
|
|
if (dirtyModes.light || hadOverride.light) {
|
|
|
|
|
entry.light = editState.light;
|
|
|
|
|
}
|
|
|
|
|
if (dirtyModes.dark || hadOverride.dark) {
|
|
|
|
|
entry.dark = editState.dark;
|
|
|
|
|
}
|
2026-08-26 16:04:48 -04:00
|
|
|
|
2026-08-26 16:11:24 -04:00
|
|
|
if (!entry.light && !entry.dark) {
|
|
|
|
|
delete settings.subredditColors[currentSubreddit];
|
|
|
|
|
} else {
|
|
|
|
|
settings.subredditColors[currentSubreddit] = entry;
|
|
|
|
|
}
|
2026-08-26 16:04:48 -04:00
|
|
|
await window.RedditTweaks.saveSettings(settings);
|
|
|
|
|
close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function resetToDefault() {
|
|
|
|
|
if (!currentSubreddit) return;
|
|
|
|
|
|
|
|
|
|
var settings = await window.RedditTweaks.loadSettings();
|
|
|
|
|
delete settings.subredditColors[currentSubreddit];
|
|
|
|
|
await window.RedditTweaks.saveSettings(settings);
|
|
|
|
|
|
2026-08-26 16:11:24 -04:00
|
|
|
resetTracking();
|
2026-08-26 16:04:48 -04:00
|
|
|
editState.light = getDefaultsForMode(settings, "light");
|
|
|
|
|
editState.dark = getDefaultsForMode(settings, "dark");
|
2026-08-26 17:14:02 -04:00
|
|
|
closePicker();
|
2026-08-26 16:04:48 -04:00
|
|
|
loadModeIntoInputs();
|
|
|
|
|
updatePreview();
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 16:11:24 -04:00
|
|
|
function refreshTheme(settings) {
|
|
|
|
|
if (!popoverEl || !popoverEl.classList.contains("rt-popover-visible")) return;
|
|
|
|
|
applyDarkModeToPopover(settings);
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 16:04:48 -04:00
|
|
|
window.RedditTweaks = window.RedditTweaks || {};
|
|
|
|
|
window.RedditTweaks.colorPopover = {
|
|
|
|
|
open: open,
|
|
|
|
|
close: close,
|
2026-08-26 16:11:24 -04:00
|
|
|
refreshTheme: refreshTheme,
|
2026-08-26 16:04:48 -04:00
|
|
|
};
|
|
|
|
|
})();
|