Snap Dark Flat Theme

I have successfully created a dark theme for snap, sort of. I created it as a userscript. What it does is, add a new item to the settings menu which switches between light and dark theme. Additionally, when you turn on flat design, it isn't automatically light theme, so you can now have a dark flat theme.

Link: https://ego-lay-atman-bay.github.io/snap-extensions/userscripts/snap-editor-theme.user.js

Just add that into tapermonkey, and then you'll get it.

Screenshots
image


Source
// ==UserScript==
// @name         Snap! editor theme
// @namespace    https://ego-lay-atman-bay.github.io/snap-extensions/
// @version      0.5
// @description  New snap editor theme
// @author       ego-lay_atman-bay
// @match        https://snap.berkeley.edu/snap/snap.html
// @icon         https://forum.snap.berkeley.edu/favicon/proxied?https%3A%2F%2Fd1eo0ig0pi5tcs.cloudfront.net%2Foptimized%2F2X%2Ff%2Ffec08d3829a26a75ae620be49835ef91b13ba8e9_2_32x32.png
// @grant        none
// ==/UserScript==
(function () {
    'use strict';
    console.log('Injecting theme');

    MorphicPreferences.isLight = MorphicPreferences.isFlat

    function update_settings() {
        var settings = IDE_Morph.prototype.applySavedSettings.toString();
        var settings_lines = settings.split('\n');

        var get_light_mode = "        theme = this.getSetting('theme');\n\n    if (theme === 'light') {\n        this.setLightDesign();\n    } else if (theme == 'dark') {\n        this.setDarkDesign();\n    } else {\n        if (design == 'flat') {\n            this.setLightDesign();\n        } else {\n            this.setDarkDesign();\n        }\n    }";

        settings_lines.splice(settings_lines.indexOf(''), 0, get_light_mode);

        const settings_func = new Function('IDE_Morph.prototype.applySavedSettings = ' + settings_lines.join('\n'));
        settings_func();

        IDE_Morph.prototype.applySavedSettings();
    }

    IDE_Morph.prototype.darkDesign = function () {
        this.setDarkDesign();

        this.refreshIDE();
        this.saveSetting('theme', 'dark');
    };

    IDE_Morph.prototype.lightDesign = function () {
        this.setLightDesign();

        this.refreshIDE();
        this.saveSetting('theme', 'light');
    };

    function replace_flat(text) {
        return text.replace('MorphicPreferences.isFlat', 'MorphicPreferences.isLight');
    }

    function set_func(name) {
        const getFunc = new Function('return ' + name)
        var func = getFunc()

        var string = replace_flat(func.toString());
        const activate = new Function(name + ' = ' + string);
        activate();
    }

    function inject_design() {
        var injection = "    if (MorphicPreferences.isLight) {\n        this.saveSetting('theme', 'light');\n    } else {\n        this.saveSetting('theme', 'dark');\n    }";

        var flatdesign = IDE_Morph.prototype.flatDesign.toString().split('\n');
        var defaultdesign = IDE_Morph.prototype.defaultDesign.toString().split('\n');

        flatdesign.splice(flatdesign['length']-1, 0, injection);
        defaultdesign.splice(defaultdesign['length']-1, 0, injection);

        const injected_flat = new Function('IDE_Morph.prototype.flatDesign = ' + flatdesign.join('\n'));
        const injected_default = new Function('IDE_Morph.prototype.defaultDesign = ' + defaultdesign.join('\n'));

        injected_flat();
        injected_default();
    }

    inject_design();

    set_func('IDE_Morph.prototype.createLogo');

    set_func('IDE_Morph.prototype.createControlBar');

    set_func('IDE_Morph.prototype.createCategories');
    set_func('IDE_Morph.prototype.createSpriteBar');
    set_func('IDE_Morph.prototype.createCorralBar');
    set_func('BlockDialogMorph.prototype.addCategoryButton');
    set_func('BlockDialogMorph.prototype.addCustomCategoryButton');
    set_func('SpriteMorph.prototype.searchBlocks');

    var dark = replace_flat(IDE_Morph.prototype.setDefaultDesign.toString());
    var light = replace_flat(IDE_Morph.prototype.setFlatDesign.toString())

    dark = dark.split('\n')
    dark.splice(-1, 0, "PushButtonMorph.prototype.outlineColor = IDE_Morph.prototype.frameColor;\n    ToggleButtonMorph.prototype.outlineColor = IDE_Morph.prototype.frameColor;\n    TabMorph.prototype.outlineColor = IDE_Morph.prototype.frameColor;\n    ToggleMorph.prototype.outlineColor = IDE_Morph.prototype.frameColor;\n    ToggleElementMorph.prototype.outlineColor = IDE_Morph.prototype.frameColor;")
    dark = dark.join('\n')

    light = light.split('\n')
    light.splice(-1, 0, "    PushButtonMorph.prototype.outlineColor = IDE_Morph.prototype.frameColor;\n    ToggleButtonMorph.prototype.outlineColor = IDE_Morph.prototype.frameColor;\n    TabMorph.prototype.outlineColor = IDE_Morph.prototype.frameColor;\n    ToggleMorph.prototype.outlineColor = IDE_Morph.prototype.frameColor;\n    ToggleElementMorph.prototype.outlineColor = IDE_Morph.prototype.frameColor;")
    light = light.join('\n')

    // console.log(dark)
    // console.log(light)

    const setdark = new Function('IDE_Morph.prototype.setDarkDesign = ' + dark);
    const setlight = new Function('IDE_Morph.prototype.setLightDesign = ' + light);

    setdark()
    setlight()

    IDE_Morph.prototype.setFlatDesign = function () {
        MorphicPreferences.isFlat = true;
        IDE_Morph.prototype.scriptsPaneTexture = null;
    };

    IDE_Morph.prototype.setDefaultDesign = function () {
        MorphicPreferences.isFlat = false;
        IDE_Morph.prototype.scriptsPaneTexture = this.scriptsTexture();
    };

    var menu = IDE_Morph.prototype.settingsMenu.toString();
    var split = menu.split("\n    addPreference(\n        'Flat design',\n        () => {\n            if (MorphicPreferences.isFlat) {\n                return this.defaultDesign();\n            }\n            this.flatDesign();\n        },\n        MorphicPreferences.isFlat,\n        'uncheck for default\\nGUI design',\n        'check for alternative\\nGUI design',\n        false\n    );");
    split.splice(1, 0, "    addPreference(\n        'Flat design',\n        () => {\n            if (MorphicPreferences.isFlat) {                return this.defaultDesign();\n            }\n            this.flatDesign();\n        },        MorphicPreferences.isFlat,\n        'uncheck for default\\nGUI design',        'check for alternative\\nGUI design',\n        false\n    );\n	addPreference(\n        'Dark theme',\n        () => {\n            if (MorphicPreferences.isLight) {\n                return this.darkDesign();\n            }\n            this.lightDesign();\n        },\n        !MorphicPreferences.isLight,\n        'uncheck for light\\nGUI theme',\n        'check for dark\\nGUI theme',\n        false\n    );");
    var newFun = split.join('');
    const dark_mode = new Function('IDE_Morph.prototype.settingsMenu = ' + newFun);
    dark_mode();

    update_settings();

})();

