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:
Codex Agent
2025-11-25 19:31:52 +01:00
parent 4d31eb4d42
commit 9bde8f3f32
38 changed files with 2420 additions and 104 deletions

View File

@@ -10,12 +10,16 @@ function TabLink({
children,
isActive,
accentColor,
radius,
style,
compact = false,
}: {
to: string;
children: React.ReactNode;
isActive: boolean;
accentColor: string;
radius: number;
style?: React.CSSProperties;
compact?: boolean;
}) {
const activeStyle = isActive
@@ -23,8 +27,10 @@ function TabLink({
background: `linear-gradient(135deg, ${accentColor}, ${accentColor}cc)`,
color: '#ffffff',
boxShadow: `0 12px 30px ${accentColor}33`,
borderRadius: radius,
...style,
}
: undefined;
: { borderRadius: radius, ...style };
return (
<NavLink
@@ -47,6 +53,10 @@ export default function BottomNav() {
const { event, status } = useEventData();
const { t } = useTranslation();
const { branding } = useEventBranding();
const radius = branding.buttons?.radius ?? 12;
const buttonStyle = branding.buttons?.style ?? 'filled';
const linkColor = branding.buttons?.linkColor ?? branding.secondaryColor;
const surface = branding.palette?.surface ?? branding.backgroundColor;
const isReady = status === 'ready' && !!event;
@@ -79,13 +89,27 @@ export default function BottomNav() {
>
<div className="mx-auto flex max-w-lg items-center gap-3">
<div className="flex flex-1 justify-evenly gap-2">
<TabLink to={`${base}`} isActive={isHomeActive} accentColor={branding.primaryColor} compact={compact}>
<TabLink
to={`${base}`}
isActive={isHomeActive}
accentColor={branding.primaryColor}
radius={radius}
compact={compact}
style={buttonStyle === 'outline' ? { background: 'transparent', color: linkColor, border: `1px solid ${linkColor}` } : undefined}
>
<div className="flex flex-col items-center gap-1">
<Home className="h-5 w-5" aria-hidden />
<span>{labels.home}</span>
</div>
</TabLink>
<TabLink to={`${base}/tasks`} isActive={isTasksActive} accentColor={branding.primaryColor} compact={compact}>
<TabLink
to={`${base}/tasks`}
isActive={isTasksActive}
accentColor={branding.primaryColor}
radius={radius}
compact={compact}
style={buttonStyle === 'outline' ? { background: 'transparent', color: linkColor, border: `1px solid ${linkColor}` } : undefined}
>
<div className="flex flex-col items-center gap-1">
<CheckSquare className="h-5 w-5" aria-hidden />
<span>{labels.tasks}</span>
@@ -102,6 +126,7 @@ export default function BottomNav() {
style={{
background: `radial-gradient(circle at 20% 20%, ${branding.secondaryColor}, ${branding.primaryColor})`,
boxShadow: `0 20px 35px ${branding.primaryColor}44`,
borderRadius: radius,
}}
>
<Camera className="h-6 w-6" aria-hidden />
@@ -112,6 +137,8 @@ export default function BottomNav() {
to={`${base}/achievements`}
isActive={isAchievementsActive}
accentColor={branding.primaryColor}
radius={radius}
style={buttonStyle === 'outline' ? { background: 'transparent', color: linkColor, border: `1px solid ${linkColor}` } : undefined}
compact={compact}
>
<div className="flex flex-col items-center gap-1">
@@ -123,6 +150,8 @@ export default function BottomNav() {
to={`${base}/gallery`}
isActive={isGalleryActive}
accentColor={branding.primaryColor}
radius={radius}
style={buttonStyle === 'outline' ? { background: 'transparent', color: linkColor, border: `1px solid ${linkColor}` } : undefined}
compact={compact}
>
<div className="flex flex-col items-center gap-1">