diff --git a/src/assets/themes/tron-colorfilter.json b/src/assets/themes/tron-colorfilter.json new file mode 100644 index 00000000..8407df98 --- /dev/null +++ b/src/assets/themes/tron-colorfilter.json @@ -0,0 +1,34 @@ +{ + "colors": { + "r": 170, + "g": 207, + "b": 209, + "black": "#000000", + "light_black": "#05080d", + "grey": "#262828" + }, + "cssvars": { + "font_main": "United Sans Medium", + "font_main_light": "United Sans Light" + }, + "terminal": { + "fontFamily": "Fira Mono", + "cursorStyle": "block", + "foreground": "#aacfd1", + "background": "#05080d", + "cursor": "#aacfd1", + "cursorAccent": "#aacfd1", + "selection": "rgba(170,207,209,0.3)", + "colorFilter": [ + "rotate(180)", + "saturate(0.5)", + "mix(0.7)" + ] + }, + "globe": { + "base": "#000000", + "marker": "#aacfd1", + "pin": "#aacfd1", + "satellite": "#aacfd1" + } +} diff --git a/src/classes/terminal.class.js b/src/classes/terminal.class.js index 66833aa1..82b3010f 100644 --- a/src/classes/terminal.class.js +++ b/src/classes/terminal.class.js @@ -27,10 +27,74 @@ class Terminal { this.Ipc.send("terminal_channel-"+this.port, "Resize", cols, rows); }; + // Support for custom color filters on the terminal - see #483 + let doCustomFilter = false; + + // Typechecking condition to ensure that provided filters are valid and prevent code injection + if (typeof window.theme.terminal.colorFilter === "object" && window.theme.terminal.colorFilter.length > 0) { + doCustomFilter = window.theme.terminal.colorFilter.every((step, i, a) => { + let func = step.slice(0, step.indexOf("(")); + + switch(func) { + case "negate": + case "grayscale": + a[i] = { + func, + arg: [] + }; + return true; + case "lighten": + case "darken": + case "saturate": + case "desaturate": + case "whiten": + case "blacken": + case "fade": + case "opaquer": + case "rotate": + case "mix": + break; + default: + return false; + } + + let arg = step.slice(step.indexOf("(")+1, step.indexOf(")")); + + if (typeof Number(arg) === "number") { + a[i] = { + func, + arg: [Number(arg)] + }; + return true; + } + + return false; + }); + } + let color = require("color"); - let colorify = (base, target) => { - return color(base).grayscale().mix(color(target), 0.3).hex(); - }; + let colorify; + if (doCustomFilter) { + colorify = (base, target) => { + let newColor = color(base); + target = color(target); + + for (let i = 0; i < window.theme.terminal.colorFilter.length; i++) { + if (window.theme.terminal.colorFilter[i].func === "mix") { + newColor = newColor[window.theme.terminal.colorFilter[i].func](target, ...window.theme.terminal.colorFilter[i].arg); + } else { + newColor = newColor[window.theme.terminal.colorFilter[i].func](...window.theme.terminal.colorFilter[i].arg); + } + } + + return newColor.hex(); + }; + } else { + colorify = (base, target) => { + return color(base).grayscale().mix(color(target), 0.3).hex(); + }; + } + let themeColor = `rgb(${window.theme.r}, ${window.theme.g}, ${window.theme.b})`; this.term = new this.xTerm({