calculate new CSS tinting when we change theme
parent
b2ddcb8027
commit
e72e30197a
226
src/Tinter.js
226
src/Tinter.js
|
@ -80,7 +80,115 @@ const svgAttrs = [
|
||||||
|
|
||||||
let cached = false;
|
let cached = false;
|
||||||
|
|
||||||
function calcCssFixups() {
|
function hexToRgb(color) {
|
||||||
|
if (color[0] === '#') color = color.slice(1);
|
||||||
|
if (color.length === 3) {
|
||||||
|
color = color[0] + color[0] +
|
||||||
|
color[1] + color[1] +
|
||||||
|
color[2] + color[2];
|
||||||
|
}
|
||||||
|
const val = parseInt(color, 16);
|
||||||
|
const r = (val >> 16) & 255;
|
||||||
|
const g = (val >> 8) & 255;
|
||||||
|
const b = val & 255;
|
||||||
|
return [r, g, b];
|
||||||
|
}
|
||||||
|
|
||||||
|
function rgbToHex(rgb) {
|
||||||
|
const val = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
|
||||||
|
return '#' + (0x1000000 + val).toString(16).slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// List of functions to call when the tint changes.
|
||||||
|
const tintables = [];
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Register a callback to fire when the tint changes.
|
||||||
|
* This is used to rewrite the tintable SVGs with the new tint.
|
||||||
|
*
|
||||||
|
* It's not possible to unregister a tintable callback. So this can only be
|
||||||
|
* used to register a static callback. If a set of tintables will change
|
||||||
|
* over time then the best bet is to register a single callback for the
|
||||||
|
* entire set.
|
||||||
|
*
|
||||||
|
* @param {Function} tintable Function to call when the tint changes.
|
||||||
|
*/
|
||||||
|
registerTintable: function(tintable) {
|
||||||
|
tintables.push(tintable);
|
||||||
|
},
|
||||||
|
|
||||||
|
getKeyRgb: function() {
|
||||||
|
return keyRgb;
|
||||||
|
},
|
||||||
|
|
||||||
|
tint: function(primaryColor, secondaryColor, tertiaryColor) {
|
||||||
|
if (!cached) {
|
||||||
|
this.calcCssFixups();
|
||||||
|
cached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!primaryColor) {
|
||||||
|
const theme = UserSettingsStore.getTheme();
|
||||||
|
primaryColor = keyRgb[0];
|
||||||
|
secondaryColor = keyRgb[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!secondaryColor) {
|
||||||
|
const x = 0.16; // average weighting factor calculated from vector green & light green
|
||||||
|
const rgb = hexToRgb(primaryColor);
|
||||||
|
rgb[0] = x * rgb[0] + (1 - x) * 255;
|
||||||
|
rgb[1] = x * rgb[1] + (1 - x) * 255;
|
||||||
|
rgb[2] = x * rgb[2] + (1 - x) * 255;
|
||||||
|
secondaryColor = rgbToHex(rgb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tertiaryColor) {
|
||||||
|
const x = 0.19;
|
||||||
|
const rgb1 = hexToRgb(primaryColor);
|
||||||
|
const rgb2 = hexToRgb(secondaryColor);
|
||||||
|
rgb1[0] = x * rgb1[0] + (1 - x) * rgb2[0];
|
||||||
|
rgb1[1] = x * rgb1[1] + (1 - x) * rgb2[1];
|
||||||
|
rgb1[2] = x * rgb1[2] + (1 - x) * rgb2[2];
|
||||||
|
tertiaryColor = rgbToHex(rgb1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colors[0] === primaryColor &&
|
||||||
|
colors[1] === secondaryColor &&
|
||||||
|
colors[2] === tertiaryColor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
colors[0] = primaryColor;
|
||||||
|
colors[1] = secondaryColor;
|
||||||
|
colors[2] = tertiaryColor;
|
||||||
|
|
||||||
|
if (DEBUG) console.log("Tinter.tint");
|
||||||
|
|
||||||
|
// go through manually fixing up the stylesheets.
|
||||||
|
this.applyCssFixups();
|
||||||
|
|
||||||
|
// tell all the SVGs to go fix themselves up
|
||||||
|
// we don't do this as a dispatch otherwise it will visually lag
|
||||||
|
tintables.forEach(function(tintable) {
|
||||||
|
tintable();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
tintSvgWhite: function(whiteColor) {
|
||||||
|
if (!whiteColor) {
|
||||||
|
whiteColor = colors[3];
|
||||||
|
}
|
||||||
|
if (colors[3] === whiteColor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
colors[3] = whiteColor;
|
||||||
|
tintables.forEach(function(tintable) {
|
||||||
|
tintable();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
calcCssFixups: function() {
|
||||||
if (DEBUG) console.log("calcCssFixups start");
|
if (DEBUG) console.log("calcCssFixups start");
|
||||||
|
|
||||||
// update keyRgb from the current theme CSS itself, if it defines it
|
// update keyRgb from the current theme CSS itself, if it defines it
|
||||||
|
@ -148,123 +256,15 @@ function calcCssFixups() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (DEBUG) console.log("calcCssFixups end");
|
if (DEBUG) console.log("calcCssFixups end");
|
||||||
}
|
},
|
||||||
|
|
||||||
function applyCssFixups() {
|
applyCssFixups: function() {
|
||||||
if (DEBUG) console.log("applyCssFixups start");
|
if (DEBUG) console.log("applyCssFixups start");
|
||||||
for (let i = 0; i < cssFixups.length; i++) {
|
for (let i = 0; i < cssFixups.length; i++) {
|
||||||
const cssFixup = cssFixups[i];
|
const cssFixup = cssFixups[i];
|
||||||
cssFixup.style[cssFixup.attr] = colors[cssFixup.index];
|
cssFixup.style[cssFixup.attr] = colors[cssFixup.index];
|
||||||
}
|
}
|
||||||
if (DEBUG) console.log("applyCssFixups end");
|
if (DEBUG) console.log("applyCssFixups end");
|
||||||
}
|
|
||||||
|
|
||||||
function hexToRgb(color) {
|
|
||||||
if (color[0] === '#') color = color.slice(1);
|
|
||||||
if (color.length === 3) {
|
|
||||||
color = color[0] + color[0] +
|
|
||||||
color[1] + color[1] +
|
|
||||||
color[2] + color[2];
|
|
||||||
}
|
|
||||||
const val = parseInt(color, 16);
|
|
||||||
const r = (val >> 16) & 255;
|
|
||||||
const g = (val >> 8) & 255;
|
|
||||||
const b = val & 255;
|
|
||||||
return [r, g, b];
|
|
||||||
}
|
|
||||||
|
|
||||||
function rgbToHex(rgb) {
|
|
||||||
const val = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
|
|
||||||
return '#' + (0x1000000 + val).toString(16).slice(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// List of functions to call when the tint changes.
|
|
||||||
const tintables = [];
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
/**
|
|
||||||
* Register a callback to fire when the tint changes.
|
|
||||||
* This is used to rewrite the tintable SVGs with the new tint.
|
|
||||||
*
|
|
||||||
* It's not possible to unregister a tintable callback. So this can only be
|
|
||||||
* used to register a static callback. If a set of tintables will change
|
|
||||||
* over time then the best bet is to register a single callback for the
|
|
||||||
* entire set.
|
|
||||||
*
|
|
||||||
* @param {Function} tintable Function to call when the tint changes.
|
|
||||||
*/
|
|
||||||
registerTintable: function(tintable) {
|
|
||||||
tintables.push(tintable);
|
|
||||||
},
|
|
||||||
|
|
||||||
getKeyRgb: function() {
|
|
||||||
return keyRgb;
|
|
||||||
},
|
|
||||||
|
|
||||||
tint: function(primaryColor, secondaryColor, tertiaryColor) {
|
|
||||||
if (!cached) {
|
|
||||||
calcCssFixups();
|
|
||||||
cached = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!primaryColor) {
|
|
||||||
const theme = UserSettingsStore.getTheme();
|
|
||||||
primaryColor = keyRgb[0];
|
|
||||||
secondaryColor = keyRgb[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!secondaryColor) {
|
|
||||||
const x = 0.16; // average weighting factor calculated from vector green & light green
|
|
||||||
const rgb = hexToRgb(primaryColor);
|
|
||||||
rgb[0] = x * rgb[0] + (1 - x) * 255;
|
|
||||||
rgb[1] = x * rgb[1] + (1 - x) * 255;
|
|
||||||
rgb[2] = x * rgb[2] + (1 - x) * 255;
|
|
||||||
secondaryColor = rgbToHex(rgb);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tertiaryColor) {
|
|
||||||
const x = 0.19;
|
|
||||||
const rgb1 = hexToRgb(primaryColor);
|
|
||||||
const rgb2 = hexToRgb(secondaryColor);
|
|
||||||
rgb1[0] = x * rgb1[0] + (1 - x) * rgb2[0];
|
|
||||||
rgb1[1] = x * rgb1[1] + (1 - x) * rgb2[1];
|
|
||||||
rgb1[2] = x * rgb1[2] + (1 - x) * rgb2[2];
|
|
||||||
tertiaryColor = rgbToHex(rgb1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (colors[0] === primaryColor &&
|
|
||||||
colors[1] === secondaryColor &&
|
|
||||||
colors[2] === tertiaryColor) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
colors[0] = primaryColor;
|
|
||||||
colors[1] = secondaryColor;
|
|
||||||
colors[2] = tertiaryColor;
|
|
||||||
|
|
||||||
if (DEBUG) console.log("Tinter.tint");
|
|
||||||
|
|
||||||
// go through manually fixing up the stylesheets.
|
|
||||||
applyCssFixups();
|
|
||||||
|
|
||||||
// tell all the SVGs to go fix themselves up
|
|
||||||
// we don't do this as a dispatch otherwise it will visually lag
|
|
||||||
tintables.forEach(function(tintable) {
|
|
||||||
tintable();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
tintSvgWhite: function(whiteColor) {
|
|
||||||
if (!whiteColor) {
|
|
||||||
whiteColor = colors[3];
|
|
||||||
}
|
|
||||||
if (colors[3] === whiteColor) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
colors[3] = whiteColor;
|
|
||||||
tintables.forEach(function(tintable) {
|
|
||||||
tintable();
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// XXX: we could just move this all into TintableSvg, but as it's so similar
|
// XXX: we could just move this all into TintableSvg, but as it's so similar
|
||||||
|
@ -299,7 +299,9 @@ module.exports = {
|
||||||
for (let k = 0; k < svgAttrs.length; k++) {
|
for (let k = 0; k < svgAttrs.length; k++) {
|
||||||
const attr = svgAttrs[k];
|
const attr = svgAttrs[k];
|
||||||
for (let l = 0; l < keyHex.length; l++) {
|
for (let l = 0; l < keyHex.length; l++) {
|
||||||
if (tag.getAttribute(attr) && tag.getAttribute(attr).toUpperCase() === keyHex[l]) {
|
if (tag.getAttribute(attr) &&
|
||||||
|
tag.getAttribute(attr).toUpperCase() === keyHex[l])
|
||||||
|
{
|
||||||
fixups.push({
|
fixups.push({
|
||||||
node: tag,
|
node: tag,
|
||||||
attr: attr,
|
attr: attr,
|
||||||
|
|
|
@ -919,6 +919,8 @@ module.exports = React.createClass({
|
||||||
});
|
});
|
||||||
styleElements[theme].disabled = false;
|
styleElements[theme].disabled = false;
|
||||||
|
|
||||||
|
Tinter.calcCssFixups();
|
||||||
|
|
||||||
if (theme === 'dark') {
|
if (theme === 'dark') {
|
||||||
// abuse the tinter to change all the SVG's #fff to #2d2d2d
|
// abuse the tinter to change all the SVG's #fff to #2d2d2d
|
||||||
// XXX: obviously this shouldn't be hardcoded here.
|
// XXX: obviously this shouldn't be hardcoded here.
|
||||||
|
|
Loading…
Reference in New Issue