edit: This now works for Snap! 8.0 and probably even 9.0 (when it's made).

depending on if the flat design item is changed in 9.0

Fix the shading we’re the Snap! logo is?

Beautiful dark theme :star_struck:

add to snapfox?

I want to fix that, but I don't know how.

my other extension (not *monkey) wants to do the job
if you have that problem too, click here and copy the code to the new script in *monkey





also, thanks for making this script. this will keep my eyes from burning

that's just a link to my script...

yes, it's very pretty, i like it

yeah and its the script code to copy and paste if someones other extention (like my custom right-click menu) wants to do the job, my custom right-click menu extenton wanted to do the userscript install because my extention had the same id as the link provided by you:

I just realized what you mean. You can used userscripts in other browser extensions, not just tapermonkey.

After a long time, I have finally updated this. It now works with 8.0, and probably even beyond. I did also move it to my snap extensions page.

New link: https://ego-lay-atman-bay.github.io/snap-extensions/userscripts/snap-editor-theme.user.js

For those who are curious

I changed it so that it doesn't just replace the menu. It now gets the menu, then removes the current flat design option. After that, it adds my 2 new options where flat design used to be (well, it still it, but I'm talking about the vanilla option). After that, it just replaces the menu with the edited version.

The way it gets the flat design option is by finding this string

"
    addPreference(
        'Flat design',
        () => {
            if (MorphicPreferences.isFlat) {
                return this.defaultDesign();
            }
            this.flatDesign();\n        },
        MorphicPreferences.isFlat,
        'uncheck for default\\nGUI design',
        'check for alternative\\nGUI design',
        false
    );"

(well, the newlines are \n, but this looks better)

so if this changes at all, the userscript will then become broken.

Tried making it as a bookmarklet, but it didn't work.

yeah, I add a bunch of new functions, so it probably wouldn't be possible. Plus, there are large strings in it.

Yeah, I don't have a user script extension yet.

Huh, I ran it in my little bookmarklet inspect tools and it worked.

Bug:

All menus that pop up are not the dark theme.

It's not a bug. I just used the same colors for snap default design, and the dark flat theme, in fact the set default theme function just sets it to non-flat. The dark mode option just changes the colors.

I did also just make an update, which modifies the vanilla theme functions to get the colors, so if they're updated, then they'll still work. If you made a userscript to change the colors, make sure to run that before this userscript.

Are you going to make a default light theme?

