-
Notifications
You must be signed in to change notification settings - Fork 83
Expand file tree
/
Copy pathgenerate-brand-css.js
More file actions
236 lines (203 loc) · 9.13 KB
/
Copy pathgenerate-brand-css.js
File metadata and controls
236 lines (203 loc) · 9.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
const fs = require('fs');
const path = require('path');
// Import brand configuration from project root
const brandConfig = require('../brand.config.json');
// Main function to update brand colors in _themes.scss
const updateBrandColorsInThemes = () => {
const themesPath = path.join(__dirname, '../src/components/shared/styles/_themes.scss');
if (!fs.existsSync(themesPath)) {
console.error('❌ _themes.scss file not found');
process.exit(1);
}
// Read the current themes file
let themesContent = fs.readFileSync(themesPath, 'utf8');
const originalContent = themesContent;
// Extract colors and typography from brand config
const { colors, typography } = brandConfig;
// Generate brand color variables from config
const brandColorLines = [
' /* Brand colors - dynamically generated from brand.config.json */',
` --brand-white: ${colors.white};`,
` --brand-dark-grey: ${colors.black};`,
` --brand-red-coral: ${colors.primary}; /* legacy compatibility */`,
` --brand-orange: ${colors.tertiary}; /* legacy compatibility */`,
'',
' /* Dynamic brand colors (set by brand configuration) */',
` --brand-primary: ${colors.primary};`,
` --brand-secondary: ${colors.secondary};`,
` --brand-tertiary: ${colors.tertiary};`,
` --brand-success: ${colors.success};`,
` --brand-danger: ${colors.danger};`,
` --brand-warning: ${colors.warning};`,
` --brand-info: ${colors.info};`,
` --brand-neutral: ${colors.neutral};`,
];
// Generate typography variables if available
if (typography && typography.font_family) {
brandColorLines.push('');
brandColorLines.push(' /* Brand typography - dynamically generated from brand.config.json */');
brandColorLines.push(` --brand-font-primary: ${typography.font_family.primary};`);
brandColorLines.push(` --brand-font-secondary: ${typography.font_family.secondary};`);
brandColorLines.push(` --brand-font-monospace: ${typography.font_family.monospace};`);
}
// Find and replace the brand colors section
let insertionPoint = -1;
let endPoint = -1;
// Look for existing brand colors section (with or without AI markers)
const brandCommentStart = themesContent.indexOf(
'/* Brand colors - dynamically generated from brand.config.json */'
);
const legacyBrandStart = themesContent.indexOf(' // Brand primary colors');
if (brandCommentStart !== -1) {
// Found modern brand section with comment
insertionPoint = themesContent.lastIndexOf('\n', brandCommentStart) + 1;
// Look for end marker - either AI closing tag or next major section
const aiEndMarker = themesContent.indexOf('/* [/AI] */', brandCommentStart);
if (aiEndMarker !== -1) {
endPoint = themesContent.indexOf('\n', aiEndMarker) + 1;
} else {
// Find end by looking for next CSS section or end of root block
const nextSection = themesContent.indexOf('\n // App Cards', brandCommentStart);
const nextComment = themesContent.indexOf('\n /*', brandCommentStart + 100); // Skip current comment
const nextThemeClass = themesContent.indexOf('\n .theme--', brandCommentStart);
endPoint = Math.min(...[nextSection, nextComment, nextThemeClass].filter(pos => pos > -1));
if (endPoint === Infinity) {
// Fallback - find next blank lines
endPoint = themesContent.indexOf('\n\n ', brandCommentStart + 100);
}
}
} else if (legacyBrandStart !== -1) {
// Found legacy brand section
insertionPoint = legacyBrandStart;
endPoint = themesContent.indexOf('\n // App Cards', legacyBrandStart);
if (endPoint === -1) {
endPoint = themesContent.indexOf('\n .theme--', legacyBrandStart);
}
} else {
// No existing brand section - insert after text align
const textAlignEnd = themesContent.indexOf(' --text-align-center: center;');
if (textAlignEnd !== -1) {
insertionPoint = themesContent.indexOf('\n', textAlignEnd) + 1;
endPoint = insertionPoint;
}
}
if (insertionPoint === -1) {
console.error('❌ Could not find insertion point in _themes.scss');
process.exit(1);
}
// Replace or insert the brand colors section
const beforeSection = themesContent.substring(0, insertionPoint);
const afterSection =
endPoint > insertionPoint ? themesContent.substring(endPoint) : themesContent.substring(insertionPoint);
themesContent = beforeSection + '\n\n' + brandColorLines.join('\n') + '\n' + afterSection;
// Write the updated file
fs.writeFileSync(themesPath, themesContent, 'utf8');
// Check if changes were made
const hasChanges = originalContent !== themesContent;
if (hasChanges) {
console.log('✅ Brand styling updated successfully in _themes.scss!');
console.log(`📁 Updated: ${themesPath}`);
console.log('📊 Changes made:');
console.log(' Colors:');
console.log(` • Brand White: ${colors.white}`);
console.log(` • Brand Dark Grey: ${colors.black}`);
console.log(` • Primary: ${colors.primary}`);
console.log(` • Secondary: ${colors.secondary}`);
console.log(` • Tertiary: ${colors.tertiary}`);
console.log(` • Success: ${colors.success}`);
console.log(` • Danger: ${colors.danger}`);
console.log(` • Warning: ${colors.warning}`);
console.log(` • Info: ${colors.info}`);
if (typography && typography.font_family) {
console.log(' Typography:');
console.log(` • Primary Font: ${typography.font_family.primary.substring(0, 50)}...`);
console.log(` • Secondary Font: ${typography.font_family.secondary}`);
console.log(` • Monospace Font: ${typography.font_family.monospace}`);
}
} else {
console.log('✓ No changes needed - brand styling already up to date');
}
return hasChanges;
};
// Validation function
const validateBrandConfig = () => {
const issues = [];
if (!brandConfig.colors) {
issues.push('Missing colors configuration in brand.config.json');
} else {
const requiredColors = [
'primary',
'secondary',
'tertiary',
'success',
'danger',
'warning',
'info',
'neutral',
'white',
'black',
];
requiredColors.forEach(color => {
if (!brandConfig.colors[color]) {
issues.push(`Missing required color: ${color}`);
}
});
}
// Optional typography validation (warnings only)
if (brandConfig.typography) {
if (!brandConfig.typography.font_family) {
console.warn('⚠️ Typography configuration found but font_family is missing');
} else {
const requiredFonts = ['primary', 'secondary', 'monospace'];
requiredFonts.forEach(font => {
if (!brandConfig.typography.font_family[font]) {
console.warn(`⚠️ Missing recommended font: ${font}`);
}
});
}
}
if (issues.length > 0) {
console.error('❌ Brand configuration issues:');
issues.forEach(issue => console.error(` - ${issue}`));
process.exit(1);
}
console.log('✅ Brand configuration is valid');
return true;
};
// Add script to package.json if it doesn't exist
const addPackageScript = () => {
const packageJsonPath = path.join(__dirname, '../package.json');
if (!fs.existsSync(packageJsonPath)) {
console.log('⚠️ package.json not found, skipping script addition');
return;
}
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
if (!packageJson.scripts) {
packageJson.scripts = {};
}
if (!packageJson.scripts['generate:brand-css']) {
packageJson.scripts['generate:brand-css'] = 'node scripts/generate-brand-css.js';
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8');
console.log('✅ Added "generate:brand-css" script to package.json');
}
};
// Main execution
if (require.main === module) {
console.log('🎨 Updating brand colors in _themes.scss...\n');
validateBrandConfig();
const hasChanges = updateBrandColorsInThemes();
addPackageScript();
console.log('\n🎯 Next steps:');
if (hasChanges) {
console.log('1. The brand colors in _themes.scss have been updated with AI markers');
console.log('2. To regenerate: npm run generate:brand-css');
console.log('3. Restart your dev server to see the changes');
} else {
console.log('1. No changes were needed');
console.log('2. To force regeneration: npm run generate:brand-css');
}
}
module.exports = {
updateBrandColorsInThemes,
validateBrandConfig,
};