WebMD Retro Theme

Customizable theme for Web MiniDisc Pro, configuration can be found at the bottom of the settings dialog

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name         WebMD Retro Theme
// @namespace    http://tampermonkey.net/
// @version      2024-11-15
// @license MIT
// @description  Customizable theme for Web MiniDisc Pro, configuration can be found at the bottom of the settings dialog
// @author       Pablo Maciá
// @match        https://web.minidisc.wiki/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const MIN_BRIGHTNESS = 2;
    const MAX_BRIGHTNESS = 10;

    const themes = {
        white:   ['#F0F0F0', '#AAAAAA', '#555555', '#000000'],
        gray:    ['#7F7F7F', '#555555', '#2A2A2A', '#000000'],
        red:     ['#FF0000', '#AA0000', '#550000', '#000000'],
        orange:  ['#FF7F00', '#AA5500', '#552A00', '#000000'],
        yellow:  ['#FFFF00', '#AAAA00', '#555500', '#000000'],
        leaf:    ['#7FFF00', '#55AA00', '#2A5500', '#000000'],
        green:   ['#00FF00', '#00AA00', '#005500', '#000000'],
        aqua:    ['#00FF7F', '#00AA55', '#00552A', '#000000'],
        cyan:    ['#00FFFF', '#00AAAA', '#005555', '#000000'],
        azure:   ['#007FFF', '#0055AA', '#002A55', '#000000'],
        blue:    ['#0000FF', '#0000AA', '#000055', '#000000'],
        purple:  ['#7F00FF', '#5500AA', '#2A0055', '#000000'],
        pink:    ['#FF007F', '#AA0055', '#55002A', '#000000'],
        magenta: ['#FF00FF', '#AA00AA', '#550055', '#000000'],
        DMG:     ['#8cad28', '#6c9421', '#426b29', '#214231'],
    };

    const filters = {
        none: 'none',
        crt1: 'crt1',
        crt2: 'crt2',
        lcd: 'lcd'
    };

    const settings = {
        enabled: true,
        darkMode: true,
        theme: 'white',
        filter: filters.none,
        brightness: 10,
    };

    let themeLoaded = false;
    let activeTheme;
    let themeStyle;
    let pageStyle;
    let screenFilter;
    let screenBrightnessFilter;

    function readSetting(key, defaultValue) {
        return localStorage[key] === undefined ? defaultValue : localStorage[key];
    }

    function loadSettings() {
        settings.enabled = readSetting('rt_enabled', settings.enabled);
        settings.darkMode = readSetting('rt_dark_mode', settings.darkMode);
        settings.theme = readSetting('rt_theme', settings.theme);
        settings.filter = readSetting('rt_filter', settings.filter);
        settings.brightness = readSetting('rt_brightness', settings.brightness);
        saveSettings();
    }

    function saveSettings() {
        localStorage.rt_enabled = settings.enabled;
        localStorage.rt_dark_mode = settings.darkMode;
        localStorage.rt_theme = settings.theme;
        localStorage.rt_filter = settings.filter;
        localStorage.rt_brightness = settings.brightness;
    }

    function setEnabledSetting(value) {
        settings.enabled = value;
        saveSettings();
    }

    function setDarkModeSetting(value) {
        settings.darkMode = value;
        saveSettings();
    }

    function setThemeSetting(value) {
        settings.theme = value;
        saveSettings();
    }

    function setFilterSetting(value) {
        settings.filter = value;
        saveSettings();
    }

    function setBrightnessSetting(value) {
        settings.brightness = value;
        saveSettings();
        setBrightness(settings.brightness);
    }

    function init() {
        loadSettings();
        initEvents();
        if (settings.enabled === 'true') {
            insertStyles();
            insertScreenModifiers();
            themeLoaded = true;
        }
    }

    function initEvents() {
        initOnSettingsDialogOpenEvent();
    }

    function initOnSettingsDialogOpenEvent() {
        const body = document.querySelector('body');
        const config = { childList: true };
        const callback = (mutationsList, observer) => {
            let settingsDialog = null;

            for(const mutation of mutationsList) {
                if (mutation.type === 'childList') {
                    for (let i = 0; i < mutation.addedNodes.length; i++) {
                        const node = mutation.addedNodes[i];
                        if (node.classList.contains('MuiDialog-root') && node.querySelector('h2').innerText == 'Settings') {
                            settingsDialog = node;
                            break;
                        }
                    }
                }
            }

            if (settingsDialog) {
                insertThemeSettingsToDialog(settingsDialog);
            }
        };
        const observer = new MutationObserver(callback);
        observer.observe(body, config);
    }

    function insertThemeSettingsToDialog(dialog) {
        const content = dialog.querySelector('.MuiDialogContent-root');
        console.log(content);

        const sectionLabel = document.createElement('p');
        sectionLabel.classList.add('MuiTypography-root', 'MuiDialogContentText-root', 'MuiTypography-body1', 'css-1rddy68-header');
        sectionLabel.innerText = 'WebMD Retro Theme (Reload to apply changes)';
        content.appendChild(sectionLabel);

        const enabledLabel = document.createElement('label');
        enabledLabel.classList.add('MuiFormControlLabel-root', 'MuiFormControlLabel-labelPlacementStart', 'css-1q5bp8s-propertyBox');
        content.appendChild(enabledLabel);

        const enabledCb = document.createElement('input');
        enabledCb.id = 'rt_enabled';
        enabledCb.checked = settings.enabled === 'true';
        enabledCb.type = 'checkbox';
        enabledCb.addEventListener('change', () => { setEnabledSetting(enabledCb.checked); });
        enabledLabel.appendChild(enabledCb);

        const enabledLabelText = document.createElement('span');
        enabledLabelText.classList.add('MuiTypography-root', 'MuiTypography-body1', 'MuiFormControlLabel-label', 'css-1fmsrhg-spread');
        enabledLabelText.innerText = 'Enable retro theme';
        enabledLabel.appendChild(enabledLabelText);

        const darkModeLabel = document.createElement('label');
        darkModeLabel.classList.add('MuiFormControlLabel-root', 'MuiFormControlLabel-labelPlacementStart', 'css-1q5bp8s-propertyBox');
        content.appendChild(darkModeLabel);

        const darkModeCb = document.createElement('input');
        darkModeCb.id = 'rt_dark_mode';
        darkModeCb.type = 'checkbox';
        darkModeCb.checked = settings.darkMode === 'true';
        darkModeCb.addEventListener('change', () => { setDarkModeSetting(darkModeCb.checked); });
        darkModeLabel.appendChild(darkModeCb);

        const darkModeLabelText = document.createElement('span');
        darkModeLabelText.classList.add('MuiTypography-root', 'MuiTypography-body1', 'MuiFormControlLabel-label', 'css-1fmsrhg-spread');
        darkModeLabelText.innerText = 'Dark mode';
        darkModeLabel.appendChild(darkModeLabelText);

        const themeLabel = document.createElement('label');
        themeLabel.classList.add('MuiFormControlLabel-root', 'MuiFormControlLabel-labelPlacementStart', 'css-1q5bp8s-propertyBox');
        content.appendChild(themeLabel);

        const themeSelect = document.createElement('select');
        themeSelect.id = 'rt_theme';
        themeSelect.addEventListener('change', () => { setThemeSetting(themeSelect.value); });
        themeLabel.appendChild(themeSelect);

        Object.keys(themes).forEach(themeName => {
            const themeOption = document.createElement('option');
            themeOption.innerText = themeName;
            themeOption.value = themeName;
            if (themeName === settings.theme) {
                themeOption.selected = true;
            }
            themeSelect.appendChild(themeOption);
        });

        const themeLabelText = document.createElement('span');
        themeLabelText.classList.add('MuiTypography-root', 'MuiTypography-body1', 'MuiFormControlLabel-label', 'css-1fmsrhg-spread');
        themeLabelText.innerText = 'Theme';
        themeLabel.appendChild(themeLabelText);

        const filterLabel = document.createElement('label');
        filterLabel.classList.add('MuiFormControlLabel-root', 'MuiFormControlLabel-labelPlacementStart', 'css-1q5bp8s-propertyBox');
        content.appendChild(filterLabel);

        const filterSelect = document.createElement('select');
        filterSelect.id = 'rt_filter';
        filterSelect.addEventListener('change', () => { setFilterSetting(filterSelect.value); });
        filterLabel.appendChild(filterSelect);

        Object.keys(filters).forEach(filterName => {
            const filterOption = document.createElement('option');
            filterOption.innerText = filterName;
            filterOption.value = filterName;
            if (filterName === settings.filter) {
                filterOption.selected = true;
            }
            filterSelect.appendChild(filterOption);
        });

        const filterLabelText = document.createElement('span');
        filterLabelText.classList.add('MuiTypography-root', 'MuiTypography-body1', 'MuiFormControlLabel-label', 'css-1fmsrhg-spread');
        filterLabelText.innerText = 'Filter';
        filterLabel.appendChild(filterLabelText);

        const brightnessLabel = document.createElement('label');
        brightnessLabel.classList.add('MuiFormControlLabel-root', 'MuiFormControlLabel-labelPlacementStart', 'css-1q5bp8s-propertyBox');
        content.appendChild(brightnessLabel);

        const brightnessRange = document.createElement('input');
        brightnessRange.id = 'rt_brightness';
        brightnessRange.type = 'range';
        brightnessRange.min = MIN_BRIGHTNESS;
        brightnessRange.max = MAX_BRIGHTNESS;
        brightnessRange.value = settings.brightness;
        brightnessRange.addEventListener('change', () => { setBrightnessSetting(brightnessRange.value); });
        brightnessLabel.appendChild(brightnessRange);

        const brightnessLabelText = document.createElement('span');
        brightnessLabelText.classList.add('MuiTypography-root', 'MuiTypography-body1', 'MuiFormControlLabel-label', 'css-1fmsrhg-spread');
        brightnessLabelText.innerText = 'Brightness';
        brightnessLabel.appendChild(brightnessLabelText);
    }

    function getThemeColor(colorIndex) {
        return activeTheme[settings.darkMode === 'true' ? 3 - colorIndex : colorIndex];
    }

    function generateThemeStyles() {
        return ':root{--color-0: ' + getThemeColor(0) + '; --color-1: ' + getThemeColor(1) + '; --color-2: ' + getThemeColor(2) + '; --color-3: ' + getThemeColor(3) + '}';
    }

    function setActiveTheme(newTheme) {
        activeTheme = newTheme;

        if (!themeStyle) {
            themeStyle = document.createElement('style');
            document.getElementsByTagName('body')[0].appendChild(themeStyle);
        }

        themeStyle.innerText = generateThemeStyles();
    }

    function setBrightness(value) {
        if (!screenBrightnessFilter) { return; }
        value = value < MIN_BRIGHTNESS ? MIN_BRIGHTNESS : value;
        value = value > MAX_BRIGHTNESS ? MAX_BRIGHTNESS : value;
        const filterOpacity = (MAX_BRIGHTNESS - value) / 10;
        screenBrightnessFilter.style.opacity = filterOpacity;
    }

    function insertScreenModifiers() {
        screenFilter = document.createElement('div');
        screenFilter.id = 'rt-screen-filter';
        screenFilter.classList.add('rt-screen-filter', settings.filter);
        document.getElementsByTagName('body')[0].appendChild(screenFilter);

        screenBrightnessFilter = document.createElement('div');
        screenBrightnessFilter.id = 'rt-screen-brightness';
        screenBrightnessFilter.classList.add('rt-screen-filter');
        document.getElementsByTagName('body')[0].appendChild(screenBrightnessFilter);
        setBrightness(settings.brightness);
    }

    function insertStyles() {
        setActiveTheme(themes[settings.theme]);

        // GLOBALS
        let css = 'svg, h1, h2, h3, h4, p, i, b, li, .MuiTypography-root, .MuiAlert-message, .MuiTooltip-tooltip{color: var(--color-3); font-family: Courier !important;}';
        css += '.Mui-error, .Mui-focused{color: var(--color-3) !important; font-family: Courier !important;}';

        // SCREEN FILTERS
        css += '.rt-screen-filter{z-index: 1000000001; position: fixed; top: 0; left: 0; width: 100%; height: 100vh; pointer-events: none;}';

        // CRT filter
        css += '.rt-screen-filter.crt1{background: repeating-linear-gradient(0deg, #111, #111 1px, transparent 3px, transparent 4px); opacity: 0.2}';
        css += '.rt-screen-filter.crt2{background: repeating-linear-gradient(0deg, #111, #111 1px, transparent 3px, transparent 4px), radial-gradient(white, black 65%); opacity: 0.2}';

        // LCD filter
        css += '.rt-screen-filter.lcd{background: repeating-linear-gradient(0deg, #11111133, #11111133 1px, transparent 2px, transparent 5px), repeating-linear-gradient(90deg, #11111133, #11111133 1px, transparent 2px, transparent 5px); opacity: 0.2}';

        // Brightness filter
        css += '#rt-screen-brightness{background: #000000; opacity: 0.0}';

        // CONTAINERS
        // Body
        css += 'body{background: var(--color-0);}';

        // Card container
        css += '.MuiPaper-root.MuiPaper-elevation{background: var(--color-0); border: solid 1px var(--color-3); border-radius: 0px !important;}';

        // Tooltip
        css += '.MuiTooltip-tooltip{background: var(--color-1); border: solid 1px var(--color-3); border-radius: 0px !important;}';

        // Menu box
        css += '[class*="-menuContainer"].MuiBox-root{background: var(--color-1); border: solid 1px var(--color-3); border-radius: 0px !important;}';

        // COMPONENTS
        // Scrollbar
        css += '::-webkit-scrollbar{width: 20px;}';
        css += '::-webkit-scrollbar-track {background: var(--color-1);}';
        css += '::-webkit-scrollbar-thumb {background: var(--color-2);}';
        css += '::-webkit-scrollbar-thumb:hover, ::-webkit-scrollbar-thumb:active {background: var(--color-3);}';

        // Button
        css += 'button{background: var(--color-2) !important; color: var(--color-0) !important; border-radius: 0px !important; font-family: Courier !important; font-weight: bold !important;}';
        css += 'button:hover, button:active{background: var(--color-3) !important}';
        css += 'button.MuiButtonGroup-firstButton, button.MuiButtonGroup-middleButton{border-right: 1px solid var(--color-0) !important; border-color: var(--color-0) !important;}';
        css += 'button svg{color: var(--color-0) !important;}';

        // List
        css += '.MuiList-root .MuiMenuItem-root{color: var(--color-3)}';
        css += '.MuiList-root .MuiMenuItem-root:hover, .MuiList-root .MuiMenuItem-root:hover .MuiTypography-root, .MuiList-root .MuiMenuItem-root:hover svg{background: var(--color-2); color: var(--color-0)}';
        css += '.MuiList-root .MuiMenuItem-root.Mui-selected{background: var(--color-3); color: var(--color-0);}';
        css += '.MuiList-root .MuiMenuItem-root button{background: transparent !important;}';
        css += '.MuiList-root .MuiMenuItem-root button svg{color: var(--color-3) !important;}';
        css += '.MuiList-root .MuiMenuItem-root.Mui-selected button svg, .MuiList-root .MuiMenuItem-root:hover button svg{color: var(--color-0) !important;}';

        // Input
        css += '.MuiFormLabel-root, .MuiInputLabel-standard, .MuiInputBase-input{color: var(--color-2)}';
        css += '.Mui-focused .MuiInputBase-input{color: var(--color-3)}';
        css += '.MuiInputBase-root.MuiInput-underline::before, .MuiInputBase-root.MuiInput-underline::after{border-color: var(--color-1) !important;}';
        css += '.MuiInputBase-root svg{color: var(--color-3) !important;}';

        // Select
        css += '.MuiSelect-select{color: var(--color-3)}';

        // Checkbox
        css += '.MuiSwitch-root .MuiButtonBase-root{color: var(--color-2);}';
        css += '.MuiSwitch-root .MuiSwitch-track{background: var(--color-1); opacity: 1;}';
        css += '.MuiSwitch-root .Mui-checked{color: var(--color-3);}';
        css += '.MuiSwitch-root .Mui-checked + .MuiSwitch-track{background: var(--color-2); opacity: 1;}';

        // Progress bar
        css += '.MuiLinearProgress-root{background: var(--color-1) !important;}';
        css += '.MuiLinearProgress-root .MuiLinearProgress-bar{background: var(--color-3) !important;}';

        // Toolbar
        css += '[class*="-toolbarHighlight"].MuiToolbar-regular{background: var(--color-2) !important;}';

        // Playlist table
        css += '.MuiTableCell-head, .MuiTableCell-body{border-color: var(--color-1);}';
        css += '.MuiTableCell-body svg{color: var(--color-3)}';
        css += '.MuiTableCell-head, .MuiTableCell-body, .MuiTableCell-body span{color: var(--color-2); font-family: Courier !important;}';
        css += '.MuiTableRow-hover:hover{background: var(--color-2) !important;}';
        css += '.MuiTableRow-hover:hover .MuiTableCell-head, .MuiTableRow-hover:hover .MuiTableCell-body, .MuiTableRow-hover:hover .MuiTableCell-body span{color: var(--color-0);}';
        css += '[class*="-currentTrackRow"] .MuiTableCell-head, [class*="-currentTrackRow"] .MuiTableCell-body, [class*="-currentTrackRow"] .MuiTableCell-body span{color: var(--color-3)}';
        css += '[class*="-rowClass-trackRow"].Mui-selected{background: var(--color-1) !important;}';
        css += '[class*="-rowClass-trackRow"].Mui-selected:hover{background: var(--color-2) !important;}';

        // Format badge
        css += '[class*="-formatBadge"]{background: var(--color-3) !important; color: var(--color-0) !important; border: none;}';

        // LCD
        css += '[class*="-lcd"]{background: var(--color-0); border-radius: 0; border: solid 1px var(--color-3)}';
        css += '[class*="-lcdText"]{color: var(--color-3) !important; background: transparent; border: none;}';
        css += '[class*="-lcdDisc"]{background: transparent; border: none;}';
        css += '[class*="-lcdDisc"] svg, [class*="-lcdDisc"] g{color: var(--color-3) !important; fill: var(--color-3) !important;}';

        // Duration bar
        css += '.css-biokn-duration{background: var(--color-3); filter: none;}';

        pageStyle = document.createElement('style');
        pageStyle.innerText = css;
        document.getElementsByTagName('body')[0].appendChild(pageStyle);
    }

    init();
})();