diff --git a/res/img/03b381.png b/res/img/03b381.png deleted file mode 100644 index cf28fc7e59..0000000000 Binary files a/res/img/03b381.png and /dev/null differ diff --git a/res/img/368bd6.png b/res/img/368bd6.png deleted file mode 100644 index a2700bd0ae..0000000000 Binary files a/res/img/368bd6.png and /dev/null differ diff --git a/res/img/ac3ba8.png b/res/img/ac3ba8.png deleted file mode 100644 index 031471d85a..0000000000 Binary files a/res/img/ac3ba8.png and /dev/null differ diff --git a/res/themes/light-custom/css/_custom.scss b/res/themes/light-custom/css/_custom.scss index e4a08277f9..64c4cac7e3 100644 --- a/res/themes/light-custom/css/_custom.scss +++ b/res/themes/light-custom/css/_custom.scss @@ -17,6 +17,7 @@ limitations under the License. // // --accent-color $accent-color: var(--accent-color); +$accent-bg-color: var(--accent-color-15pct); $button-bg-color: var(--accent-color); $button-link-fg-color: var(--accent-color); $button-primary-bg-color: var(--accent-color); @@ -124,3 +125,12 @@ $notice-primary-color: var(--warning-color); $pinned-unread-color: var(--warning-color); $warning-color: var(--warning-color); $button-danger-disabled-bg-color: var(--warning-color-50pct); // still needs alpha at 0.5 + +$username-variant1-color: var(--username-colors_1, $username-variant1-color); +$username-variant2-color: var(--username-colors_2, $username-variant2-color); +$username-variant3-color: var(--username-colors_3, $username-variant3-color); +$username-variant4-color: var(--username-colors_4, $username-variant4-color); +$username-variant5-color: var(--username-colors_5, $username-variant5-color); +$username-variant6-color: var(--username-colors_6, $username-variant6-color); +$username-variant7-color: var(--username-colors_7, $username-variant7-color); +$username-variant8-color: var(--username-colors_8, $username-variant8-color); diff --git a/src/Avatar.js b/src/Avatar.js index 217b196348..8393ce02b2 100644 --- a/src/Avatar.js +++ b/src/Avatar.js @@ -53,13 +53,56 @@ export function avatarUrlForUser(user, width, height, resizeMethod) { return url; } +function isValidHexColor(color) { + return typeof color === "string" && + (color.length === 7 || color.lengh === 9) && + color.charAt(0) === "#" && + !color.substr(1).split("").some(c => isNaN(parseInt(c, 16))); +} + +function urlForColor(color) { + const size = 40; + const canvas = document.createElement("canvas"); + canvas.width = size; + canvas.height = size; + const ctx = canvas.getContext("2d"); + // bail out when using jsdom in unit tests + if (!ctx) { + return ""; + } + ctx.fillStyle = color; + ctx.fillRect(0, 0, size, size); + return canvas.toDataURL(); +} + +// XXX: Ideally we'd clear this cache when the theme changes +// but since this function is at global scope, it's a bit +// hard to install a listener here, even if there were a clear event to listen to +const colorToDataURLCache = new Map(); + export function defaultAvatarUrlForString(s) { - const images = ['03b381', '368bd6', 'ac3ba8']; + const defaultColors = ['#03b381', '#368bd6', '#ac3ba8']; let total = 0; for (let i = 0; i < s.length; ++i) { total += s.charCodeAt(i); } - return require('../res/img/' + images[total % images.length] + '.png'); + const colorIndex = total % defaultColors.length; + // overwritten color value in custom themes + const cssVariable = `--avatar-background-colors_${colorIndex}`; + const cssValue = document.body.style.getPropertyValue(cssVariable); + const color = cssValue || defaultColors[colorIndex]; + let dataUrl = colorToDataURLCache.get(color); + if (!dataUrl) { + // validate color as this can come from account_data + // with custom theming + if (isValidHexColor(color)) { + dataUrl = urlForColor(color); + colorToDataURLCache.set(color, dataUrl); + } else { + dataUrl = ""; + } + } + return dataUrl; } /** diff --git a/src/theme.js b/src/theme.js index 442a89e25f..ab5974f207 100644 --- a/src/theme.js +++ b/src/theme.js @@ -141,16 +141,31 @@ export function enumerateThemes() { return Object.assign({}, customThemeNames, BUILTIN_THEMES); } + function setCustomThemeVars(customTheme) { const {style} = document.body; - if (customTheme.colors) { - for (const [name, hexColor] of Object.entries(customTheme.colors)) { - style.setProperty(`--${name}`, hexColor); - // uses #rrggbbaa to define the color with alpha values at 0% and 50% + + function setCSSVariable(name, hexColor, doPct = true) { + style.setProperty(`--${name}`, hexColor); + if (doPct) { + // uses #rrggbbaa to define the color with alpha values at 0%, 15% and 50% style.setProperty(`--${name}-0pct`, hexColor + "00"); + style.setProperty(`--${name}-15pct`, hexColor + "26"); style.setProperty(`--${name}-50pct`, hexColor + "7F"); } } + + if (customTheme.colors) { + for (const [name, value] of Object.entries(customTheme.colors)) { + if (Array.isArray(value)) { + for (let i = 0; i < value.length; i += 1) { + setCSSVariable(`${name}_${i}`, value[i], false); + } + } else { + setCSSVariable(name, value); + } + } + } } function getCustomTheme(themeName) {