@shohojdhara/atomix 0.3.1 → 0.3.2
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/CHANGELOG.md +0 -1
- package/README.md +3 -5
- package/dist/atomix.css +458 -552
- package/dist/atomix.min.css +3 -3
- package/dist/index.d.ts +2435 -358
- package/dist/index.esm.js +5758 -1901
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +5768 -1933
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +1 -11
- package/src/lib/composables/useAtomixGlass.ts +46 -46
- package/src/lib/index.ts +1 -4
- package/src/lib/theme/config/index.ts +21 -0
- package/src/lib/theme/config/loader.ts +276 -0
- package/src/lib/theme/config/types.ts +98 -0
- package/src/lib/theme/config/validator.ts +326 -0
- package/src/lib/theme/constants.ts +183 -0
- package/src/lib/theme/core/ThemeCache.ts +283 -0
- package/src/lib/theme/core/ThemeEngine.test.ts +146 -0
- package/src/lib/theme/core/ThemeEngine.ts +657 -0
- package/src/lib/theme/core/ThemeRegistry.ts +284 -0
- package/src/lib/theme/core/ThemeValidator.ts +530 -0
- package/src/lib/theme/core/index.ts +24 -0
- package/src/lib/theme/createTheme.ts +81 -70
- package/src/lib/theme/devtools/CLI.ts +279 -0
- package/src/lib/theme/devtools/Inspector.tsx +594 -0
- package/src/lib/theme/devtools/Preview.tsx +392 -0
- package/src/lib/theme/devtools/index.ts +21 -0
- package/src/lib/theme/errors.test.ts +207 -0
- package/src/lib/theme/errors.ts +233 -0
- package/src/lib/theme/generateCSSVariables.ts +93 -9
- package/src/lib/theme/generators/CSSGenerator.ts +311 -0
- package/src/lib/theme/generators/ConfigGenerator.ts +287 -0
- package/src/lib/theme/generators/TypeGenerator.ts +228 -0
- package/src/lib/theme/generators/index.ts +21 -0
- package/src/lib/theme/i18n/index.ts +9 -0
- package/src/lib/theme/i18n/rtl.ts +325 -0
- package/src/lib/theme/index.ts +155 -11
- package/src/lib/theme/monitoring/ThemeAnalytics.ts +409 -0
- package/src/lib/theme/monitoring/index.ts +17 -0
- package/src/lib/theme/overrides/ComponentOverrides.ts +243 -0
- package/src/lib/theme/overrides/index.ts +15 -0
- package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +233 -0
- package/src/lib/theme/runtime/ThemeManager.test.ts +176 -0
- package/src/lib/theme/runtime/ThemeManager.ts +442 -0
- package/src/lib/theme/runtime/ThemeProvider.tsx +318 -0
- package/src/lib/theme/runtime/index.ts +17 -0
- package/src/lib/theme/runtime/useTheme.ts +52 -0
- package/src/lib/theme/studio/ThemeStudio.tsx +312 -0
- package/src/lib/theme/studio/index.ts +8 -0
- package/src/lib/theme/types.ts +3 -1
- package/src/lib/theme/utils.ts +23 -22
- package/src/lib/theme/whitelabel/WhiteLabelManager.ts +364 -0
- package/src/lib/theme/whitelabel/index.ts +13 -0
- package/src/styles/01-settings/_settings.badge.scss +1 -1
- package/src/styles/01-settings/_settings.callout.scss +1 -1
- package/src/styles/01-settings/_settings.card.scss +1 -1
- package/src/styles/01-settings/_settings.input.scss +1 -1
- package/src/styles/01-settings/_settings.navbar.scss +1 -1
- package/src/styles/01-settings/_settings.upload.scss +1 -1
- package/src/styles/06-components/_components.chart.scss +2 -2
- package/src/styles/99-utilities/_utilities.border.scss +27 -58
- package/src/styles/99-utilities/_utilities.gradient.scss +12 -0
- package/src/styles/99-utilities/_utilities.position.scss +8 -15
- package/src/styles/99-utilities/_utilities.scss +2 -0
- package/src/styles/99-utilities/_utilities.spacing.scss +76 -121
- package/src/styles/99-utilities/_utilities.text.scss +30 -49
- package/dist/themes/applemix.css +0 -15615
- package/dist/themes/applemix.min.css +0 -70
- package/dist/themes/boomdevs.css +0 -15193
- package/dist/themes/boomdevs.min.css +0 -403
- package/dist/themes/esrar.css +0 -17399
- package/dist/themes/esrar.min.css +0 -187
- package/dist/themes/flashtrade.css +0 -16613
- package/dist/themes/flashtrade.min.css +0 -190
- package/dist/themes/mashroom.css +0 -30104
- package/dist/themes/mashroom.min.css +0 -401
- package/dist/themes/shaj-default.css +0 -16228
- package/dist/themes/shaj-default.min.css +0 -498
- package/src/lib/theme/ThemeManager.integration.test.ts +0 -124
- package/src/lib/theme/ThemeManager.stories.tsx +0 -472
- package/src/lib/theme/ThemeManager.test.ts +0 -190
- package/src/lib/theme/ThemeManager.ts +0 -645
- package/src/lib/theme/ThemeProvider.tsx +0 -377
- package/src/lib/theme/createTheme.test.ts +0 -475
- package/src/lib/theme/useTheme.test.tsx +0 -67
- package/src/lib/theme/useTheme.ts +0 -64
- package/src/lib/theme/utils.test.ts +0 -140
package/src/lib/theme/types.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* TypeScript types and interfaces for the Atomix Design System theme management system.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type { ThemeManager as ThemeManagerType } from './ThemeManager';
|
|
7
|
+
import type { ThemeManager as ThemeManagerType } from './runtime/ThemeManager';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Theme metadata interface matching themes.config.js structure
|
|
@@ -71,6 +71,8 @@ export interface ThemeManagerConfig {
|
|
|
71
71
|
onThemeChange?: (theme: string | Theme) => void;
|
|
72
72
|
/** Callback when theme load fails */
|
|
73
73
|
onError?: (error: Error, themeName: string) => void;
|
|
74
|
+
/** RTL configuration */
|
|
75
|
+
rtl?: import('./i18n/rtl').RTLConfig;
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
/**
|
package/src/lib/theme/utils.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { ThemeMetadata, ThemeValidationResult } from './types';
|
|
9
|
+
import { THEME_LINK_ID_PREFIX } from './constants';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Check if code is running in a browser environment
|
|
@@ -25,7 +26,7 @@ export const isServer = (): boolean => {
|
|
|
25
26
|
* Generate a unique ID for theme link elements
|
|
26
27
|
*/
|
|
27
28
|
export const getThemeLinkId = (themeName: string): string => {
|
|
28
|
-
return
|
|
29
|
+
return `${THEME_LINK_ID_PREFIX}${themeName}`;
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
/**
|
|
@@ -65,28 +66,24 @@ export const buildThemePath = (
|
|
|
65
66
|
return `${cleanBasePath}/${cleanFileName}`;
|
|
66
67
|
};
|
|
67
68
|
|
|
69
|
+
|
|
70
|
+
|
|
68
71
|
/**
|
|
69
|
-
* Load theme CSS
|
|
72
|
+
* Load theme CSS from a full path
|
|
70
73
|
*
|
|
71
|
-
* @param
|
|
72
|
-
* @param
|
|
73
|
-
* @param useMinified - Whether to use minified CSS
|
|
74
|
-
* @param cdnPath - Optional CDN path
|
|
74
|
+
* @param fullPath - Full path to the CSS file
|
|
75
|
+
* @param linkId - ID for the link element
|
|
75
76
|
* @returns Promise that resolves when CSS is loaded
|
|
76
77
|
*/
|
|
77
78
|
export const loadThemeCSS = (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
useMinified: boolean = false,
|
|
81
|
-
cdnPath: string | null = null
|
|
79
|
+
fullPath: string,
|
|
80
|
+
linkId: string
|
|
82
81
|
): Promise<void> => {
|
|
83
82
|
if (isServer()) {
|
|
84
83
|
return Promise.resolve();
|
|
85
84
|
}
|
|
86
85
|
|
|
87
86
|
return new Promise((resolve, reject) => {
|
|
88
|
-
const linkId = getThemeLinkId(themeName);
|
|
89
|
-
|
|
90
87
|
// Check if theme is already loaded
|
|
91
88
|
const existingLink = document.getElementById(linkId);
|
|
92
89
|
if (existingLink) {
|
|
@@ -99,10 +96,10 @@ export const loadThemeCSS = (
|
|
|
99
96
|
link.id = linkId;
|
|
100
97
|
link.rel = 'stylesheet';
|
|
101
98
|
link.type = 'text/css';
|
|
102
|
-
link.href =
|
|
99
|
+
link.href = fullPath;
|
|
103
100
|
|
|
104
101
|
// Add data attribute for tracking
|
|
105
|
-
link.setAttribute('data-atomix-theme',
|
|
102
|
+
link.setAttribute('data-atomix-theme', 'true');
|
|
106
103
|
|
|
107
104
|
// Handle load success
|
|
108
105
|
link.onload = () => {
|
|
@@ -113,7 +110,7 @@ export const loadThemeCSS = (
|
|
|
113
110
|
link.onerror = () => {
|
|
114
111
|
// Remove failed link element
|
|
115
112
|
link.remove();
|
|
116
|
-
reject(new Error(`Failed to load theme: ${
|
|
113
|
+
reject(new Error(`Failed to load theme CSS: ${fullPath}`));
|
|
117
114
|
};
|
|
118
115
|
|
|
119
116
|
// Append to head
|
|
@@ -124,15 +121,19 @@ export const loadThemeCSS = (
|
|
|
124
121
|
/**
|
|
125
122
|
* Remove theme CSS from the DOM
|
|
126
123
|
*
|
|
127
|
-
* @param
|
|
124
|
+
* @param themeNameOrLinkId - Name of the theme or link ID to remove
|
|
128
125
|
*/
|
|
129
|
-
export const removeThemeCSS = (
|
|
126
|
+
export const removeThemeCSS = (themeNameOrLinkId: string): void => {
|
|
130
127
|
if (isServer()) {
|
|
131
128
|
return;
|
|
132
129
|
}
|
|
133
130
|
|
|
134
|
-
|
|
135
|
-
|
|
131
|
+
// Try as link ID first, then as theme name
|
|
132
|
+
let link = document.getElementById(themeNameOrLinkId);
|
|
133
|
+
if (!link) {
|
|
134
|
+
const linkId = getThemeLinkId(themeNameOrLinkId);
|
|
135
|
+
link = document.getElementById(linkId);
|
|
136
|
+
}
|
|
136
137
|
|
|
137
138
|
if (link) {
|
|
138
139
|
link.remove();
|
|
@@ -154,12 +155,12 @@ export const removeAllThemeCSS = (): void => {
|
|
|
154
155
|
/**
|
|
155
156
|
* Apply theme data attributes to the document
|
|
156
157
|
*
|
|
157
|
-
* @param themeName - Name of the theme
|
|
158
158
|
* @param dataAttribute - Data attribute name (default: 'data-theme')
|
|
159
|
+
* @param themeName - Name of the theme
|
|
159
160
|
*/
|
|
160
161
|
export const applyThemeAttributes = (
|
|
161
|
-
|
|
162
|
-
|
|
162
|
+
dataAttribute: string,
|
|
163
|
+
themeName: string
|
|
163
164
|
): void => {
|
|
164
165
|
if (isServer()) {
|
|
165
166
|
return;
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* White Label Manager
|
|
3
|
+
*
|
|
4
|
+
* Provides white labeling capabilities for themes
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Theme, ThemeOptions } from '../types';
|
|
8
|
+
import { createTheme } from '../createTheme';
|
|
9
|
+
import { extendTheme } from '../composeTheme';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Brand configuration
|
|
13
|
+
*/
|
|
14
|
+
export interface BrandConfig {
|
|
15
|
+
/** Brand name */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Brand logo URL */
|
|
18
|
+
logo?: string;
|
|
19
|
+
/** Primary brand color */
|
|
20
|
+
primaryColor?: string;
|
|
21
|
+
/** Secondary brand color */
|
|
22
|
+
secondaryColor?: string;
|
|
23
|
+
/** Brand fonts */
|
|
24
|
+
fonts?: {
|
|
25
|
+
primary?: string;
|
|
26
|
+
secondary?: string;
|
|
27
|
+
};
|
|
28
|
+
/** Brand favicon */
|
|
29
|
+
favicon?: string;
|
|
30
|
+
/** Custom CSS */
|
|
31
|
+
customCSS?: string;
|
|
32
|
+
/** Custom meta tags */
|
|
33
|
+
metaTags?: Record<string, string>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* White label configuration
|
|
38
|
+
*/
|
|
39
|
+
export interface WhiteLabelConfig {
|
|
40
|
+
/** Brand configuration */
|
|
41
|
+
brand: BrandConfig;
|
|
42
|
+
/** Theme overrides */
|
|
43
|
+
themeOverrides?: Partial<ThemeOptions>;
|
|
44
|
+
/** Component overrides */
|
|
45
|
+
componentOverrides?: Record<string, any>;
|
|
46
|
+
/** CSS variable overrides */
|
|
47
|
+
cssVariableOverrides?: Record<string, string>;
|
|
48
|
+
/** Enable DOM mutations (default: false for headless/server safety) */
|
|
49
|
+
enableDOMOperations?: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* White Label Manager
|
|
54
|
+
*
|
|
55
|
+
* Manages white labeling for themes
|
|
56
|
+
*/
|
|
57
|
+
export class WhiteLabelManager {
|
|
58
|
+
private config: WhiteLabelConfig | null = null;
|
|
59
|
+
private baseTheme: Theme | null = null;
|
|
60
|
+
|
|
61
|
+
constructor(baseTheme?: Theme) {
|
|
62
|
+
if (baseTheme) {
|
|
63
|
+
this.baseTheme = baseTheme;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Set base theme
|
|
69
|
+
*/
|
|
70
|
+
setBaseTheme(theme: Theme): void {
|
|
71
|
+
this.baseTheme = theme;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Configure white label
|
|
76
|
+
*/
|
|
77
|
+
configure(config: WhiteLabelConfig): void {
|
|
78
|
+
this.config = config;
|
|
79
|
+
this.applyWhiteLabel();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get white labeled theme
|
|
84
|
+
*/
|
|
85
|
+
getWhiteLabeledTheme(): Theme | null {
|
|
86
|
+
if (!this.baseTheme || !this.config) {
|
|
87
|
+
return this.baseTheme;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Create theme with white label overrides
|
|
91
|
+
const themeOptions: ThemeOptions = {
|
|
92
|
+
...this.baseTheme,
|
|
93
|
+
name: this.config.brand.name,
|
|
94
|
+
...this.config.themeOverrides,
|
|
95
|
+
palette: {
|
|
96
|
+
...this.baseTheme.palette,
|
|
97
|
+
...(this.config.brand.primaryColor && {
|
|
98
|
+
primary: {
|
|
99
|
+
...this.baseTheme.palette.primary,
|
|
100
|
+
main: this.config.brand.primaryColor,
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
...(this.config.brand.secondaryColor && {
|
|
104
|
+
secondary: {
|
|
105
|
+
...this.baseTheme.palette.secondary,
|
|
106
|
+
main: this.config.brand.secondaryColor,
|
|
107
|
+
},
|
|
108
|
+
}),
|
|
109
|
+
...this.config.themeOverrides?.palette,
|
|
110
|
+
},
|
|
111
|
+
typography: {
|
|
112
|
+
...this.baseTheme.typography,
|
|
113
|
+
...(this.config.brand.fonts?.primary && {
|
|
114
|
+
fontFamily: this.config.brand.fonts.primary,
|
|
115
|
+
}),
|
|
116
|
+
...this.config.themeOverrides?.typography,
|
|
117
|
+
},
|
|
118
|
+
custom: {
|
|
119
|
+
...this.baseTheme.custom,
|
|
120
|
+
whiteLabel: {
|
|
121
|
+
brand: this.config.brand,
|
|
122
|
+
componentOverrides: this.config.componentOverrides,
|
|
123
|
+
cssVariableOverrides: this.config.cssVariableOverrides,
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
return createTheme(themeOptions);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Apply white label to DOM
|
|
133
|
+
*/
|
|
134
|
+
private applyWhiteLabel(): void {
|
|
135
|
+
if (!this.config?.enableDOMOperations || typeof document === 'undefined') {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const { brand } = this.config;
|
|
140
|
+
|
|
141
|
+
// Apply logo
|
|
142
|
+
if (brand.logo) {
|
|
143
|
+
this.applyLogo(brand.logo);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Apply favicon
|
|
147
|
+
if (brand.favicon) {
|
|
148
|
+
this.applyFavicon(brand.favicon);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Apply meta tags
|
|
152
|
+
if (brand.metaTags) {
|
|
153
|
+
this.applyMetaTags(brand.metaTags);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Apply custom CSS
|
|
157
|
+
if (brand.customCSS) {
|
|
158
|
+
this.applyCustomCSS(brand.customCSS);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Apply CSS variable overrides
|
|
162
|
+
if (this.config.cssVariableOverrides) {
|
|
163
|
+
this.applyCSSVariables(this.config.cssVariableOverrides);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Apply logo
|
|
169
|
+
*/
|
|
170
|
+
applyLogo(logoUrl: string, selector?: string, element?: HTMLElement): void {
|
|
171
|
+
if (!this.config?.enableDOMOperations || typeof document === 'undefined') {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Find or create logo element
|
|
176
|
+
let logoElement = element || (selector ? document.querySelector(selector) : null) as HTMLImageElement | null;
|
|
177
|
+
|
|
178
|
+
if (!logoElement) {
|
|
179
|
+
logoElement = document.querySelector('[data-whitelabel-logo]') as HTMLImageElement;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (!logoElement) {
|
|
183
|
+
logoElement = document.createElement('img');
|
|
184
|
+
logoElement.setAttribute('data-whitelabel-logo', 'true');
|
|
185
|
+
logoElement.style.maxHeight = '40px';
|
|
186
|
+
logoElement.style.maxWidth = '200px';
|
|
187
|
+
|
|
188
|
+
// Try to find a container (e.g., header, navbar)
|
|
189
|
+
const container = selector
|
|
190
|
+
? document.querySelector(selector)
|
|
191
|
+
: document.querySelector('header, [role="banner"], .navbar, .header');
|
|
192
|
+
|
|
193
|
+
if (container) {
|
|
194
|
+
container.insertBefore(logoElement, container.firstChild);
|
|
195
|
+
} else {
|
|
196
|
+
document.body.insertBefore(logoElement, document.body.firstChild);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
(logoElement as HTMLImageElement).src = logoUrl;
|
|
201
|
+
(logoElement as HTMLImageElement).alt = this.config?.brand.name || 'Logo';
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Apply favicon
|
|
206
|
+
*/
|
|
207
|
+
applyFavicon(faviconUrl: string, selector?: string): void {
|
|
208
|
+
if (!this.config?.enableDOMOperations || typeof document === 'undefined') {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Remove existing favicons
|
|
213
|
+
const existingFavicons = document.querySelectorAll('link[rel="icon"], link[rel="shortcut icon"]');
|
|
214
|
+
existingFavicons.forEach(favicon => favicon.remove());
|
|
215
|
+
|
|
216
|
+
// Create new favicon link
|
|
217
|
+
const link = document.createElement('link');
|
|
218
|
+
link.rel = 'icon';
|
|
219
|
+
link.type = 'image/x-icon';
|
|
220
|
+
link.href = faviconUrl;
|
|
221
|
+
|
|
222
|
+
const target = selector ? document.querySelector(selector) : document.head;
|
|
223
|
+
if (target) {
|
|
224
|
+
target.appendChild(link);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Apply meta tags
|
|
230
|
+
*/
|
|
231
|
+
applyMetaTags(metaTags: Record<string, string>, selector?: string): void {
|
|
232
|
+
if (!this.config?.enableDOMOperations || typeof document === 'undefined') {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const target = selector ? document.querySelector(selector) : document.head;
|
|
237
|
+
if (!target) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
for (const [name, content] of Object.entries(metaTags)) {
|
|
242
|
+
// Check if meta tag exists
|
|
243
|
+
let metaElement = document.querySelector(`meta[name="${name}"]`) as HTMLMetaElement;
|
|
244
|
+
|
|
245
|
+
if (!metaElement) {
|
|
246
|
+
metaElement = document.createElement('meta');
|
|
247
|
+
metaElement.name = name;
|
|
248
|
+
target.appendChild(metaElement);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
metaElement.content = content;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Apply custom CSS
|
|
257
|
+
*/
|
|
258
|
+
applyCustomCSS(css: string, styleId?: string): void {
|
|
259
|
+
if (!this.config?.enableDOMOperations || typeof document === 'undefined') {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const id = styleId || 'whitelabel-custom-css';
|
|
264
|
+
|
|
265
|
+
// Remove existing white label CSS
|
|
266
|
+
const existingStyle = document.getElementById(id);
|
|
267
|
+
if (existingStyle) {
|
|
268
|
+
existingStyle.remove();
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Create new style element
|
|
272
|
+
const style = document.createElement('style');
|
|
273
|
+
style.id = id;
|
|
274
|
+
style.textContent = css;
|
|
275
|
+
document.head.appendChild(style);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Apply CSS variables
|
|
280
|
+
*/
|
|
281
|
+
applyCSSVariables(variables: Record<string, string>, root?: HTMLElement | string): void {
|
|
282
|
+
if (!this.config?.enableDOMOperations || typeof document === 'undefined') {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
let targetElement: HTMLElement;
|
|
287
|
+
|
|
288
|
+
if (typeof root === 'string') {
|
|
289
|
+
const element = document.querySelector(root);
|
|
290
|
+
if (!element || !(element instanceof HTMLElement)) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
targetElement = element;
|
|
294
|
+
} else if (root instanceof HTMLElement) {
|
|
295
|
+
targetElement = root;
|
|
296
|
+
} else {
|
|
297
|
+
targetElement = document.documentElement;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
301
|
+
targetElement.style.setProperty(key.startsWith('--') ? key : `--${key}`, value);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Remove white label
|
|
307
|
+
*/
|
|
308
|
+
removeWhiteLabel(): void {
|
|
309
|
+
// Remove logo
|
|
310
|
+
const logo = document.querySelector('[data-whitelabel-logo]');
|
|
311
|
+
logo?.remove();
|
|
312
|
+
|
|
313
|
+
// Remove custom CSS
|
|
314
|
+
const customCSS = document.getElementById('whitelabel-custom-css');
|
|
315
|
+
customCSS?.remove();
|
|
316
|
+
|
|
317
|
+
// Remove CSS variables (would need to track original values)
|
|
318
|
+
if (this.config?.cssVariableOverrides) {
|
|
319
|
+
const root = document.documentElement;
|
|
320
|
+
for (const key of Object.keys(this.config.cssVariableOverrides)) {
|
|
321
|
+
root.style.removeProperty(key.startsWith('--') ? key : `--${key}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
this.config = null;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Get current configuration
|
|
330
|
+
*/
|
|
331
|
+
getConfig(): WhiteLabelConfig | null {
|
|
332
|
+
return this.config;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Export configuration
|
|
337
|
+
*/
|
|
338
|
+
exportConfig(): string {
|
|
339
|
+
if (!this.config) {
|
|
340
|
+
throw new Error('No white label configuration to export');
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return JSON.stringify(this.config, null, 2);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Import configuration
|
|
348
|
+
*/
|
|
349
|
+
importConfig(json: string): void {
|
|
350
|
+
try {
|
|
351
|
+
const config = JSON.parse(json) as WhiteLabelConfig;
|
|
352
|
+
this.configure(config);
|
|
353
|
+
} catch (error) {
|
|
354
|
+
throw new Error(`Failed to import white label configuration: ${error instanceof Error ? error.message : String(error)}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Create white label manager
|
|
361
|
+
*/
|
|
362
|
+
export function createWhiteLabelManager(baseTheme?: Theme): WhiteLabelManager {
|
|
363
|
+
return new WhiteLabelManager(baseTheme);
|
|
364
|
+
}
|
|
@@ -15,4 +15,4 @@ $badge-border-radius: radius.$border-radius-pill !default;
|
|
|
15
15
|
|
|
16
16
|
$badge-icon-size: map.get($spacing-sizes, 4) !default; //16px
|
|
17
17
|
|
|
18
|
-
$badge-inner-items-gap: map.get($spacing-sizes,
|
|
18
|
+
$badge-inner-items-gap: map.get($spacing-sizes, 'px-6') !default; //6px
|
|
@@ -29,7 +29,7 @@ $callout-title-font-size: map.get($spacing-sizes, 4) !default; //16px
|
|
|
29
29
|
$callout-title-font-weight: 600 !default;
|
|
30
30
|
$callout-title-color: var(--#{config.$prefix}body-color) !default;
|
|
31
31
|
|
|
32
|
-
$callout-text-font-size: map.get($spacing-sizes,
|
|
32
|
+
$callout-text-font-size: map.get($spacing-sizes, 'px-14') !default; //14px
|
|
33
33
|
$callout-text-font-weight: 400 !default;
|
|
34
34
|
$callout-text-color: var(--#{config.$prefix}body-color) !default;
|
|
35
35
|
|
|
@@ -30,7 +30,7 @@ $card-bg: var(--#{config.$prefix}primary-bg-subtle) !default;
|
|
|
30
30
|
$card-bg-hover: var(--#{config.$prefix}secondary-bg-subtle) !default;
|
|
31
31
|
|
|
32
32
|
$card-icon-size: map.get($spacing-sizes, 5) !default; //20px
|
|
33
|
-
$card-icon-padding: map.get($spacing-sizes,
|
|
33
|
+
$card-icon-padding: map.get($spacing-sizes, 'px-10') !default; //10px
|
|
34
34
|
$card-icon-bg: var(--#{config.$prefix}brand-bg-subtle) !default;
|
|
35
35
|
$card-icon-color: var(--#{config.$prefix}brand-text-emphasis) !default;
|
|
36
36
|
|
|
@@ -16,7 +16,7 @@ $input-line-height-sm: 20px !default;
|
|
|
16
16
|
$input-line-height-lg: 24px !default;
|
|
17
17
|
|
|
18
18
|
$input-padding-x: map.get($spacing-sizes, 3) !default; //12px
|
|
19
|
-
$input-padding-y: map.get($spacing-sizes,
|
|
19
|
+
$input-padding-y: map.get($spacing-sizes, 'px-10') !default; //10px
|
|
20
20
|
$input-padding-x-sm: map.get($spacing-sizes, 3) !default; //12px
|
|
21
21
|
$input-padding-y-sm: map.get($spacing-sizes, 1.5) !default; //6px
|
|
22
22
|
$input-padding-x-lg: map.get($spacing-sizes, 3) !default; //12px
|
|
@@ -18,7 +18,7 @@ $navbar-border-color: var(--#{$prefix}primary-border-subtle) !default;
|
|
|
18
18
|
$navbar-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !default;
|
|
19
19
|
|
|
20
20
|
// Brand/logo
|
|
21
|
-
$navbar-brand-margin-end: map.get($spacing-sizes,
|
|
21
|
+
$navbar-brand-margin-end: map.get($spacing-sizes, 'px-30') !default; //30px
|
|
22
22
|
$navbar-brand-font-size: $font-size-lg !default;
|
|
23
23
|
$navbar-brand-font-weight: $font-weight-bold !default;
|
|
24
24
|
$navbar-brand-color: var(--#{$prefix}body-color) !default;
|
|
@@ -64,7 +64,7 @@ $upload-loader-text-color: var(--#{config.$prefix}tertiary-text-emphasis) !defau
|
|
|
64
64
|
$upload-loader-text-font-size: typography.$font-size-sm !default;
|
|
65
65
|
$upload-loader-text-margin-top: 5px !default;
|
|
66
66
|
$upload-loader-bar-height: 10px !default;
|
|
67
|
-
$upload-loader-bar-margin-top: map.get($spacing-sizes,
|
|
67
|
+
$upload-loader-bar-margin-top: map.get($spacing-sizes, 'px-10') !default; //10px
|
|
68
68
|
$upload-loader-control-icon-size: map.get($spacing-sizes, 5) !default; //20px
|
|
69
69
|
$upload-loader-contorl-color: var(--#{config.$prefix}body-color) !default;
|
|
70
70
|
|
|
@@ -313,7 +313,7 @@
|
|
|
313
313
|
transition: all $chart-transition-duration $chart-transition-timing;
|
|
314
314
|
position: relative;
|
|
315
315
|
overflow: hidden;
|
|
316
|
-
font-size: map.get($spacing-sizes,
|
|
316
|
+
font-size: map.get($spacing-sizes, 'px-14');
|
|
317
317
|
|
|
318
318
|
&::before {
|
|
319
319
|
content: '';
|
|
@@ -492,7 +492,7 @@
|
|
|
492
492
|
display: flex;
|
|
493
493
|
align-items: center;
|
|
494
494
|
justify-content: space-between;
|
|
495
|
-
padding: map.get($spacing-sizes,
|
|
495
|
+
padding: map.get($spacing-sizes, 'px-6') 0;
|
|
496
496
|
gap: map.get($spacing-sizes, 3);
|
|
497
497
|
|
|
498
498
|
&--info {
|