@udixio/theme 1.0.0-beta.2 → 1.0.0-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.container.d.ts +5 -0
- package/dist/app.module.d.ts +2 -2
- package/dist/app.service.d.ts +9 -3
- package/dist/color/color.interface.d.ts +1 -2
- package/dist/color/color.module.d.ts +2 -2
- package/dist/color/entities/color.entity.d.ts +6 -1
- package/dist/color/entities/index.d.ts +1 -0
- package/dist/color/index.d.ts +5 -0
- package/dist/color/models/default-color.model.d.ts +2 -3
- package/dist/color/models/index.d.ts +1 -0
- package/dist/color/services/color-manager.service.d.ts +18 -0
- package/dist/color/services/color.service.d.ts +21 -0
- package/dist/color/services/index.d.ts +2 -0
- package/dist/config/config.interface.d.ts +13 -0
- package/dist/config/config.module.d.ts +2 -0
- package/dist/config/config.service.d.ts +12 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/index.d.ts +11 -0
- package/dist/main.d.ts +2 -1
- package/dist/material-color-utilities/index.d.ts +1 -0
- package/dist/plugin/index.d.ts +3 -0
- package/dist/plugin/plugin.abstract.d.ts +7 -0
- package/dist/plugin/plugin.module.d.ts +2 -0
- package/dist/plugin/plugin.service.d.ts +12 -0
- package/dist/plugins/font/font.plugin.d.ts +38 -0
- package/dist/plugins/font/index.d.ts +1 -0
- package/dist/plugins/tailwind/index.d.ts +3 -0
- package/dist/plugins/tailwind/main.d.ts +13 -0
- package/dist/plugins/tailwind/plugins-tailwind/font.d.ts +5 -0
- package/dist/plugins/tailwind/plugins-tailwind/index.d.ts +2 -0
- package/dist/plugins/tailwind/plugins-tailwind/state.d.ts +4 -0
- package/dist/plugins/tailwind/plugins-tailwind/themer.d.ts +4 -0
- package/dist/plugins/tailwind/tailwind.plugin.d.ts +17 -0
- package/dist/theme/entities/index.d.ts +2 -0
- package/dist/theme/entities/variant.entity.d.ts +2 -1
- package/dist/theme/index.d.ts +4 -0
- package/dist/theme/models/index.d.ts +1 -0
- package/dist/theme/services/index.d.ts +3 -0
- package/dist/theme/services/scheme.service.d.ts +7 -2
- package/dist/theme/services/theme.service.d.ts +16 -7
- package/dist/theme/services/variant.service.d.ts +8 -2
- package/dist/theme/theme.module.d.ts +2 -2
- package/dist/theme.cjs.development.js +1316 -579
- package/dist/theme.cjs.development.js.map +1 -1
- package/dist/theme.cjs.production.min.js +1 -1
- package/dist/theme.cjs.production.min.js.map +1 -1
- package/dist/theme.esm.js +1284 -580
- package/dist/theme.esm.js.map +1 -1
- package/package.json +21 -22
- package/src/app.container.ts +46 -0
- package/src/app.module.ts +5 -8
- package/src/app.service.spec.ts +1 -1
- package/src/app.service.ts +20 -8
- package/src/color/color.interface.ts +1 -3
- package/src/color/color.module.ts +8 -10
- package/src/color/entities/color.entity.ts +14 -3
- package/src/color/entities/index.ts +1 -0
- package/src/color/index.ts +5 -0
- package/src/color/models/default-color.model.ts +205 -202
- package/src/color/models/index.ts +1 -0
- package/src/color/{color-manager.service.ts → services/color-manager.service.ts} +22 -17
- package/src/color/{color.service.spec.ts → services/color.service.spec.ts} +1 -1
- package/src/color/services/color.service.ts +75 -0
- package/src/color/services/index.ts +2 -0
- package/src/config/config.interface.ts +14 -0
- package/src/config/config.module.ts +7 -0
- package/src/config/config.service.ts +95 -0
- package/src/config/index.ts +3 -0
- package/src/index.ts +11 -0
- package/src/main.ts +10 -7
- package/src/material-color-utilities/index.ts +1 -0
- package/src/plugin/index.ts +3 -0
- package/src/plugin/plugin.abstract.ts +9 -0
- package/src/plugin/plugin.module.ts +7 -0
- package/src/plugin/plugin.service.ts +48 -0
- package/src/plugins/font/font.plugin.ts +172 -0
- package/src/plugins/font/index.ts +1 -0
- package/src/plugins/tailwind/index.ts +3 -0
- package/src/plugins/tailwind/main.ts +19 -0
- package/src/plugins/tailwind/plugins-tailwind/font.ts +69 -0
- package/src/plugins/tailwind/plugins-tailwind/index.ts +2 -0
- package/src/plugins/tailwind/plugins-tailwind/state.ts +88 -0
- package/src/plugins/tailwind/plugins-tailwind/themer.ts +53 -0
- package/src/plugins/tailwind/tailwind.plugin.ts +64 -0
- package/src/theme/entities/index.ts +2 -0
- package/src/theme/entities/variant.entity.ts +2 -1
- package/src/theme/index.ts +4 -0
- package/src/theme/models/index.ts +1 -0
- package/src/theme/models/variant.model.ts +7 -0
- package/src/theme/services/index.ts +3 -0
- package/src/theme/services/scheme.service.ts +39 -11
- package/src/theme/services/theme.service.ts +30 -14
- package/src/theme/services/variant.service.ts +40 -5
- package/src/theme/theme.module.ts +8 -9
- package/dist/color/color-manager.service.d.ts +0 -15
- package/dist/color/color.service.d.ts +0 -13
- package/src/color/color.service.ts +0 -52
package/src/index.ts
CHANGED
|
@@ -1 +1,12 @@
|
|
|
1
|
+
export { default as AppContainer } from './app.container';
|
|
2
|
+
export * from './app.container';
|
|
3
|
+
export * from './app.module';
|
|
4
|
+
export * from './app.service';
|
|
5
|
+
export * from './color';
|
|
6
|
+
export * from './config';
|
|
1
7
|
export * from './main';
|
|
8
|
+
export * from './material-color-utilities';
|
|
9
|
+
export * from './plugin';
|
|
10
|
+
export * from './plugins/font';
|
|
11
|
+
export * from './plugins/tailwind';
|
|
12
|
+
export * from './theme';
|
package/src/main.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { AppModule } from './app.module';
|
|
1
|
+
import AppContainer from './app.container';
|
|
3
2
|
import { AppService } from './app.service';
|
|
3
|
+
import { ConfigService } from './config';
|
|
4
4
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
export function bootstrap(): AppService {
|
|
6
|
+
return AppContainer.resolve<AppService>('appService');
|
|
7
|
+
}
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
export function bootstrapFromConfig(path?: string): AppService {
|
|
10
|
+
const configService = AppContainer.resolve<ConfigService>('configService');
|
|
11
|
+
if (path) configService.configPath = path;
|
|
12
|
+
configService.loadConfig();
|
|
13
|
+
return AppContainer.resolve<AppService>('appService');
|
|
11
14
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AppService } from '../app.service';
|
|
2
|
+
import { PluginConstructor } from './plugin.service';
|
|
3
|
+
|
|
4
|
+
export abstract class PluginAbstract {
|
|
5
|
+
static dependencies: PluginConstructor[] = [];
|
|
6
|
+
|
|
7
|
+
protected abstract appService: AppService;
|
|
8
|
+
protected abstract options: object;
|
|
9
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { PluginAbstract } from './plugin.abstract';
|
|
2
|
+
import { AppService } from '../app.service';
|
|
3
|
+
|
|
4
|
+
export type PluginConstructor = (new (
|
|
5
|
+
appService: AppService,
|
|
6
|
+
options: any
|
|
7
|
+
) => PluginAbstract) & { dependencies: PluginConstructor[] };
|
|
8
|
+
|
|
9
|
+
export class PluginService {
|
|
10
|
+
private pluginInstances = new Map<string, PluginAbstract>();
|
|
11
|
+
private pluginConstructors = new Map<string, [PluginConstructor, object]>();
|
|
12
|
+
|
|
13
|
+
public addPlugin(plugin: PluginConstructor, config: object) {
|
|
14
|
+
this.pluginConstructors.set(plugin.name, [plugin, config]);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public loadPlugins(appService: AppService) {
|
|
18
|
+
const plugins = new Map(this.pluginConstructors);
|
|
19
|
+
|
|
20
|
+
let size = 0;
|
|
21
|
+
do {
|
|
22
|
+
size = plugins.size;
|
|
23
|
+
plugins.forEach(([plugin, option], key) => {
|
|
24
|
+
const deps = plugin.dependencies.filter(
|
|
25
|
+
(dep) => !this.pluginInstances.has(dep.name)
|
|
26
|
+
);
|
|
27
|
+
if (deps.length === 0) {
|
|
28
|
+
this.pluginInstances.set(plugin.name, new plugin(appService, option));
|
|
29
|
+
plugins.delete(key);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
} while (plugins.size != 0 && plugins.size < size);
|
|
33
|
+
|
|
34
|
+
if (plugins.size > 0)
|
|
35
|
+
console.log(
|
|
36
|
+
"Some plugins couldn't be loaded due to missing dependencies: ",
|
|
37
|
+
Array.from(plugins.keys())
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public getPlugin<T extends PluginAbstract>(
|
|
42
|
+
plugin: new (appService: AppService, options: any) => T
|
|
43
|
+
): T {
|
|
44
|
+
const pluginInstance = this.pluginInstances.get(plugin.name);
|
|
45
|
+
if (!pluginInstance) throw new Error(`Plugin ${plugin.name} not found`);
|
|
46
|
+
return pluginInstance as T;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { PluginAbstract } from '../../plugin';
|
|
2
|
+
import { AppService } from '../../app.service';
|
|
3
|
+
|
|
4
|
+
export enum FontFamily {
|
|
5
|
+
Expressive = 'expressive',
|
|
6
|
+
Neutral = 'neutral',
|
|
7
|
+
}
|
|
8
|
+
export type FontStyle = {
|
|
9
|
+
fontSize: number;
|
|
10
|
+
lineHeight: number;
|
|
11
|
+
fontWeight: number;
|
|
12
|
+
letterSpacing?: number;
|
|
13
|
+
fontFamily: FontFamily;
|
|
14
|
+
};
|
|
15
|
+
export type FontRole = 'display' | 'headline' | 'title' | 'label' | 'body';
|
|
16
|
+
export type FontSize = 'large' | 'medium' | 'small';
|
|
17
|
+
interface FontPluginOptions {
|
|
18
|
+
fontFamily?: {
|
|
19
|
+
expressive?: string[];
|
|
20
|
+
neutral?: string[];
|
|
21
|
+
};
|
|
22
|
+
fontStyles?: Partial<Record<FontRole, Record<FontSize, Partial<FontStyle>>>>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class FontPlugin extends PluginAbstract {
|
|
26
|
+
private readonly fontFamily: { expressive: string[]; neutral: string[] };
|
|
27
|
+
private readonly fontStyles: Record<FontRole, Record<FontSize, FontStyle>>;
|
|
28
|
+
|
|
29
|
+
constructor(
|
|
30
|
+
protected appService: AppService,
|
|
31
|
+
protected options: FontPluginOptions
|
|
32
|
+
) {
|
|
33
|
+
super();
|
|
34
|
+
this.fontFamily = {
|
|
35
|
+
expressive: options?.fontFamily?.expressive ?? ['Roboto', 'sans-serif'],
|
|
36
|
+
neutral: options?.fontFamily?.neutral ?? ['Roboto', 'sans-serif'],
|
|
37
|
+
};
|
|
38
|
+
this.fontStyles = {
|
|
39
|
+
display: {
|
|
40
|
+
large: {
|
|
41
|
+
fontWeight: 400,
|
|
42
|
+
fontSize: 3.5625,
|
|
43
|
+
lineHeight: 4,
|
|
44
|
+
letterSpacing: -0.015625,
|
|
45
|
+
fontFamily: FontFamily.Expressive,
|
|
46
|
+
},
|
|
47
|
+
medium: {
|
|
48
|
+
fontWeight: 400,
|
|
49
|
+
fontSize: 2.8125,
|
|
50
|
+
lineHeight: 3.25,
|
|
51
|
+
fontFamily: FontFamily.Expressive,
|
|
52
|
+
},
|
|
53
|
+
small: {
|
|
54
|
+
fontWeight: 400,
|
|
55
|
+
fontSize: 2.25,
|
|
56
|
+
lineHeight: 2.75,
|
|
57
|
+
fontFamily: FontFamily.Expressive,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
headline: {
|
|
61
|
+
large: {
|
|
62
|
+
fontWeight: 400,
|
|
63
|
+
fontSize: 2,
|
|
64
|
+
lineHeight: 2.5,
|
|
65
|
+
fontFamily: FontFamily.Expressive,
|
|
66
|
+
},
|
|
67
|
+
medium: {
|
|
68
|
+
fontWeight: 400,
|
|
69
|
+
fontSize: 1.75,
|
|
70
|
+
lineHeight: 2.25,
|
|
71
|
+
fontFamily: FontFamily.Expressive,
|
|
72
|
+
},
|
|
73
|
+
small: {
|
|
74
|
+
fontWeight: 400,
|
|
75
|
+
fontSize: 1.5,
|
|
76
|
+
lineHeight: 2,
|
|
77
|
+
fontFamily: FontFamily.Expressive,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
title: {
|
|
81
|
+
large: {
|
|
82
|
+
fontWeight: 400,
|
|
83
|
+
fontSize: 1.375,
|
|
84
|
+
lineHeight: 1.75,
|
|
85
|
+
fontFamily: FontFamily.Neutral,
|
|
86
|
+
},
|
|
87
|
+
medium: {
|
|
88
|
+
fontWeight: 500,
|
|
89
|
+
fontSize: 1,
|
|
90
|
+
lineHeight: 1.5,
|
|
91
|
+
fontFamily: FontFamily.Neutral,
|
|
92
|
+
letterSpacing: 0.009375,
|
|
93
|
+
},
|
|
94
|
+
small: {
|
|
95
|
+
fontWeight: 500,
|
|
96
|
+
fontSize: 0.875,
|
|
97
|
+
lineHeight: 1.25,
|
|
98
|
+
fontFamily: FontFamily.Neutral,
|
|
99
|
+
letterSpacing: 0.00625,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
label: {
|
|
103
|
+
large: {
|
|
104
|
+
fontWeight: 500,
|
|
105
|
+
fontSize: 0.875,
|
|
106
|
+
lineHeight: 1.25,
|
|
107
|
+
fontFamily: FontFamily.Neutral,
|
|
108
|
+
letterSpacing: 0.00625,
|
|
109
|
+
},
|
|
110
|
+
medium: {
|
|
111
|
+
fontWeight: 500,
|
|
112
|
+
fontSize: 0.75,
|
|
113
|
+
lineHeight: 1,
|
|
114
|
+
fontFamily: FontFamily.Neutral,
|
|
115
|
+
letterSpacing: 0.03125,
|
|
116
|
+
},
|
|
117
|
+
small: {
|
|
118
|
+
fontWeight: 500,
|
|
119
|
+
fontSize: 0.6875,
|
|
120
|
+
lineHeight: 1,
|
|
121
|
+
fontFamily: FontFamily.Neutral,
|
|
122
|
+
letterSpacing: 0.03125,
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
body: {
|
|
126
|
+
large: {
|
|
127
|
+
fontWeight: 400,
|
|
128
|
+
fontSize: 1,
|
|
129
|
+
lineHeight: 1.5625,
|
|
130
|
+
fontFamily: FontFamily.Neutral,
|
|
131
|
+
letterSpacing: 0.03125,
|
|
132
|
+
},
|
|
133
|
+
medium: {
|
|
134
|
+
fontWeight: 400,
|
|
135
|
+
fontSize: 0.875,
|
|
136
|
+
lineHeight: 1.25,
|
|
137
|
+
fontFamily: FontFamily.Neutral,
|
|
138
|
+
letterSpacing: 0.015625,
|
|
139
|
+
},
|
|
140
|
+
small: {
|
|
141
|
+
fontWeight: 400,
|
|
142
|
+
fontSize: 0.75,
|
|
143
|
+
lineHeight: 1,
|
|
144
|
+
fontFamily: FontFamily.Neutral,
|
|
145
|
+
letterSpacing: 0.025,
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
if (options && options.fontStyles)
|
|
150
|
+
Object.entries(options.fontStyles).forEach(([key, fontParam]) => {
|
|
151
|
+
const fontRole: FontRole = key as FontRole;
|
|
152
|
+
Object.entries(fontParam).forEach(([size, fontStyle]) => {
|
|
153
|
+
const fontSize: FontSize = size as FontSize;
|
|
154
|
+
if (fontStyle) {
|
|
155
|
+
this.fontStyles[fontRole][fontSize] = {
|
|
156
|
+
...this.fontStyles[fontRole][fontSize],
|
|
157
|
+
...fontStyle,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
static config(options: FontPluginOptions): FontPluginOptions {
|
|
164
|
+
return options;
|
|
165
|
+
}
|
|
166
|
+
getFonts() {
|
|
167
|
+
return {
|
|
168
|
+
fontStyles: this.fontStyles,
|
|
169
|
+
fontFamily: this.fontFamily,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './font.plugin';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PluginsConfig } from 'tailwindcss/types/config';
|
|
2
|
+
import { bootstrapFromConfig } from '../../main';
|
|
3
|
+
import { TailwindPlugin } from './tailwind.plugin';
|
|
4
|
+
import { AppService } from '../../app.service';
|
|
5
|
+
|
|
6
|
+
export type Theme = {
|
|
7
|
+
colors: Record<string, string>;
|
|
8
|
+
fontFamily: { expressive: string[]; neutral: string[] };
|
|
9
|
+
plugins: Partial<PluginsConfig>;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const createTheme = (): Theme & { appService: AppService } => {
|
|
13
|
+
const app = bootstrapFromConfig();
|
|
14
|
+
const plugin = app.pluginService.getPlugin(TailwindPlugin);
|
|
15
|
+
if (!plugin) {
|
|
16
|
+
throw new Error('Tailwind plugin not found');
|
|
17
|
+
}
|
|
18
|
+
return { ...plugin.getTheme(), appService: app };
|
|
19
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import plugin from 'tailwindcss/plugin';
|
|
2
|
+
import { CSSRuleObject, PluginAPI } from 'tailwindcss/types/config';
|
|
3
|
+
import { FontRole, FontSize, FontStyle } from '../../font/font.plugin';
|
|
4
|
+
|
|
5
|
+
export const font = (
|
|
6
|
+
fontStyles: Record<FontRole, Record<FontSize, FontStyle>>,
|
|
7
|
+
responsiveBreakPoints: Record<string, number>
|
|
8
|
+
) => {
|
|
9
|
+
const createUtilities = ({
|
|
10
|
+
theme,
|
|
11
|
+
}: Pick<PluginAPI, 'theme'>): CSSRuleObject => {
|
|
12
|
+
const pixelUnit = 'rem';
|
|
13
|
+
const newUtilities: any = {};
|
|
14
|
+
|
|
15
|
+
const baseTextStyle = (sizeValue: FontStyle) => ({
|
|
16
|
+
fontSize: sizeValue.fontSize + pixelUnit,
|
|
17
|
+
fontWeight: sizeValue.fontWeight as unknown as CSSRuleObject,
|
|
18
|
+
lineHeight: sizeValue.lineHeight + pixelUnit,
|
|
19
|
+
letterSpacing: sizeValue.letterSpacing
|
|
20
|
+
? sizeValue.letterSpacing + pixelUnit
|
|
21
|
+
: null,
|
|
22
|
+
fontFamily: theme('fontFamily.' + sizeValue.fontFamily),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const responsiveTextStyle = (
|
|
26
|
+
sizeValue: FontStyle,
|
|
27
|
+
breakPointName: string,
|
|
28
|
+
breakPointRatio: number
|
|
29
|
+
) => ({
|
|
30
|
+
[`@media (min-width: ${theme('screens.' + breakPointName, {})})`]: {
|
|
31
|
+
fontSize: sizeValue.fontSize * breakPointRatio + pixelUnit,
|
|
32
|
+
lineHeight: sizeValue.lineHeight * breakPointRatio + pixelUnit,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
for (const [roleName, roleValue] of Object.entries(fontStyles)) {
|
|
37
|
+
for (const [sizeName, sizeValue] of Object.entries(roleValue)) {
|
|
38
|
+
newUtilities['.text-' + roleName + '-' + sizeName] = {
|
|
39
|
+
...baseTextStyle(sizeValue),
|
|
40
|
+
...Object.entries(responsiveBreakPoints).reduce(
|
|
41
|
+
(acc, [breakPointName, breakPointRatio]) => {
|
|
42
|
+
acc = {
|
|
43
|
+
...acc,
|
|
44
|
+
...responsiveTextStyle(
|
|
45
|
+
sizeValue,
|
|
46
|
+
breakPointName,
|
|
47
|
+
breakPointRatio
|
|
48
|
+
),
|
|
49
|
+
};
|
|
50
|
+
return acc;
|
|
51
|
+
},
|
|
52
|
+
{}
|
|
53
|
+
),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return newUtilities as CSSRuleObject;
|
|
59
|
+
};
|
|
60
|
+
return plugin(
|
|
61
|
+
({
|
|
62
|
+
addUtilities,
|
|
63
|
+
theme,
|
|
64
|
+
}: Pick<PluginAPI, 'theme'> & Pick<PluginAPI, 'addUtilities'>) => {
|
|
65
|
+
const newUtilities = createUtilities({ theme });
|
|
66
|
+
addUtilities(newUtilities);
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// from tailwindcss src/util/flattenColors
|
|
2
|
+
import plugin from 'tailwindcss/plugin';
|
|
3
|
+
import { PluginAPI } from 'tailwindcss/types/config';
|
|
4
|
+
|
|
5
|
+
type State = {
|
|
6
|
+
statePrefix: string;
|
|
7
|
+
disabledStyles: {
|
|
8
|
+
textOpacity: number;
|
|
9
|
+
backgroundOpacity: number;
|
|
10
|
+
};
|
|
11
|
+
transition: {
|
|
12
|
+
duration: number;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
type Components = Record<string, Record<string, {}>>;
|
|
17
|
+
|
|
18
|
+
export const state = (colorkeys: string[]) =>
|
|
19
|
+
plugin((pluginArgs: PluginAPI) => {
|
|
20
|
+
addAllNewComponents(
|
|
21
|
+
pluginArgs,
|
|
22
|
+
{
|
|
23
|
+
statePrefix: 'state',
|
|
24
|
+
disabledStyles: {
|
|
25
|
+
textOpacity: 0.38,
|
|
26
|
+
backgroundOpacity: 0.12,
|
|
27
|
+
},
|
|
28
|
+
transition: {
|
|
29
|
+
duration: 150,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
colorkeys
|
|
33
|
+
);
|
|
34
|
+
}, {});
|
|
35
|
+
|
|
36
|
+
const addAllNewComponents = (
|
|
37
|
+
{ addComponents }: PluginAPI,
|
|
38
|
+
{ statePrefix, disabledStyles, transition }: State,
|
|
39
|
+
colorKeys: string[]
|
|
40
|
+
) => {
|
|
41
|
+
const newComponents: Components = {};
|
|
42
|
+
|
|
43
|
+
for (const isGroup of [false, true]) {
|
|
44
|
+
const group = isGroup ? 'group-' : '';
|
|
45
|
+
for (const colorName of colorKeys) {
|
|
46
|
+
const className = `.${group}${statePrefix}-${colorName}`;
|
|
47
|
+
newComponents[className] = {
|
|
48
|
+
[`@apply ${group}hover:bg-${colorName}/[0.08]`]: {},
|
|
49
|
+
[`@apply ${group}active:bg-${colorName}/[0.12]`]: {},
|
|
50
|
+
[`@apply ${group}focus-visible:bg-${colorName}/[0.12]`]: {},
|
|
51
|
+
};
|
|
52
|
+
if (transition) {
|
|
53
|
+
newComponents[className][`@apply transition-colors`] = {};
|
|
54
|
+
newComponents[className][`@apply duration-${transition.duration}`] = {};
|
|
55
|
+
}
|
|
56
|
+
if (disabledStyles) {
|
|
57
|
+
newComponents[className][
|
|
58
|
+
`@apply ${group}disabled:text-on-surface/[${disabledStyles.textOpacity}]`
|
|
59
|
+
] = {};
|
|
60
|
+
newComponents[className][
|
|
61
|
+
`@apply ${group}disabled:bg-on-surface/[${disabledStyles.backgroundOpacity}]`
|
|
62
|
+
] = {};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
for (const colorName of colorKeys) {
|
|
67
|
+
for (const stateName of ['hover', 'active', 'focus', 'disabled']) {
|
|
68
|
+
const className = `.${stateName}-${statePrefix}-${colorName}`;
|
|
69
|
+
if (stateName === 'active' || stateName === 'focus') {
|
|
70
|
+
newComponents[className] = {
|
|
71
|
+
[`@apply bg-${colorName}/[0.12]`]: {},
|
|
72
|
+
};
|
|
73
|
+
} else if (stateName === 'hover') {
|
|
74
|
+
newComponents[className] = {
|
|
75
|
+
[`@apply bg-${colorName}/[0.08]`]: {},
|
|
76
|
+
};
|
|
77
|
+
} else if (stateName === 'disabled') {
|
|
78
|
+
newComponents[className] = {
|
|
79
|
+
[`@apply text-on-surface/[${disabledStyles.textOpacity}]`]: {},
|
|
80
|
+
};
|
|
81
|
+
newComponents[className] = {
|
|
82
|
+
[`@apply bg-on-surface/[${disabledStyles.backgroundOpacity}]`]: {},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
addComponents(newComponents);
|
|
88
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export const themer = (
|
|
2
|
+
colors: Record<
|
|
3
|
+
string,
|
|
4
|
+
{
|
|
5
|
+
light: string;
|
|
6
|
+
dark: string;
|
|
7
|
+
}
|
|
8
|
+
>,
|
|
9
|
+
darkMode: 'class' | 'media'
|
|
10
|
+
) => {
|
|
11
|
+
const options: {
|
|
12
|
+
defaultTheme: {
|
|
13
|
+
extend: {
|
|
14
|
+
colors: Record<string, string>;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
themes: [
|
|
18
|
+
{
|
|
19
|
+
name: 'darkTheme';
|
|
20
|
+
selectors?: ['.dark-mode', '[data-theme="dark"]'];
|
|
21
|
+
mediaQuery?: '@media (prefers-color-scheme: dark)';
|
|
22
|
+
extend: {
|
|
23
|
+
colors: Record<string, string>;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
];
|
|
27
|
+
} = {
|
|
28
|
+
defaultTheme: {
|
|
29
|
+
extend: {
|
|
30
|
+
colors: {},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
themes: [
|
|
34
|
+
{
|
|
35
|
+
name: 'darkTheme',
|
|
36
|
+
extend: {
|
|
37
|
+
colors: {},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
Object.entries(colors).forEach(([key, value]) => {
|
|
44
|
+
options.defaultTheme.extend.colors[key] = value.light;
|
|
45
|
+
options.themes[0].extend.colors[key] = value.dark;
|
|
46
|
+
});
|
|
47
|
+
options.themes[0].selectors =
|
|
48
|
+
darkMode === 'class' ? ['.dark-mode', '[data-theme="dark"]'] : undefined;
|
|
49
|
+
options.themes[0].mediaQuery =
|
|
50
|
+
darkMode === 'media' ? '@media (prefers-color-scheme: dark)' : undefined;
|
|
51
|
+
|
|
52
|
+
return require('tailwindcss-themer')(options);
|
|
53
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { PluginAbstract } from '../../plugin/plugin.abstract';
|
|
2
|
+
import { AppService } from '../../app.service';
|
|
3
|
+
import { Theme } from './main';
|
|
4
|
+
import { state } from './plugins-tailwind/state';
|
|
5
|
+
import { themer } from './plugins-tailwind/themer';
|
|
6
|
+
import { FontPlugin } from '../font/font.plugin';
|
|
7
|
+
import { font } from './plugins-tailwind/font';
|
|
8
|
+
|
|
9
|
+
interface TailwindPluginOptions {
|
|
10
|
+
darkMode?: 'class' | 'media';
|
|
11
|
+
responsiveBreakPoints?: Record<string, number>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class TailwindPlugin extends PluginAbstract {
|
|
15
|
+
static dependencies = [FontPlugin];
|
|
16
|
+
constructor(
|
|
17
|
+
protected appService: AppService,
|
|
18
|
+
protected options: TailwindPluginOptions
|
|
19
|
+
) {
|
|
20
|
+
options.darkMode ??= 'class';
|
|
21
|
+
options.responsiveBreakPoints ??= {
|
|
22
|
+
lg: 1.125,
|
|
23
|
+
};
|
|
24
|
+
super();
|
|
25
|
+
}
|
|
26
|
+
static config(options: TailwindPluginOptions): TailwindPluginOptions {
|
|
27
|
+
return options;
|
|
28
|
+
}
|
|
29
|
+
getTheme(): Theme {
|
|
30
|
+
const colors: Record<
|
|
31
|
+
string,
|
|
32
|
+
{
|
|
33
|
+
light: string;
|
|
34
|
+
dark: string;
|
|
35
|
+
}
|
|
36
|
+
> = {};
|
|
37
|
+
|
|
38
|
+
for (const isDark of [false, true]) {
|
|
39
|
+
this.appService.themeService.update({ isDark: isDark });
|
|
40
|
+
for (const [key, value] of this.appService.colorService
|
|
41
|
+
.getColors()
|
|
42
|
+
.entries()) {
|
|
43
|
+
const newKey = key
|
|
44
|
+
.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2')
|
|
45
|
+
.toLowerCase();
|
|
46
|
+
colors[newKey] ??= { light: '', dark: '' };
|
|
47
|
+
colors[newKey][isDark ? 'dark' : 'light'] = value.getHex();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const { fontStyles, fontFamily } = this.appService.pluginService
|
|
52
|
+
.getPlugin(FontPlugin)
|
|
53
|
+
.getFonts();
|
|
54
|
+
return {
|
|
55
|
+
colors: {},
|
|
56
|
+
fontFamily: fontFamily,
|
|
57
|
+
plugins: [
|
|
58
|
+
state(Object.keys(colors)),
|
|
59
|
+
themer(colors, this.options.darkMode!),
|
|
60
|
+
font(fontStyles, this.options.responsiveBreakPoints!),
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -33,6 +33,7 @@ export const getRotatedHue = (
|
|
|
33
33
|
|
|
34
34
|
export class VariantEntity {
|
|
35
35
|
constructor(
|
|
36
|
-
public palettes: Record<string, (sourceColorHct: Hct) => TonalPalette> = {}
|
|
36
|
+
public palettes: Record<string, (sourceColorHct: Hct) => TonalPalette> = {},
|
|
37
|
+
public customPalettes?: (colorHct: Hct) => TonalPalette
|
|
37
38
|
) {}
|
|
38
39
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './variant.model';
|
|
@@ -21,6 +21,8 @@ export class VariantModel {
|
|
|
21
21
|
neutralVariant: (sourceColorHct) =>
|
|
22
22
|
TonalPalette.fromHueAndChroma(sourceColorHct.hue, 8.0),
|
|
23
23
|
},
|
|
24
|
+
customPalettes: (colorHct) =>
|
|
25
|
+
TonalPalette.fromHueAndChroma(colorHct.hue, 16),
|
|
24
26
|
};
|
|
25
27
|
static vibrant: VariantEntity = {
|
|
26
28
|
palettes: {
|
|
@@ -41,6 +43,11 @@ export class VariantModel {
|
|
|
41
43
|
neutralVariant: (sourceColorHct) =>
|
|
42
44
|
TonalPalette.fromHueAndChroma(sourceColorHct.hue, 8.0),
|
|
43
45
|
},
|
|
46
|
+
customPalettes: (colorHct) =>
|
|
47
|
+
TonalPalette.fromHueAndChroma(
|
|
48
|
+
getRotatedHue(colorHct, this.hues, this.secondaryRotations),
|
|
49
|
+
24.0
|
|
50
|
+
),
|
|
44
51
|
};
|
|
45
52
|
|
|
46
53
|
private static readonly hues = [
|