Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
… Settings. Custom colors.
  • Loading branch information
OlgaLarina committed Oct 22, 2024
1 parent 3acc052 commit 0c27af5
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Serializer, Base, property, ArrayChanges, EventBase, ILoadFromJSONOptions, ISaveToJSONOptions } from "survey-core";
import { getLocString } from "../editorLocalization";
import { assign, roundTo2Decimals } from "../utils/utils";
import { assign, roundTo2Decimals, ColorCalculator } from "../utils/utils";
import { CreatorThemes, ICreatorTheme, PredefinedCreatorThemes } from "./creator-themes";
import * as Themes from "survey-creator-core/themes";

Expand All @@ -14,8 +14,12 @@ Object.keys(Themes || {}).forEach(themeName => {

export class CreatorThemeModel extends Base implements ICreatorTheme {
static defautlThemeName = "sc2020";

initialCssVariables: { [index: string]: string } = {};
themeCssVariablesChanges?: { [index: string]: string } = {};
private primaryColorCalculator = new ColorCalculator();
private secondaryColorCalculator = new ColorCalculator();
private backgroundColorCalculator = new ColorCalculator();

unitDictionary: { [index: string]: number } = {
"--ctr-font-unit": 8,
Expand All @@ -36,6 +40,35 @@ export class CreatorThemeModel extends Base implements ICreatorTheme {
public onThemeSelected = new EventBase<CreatorThemeModel, { theme: ICreatorTheme }>();
public onThemePropertyChanged = new EventBase<CreatorThemeModel, { name: string, value: any }>();

private initializeColorCalculators(cssVariables: { [index: string]: string }) {
this.initializeColorCalculator(this.primaryColorCalculator, cssVariables, "--sjs-primary-background-500", "--sjs-primary-background-10", "--sjs-primary-background-400");
this.initializeColorCalculator(this.secondaryColorCalculator, cssVariables, "--sjs-secondary-background-500", "--sjs-secondary-background-10", "--sjs-secondary-background-25");
this.initializeColorCalculator(this.backgroundColorCalculator, cssVariables, "--sjs-special-background", "--sjs-special-haze", "--sjs-special-glow");
}
private initializeColorCalculator(calculator: ColorCalculator, cssVariables: { [index: string]: string }, baseColorName: string, lightColorName: string, darkColorName: string) {
if (!cssVariables[baseColorName] ||
!cssVariables[lightColorName] ||
!cssVariables[darkColorName]) {
return;
}

calculator.initialize(
cssVariables[baseColorName],
cssVariables[lightColorName],
cssVariables[darkColorName]
);
}

private updateColorPropertiesDependentOnBaseColor(calculator: ColorCalculator, value: string, baseColorName: string, lightColorName: string, darkColorName: string) {
this.setPropertyValue(baseColorName, value);
this.setThemeCssVariablesChanges(baseColorName, value);
calculator.calculateColors(value);
this.setPropertyValue(lightColorName, calculator.colorSettings.newColorLight);
this.setPropertyValue(darkColorName, calculator.colorSettings.newColorDark);
this.setThemeCssVariablesChanges(lightColorName, calculator.colorSettings.newColorLight);
this.setThemeCssVariablesChanges(darkColorName, calculator.colorSettings.newColorDark);
}

constructor() {
super();
this.onPropertyValueChangedCallback = (
Expand Down Expand Up @@ -75,6 +108,12 @@ export class CreatorThemeModel extends Base implements ICreatorTheme {
if (name === "themeName") {
this.loadTheme({ themeName: newValue });
this.onThemeSelected.fire(this, { theme: this.toJSON() });
} else if (name === "--sjs-primary-background-500") {
this.updateColorPropertiesDependentOnBaseColor(this.primaryColorCalculator, newValue, "--sjs-primary-background-500", "--sjs-primary-background-10", "--sjs-primary-background-400");
} else if (name === "--sjs-secondary-background-500") {
this.updateColorPropertiesDependentOnBaseColor(this.secondaryColorCalculator, newValue, "--sjs-secondary-background-500", "--sjs-secondary-background-10", "--sjs-secondary-background-25");
} else if (name === "--sjs-special-background") {
this.updateColorPropertiesDependentOnBaseColor(this.backgroundColorCalculator, newValue, "--sjs-special-background", "--sjs-special-haze", "--sjs-special-glow");
} else if (name.indexOf("--") === 0) {
this.setThemeCssVariablesChanges(name, newValue);
} else if (name == "fontScale" || name == "scale" || name == "surfaceScale") {
Expand Down Expand Up @@ -144,7 +183,7 @@ export class CreatorThemeModel extends Base implements ICreatorTheme {
const effectiveTheme: ICreatorTheme = {};
assign(effectiveTheme, baseTheme, theme, { cssVariables: effectiveThemeCssVariables, themeName: this.themeName });

// this.initializeColorCalculator(effectiveTheme.cssVariables);
this.initializeColorCalculators(effectiveTheme.cssVariables);
this.fromJSON(effectiveTheme);
} finally {
this.blockThemeChangedNotifications -= 1;
Expand Down Expand Up @@ -306,4 +345,10 @@ Serializer.addProperties("creatortheme", [
visible: false,
isSerializable: false,
},
{ name: "--sjs-primary-background-400", visible: false },
{ name: "--sjs-primary-background-10", visible: false },
{ name: "--sjs-secondary-background-25", visible: false },
{ name: "--sjs-secondary-background-10", visible: false },
{ name: "--sjs-special-haze", visible: false },
{ name: "--sjs-special-glow", visible: false },
]);
33 changes: 25 additions & 8 deletions packages/survey-creator-core/src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,11 +337,8 @@ export function scrollElementIntoView(elementId: string) {

export function ingectAlpha(baseColor: any, alpha: number): any {
if (!!baseColor && alpha !== undefined) {
const r = parseInt(baseColor.slice(1, 3), 16);
const g = parseInt(baseColor.slice(3, 5), 16);
const b = parseInt(baseColor.slice(5, 7), 16);

return `rgba(${r}, ${g}, ${b}, ${alpha})`;
const rgbValue = HEXToRGB(baseColor);
return `rgba(${rgbValue[0]}, ${rgbValue[1]}, ${rgbValue[2]}, ${rgbValue[3] || alpha})`;
}
}

Expand Down Expand Up @@ -375,6 +372,17 @@ export function parseColor(value: string = ""): { color: string, opacity: number
return { color: value, opacity: 100 };
}
}
export function HEXToRGB(baseColor: any): any {
if (!!baseColor) {
const r = parseInt(baseColor.slice(1, 3), 16);
const g = parseInt(baseColor.slice(3, 5), 16);
const b = parseInt(baseColor.slice(5, 7), 16);
const alpha = roundTo2Decimals(parseInt(baseColor.slice(7, 9), 16) / 255);

return [r, g, b, alpha];
}
return [];
}

export function HSBToRGB(h, s, b) {
s /= 100;
Expand Down Expand Up @@ -421,9 +429,18 @@ export class ColorCalculator {
colorSettings = { baseColorAlpha: 1, darkColorAlpha: 1, lightColorAlpha: 1, deltaDarkColor: 0, deltaLightColor: 0, newColorLight: "", newColorDark: "" };

initialize(baseColor: string, lightColor: string, darkColor: string) {
const primaryColorRgba = parseRgbaFromString(baseColor);
const primaryColorDarkRgba = parseRgbaFromString(darkColor);
const primaryColorLightRgba = parseRgbaFromString(lightColor);
let primaryColorRgba = parseRgbaFromString(baseColor);
if (primaryColorRgba.length === 0) {
primaryColorRgba = parseRgbaFromString(ingectAlpha(baseColor, 1));
}
let primaryColorDarkRgba = parseRgbaFromString(darkColor);
if (primaryColorDarkRgba.length === 0) {
primaryColorDarkRgba = parseRgbaFromString(ingectAlpha(darkColor, 1));
}
let primaryColorLightRgba = parseRgbaFromString(lightColor);
if (primaryColorLightRgba.length === 0) {
primaryColorLightRgba = parseRgbaFromString(ingectAlpha(lightColor, 1));
}
this.colorSettings.baseColorAlpha = primaryColorRgba[3];
this.colorSettings.darkColorAlpha = primaryColorDarkRgba[3];
this.colorSettings.lightColorAlpha = primaryColorLightRgba[3];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,79 @@ test("Creator theme check scale", (): any => {
expect(themeModelJsonCssVariables["--ctr-size-unit"]).toEqual("18px");
expect(themeModelJsonCssVariables["--ctr-spacing-unit"]).toEqual("18px");
expect(themeModelJsonCssVariables["--ctr-corner-radius-unit"]).toEqual("18px");
});

test("Update --sjs-primary-background-10 && --sjs-primary-background-400", (): any => {
const fefefeColor = "#fefefe"; // rgba(254, 254, 254, 1)
const themeModel = new CreatorThemeModel();
themeModel.loadTheme({
themeName: "custom",
cssVariables: {
"--sjs-primary-background-500": "#19B394FF",
"--sjs-primary-background-400": "#14A48BFF",
"--sjs-primary-background-10": "#19B3941A",
}
});

expect(themeModel["--sjs-primary-background-500"]).toEqual("#19B394FF");
expect(themeModel["--sjs-primary-background-10"]).toEqual("#19B3941A");
expect(themeModel["--sjs-primary-background-400"]).toEqual("#14A48BFF");
expect(themeModel.themeCssVariablesChanges).toStrictEqual({});

themeModel["--sjs-primary-background-500"] = fefefeColor;
expect(themeModel.themeCssVariablesChanges).toStrictEqual({
"--sjs-primary-background-500": fefefeColor,
"--sjs-primary-background-400": "rgba(239, 239, 239, 1)",
"--sjs-primary-background-10": "rgba(254, 254, 254, 0.1)",
});
});

test("Update --sjs-secondary-background-25 && --sjs-secondary-background-10", (): any => {
const fefefeColor = "#fefefe"; // rgba(254, 254, 254, 1)
const themeModel = new CreatorThemeModel();
themeModel.loadTheme({
themeName: "custom",
cssVariables: {
"--sjs-secondary-background-500": "#FF9814FF",
"--sjs-secondary-background-25": "#FF981440",
"--sjs-secondary-background-10": "#FF98141A",
}
});

expect(themeModel["--sjs-secondary-background-500"]).toEqual("#FF9814FF"); // rgba(255, 152, 20, 1)
expect(themeModel["--sjs-secondary-background-25"]).toEqual("#FF981440"); // rgba(255, 152, 20, 0.25)
expect(themeModel["--sjs-secondary-background-10"]).toEqual("#FF98141A"); //rgba(255, 152, 20, 0.1)
expect(themeModel.themeCssVariablesChanges).toStrictEqual({});

themeModel["--sjs-secondary-background-500"] = fefefeColor;
expect(themeModel.themeCssVariablesChanges).toStrictEqual({
"--sjs-secondary-background-500": fefefeColor,
"--sjs-secondary-background-25": "rgba(254, 254, 254, 0.25)",
"--sjs-secondary-background-10": "rgba(254, 254, 254, 0.1)",
});
});

test("Update --sjs-special-haze && --sjs-special-glow", (): any => {
const fefefeColor = "#fefefe"; // rgba(254, 254, 254, 1)
const themeModel = new CreatorThemeModel();
themeModel.loadTheme({
themeName: "custom",
cssVariables: {
"--sjs-special-background": "#EDF9F7FF",
"--sjs-special-haze": "#CCEEEE59",
"--sjs-special-glow": "#004C441A",
}
});

expect(themeModel["--sjs-special-background"]).toEqual("#EDF9F7FF"); // rgba(237, 249, 247, 1)
expect(themeModel["--sjs-special-haze"]).toEqual("#CCEEEE59"); // rgba(204, 238, 238, 0.35)
expect(themeModel["--sjs-special-glow"]).toEqual("#004C441A"); // rgba(0, 76, 68, 0.1)
expect(themeModel.themeCssVariablesChanges).toStrictEqual({});

themeModel["--sjs-special-background"] = fefefeColor;
expect(themeModel.themeCssVariablesChanges).toStrictEqual({
"--sjs-special-background": fefefeColor,
"--sjs-special-haze": "rgba(243, 243, 243, 0.35)",
"--sjs-special-glow": "rgba(81, 81, 81, 0.1)",
});
});
37 changes: 34 additions & 3 deletions packages/survey-creator-core/tests/utils.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ test("RGBToHSB HSBToRGB", (): any => {
expect(newPrimaryColorLightRGB).toEqual([25, 179, 148]);
});

test("ColorCalculator", (): any => {
test("ColorCalculator rgba", (): any => {
const primaryColor = "rgba(25, 179, 148, 1)";
const primaryColorLight = "rgba(25, 179, 148, 0.1)";
const primaryColorDark = "rgba(20, 164, 139, 1)";
Expand All @@ -40,7 +40,8 @@ test("ColorCalculator", (): any => {
deltaDarkColor: 5.882352941176464,
deltaLightColor: 0,
newColorDark: "",
newColorLight: "" }
newColorLight: ""
}
);

colorCalculator.calculateColors(primaryColor);
Expand All @@ -51,6 +52,36 @@ test("ColorCalculator", (): any => {
deltaDarkColor: 5.882352941176464,
deltaLightColor: 0,
newColorDark: "rgba(23, 164, 136, 1)",
newColorLight: "rgba(25, 179, 148, 0.1)" }
newColorLight: "rgba(25, 179, 148, 0.1)"
}
);
});

test("ColorCalculator hex", (): any => {
const primaryColor = "#19B394FF";
const primaryColorLight = "#19B3941A";
const primaryColorDark = "#14A48BFF";
const colorCalculator = new ColorCalculator();

colorCalculator.initialize(primaryColor, primaryColorLight, primaryColorDark);
expect(colorCalculator.colorSettings).toEqual({
baseColorAlpha: 1,
darkColorAlpha: 1,
lightColorAlpha: 0.1,
deltaDarkColor: 5.882352941176464,
deltaLightColor: 0,
newColorDark: "",
newColorLight: ""
});

colorCalculator.calculateColors(primaryColor);
expect(colorCalculator.colorSettings).toEqual({
baseColorAlpha: 1,
darkColorAlpha: 1,
lightColorAlpha: 0.1,
deltaDarkColor: 5.882352941176464,
deltaLightColor: 0,
newColorDark: "rgba(23, 164, 136, 1)",
newColorLight: "rgba(25, 179, 148, 0.1)"
});
});

0 comments on commit 0c27af5

Please sign in to comment.