Files
fotospiel-app/resources/js/admin/lib/branding.ts
Codex Agent 9bde8f3f32 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.
2025-11-25 19:31:52 +01:00

53 lines
1.8 KiB
TypeScript

import type { TenantEvent } from '../api';
export type BrandingPalette = {
colors: string[];
font?: string;
};
export function extractBrandingPalette(settings: TenantEvent['settings'] | null | undefined): BrandingPalette {
const colors: string[] = [];
let font: string | undefined;
if (settings && typeof settings === 'object') {
const brand = (settings as Record<string, unknown>).branding;
if (brand && typeof brand === 'object') {
const palette = (brand as Record<string, unknown>).palette as Record<string, unknown> | undefined;
const colorPalette = palette ?? (brand as Record<string, unknown>).colors;
if (colorPalette && typeof colorPalette === 'object') {
const paletteRecord = colorPalette as Record<string, unknown>;
for (const key of Object.keys(paletteRecord)) {
const value = paletteRecord[key];
if (typeof value === 'string' && value.trim().length) {
colors.push(value);
}
}
}
const directColors = [
(brand as Record<string, unknown>).primary_color,
(brand as Record<string, unknown>).secondary_color,
(brand as Record<string, unknown>).background_color,
];
directColors.forEach((value) => {
if (typeof value === 'string' && value.trim()) {
colors.push(value);
}
});
const typography = (brand as Record<string, unknown>).typography as Record<string, unknown> | undefined;
const fontValue = (brand as Record<string, unknown>).font_family
?? (typography?.body as string | undefined)
?? (typography?.heading as string | undefined);
if (typeof fontValue === 'string' && fontValue.trim()) {
font = fontValue.trim();
}
}
}
return {
colors,
font,
};
}