Wire guest branding theme
This commit is contained in:
35
resources/js/guest/lib/__tests__/guestTheme.test.ts
Normal file
35
resources/js/guest/lib/__tests__/guestTheme.test.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { describe, expect, it, afterEach } from 'vitest';
|
||||
import { applyGuestTheme } from '../guestTheme';
|
||||
|
||||
const baseTheme = {
|
||||
primary: '#ff3366',
|
||||
secondary: '#ff99aa',
|
||||
background: '#111111',
|
||||
surface: '#222222',
|
||||
mode: 'dark' as const,
|
||||
};
|
||||
|
||||
describe('applyGuestTheme', () => {
|
||||
afterEach(() => {
|
||||
const root = document.documentElement;
|
||||
root.classList.remove('guest-theme', 'dark');
|
||||
root.style.removeProperty('color-scheme');
|
||||
root.style.removeProperty('--guest-primary');
|
||||
root.style.removeProperty('--guest-secondary');
|
||||
root.style.removeProperty('--guest-background');
|
||||
root.style.removeProperty('--guest-surface');
|
||||
});
|
||||
|
||||
it('applies and restores guest theme settings', () => {
|
||||
const cleanup = applyGuestTheme(baseTheme);
|
||||
|
||||
expect(document.documentElement.classList.contains('guest-theme')).toBe(true);
|
||||
expect(document.documentElement.classList.contains('dark')).toBe(true);
|
||||
expect(document.documentElement.style.colorScheme).toBe('dark');
|
||||
expect(document.documentElement.style.getPropertyValue('--guest-background')).toBe('#111111');
|
||||
|
||||
cleanup();
|
||||
|
||||
expect(document.documentElement.classList.contains('guest-theme')).toBe(false);
|
||||
});
|
||||
});
|
||||
103
resources/js/guest/lib/guestTheme.ts
Normal file
103
resources/js/guest/lib/guestTheme.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
export type GuestThemePayload = {
|
||||
primary: string;
|
||||
secondary: string;
|
||||
background: string;
|
||||
surface: string;
|
||||
mode?: 'light' | 'dark' | 'auto';
|
||||
};
|
||||
|
||||
type GuestThemeCleanup = () => void;
|
||||
|
||||
const prefersDarkScheme = (): boolean => {
|
||||
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
};
|
||||
|
||||
const applyColorScheme = (root: HTMLElement, theme: 'light' | 'dark') => {
|
||||
if (theme === 'dark') {
|
||||
root.classList.add('dark');
|
||||
root.style.colorScheme = 'dark';
|
||||
} else {
|
||||
root.classList.remove('dark');
|
||||
root.style.colorScheme = 'light';
|
||||
}
|
||||
};
|
||||
|
||||
export function applyGuestTheme(payload: GuestThemePayload): GuestThemeCleanup {
|
||||
if (typeof document === 'undefined') {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
const root = document.documentElement;
|
||||
const hadGuestTheme = root.classList.contains('guest-theme');
|
||||
const wasDark = root.classList.contains('dark');
|
||||
const previousColorScheme = root.style.colorScheme;
|
||||
const previousVars = {
|
||||
primary: root.style.getPropertyValue('--guest-primary'),
|
||||
secondary: root.style.getPropertyValue('--guest-secondary'),
|
||||
background: root.style.getPropertyValue('--guest-background'),
|
||||
surface: root.style.getPropertyValue('--guest-surface'),
|
||||
};
|
||||
|
||||
root.classList.add('guest-theme');
|
||||
root.style.setProperty('--guest-primary', payload.primary);
|
||||
root.style.setProperty('--guest-secondary', payload.secondary);
|
||||
root.style.setProperty('--guest-background', payload.background);
|
||||
root.style.setProperty('--guest-surface', payload.surface);
|
||||
|
||||
const mode = payload.mode ?? 'auto';
|
||||
if (mode === 'dark') {
|
||||
applyColorScheme(root, 'dark');
|
||||
} else if (mode === 'light') {
|
||||
applyColorScheme(root, 'light');
|
||||
} else {
|
||||
applyColorScheme(root, prefersDarkScheme() ? 'dark' : 'light');
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (hadGuestTheme) {
|
||||
root.classList.add('guest-theme');
|
||||
} else {
|
||||
root.classList.remove('guest-theme');
|
||||
}
|
||||
|
||||
if (wasDark) {
|
||||
root.classList.add('dark');
|
||||
} else {
|
||||
root.classList.remove('dark');
|
||||
}
|
||||
|
||||
if (previousColorScheme) {
|
||||
root.style.colorScheme = previousColorScheme;
|
||||
} else {
|
||||
root.style.removeProperty('color-scheme');
|
||||
}
|
||||
|
||||
if (previousVars.primary) {
|
||||
root.style.setProperty('--guest-primary', previousVars.primary);
|
||||
} else {
|
||||
root.style.removeProperty('--guest-primary');
|
||||
}
|
||||
|
||||
if (previousVars.secondary) {
|
||||
root.style.setProperty('--guest-secondary', previousVars.secondary);
|
||||
} else {
|
||||
root.style.removeProperty('--guest-secondary');
|
||||
}
|
||||
|
||||
if (previousVars.background) {
|
||||
root.style.setProperty('--guest-background', previousVars.background);
|
||||
} else {
|
||||
root.style.removeProperty('--guest-background');
|
||||
}
|
||||
|
||||
if (previousVars.surface) {
|
||||
root.style.setProperty('--guest-surface', previousVars.surface);
|
||||
} else {
|
||||
root.style.removeProperty('--guest-surface');
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user