Neue Branding-Page und Gäste-PWA reagiert nun auf Branding-Einstellungen vom event-admin. Implemented local Google Fonts pipeline and admin UI selects for branding and invites.
- Added fonts:sync-google command (uses GOOGLE_FONTS_API_KEY, generates /public/fonts/google files, manifest, CSS, cache flush) and
exposed manifest via new GET /api/v1/tenant/fonts endpoint with fallbacks for existing local fonts.
- Imported generated fonts CSS, added API client + font loader hook, and wired branding page font fields to searchable selects (with
custom override) that auto-load selected fonts.
- Invites layout editor now offers font selection per element with runtime font loading for previews/export alignment.
- New tests cover font sync command and font manifest API.
Tests run: php artisan test --filter=Fonts --testsuite=Feature.
Note: repository already has other modified files (e.g., EventPublicController, SettingsStoreRequest, guest components, etc.); left
untouched. Run php artisan fonts:sync-google after setting the API key to populate /public/fonts/google.
This commit is contained in:
50
resources/js/guest/lib/color.ts
Normal file
50
resources/js/guest/lib/color.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
export function hexToRgb(hex: string): { r: number; g: number; b: number } | null {
|
||||
const normalized = hex.trim();
|
||||
if (!/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(normalized)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let r: number;
|
||||
let g: number;
|
||||
let b: number;
|
||||
|
||||
if (normalized.length === 4) {
|
||||
r = parseInt(normalized[1] + normalized[1], 16);
|
||||
g = parseInt(normalized[2] + normalized[2], 16);
|
||||
b = parseInt(normalized[3] + normalized[3], 16);
|
||||
} else {
|
||||
r = parseInt(normalized.slice(1, 3), 16);
|
||||
g = parseInt(normalized.slice(3, 5), 16);
|
||||
b = parseInt(normalized.slice(5, 7), 16);
|
||||
}
|
||||
|
||||
return { r, g, b };
|
||||
}
|
||||
|
||||
export function relativeLuminance(hex: string): number {
|
||||
const rgb = hexToRgb(hex);
|
||||
if (!rgb) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const normalize = (channel: number) => {
|
||||
const c = channel / 255;
|
||||
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
||||
};
|
||||
|
||||
const r = normalize(rgb.r);
|
||||
const g = normalize(rgb.g);
|
||||
const b = normalize(rgb.b);
|
||||
|
||||
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||
}
|
||||
|
||||
export function getContrastingTextColor(
|
||||
backgroundHex: string,
|
||||
lightColor = '#ffffff',
|
||||
darkColor = '#0f172a',
|
||||
): string {
|
||||
const luminance = relativeLuminance(backgroundHex);
|
||||
|
||||
return luminance > 0.5 ? darkColor : lightColor;
|
||||
}
|
||||
Reference in New Issue
Block a user