- add complete theme generation
This commit is contained in:
parent
4b94f300f2
commit
dbbbbf5997
@ -1,20 +1,33 @@
|
||||
import { countDecimals } from "Utils";
|
||||
import { fromString } from "css-color-converter";
|
||||
|
||||
export interface ColorsInput {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export interface ShadesOptions {
|
||||
keys?: string[];
|
||||
keyPrefix?: string;
|
||||
keySuffix?: string;
|
||||
opacities?: number[];
|
||||
structure?: "flat" | "nested";
|
||||
format?: "default" | "css-variable";
|
||||
}
|
||||
|
||||
const DEFAULT_OPACITIES = [0.1, 0.25, 0.5, 0.75];
|
||||
const DEFAULT_STRUCTURE = "flat";
|
||||
|
||||
const formatColor = ({
|
||||
prefix,
|
||||
key,
|
||||
rgb,
|
||||
opacity,
|
||||
}: {
|
||||
prefix?: string;
|
||||
key?: string;
|
||||
rgb: string;
|
||||
opacity?: number;
|
||||
}) => {
|
||||
return {
|
||||
[`${prefix ? prefix + "-" : ""}${
|
||||
[`${key ? key + "-" : ""}${
|
||||
opacity !== undefined
|
||||
? countDecimals(opacity) === 1
|
||||
? (opacity + "").split(".")[1] + "0"
|
||||
@ -24,16 +37,7 @@ const formatColor = ({
|
||||
};
|
||||
};
|
||||
|
||||
const generateShades = (
|
||||
colors: { [key: string]: string },
|
||||
options?: {
|
||||
keys?: string[];
|
||||
keyPrefix?: string;
|
||||
opacities?: number[];
|
||||
structure?: "flat" | "nested";
|
||||
format?: "default" | "css-variable";
|
||||
}
|
||||
) => {
|
||||
const generateShades = (colors: ColorsInput, options?: ShadesOptions) => {
|
||||
const colorKeys = options?.keys
|
||||
? Object.keys(colors).filter((key) => options.keys?.includes(key))
|
||||
: Object.keys(colors);
|
||||
@ -47,7 +51,7 @@ const generateShades = (
|
||||
const generatedColorShadesArr: object[] = [];
|
||||
|
||||
colorKeys.forEach((_key) => {
|
||||
const key = (options?.keyPrefix || "") + _key;
|
||||
const key = (options?.keyPrefix || "") + _key + (options?.keySuffix || "");
|
||||
const colorString = colors[_key];
|
||||
|
||||
const opacities = options?.opacities
|
||||
@ -57,9 +61,7 @@ const generateShades = (
|
||||
if (structure === "flat") {
|
||||
opacities.forEach((opacity) => {
|
||||
const rgba = fromString(colorString).toRgbaArray();
|
||||
generatedColorShadesArr.push(
|
||||
formatColor({ prefix: key, rgb: rgba, opacity })
|
||||
);
|
||||
generatedColorShadesArr.push(formatColor({ key, rgb: rgba, opacity }));
|
||||
});
|
||||
} else {
|
||||
generatedColorShadesArr.push({
|
||||
|
74
src/Theme/index.test.ts
Normal file
74
src/Theme/index.test.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import {
|
||||
generateThemeOverrideClass,
|
||||
generateThemeRoot,
|
||||
generateTheme,
|
||||
ThemeInput,
|
||||
} from ".";
|
||||
|
||||
const exampleProperties = {
|
||||
"color-main-10": "black",
|
||||
"color-main-50": "grey",
|
||||
};
|
||||
|
||||
const exampleThemes: ThemeInput[] = [
|
||||
{
|
||||
name: "default",
|
||||
colors: { "color-main": "black" },
|
||||
},
|
||||
{
|
||||
name: "dark",
|
||||
colors: { "color-main": "white", "color-secondary": "blue" },
|
||||
},
|
||||
{ name: "light", colors: { "color-secondary": "grey" } },
|
||||
];
|
||||
|
||||
test("it generates css based on input properties", () => {
|
||||
const themeClass = generateThemeOverrideClass({
|
||||
properties: exampleProperties,
|
||||
className: "dark-theme",
|
||||
});
|
||||
|
||||
expect(themeClass).toBeDefined();
|
||||
});
|
||||
|
||||
test("no input so it returns empty string", () => {
|
||||
const themeClass = generateThemeOverrideClass({
|
||||
properties: {},
|
||||
className: "dark-theme",
|
||||
});
|
||||
|
||||
expect(themeClass).toBeDefined();
|
||||
expect(themeClass).toEqual("");
|
||||
});
|
||||
|
||||
test("it generates the theme root", () => {
|
||||
const themeRoot = generateThemeRoot({ properties: exampleProperties });
|
||||
console.log(themeRoot);
|
||||
expect(themeRoot).toBeDefined();
|
||||
});
|
||||
|
||||
test("it generates the complete theme with overrides", () => {
|
||||
const theme = generateTheme({
|
||||
themes: exampleThemes,
|
||||
output: "CSS",
|
||||
});
|
||||
|
||||
console.log(theme);
|
||||
|
||||
expect(theme).toBeDefined();
|
||||
});
|
||||
|
||||
test("it generates the complete theme with overrides and color shades", () => {
|
||||
const theme = generateTheme({
|
||||
themes: exampleThemes,
|
||||
output: "CSS",
|
||||
generateColorShades: {
|
||||
structure: "flat",
|
||||
format: "css-variable",
|
||||
},
|
||||
});
|
||||
|
||||
console.log(theme);
|
||||
|
||||
expect(theme).toBeDefined();
|
||||
});
|
@ -1,3 +1,85 @@
|
||||
import * as Colors from "./Colors";
|
||||
import { generateShades, ColorsInput, ShadesOptions } from "./Colors";
|
||||
|
||||
export default { Colors };
|
||||
export interface ThemeInput {
|
||||
name: string;
|
||||
colors: ColorsInput;
|
||||
}
|
||||
|
||||
const generateThemeOverrideClass = (input: {
|
||||
properties: any;
|
||||
className: string;
|
||||
}) => {
|
||||
const propKeys = Object.keys(input.properties);
|
||||
|
||||
if (propKeys.length > 0) {
|
||||
return `
|
||||
.${input.className} {${propKeys
|
||||
.map((key) => `\t--${key}: ${input.properties[key]};`)
|
||||
.join("\n")}}`;
|
||||
} else return "";
|
||||
};
|
||||
|
||||
const generateThemeRoot = (input: { properties: any }) => {
|
||||
const propKeys = Object.keys(input.properties);
|
||||
|
||||
if (propKeys.length > 0) {
|
||||
return `
|
||||
:root {${propKeys
|
||||
.map((key) => `\t--${key}: ${input.properties[key]};`)
|
||||
.join("\n")}}`;
|
||||
} else return "";
|
||||
};
|
||||
|
||||
const generateTheme = (options: {
|
||||
output?: "CSS";
|
||||
themes: ThemeInput[];
|
||||
generateColorShades?: boolean | ShadesOptions;
|
||||
}) => {
|
||||
if (
|
||||
options.generateColorShades !== undefined &&
|
||||
options.generateColorShades !== false
|
||||
) {
|
||||
options.themes = options.themes.map((theme) => {
|
||||
theme.colors = {
|
||||
...generateShades(
|
||||
theme.colors,
|
||||
typeof options.generateColorShades !== "boolean"
|
||||
? options.generateColorShades
|
||||
: undefined
|
||||
),
|
||||
...theme.colors,
|
||||
};
|
||||
|
||||
return theme;
|
||||
});
|
||||
}
|
||||
|
||||
const themeRoot = generateThemeRoot({
|
||||
properties: { ...options.themes[0].colors },
|
||||
});
|
||||
|
||||
if (options.themes.length > 1) {
|
||||
const themeOverrides = options.themes
|
||||
.slice(1)
|
||||
.map((theme) => {
|
||||
const overrideClass = generateThemeOverrideClass({
|
||||
properties: { ...theme.colors },
|
||||
className: theme.name,
|
||||
});
|
||||
|
||||
return overrideClass;
|
||||
})
|
||||
.join("\n");
|
||||
|
||||
return themeRoot + themeOverrides;
|
||||
} else return themeRoot;
|
||||
};
|
||||
|
||||
export { generateThemeOverrideClass, generateThemeRoot, generateTheme };
|
||||
export default {
|
||||
Colors,
|
||||
generateThemeOverrideClass,
|
||||
generateThemeRoot,
|
||||
generateTheme,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user