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:
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user