WebMD Retro Theme

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

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

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