Wanikani: Judgement Day

Changes the lesson and review numbers' colors based on how many items you have pending

// ==UserScript==
// @name         Wanikani: Judgement Day
// @namespace    Wanikani: Judgement Day
// @version      1.1.2
// @description  Changes the lesson and review numbers' colors based on how many items you have pending
// @author       Kumirei
// @include      https://www.wanikani.com*
// @include      *preview.wanikani.com*
// @grant        none
// ==/UserScript==
/*jshint esversion: 8 */

(function() {
    // Make sure WKOF is installed
    if (!wkof) {
        var response = confirm('Wanikani: Judgement Day requires WaniKani Open Framework.\n Click "OK" to be forwarded to installation instructions.');
        if (response) window.location.href = 'https://community.wanikani.com/t/instructions-installing-wanikani-open-framework/28549';
        return;
    }
    else {
        wkof.include('Menu,Settings');
        wkof.ready('Menu,Settings').then(load_settings).then(install_menu).then(judge_user);
    }

    // Brings down the hammer and sentence users to death
    function judge_user() {
        var types = ['lessons', 'reviews', 'levels'];
        for (var i = 0; i<types.length; i++) {
            var type = types[i];
            if (wkof.settings.wanikani_judgement[type].judge) {
                let target, count;
                if (type != "levels") {
                    target = '.navigation-shortcut--'+type+' span';
                    count = Number($(target)[0].innerText);
                }
                else {
                    target = '.sitemap .sitemap__section:first-child';
                    count = Number($('li.user-summary__attribute a')[0].href.split('/level/')[1]);
                }
                let color;
                if (wkof.settings.wanikani_judgement[type].gradient) {
                    var max = wkof.settings.wanikani_judgement[type].max;
                    var start_color = wkof.settings.wanikani_judgement[type].start;
                    var end_color = wkof.settings.wanikani_judgement[type].end;
                    color = get_gradient_color(count, max, end_color, start_color);
                }
                else {
                    var intervals = wkof.settings.wanikani_judgement[type].intervals;
                    var colors = wkof.settings.wanikani_judgement[type].colors;
                    color = get_interval_color(count, intervals, colors);
                }
                if (type == "levels") target = ".dashboard-level";
                if ($(target)) $(target)[0].style.background = color;
            }
        }
    }

    // Returns the corresponding color from the gradient
    function get_gradient_color(count, max, color1, color2) {
        var severity = count/max;
        if (severity > 1) severity = 1;
        var color = gradient_color(hex_to_rgb(color1), hex_to_rgb(color2), severity);
        return 'rgb('+color.join()+')';
    }


    // Returns a color between the two given ones, based on the provided weight
    function gradient_color(color1, color2, weight) {
        var w1 = weight;
        var w2 = 1 - w1;
        var rgb = [Math.round(color1[0] * w1 + color2[0] * w2),
        Math.round(color1[1] * w1 + color2[1] * w2),
        Math.round(color1[2] * w1 + color2[2] * w2)];
        return rgb;
    }

    // Returns the corresponding color from the interval
    function get_interval_color(count, intervals, colors) {
        intervals = intervals.replace(/ /g, '').split(',');
        colors = colors.replace(/ /g, '').split(',');
        var color;
        for (var i = 0; i < intervals.length; i++) {
            if (count >= intervals[i]) color = colors[i];
        }
        return color;
    }

    // SETTINGS
    // ----------------------------------------------------------------------------------------------------------

    // Loads settings from storage or uses defaults
    const wk_colors = "#8c8c8c, #DD0093, #882D9E, #294DDB, #0093DD, #434343, #fbc042";
    const bd_colors = "#8c8c8c, #1d99f3, #1cdc9a, #C9CE3B, #F67400, #DA4453, #fbc042";
    var clrs = ($('body').css('background-color') == 'rgb(49, 54, 59)') ? bd_colors : wk_colors;
    function load_settings() {
        var defaults = {
            lessons: {
                judge: true,
                gradient: false,
                start: "#ffffff",
                end: "#000000",
                max: 150,
                intervals: "0, 10, 20, 40, 80, 120",
                colors: clrs,
                test_color: "#ffffff"
            },
            reviews: {
                judge: true,
                gradient: false,
                start: "#ffffff",
                end: "#000000",
                max: 700,
                intervals: "0, 50, 100, 200, 500, 700",
                colors: clrs,
                test_color: "#ffffff"
            },
            levels: {
                judge: true,
                gradient: false,
                start: "#ffffff",
                end: "#000000",
                max: 60,
                intervals: "0, 10, 20, 30, 40, 50, 60",
                colors: clrs,
                test_color: "#ffffff"
            }
        };
        return wkof.Settings.load('wanikani_judgement', defaults);
    }

    // Add settings menu to the menu
    function install_menu() {
        var config = {
            name: 'wanikani_judegement_settings',
            submenu: 'Settings',
            title: 'Judgement Day',
            on_click: open_settings
        };
        wkof.Menu.insert_script_link(config);
    }

    // Define settings menu layout
    function open_settings(items) {
        var config = {
            script_id: 'wanikani_judgement',
            title: 'Judgement Day',
            content: {
                tabs: {
                    type: 'tabset',
                    content: {
                        lessons: {
                            type: 'page',
                            label: 'Lessons',
                            content: {
                                general_group: {
                                    type: 'group',
                                    label: 'General',
                                    content: {
                                        lesson_judge: {
                                            type: 'checkbox',
                                            label: 'Judge Lessons',
                                            default: true,
                                            hover_tip: 'Apply script on lesson count',
                                            path: '@lessons.judge'
                                        }
                                    }
                                },
                                gradient_group: {
                                    type: 'group',
                                    label: 'Gradient',
                                    content: {
                                        lesson_gradient: {
                                            type: 'checkbox',
                                            label: 'Gradient',
                                            default: false,
                                            hover_tip: 'Determine the color based on an even gradient',
                                            path: '@lessons.gradient'
                                        },
                                        lesson_start_color: {
                                            type: 'color',
                                            label: 'Start color',
                                            hover_tip: 'The start of the gradient',
                                            default: "#ffffff",
                                            on_change: update_label,
                                            path: '@lessons.start'
                                        },
                                        lesson_end_color: {
                                            type: 'color',
                                            label: 'End color',
                                            hover_tip: 'The end of the gradient',
                                            default: "#000000",
                                            on_change: update_label,
                                            path: '@lessons.end'
                                        },
                                        lesson_max_value: {
                                            type: 'number',
                                            label: 'Max value',
                                            hover_tip: 'The end of the gradient',
                                            default: 150,
                                            path: '@lessons.max'
                                        }
                                    }
                                },
                                interval_group: {
                                    type: 'group',
                                    label: 'Intervals',
                                    content: {
                                        lesson_intervals: {
                                            type: 'text',
                                            label: 'Intervals',
                                            hover_tip: 'Comma separated list of upper bounds for the different colors. I.E "0, 50, 100," and so on.',
                                            default: "0, 10, 20, 40, 80, 120",
                                            path: '@lessons.intervals'
                                        },
                                        lesson_colors: {
                                            type: 'text',
                                            label: 'Interval Colors',
                                            hover_tip: 'Comma separated list of color codes for the intervals.',
                                            default: clrs,
                                            path: '@lessons.colors'
                                        },
                                        lessons_test_color: {
                                            type: 'color',
                                            label: 'Color Picker',
                                            hover_tip: 'Not a setting, just a color picker.',
                                            default: "#ffffff",
                                            on_change: update_label,
                                            path: '@lessons.test_color'
                                        }
                                    }
                                }
                            }
                        },
                        reviews: {
                            type: 'page',
                            label: 'Reviews',
                            content: {
                                general_group: {
                                    type: 'group',
                                    label: 'General',
                                    content: {
                                        review_judge: {
                                            type: 'checkbox',
                                            label: 'Judge Reviews',
                                            default: true,
                                            hover_tip: 'Apply script on review count',
                                            path: '@reviews.judge'
                                        }
                                    }
                                },
                                gradient_group: {
                                    type: 'group',
                                    label: 'Gradient',
                                    content: {
                                        review_gradient: {
                                            type: 'checkbox',
                                            label: 'Gradient',
                                            default: false,
                                            hover_tip: 'Determine the color based on an even gradient',
                                            path: '@reviews.gradient'
                                        },
                                        review_start_color: {
                                            type: 'color',
                                            label: 'Start color',
                                            hover_tip: 'The start of the gradient',
                                            default: "#ffffff",
                                            on_change: update_label,
                                            path: '@reviews.start'
                                        },
                                        review_end_color: {
                                            type: 'color',
                                            label: 'End color',
                                            hover_tip: 'The end of the gradient',
                                            default: "#000000",
                                            on_change: update_label,
                                            path: '@reviews.end'
                                        },
                                        review_max_value: {
                                            type: 'number',
                                            label: 'Max value',
                                            hover_tip: 'The end of the gradient',
                                            default: 700,
                                            path: '@reviews.max'
                                        }
                                    }
                                },
                                interval_group: {
                                    type: 'group',
                                    label: 'Intervals',
                                    content: {
                                        review_intervals: {
                                            type: 'text',
                                            label: 'Intervals',
                                            hover_tip: 'Comma separated list of upper bounds for the different colors. I.E "0, 50, 100," and so on.',
                                            default: "0, 50, 100, 200, 500, 700",
                                            path: '@reviews.intervals'
                                        },
                                        review_colors: {
                                            type: 'text',
                                            label: 'Interval Colors',
                                            hover_tip: 'Comma separated list of color codes for the intervals.',
                                            default: clrs,
                                            path: '@reviews.colors'
                                        },
                                        reviews_test_color: {
                                            type: 'color',
                                            label: 'Color Picker',
                                            hover_tip: 'Not a setting, just a color picker.',
                                            default: "#ffffff",
                                            on_change: update_label,
                                            path: '@reviews.test_color'
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        };
        if ($('.dashboard-level').length) {
            config.content.tabs.content.levels = {
                type: 'page',
                label: 'Levels',
                content: {
                    general_group: {
                        type: 'group',
                        label: 'General',
                        content: {
                            level_judge: {
                                type: 'checkbox',
                                label: 'Judge Level',
                                default: true,
                                hover_tip: 'Apply script on level',
                                path: '@levels.judge'
                            }
                        }
                    },
                    gradient_group: {
                        type: 'group',
                        label: 'Gradient',
                        content: {
                            level_gradient: {
                                type: 'checkbox',
                                label: 'Gradient',
                                default: false,
                                hover_tip: 'Determine the color based on an even gradient',
                                path: '@levels.gradient'
                            },
                            level_start_color: {
                                type: 'color',
                                label: 'Start color',
                                hover_tip: 'The start of the gradient',
                                default: "#ffffff",
                                on_change: update_label,
                                path: '@levels.start'
                            },
                            level_end_color: {
                                type: 'color',
                                label: 'End color',
                                hover_tip: 'The end of the gradient',
                                default: "#000000",
                                on_change: update_label,
                                path: '@levels.end'
                            },
                            level_max_value: {
                                type: 'number',
                                label: 'Max value',
                                hover_tip: 'The end of the gradient',
                                default: 60,
                                path: '@levels.max'
                            }
                        }
                    },
                    interval_group: {
                        type: 'group',
                        label: 'Intervals',
                        content: {
                            level_intervals: {
                                type: 'text',
                                label: 'Intervals',
                                hover_tip: 'Comma separated list of upper bounds for the different colors. I.E "0, 50, 100," and so on.',
                                default: "0, 10, 20, 30, 40, 50, 60",
                                path: '@levels.intervals'
                            },
                            level_colors: {
                                type: 'text',
                                label: 'Interval Colors',
                                hover_tip: 'Comma separated list of color codes for the intervals.',
                                default: clrs,
                                path: '@levels.colors'
                            },
                            levels_test_color: {
                                type: 'color',
                                label: 'Color Picker',
                                hover_tip: 'Not a setting, just a color picker.',
                                default: "#ffffff",
                                on_change: update_label,
                                path: '@levels.test_color'
                            }
                        }
                    }
                }
            };
        }

        var dialog = new wkof.Settings(config);
        dialog.open();
        add_color_codes();
    }

    // Add color codes to settings menu colors
    function add_color_codes() {
        $('head').append('<style id="JudgementDayCSS">'+
        '#wkof_ds .ui-dialog[aria-describedby="wkofs_wanikani_judgement"] .wkof_settings .color_label {'+
        '    position: absolute;'+
        '    line-height: 30px;'+
        '    text-align: center;'+
        '    text-shadow: none;'+
        '    background: transparent !important;'+
        '    width: 80px !important;'+
        '    left: 50%;'+
        '    transform: translate(-50%, 0);'+
        '    box-shadow: none !important;'+
        '    border: none !important;'+
        '}'+
        '</style>');
        $('.wkof_settings input[type="color"]').each((i, e)=>{
            e.parentElement.style.position = "relative";
            var color = e.value;
            var text_color = contrast_color(color);
            var label = $('<input class="color_label" style="color:'+text_color+' !important"></input>')[0];
            label.value = color;
            label.onkeyup = (event)=>{
                var hex = event.target.value;
                if (validate_hex(hex)) {
                    e.value = hex;
                    update_label(e.name, hex);
                    var name = e.name.replace(/reviews_|lessons_/,'');
                    wkof.settings.wanikani_heatmap[$('#wkofs_wanikani_judgement .ui-tabs-active')[0].innerText.toLowerCase()][name] = hex;
                }
            };
            $(e).before(label);
        });
    }

    // Updates the label of the color input
    function update_label(name, value) {
        var e = $('#wanikani_judgement_'+name)[0].previousSibling;
        e.value = value;
        $(e).attr('style', 'color: '+contrast_color(value)+' !important');
    }

    // Choses black or white as a contrast to the given color
    function contrast_color(color) {
        var [r, g, b] = hex_to_rgb(color);
        return (r+b+g)/(255*3) > 0.5 ? '#000000' : '#FFFFFF';
    }
    // Converts a hex color to rgb
    function hex_to_rgb(hex) {
        var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
        return [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)];
    }
})();