SkateSpots/src/components/EventSponsors.tsx

100 lines
3.2 KiB
TypeScript

import { ExternalLink, Sparkles } from 'lucide-react';
import { sanitizeUrl } from '@/lib/sanitizeUrl';
import { cn } from '@/lib/utils';
import { useTranslation } from '@/contexts/language';
import { EVENT_SPONSOR_TIERS, type EventSponsor } from '@/lib/types';
function SponsorLogo({ sponsor, large }: { sponsor: EventSponsor; large?: boolean }) {
const safeUrl = sponsor.url ? sanitizeUrl(sponsor.url) : null;
const safeLogo = sponsor.logo ? sanitizeUrl(sponsor.logo) : null;
const inner = (
<div
className={cn(
'group flex flex-col items-center justify-center gap-2 rounded-xl border border-white/10 bg-white/[0.03] p-3 transition-all hover:border-white/25 hover:bg-white/[0.06]',
large ? 'min-h-[96px]' : 'min-h-[72px]',
)}
>
{safeLogo ? (
<img
src={safeLogo}
alt={sponsor.name}
className={cn('object-contain', large ? 'max-h-14' : 'max-h-9')}
loading="lazy"
/>
) : (
<span className={cn('font-black uppercase tracking-wide text-white', large ? 'text-lg' : 'text-sm')}>
{sponsor.name}
</span>
)}
{safeLogo && (
<span className="max-w-full truncate text-[10px] font-bold uppercase tracking-wide text-gray-400">
{sponsor.name}
{safeUrl && (
<ExternalLink className="ml-1 inline h-2.5 w-2.5 opacity-0 transition-opacity group-hover:opacity-100" />
)}
</span>
)}
</div>
);
if (safeUrl) {
return (
<a href={safeUrl} target="_blank" rel="noopener noreferrer nofollow" className="block">
{inner}
</a>
);
}
return inner;
}
/**
* Sponsor strip for an event. Title sponsor gets a hero row; the rest render in
* a responsive grid. Sponsors give events a "this is a real production" feel and
* open a monetization surface for hosts + brands.
*/
export function EventSponsors({
sponsors,
className,
}: {
sponsors: EventSponsor[];
className?: string;
}) {
const { t } = useTranslation();
if (!sponsors || sponsors.length === 0) return null;
const title = sponsors.filter((s) => s.tier === 'title');
const rest = sponsors.filter((s) => s.tier !== 'title');
return (
<div className={cn('space-y-4', className)}>
<div className="flex items-center gap-2">
<Sparkles className="h-4 w-4 text-[#ccff00]" />
<h3 className="text-xs font-black uppercase tracking-widest text-gray-400">
{t('placesUi.sponsors.presentedBy')}
</h3>
</div>
{title.length > 0 && (
<div className="grid grid-cols-1 gap-3">
{title.map((s, i) => (
<div key={`${s.name}-${i}`} className="space-y-1.5">
<span className="text-[10px] font-black uppercase tracking-widest text-[#ccff00]">
{t(EVENT_SPONSOR_TIERS.title.labelKey)}
</span>
<SponsorLogo sponsor={s} large />
</div>
))}
</div>
)}
{rest.length > 0 && (
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3">
{rest.map((s, i) => (
<SponsorLogo key={`${s.name}-${i}`} sponsor={s} />
))}
</div>
)}
</div>
);
}