Expand branding controls and logo upload
This commit is contained in:
@@ -38,6 +38,18 @@ const EVENT_ICON_COMPONENTS: Record<string, React.ComponentType<{ className?: st
|
||||
camera: Camera,
|
||||
};
|
||||
|
||||
type LogoSize = 's' | 'm' | 'l';
|
||||
|
||||
const LOGO_SIZE_CLASSES: Record<LogoSize, { container: string; image: string; emoji: string; icon: string }> = {
|
||||
s: { container: 'h-8 w-8', image: 'h-7 w-7', emoji: 'text-lg', icon: 'h-4 w-4' },
|
||||
m: { container: 'h-10 w-10', image: 'h-9 w-9', emoji: 'text-xl', icon: 'h-5 w-5' },
|
||||
l: { container: 'h-12 w-12', image: 'h-11 w-11', emoji: 'text-2xl', icon: 'h-6 w-6' },
|
||||
};
|
||||
|
||||
function getLogoClasses(size?: LogoSize) {
|
||||
return LOGO_SIZE_CLASSES[size ?? 'm'];
|
||||
}
|
||||
|
||||
const NOTIFICATION_ICON_MAP: Record<string, React.ComponentType<{ className?: string }>> = {
|
||||
broadcast: MessageSquare,
|
||||
feedback_request: MessageSquare,
|
||||
@@ -69,18 +81,25 @@ function getInitials(name: string): string {
|
||||
return name.substring(0, 2).toUpperCase();
|
||||
}
|
||||
|
||||
function renderEventAvatar(name: string, icon: unknown, accentColor: string, textColor: string, logo?: { mode: 'emoticon' | 'upload'; value: string | null }) {
|
||||
function renderEventAvatar(
|
||||
name: string,
|
||||
icon: unknown,
|
||||
accentColor: string,
|
||||
textColor: string,
|
||||
logo?: { mode: 'emoticon' | 'upload'; value: string | null; size?: LogoSize }
|
||||
) {
|
||||
const sizes = getLogoClasses(logo?.size);
|
||||
if (logo?.mode === 'upload' && logo.value) {
|
||||
return (
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-white shadow-sm">
|
||||
<img src={logo.value} alt={name} className="h-9 w-9 rounded-full object-contain" />
|
||||
<div className={`flex items-center justify-center rounded-full bg-white shadow-sm ${sizes.container}`}>
|
||||
<img src={logo.value} alt={name} className={`rounded-full object-contain ${sizes.image}`} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (logo?.mode === 'emoticon' && logo.value && isLikelyEmoji(logo.value)) {
|
||||
return (
|
||||
<div
|
||||
className="flex h-10 w-10 items-center justify-center rounded-full text-xl shadow-sm"
|
||||
className={`flex items-center justify-center rounded-full shadow-sm ${sizes.container} ${sizes.emoji}`}
|
||||
style={{ backgroundColor: accentColor, color: textColor }}
|
||||
>
|
||||
<span aria-hidden>{logo.value}</span>
|
||||
@@ -94,21 +113,21 @@ function renderEventAvatar(name: string, icon: unknown, accentColor: string, tex
|
||||
if (trimmed) {
|
||||
const normalized = trimmed.toLowerCase();
|
||||
const IconComponent = EVENT_ICON_COMPONENTS[normalized];
|
||||
if (IconComponent) {
|
||||
return (
|
||||
<div
|
||||
className="flex h-10 w-10 items-center justify-center rounded-full shadow-sm"
|
||||
style={{ backgroundColor: accentColor, color: textColor }}
|
||||
>
|
||||
<IconComponent className="h-5 w-5" aria-hidden />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (IconComponent) {
|
||||
return (
|
||||
<div
|
||||
className={`flex items-center justify-center rounded-full shadow-sm ${sizes.container}`}
|
||||
style={{ backgroundColor: accentColor, color: textColor }}
|
||||
>
|
||||
<IconComponent className={sizes.icon} aria-hidden />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isLikelyEmoji(trimmed)) {
|
||||
return (
|
||||
<div
|
||||
className="flex h-10 w-10 items-center justify-center rounded-full text-xl shadow-sm"
|
||||
className={`flex items-center justify-center rounded-full shadow-sm ${sizes.container} ${sizes.emoji}`}
|
||||
style={{ backgroundColor: accentColor, color: textColor }}
|
||||
>
|
||||
<span aria-hidden>{trimmed}</span>
|
||||
@@ -188,6 +207,7 @@ export default function Header({ eventToken, title = '' }: { eventToken?: string
|
||||
|
||||
const headerFont = branding.typography?.heading ?? branding.fontFamily ?? undefined;
|
||||
const bodyFont = branding.typography?.body ?? branding.fontFamily ?? undefined;
|
||||
const logoPosition = branding.logo?.position ?? 'left';
|
||||
const headerStyle: React.CSSProperties = {
|
||||
background: `linear-gradient(135deg, ${branding.primaryColor}, ${branding.secondaryColor})`,
|
||||
color: headerTextColor,
|
||||
@@ -219,9 +239,20 @@ export default function Header({ eventToken, title = '' }: { eventToken?: string
|
||||
className="guest-header z-20 flex items-center justify-between border-b border-white/10 px-4 py-3 text-white shadow-sm backdrop-blur"
|
||||
style={headerStyle}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div
|
||||
className={
|
||||
logoPosition === 'center'
|
||||
? 'flex flex-col items-center gap-2 text-center'
|
||||
: logoPosition === 'right'
|
||||
? 'flex flex-row-reverse items-center gap-3'
|
||||
: 'flex items-center gap-3'
|
||||
}
|
||||
>
|
||||
{renderEventAvatar(event.name, event.type?.icon, accentColor, headerTextColor, branding.logo)}
|
||||
<div className="flex flex-col" style={headerFont ? { fontFamily: headerFont } : undefined}>
|
||||
<div
|
||||
className={`flex flex-col${logoPosition === 'center' ? ' items-center text-center' : ''}`}
|
||||
style={headerFont ? { fontFamily: headerFont } : undefined}
|
||||
>
|
||||
<div className="font-semibold text-lg">{event.name}</div>
|
||||
<div className="flex items-center gap-2 text-xs text-white/70" style={bodyFont ? { fontFamily: bodyFont } : undefined}>
|
||||
{stats && tasksEnabled && (
|
||||
|
||||
Reference in New Issue
Block a user