I could try setting the light/dark mode in the browserstorage, the same place it stores if it's flat design or not.

edit: as I was searching the source for how to save the settings, I discovered the function that sets the logo gradient. I've now modified that to now be white in light theme!

why does the world hate me

@Here
i turned it into a bookmarklet

code
javascript:void eval("!function(){const e=['!function(){\"use strict\";function e(e){return e.replace(\"MorphicPreferences.isFlat\",\"MorphicPreferences.isLight\")}function n(n){var t=e(new Function(\"return \"+n)().toString());new Function(n+\" = \"+t)()}MorphicPreferences.isLight=MorphicPreferences.isFlat,IDE_Morph.prototype.darkDesign=function(){this.setDarkDesign(),this.refreshIDE()},IDE_Morph.prototype.lightDesign=function(){this.setLightDesign(),this.refreshIDE()},n(\"IDE_Morph.prototype.createLogo\"),n(\"IDE_Morph.prototype.createControlBar\"),n(\"IDE_Morph.prototype.createCategories\"),n(\"IDE_Morph.prototype.createSpriteBar\"),n(\"IDE_Morph.prototype.createCorralBar\");var t=e(IDE_Morph.prototype.setDefaultDesign.toString()),r=e(IDE_Morph.prototype.setFlatDesign.toString());const i=new Function(\"IDE_Morph.prototype.setDarkDesign = \"+t),o=new Function(\"IDE_Morph.prototype.setLightDesign = \"+r);i(),o(),IDE_Morph.prototype.setFlatDesign=function(){MorphicPreferences.isFlat=!0,IDE_Morph.prototype.scriptsPaneTexture=null},IDE_Morph.prototype.setDefaultDesign=function(){MorphicPreferences.isFlat=!1,IDE_Morph.prototype.scriptsPaneTexture=this.scriptsTexture()},console.log(\"Injecting menu items\");var s=IDE_Morph.prototype.settingsMenu.toString().split(\"\\\\n    addPreference(\\\\n        \\'Flat design\\',\\\\n        () => {\\\\n            if (MorphicPreferences.isFlat) {\\\\n                return this.defaultDesign();\\\\n            }\\\\n            this.flatDesign();\\\\n        },\\\\n        MorphicPreferences.isFlat,\\\\n        \\'uncheck for default\\\\\\\\nGUI design\\',\\\\n        \\'check for alternative\\\\\\\\nGUI design\\',\\\\n        false\\\\n    );\");s.splice(1,0,\"    addPreference(\\\\n        \\'Flat design\\',\\\\n        () => {\\\\n            if (MorphicPreferences.isFlat) {                return this.defaultDesign();\\\\n            }\\\\n            this.flatDesign();\\\\n        },        MorphicPreferences.isFlat,\\\\n        \\'uncheck for default\\\\\\\\nGUI design\\',        \\'check for alternative\\\\\\\\nGUI design\\',\\\\n        false\\\\n    );\\\\n\\\\taddPreference(\\\\n        \\'Dark design\\',\\\\n        () => {\\\\n            if (MorphicPreferences.isLight) {\\\\n                return this.darkDesign();\\\\n            }\\\\n            this.lightDesign();\\\\n        },\\\\n        !MorphicPreferences.isLight,\\\\n        \\'uncheck for default\\\\\\\\nGUI design\\',\\\\n        \\'check for alternative\\\\\\\\nGUI design\\',\\\\n        false\\\\n    );\");var p=s.join(\"\");new Function(\"IDE_Morph.prototype.settingsMenu = \"+p)()}();'],n=[[[],[]]],t=\"0.2003274161194426-1662169419886-userscripts-ran\",r=e.length;function i(e,n){const[t,r]=e;for(const e of r)if(o(e,n))return!1;for(const e of t)if(o(e,n))return!0;return 0===t.length}function o(e,n){let t;return t=e.startsWith(\"/\")&&e.endsWith(\"/\")?new RegExp(e.slice(1,-1)):function(e){let n=e;for(let e=0;e<s.length;e++){const t=s[e],r=c[e];n=n.replace(r,\"\\\\\"+t)}return new RegExp(\"^\"+n.replace(/\\*/g,\".*\")+\"$\",\"i\")}(e),t.test(n)}const s=[\"\\\\\",\".\",\"+\",\"?\",\"^\",\"$\",\"(\",\")\",\"[\",\"]\",\"{\",\"}\",\"|\"],c=s.map((e=>new RegExp(\"\\\\\"+e,\"g\")));!function(){if(!window[t]||confirm(\"Are you sure you want to run the userscripts again?\")){window[t]=!0,window.isRunningAsBookmarkletUserscript=!0;for(let t=0;t<r;t++){const r=e[t];if(i(n[t],location.href))try{window.eval(r)}catch(e){console.error(e)}}delete window.isRunningAsBookmarkletUserscript}}()}();")