feat(theme): expand color settings to 8-token CI palette + alt button

This commit is contained in:
Luca
2026-05-05 16:04:43 +02:00
parent ee7de6f6a1
commit 114aab5777
11 changed files with 612 additions and 150 deletions
@@ -104,4 +104,59 @@ describe('publicSiteService', () => {
expect(payload.branding.logoUrl).toBe('/uploads/logos/aurora.png');
expect(payload.branding.colors.primary).toBe('#5C8762');
});
it('exposes the 8-token CI palette through branding.colors', async () => {
const publicSiteRows = buildPublicSiteRows({});
const brandingRows = buildBrandingRows({
themeConfig: {
// LBM CI palette (charcoal + teal).
primaryColor: '#014E4E',
accentColor: '#017C7C',
accentDarkColor: '#014E4E',
backgroundColor: '#0D0D0D',
surfaceColor: '#111414',
elevatedColor: '#182222',
surfaceBorderColor: '#1E2E2E',
textColor: '#EBEBEB',
mutedTextColor: '#4A6060'
}
});
db.mockImplementationOnce(() => ({ whereIn: () => Promise.resolve(publicSiteRows) }));
db.mockImplementationOnce(() => ({ whereIn: () => Promise.resolve(brandingRows) }));
const payload = await getPublicSitePayload({ bypassCache: true });
// Legacy 4 colors still mapped.
expect(payload.branding.colors.primary).toBe('#014E4E');
expect(payload.branding.colors.accent).toBe('#017C7C');
expect(payload.branding.colors.background).toBe('#0D0D0D');
expect(payload.branding.colors.text).toBe('#EBEBEB');
// 8-token CI palette additions.
expect(payload.branding.colors.accentDark).toBe('#014E4E');
expect(payload.branding.colors.surface).toBe('#111414');
expect(payload.branding.colors.elevated).toBe('#182222');
expect(payload.branding.colors.border).toBe('#1E2E2E');
expect(payload.branding.colors.mutedText).toBe('#4A6060');
});
it('falls back accentDark to legacy primaryColor when the new key is absent', async () => {
const publicSiteRows = buildPublicSiteRows({});
const brandingRows = buildBrandingRows({
themeConfig: {
primaryColor: '#5C8762',
accentColor: '#22c55e',
backgroundColor: '#fafafa',
textColor: '#171717'
// accentDarkColor intentionally omitted to simulate a legacy theme.
}
});
db.mockImplementationOnce(() => ({ whereIn: () => Promise.resolve(publicSiteRows) }));
db.mockImplementationOnce(() => ({ whereIn: () => Promise.resolve(brandingRows) }));
const payload = await getPublicSitePayload({ bypassCache: true });
expect(payload.branding.colors.accentDark).toBe('#5C8762');
});
});
+16 -1
View File
@@ -87,11 +87,19 @@ async function fetchBrandingContext() {
supportEmail: null,
logoUrl: null,
footerText: null,
// 8-token CI palette mirrored from frontend ThemeConfig.
// primary/accent are kept as legacy aliases (primary == accent-dark);
// new tokens are surface, elevated, border, mutedText, accentDark.
colors: {
primary: '#16a34a',
accent: '#0f766e',
accentDark: '#16a34a',
background: '#f4fbf6',
text: '#0f172a'
surface: '#ffffff',
elevated: '#f5f5f5',
border: '#e5e5e5',
text: '#0f172a',
mutedText: '#737373'
}
};
@@ -117,10 +125,17 @@ async function fetchBrandingContext() {
try {
const themeConfig = typeof parsed === 'string' ? JSON.parse(parsed) : parsed;
if (themeConfig && typeof themeConfig === 'object') {
// Legacy 4 colors
context.colors.primary = themeConfig.primaryColor || context.colors.primary;
context.colors.accent = themeConfig.accentColor || context.colors.accent;
context.colors.background = themeConfig.backgroundColor || context.colors.background;
context.colors.text = themeConfig.textColor || context.colors.text;
// 8-token CI palette additions
context.colors.accentDark = themeConfig.accentDarkColor || themeConfig.primaryColor || context.colors.accentDark;
context.colors.surface = themeConfig.surfaceColor || context.colors.surface;
context.colors.elevated = themeConfig.elevatedColor || context.colors.elevated;
context.colors.border = themeConfig.surfaceBorderColor || context.colors.border;
context.colors.mutedText = themeConfig.mutedTextColor || context.colors.mutedText;
}
} catch (error) {
logger.warn('Failed to parse theme configuration for public site', { error: error.message });