mirror of
https://github.com/vector-im/element-web.git
synced 2025-11-29 14:31:22 +01:00
Fix custom theme support for short hex & rgba hex strings (#29726)
* Fix custom theme support for hex colours other than 6-char Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
779543fa0f
commit
1430fd5af6
43
src/theme.ts
43
src/theme.ts
@ -129,7 +129,7 @@ function clearCustomTheme(): void {
|
|||||||
// remove all css variables, we assume these are there because of the custom theme
|
// remove all css variables, we assume these are there because of the custom theme
|
||||||
const inlineStyleProps = Object.values(document.body.style);
|
const inlineStyleProps = Object.values(document.body.style);
|
||||||
for (const prop of inlineStyleProps) {
|
for (const prop of inlineStyleProps) {
|
||||||
if (prop.startsWith("--")) {
|
if (typeof prop === "string" && prop.startsWith("--")) {
|
||||||
document.body.style.removeProperty(prop);
|
document.body.style.removeProperty(prop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -206,16 +206,49 @@ function generateCustomCompoundCSS(theme: CompoundTheme): string {
|
|||||||
return `@layer compound.custom { :root, [class*="cpd-theme-"] { ${properties.join(" ")} } }`;
|
return `@layer compound.custom { :root, [class*="cpd-theme-"] { ${properties.join(" ")} } }`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes the hex colour to 8 characters (including alpha)
|
||||||
|
* @param hexColor the hex colour to normalize
|
||||||
|
*/
|
||||||
|
function normalizeHexColour(hexColor: string): string {
|
||||||
|
switch (hexColor.length) {
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
// Short RGB or RGBA hex
|
||||||
|
return `#${hexColor
|
||||||
|
.slice(1)
|
||||||
|
.split("")
|
||||||
|
.map((c) => c + c)
|
||||||
|
.join("")}`;
|
||||||
|
case 7:
|
||||||
|
// Long RGB hex
|
||||||
|
return `${hexColor}ff`;
|
||||||
|
default:
|
||||||
|
return hexColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setHexAlpha(normalizedHexColor: string, alpha: number): string {
|
||||||
|
return normalizeHexColour(normalizedHexColor).slice(0, 7) + Math.round(alpha).toString(16).padStart(2, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseAlpha(normalizedHexColor: string): number {
|
||||||
|
return parseInt(normalizedHexColor.slice(7), 16);
|
||||||
|
}
|
||||||
|
|
||||||
function setCustomThemeVars(customTheme: CustomTheme): void {
|
function setCustomThemeVars(customTheme: CustomTheme): void {
|
||||||
const { style } = document.body;
|
const { style } = document.body;
|
||||||
|
|
||||||
function setCSSColorVariable(name: string, hexColor: string, doPct = true): void {
|
function setCSSColorVariable(name: string, hexColor: string, doPct = true): void {
|
||||||
style.setProperty(`--${name}`, hexColor);
|
style.setProperty(`--${name}`, hexColor);
|
||||||
|
const normalizedHexColor = normalizeHexColour(hexColor);
|
||||||
|
const baseAlpha = parseAlpha(normalizedHexColor);
|
||||||
|
|
||||||
if (doPct) {
|
if (doPct) {
|
||||||
// uses #rrggbbaa to define the color with alpha values at 0%, 15% and 50%
|
// uses #rrggbbaa to define the color with alpha values at 0%, 15% and 50% (relative to base alpha channel)
|
||||||
style.setProperty(`--${name}-0pct`, hexColor + "00");
|
style.setProperty(`--${name}-0pct`, setHexAlpha(normalizedHexColor, 0));
|
||||||
style.setProperty(`--${name}-15pct`, hexColor + "26");
|
style.setProperty(`--${name}-15pct`, setHexAlpha(normalizedHexColor, baseAlpha * 0.15));
|
||||||
style.setProperty(`--${name}-50pct`, hexColor + "7F");
|
style.setProperty(`--${name}-50pct`, setHexAlpha(normalizedHexColor, baseAlpha * 0.5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -135,6 +135,54 @@ describe("theme", () => {
|
|||||||
expect(spy.mock.calls[0][0].textContent).toMatchSnapshot();
|
expect(spy.mock.calls[0][0].textContent).toMatchSnapshot();
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should handle 4-char rgba hex strings", async () => {
|
||||||
|
jest.spyOn(SettingsStore, "getValue").mockReturnValue([
|
||||||
|
{
|
||||||
|
name: "blue",
|
||||||
|
colors: {
|
||||||
|
"sidebar-color": "#abcd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const spy = jest.fn();
|
||||||
|
jest.spyOn(document.body, "style", "get").mockReturnValue({
|
||||||
|
setProperty: spy,
|
||||||
|
} as any);
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTheme("custom-blue").then(resolve);
|
||||||
|
lightCustomTheme.onload!({} as Event);
|
||||||
|
});
|
||||||
|
expect(spy).toHaveBeenCalledWith("--sidebar-color", "#abcd");
|
||||||
|
expect(spy).toHaveBeenCalledWith("--sidebar-color-0pct", "#aabbcc00");
|
||||||
|
expect(spy).toHaveBeenCalledWith("--sidebar-color-15pct", "#aabbcc21");
|
||||||
|
expect(spy).toHaveBeenCalledWith("--sidebar-color-50pct", "#aabbcc6f");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle 6-char rgb hex strings", async () => {
|
||||||
|
jest.spyOn(SettingsStore, "getValue").mockReturnValue([
|
||||||
|
{
|
||||||
|
name: "blue",
|
||||||
|
colors: {
|
||||||
|
"sidebar-color": "#abcdef",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const spy = jest.fn();
|
||||||
|
jest.spyOn(document.body, "style", "get").mockReturnValue({
|
||||||
|
setProperty: spy,
|
||||||
|
} as any);
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTheme("custom-blue").then(resolve);
|
||||||
|
lightCustomTheme.onload!({} as Event);
|
||||||
|
});
|
||||||
|
expect(spy).toHaveBeenCalledWith("--sidebar-color", "#abcdef");
|
||||||
|
expect(spy).toHaveBeenCalledWith("--sidebar-color-0pct", "#abcdef00");
|
||||||
|
expect(spy).toHaveBeenCalledWith("--sidebar-color-15pct", "#abcdef26");
|
||||||
|
expect(spy).toHaveBeenCalledWith("--sidebar-color-50pct", "#abcdef80");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("enumerateThemes", () => {
|
describe("enumerateThemes", () => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user