Mark Dark Text Light in Dark Mode latest version (currently v1.0.2)
← Back to User Scripts
Script Content
// ==UserScript==
// @name Zendesk: Mark Dark Text Light in Dark Mode
// @namespace https://www.timhilton.xyz/user-scripts
// @version 1.0.2
// @description Adjusts dark text to light colour in Zendesk tickets when dark mode is active.
// @author Tim Hilton using GitHub Copilot
// @match https://*.zendesk.com/agent/tickets/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const LOG_PREFIX = '[Zendesk: Mark Dark Text Light in Dark Mode]';
const LIGHT_TEXT_COLOR = 'rgb(216, 220, 222)';
const DARK_TEXT_CLASS = 'zendesk-dark-text-adjusted';
console.debug(`${LOG_PREFIX} Initializing script`);
// Inject CSS that only applies in dark mode
const style = document.createElement('style');
style.textContent = `
section[data-theme="dark"] .${DARK_TEXT_CLASS} {
color: ${LIGHT_TEXT_COLOR} !important;
}
`;
document.head.appendChild(style);
console.debug(`${LOG_PREFIX} Styles injected`);
function isTextDark(element) {
const color = window.getComputedStyle(element).color;
// Parse RGB values
const rgbMatch = color.match(/\d+/g);
if (!rgbMatch) {
return false; // If colour can't be parsed (e.g., transparent, named colours), assume not dark
}
const rgb = rgbMatch.map(Number);
// Calculate relative luminance (WCAG formula)
const [r, g, b] = rgb.map(val => {
val = val / 255;
return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);
});
const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
// Luminance threshold - adjust as needed (0.5 is middle grey)
return luminance < 0.5;
}
function adjustDarkText() {
console.debug(`${LOG_PREFIX} Adjusting dark text`);
// Find all comment elements (in any theme)
const commentElements = document.querySelectorAll('[data-test-id="omni-log-omni-to-ag-comment"]');
console.debug(`${LOG_PREFIX} Found ${commentElements.length} comment elements`);
let adjustedCount = 0;
commentElements.forEach(commentElement => {
// Get text-containing elements within the comment
const textElements = commentElement.querySelectorAll('p, span, div, h1, h2, h3, h4, h5, h6, li, td, th, strong, em, b, i, font');
textElements.forEach(element => {
// Only process elements that have text content and are visible
if (element.textContent.trim() && element.offsetParent !== null) {
// Check if element already has the class to avoid redundant checks
if (!element.classList.contains(DARK_TEXT_CLASS)) {
if (isTextDark(element)) {
element.classList.add(DARK_TEXT_CLASS);
adjustedCount++;
}
}
}
});
});
if (adjustedCount > 0) {
console.log(`${LOG_PREFIX} ✅ Adjusted ${adjustedCount} dark text elements`);
}
}
// Use MutationObserver to handle dynamic content and navigation
let timeoutId = null;
let observerFireCount = 0;
const observer = new MutationObserver(() => {
observerFireCount++;
console.debug(`${LOG_PREFIX} MutationObserver fired (count: ${observerFireCount})`);
// Debounce to avoid excessive executions
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
adjustDarkText();
}, 100); // Wait 100ms after last mutation before processing
});
console.debug(`${LOG_PREFIX} Setting up MutationObserver`);
observer.observe(document.body, {
childList: true,
subtree: true
});
// Initial run
console.debug(`${LOG_PREFIX} Running initial adjustment`);
adjustDarkText();
console.log(`${LOG_PREFIX} 🎉 Script initialized successfully`);
})();