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`);
})();