photobooth funktionen im event admin verlinkt, gäste pwa zeigt photobooth nur noch an, wenn diese aktiviert ist. kontaktformular optimiert. teilen-link mit iMessage und whatsapp erweitert.
This commit is contained in:
@@ -456,20 +456,20 @@ function selectHighlightPackageId(packages: Package[]): number | null {
|
||||
const getAccentTheme = (variant: 'endcustomer' | 'reseller') =>
|
||||
variant === 'reseller'
|
||||
? {
|
||||
badge: 'bg-amber-50 text-amber-700',
|
||||
price: 'text-amber-600',
|
||||
buttonHighlight: 'bg-gray-900 text-white hover:bg-gray-800',
|
||||
buttonDefault: 'border border-amber-200 text-amber-700 hover:bg-amber-50',
|
||||
cardBorder: 'border border-amber-100',
|
||||
highlightShadow: 'shadow-lg shadow-amber-100/60 bg-gradient-to-br from-amber-50/70 via-white to-amber-100/60',
|
||||
badge: 'bg-amber-50 text-amber-700 dark:bg-amber-500/20 dark:text-amber-100',
|
||||
price: 'text-amber-600 dark:text-amber-100',
|
||||
buttonHighlight: 'bg-gray-900 text-white hover:bg-gray-800 dark:bg-amber-600 dark:hover:bg-amber-500',
|
||||
buttonDefault: 'border border-amber-200 text-amber-700 hover:bg-amber-50 dark:border-amber-500/50 dark:text-amber-100 dark:hover:bg-amber-500/10',
|
||||
cardBorder: 'border border-amber-100 dark:border-amber-500/40',
|
||||
highlightShadow: 'shadow-lg shadow-amber-100/60 bg-gradient-to-br from-amber-50/70 via-white to-amber-100/60 dark:shadow-amber-900/40 dark:from-amber-900/40 dark:via-gray-900 dark:to-amber-900/20',
|
||||
}
|
||||
: {
|
||||
badge: 'bg-rose-50 text-rose-700',
|
||||
price: 'text-rose-600',
|
||||
buttonHighlight: 'bg-gray-900 text-white hover:bg-gray-800',
|
||||
buttonDefault: 'border border-rose-100 text-rose-700 hover:bg-rose-50',
|
||||
cardBorder: 'border border-rose-100',
|
||||
highlightShadow: 'shadow-lg shadow-rose-100/60 bg-gradient-to-br from-rose-50/70 via-white to-rose-100/60',
|
||||
badge: 'bg-rose-50 text-rose-700 dark:bg-pink-500/20 dark:text-pink-100',
|
||||
price: 'text-rose-600 dark:text-pink-100',
|
||||
buttonHighlight: 'bg-gray-900 text-white hover:bg-gray-800 dark:bg-pink-600 dark:hover:bg-pink-500',
|
||||
buttonDefault: 'border border-rose-100 text-rose-700 hover:bg-rose-50 dark:border-pink-500/50 dark:text-pink-100 dark:hover:bg-pink-500/10',
|
||||
cardBorder: 'border border-rose-100 dark:border-pink-500/40',
|
||||
highlightShadow: 'shadow-lg shadow-rose-100/60 bg-gradient-to-br from-rose-50/70 via-white to-rose-100/60 dark:shadow-pink-900/40 dark:from-pink-900/40 dark:via-gray-900 dark:to-pink-900/10',
|
||||
};
|
||||
|
||||
type PackageMetric = {
|
||||
@@ -588,37 +588,37 @@ function PackageCard({
|
||||
const metricList = compact ? (
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{metrics.map((metric) => (
|
||||
<div key={metric.key} className="rounded-full border border-gray-200 px-3 py-1 text-xs font-semibold text-gray-700">
|
||||
<span className="text-[11px] font-medium uppercase text-gray-400">{metric.label}</span>
|
||||
<span className="ml-1 text-gray-900">{metric.value}</span>
|
||||
<div key={metric.key} className="rounded-full border border-gray-200 px-3 py-1 text-xs font-semibold text-gray-700 dark:border-gray-700 dark:text-gray-100">
|
||||
<span className="text-[11px] font-medium uppercase text-gray-400 dark:text-gray-400">{metric.label}</span>
|
||||
<span className="ml-1 text-gray-900 dark:text-gray-100">{metric.value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-2 gap-3 text-sm">
|
||||
{metrics.map((metric) => (
|
||||
<div key={metric.key} className="rounded-xl bg-gray-50 px-4 py-3">
|
||||
<p className="text-lg font-semibold text-gray-900">{metric.value}</p>
|
||||
<p className="text-xs uppercase tracking-wide text-gray-500">{metric.label}</p>
|
||||
<div key={metric.key} className="rounded-xl bg-gray-50 px-4 py-3 dark:bg-gray-800">
|
||||
<p className="text-lg font-semibold text-gray-900 dark:text-gray-100">{metric.value}</p>
|
||||
<p className="text-xs uppercase tracking-wide text-gray-500 dark:text-gray-400">{metric.label}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
const featureList = compact ? (
|
||||
<ul className="space-y-1 text-sm text-gray-700">
|
||||
<ul className="space-y-1 text-sm text-gray-700 dark:text-gray-200">
|
||||
{visibleFeatures.map((feature) => (
|
||||
<li key={feature} className="flex items-start gap-2 text-xs">
|
||||
<Check className="mt-0.5 h-3.5 w-3.5 text-gray-900" />
|
||||
<Check className="mt-0.5 h-3.5 w-3.5 text-gray-900 dark:text-gray-100" />
|
||||
<span>{t(`packages.feature_${feature}`)}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<ul className="space-y-2 text-sm text-gray-700">
|
||||
<ul className="space-y-2 text-sm text-gray-700 dark:text-gray-200">
|
||||
{visibleFeatures.map((feature) => (
|
||||
<li key={feature} className="flex items-center gap-2">
|
||||
<Check className="h-4 w-4 text-gray-900" />
|
||||
<Check className="h-4 w-4 text-gray-900 dark:text-gray-100" />
|
||||
<span>{t(`packages.feature_${feature}`)}</span>
|
||||
</li>
|
||||
))}
|
||||
@@ -628,14 +628,14 @@ function PackageCard({
|
||||
return (
|
||||
<Card
|
||||
className={cn(
|
||||
'flex h-full flex-col rounded-2xl border border-gray-100 bg-white shadow-sm transition hover:shadow-lg',
|
||||
'flex h-full flex-col rounded-2xl border border-gray-100 bg-white shadow-sm transition hover:shadow-lg dark:border-gray-800 dark:bg-gray-900 dark:text-gray-50',
|
||||
compact && 'p-3',
|
||||
highlight && `${accent.cardBorder} ${accent.highlightShadow}`,
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<CardHeader className={cn('gap-4', compact && 'gap-3 p-0')}>
|
||||
<div className="flex items-center justify-between text-xs font-semibold uppercase tracking-[0.2em] text-gray-500">
|
||||
<div className="flex items-center justify-between text-xs font-semibold uppercase tracking-[0.2em] text-gray-500 dark:text-gray-300">
|
||||
<span>{typeLabel}</span>
|
||||
{badgeLabel && (
|
||||
<span
|
||||
@@ -649,8 +649,8 @@ function PackageCard({
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<CardTitle className="text-2xl text-gray-900">{pkg.name}</CardTitle>
|
||||
<CardDescription className="text-sm text-gray-600">{pkg.description}</CardDescription>
|
||||
<CardTitle className="text-2xl text-gray-900 dark:text-gray-50">{pkg.name}</CardTitle>
|
||||
<CardDescription className="text-sm text-gray-600 dark:text-gray-200">{pkg.description}</CardDescription>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className={cn('flex flex-col gap-6', compact && 'gap-4 p-0 pt-2')}>
|
||||
@@ -658,11 +658,11 @@ function PackageCard({
|
||||
<div className={cn('flex items-baseline gap-2', compact && 'flex-wrap text-balance')}>
|
||||
<span className={cn('text-4xl font-semibold', accent.price, compact && 'text-3xl')}>{priceLabel}</span>
|
||||
{pkg.price !== 0 && (
|
||||
<span className="text-sm text-gray-500">/ {cadenceLabel}</span>
|
||||
<span className="text-sm text-gray-500 dark:text-gray-300">/ {cadenceLabel}</span>
|
||||
)}
|
||||
</div>
|
||||
{variant === 'endcustomer' && (
|
||||
<p className="text-xs text-gray-400">
|
||||
<p className="text-xs text-gray-400 dark:text-gray-300">
|
||||
{pkg.events} × {t('packages.one_time')}
|
||||
</p>
|
||||
)}
|
||||
@@ -722,11 +722,11 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
||||
return (
|
||||
<div className="grid gap-8 lg:grid-cols-[320px,1fr]">
|
||||
<div className="space-y-6">
|
||||
<div className="rounded-2xl border border-gray-100 bg-gray-50 p-6">
|
||||
<div className="rounded-2xl border border-gray-100 bg-gray-50 p-6 dark:border-gray-800 dark:bg-gray-900">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-gray-500">{t('packages.price')}</p>
|
||||
<p className="text-4xl font-semibold text-gray-900">
|
||||
<p className="text-sm font-medium text-gray-500 dark:text-gray-300">{t('packages.price')}</p>
|
||||
<p className="text-4xl font-semibold text-gray-900 dark:text-gray-100">
|
||||
{Number(packageData.price).toLocaleString(undefined, {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
@@ -734,22 +734,22 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
||||
{t('packages.currency.euro')}
|
||||
</p>
|
||||
{packageData.price > 0 && (
|
||||
<p className="text-sm text-gray-500">
|
||||
<p className="text-sm text-gray-500 dark:text-gray-300">
|
||||
/ {variant === 'reseller' ? t('packages.billing_per_year') : t('packages.billing_per_event')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{isHighlight && (
|
||||
<span className="rounded-full bg-gray-900 px-3 py-1 text-[11px] font-semibold uppercase tracking-wider text-white">
|
||||
<span className="rounded-full bg-gray-900 px-3 py-1 text-[11px] font-semibold uppercase tracking-wider text-white dark:bg-pink-600">
|
||||
{variant === 'reseller' ? t('packages.badge_best_value') : t('packages.badge_most_popular')}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-6 grid grid-cols-2 gap-3 text-sm">
|
||||
{metrics.map((metric) => (
|
||||
<div key={metric.key} className="rounded-xl bg-white px-4 py-3 text-center shadow-sm">
|
||||
<p className="text-lg font-semibold text-gray-900">{metric.value}</p>
|
||||
<p className="text-xs uppercase tracking-wide text-gray-500">{metric.label}</p>
|
||||
<div key={metric.key} className="rounded-xl bg-white px-4 py-3 text-center shadow-sm dark:bg-gray-800">
|
||||
<p className="text-lg font-semibold text-gray-900 dark:text-gray-100">{metric.value}</p>
|
||||
<p className="text-xs uppercase tracking-wide text-gray-500 dark:text-gray-400">{metric.label}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -767,23 +767,23 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
||||
<ArrowRight className="ml-2 h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
<p className="mt-3 text-xs text-gray-500">{t('packages.order_hint')}</p>
|
||||
<p className="mt-3 text-xs text-gray-500 dark:text-gray-400">{t('packages.order_hint')}</p>
|
||||
</div>
|
||||
<div className="rounded-2xl border border-gray-100 bg-white p-6">
|
||||
<h3 className="text-lg font-semibold text-gray-900">{t('packages.feature_highlights')}</h3>
|
||||
<ul className="mt-4 space-y-3 text-sm text-gray-700">
|
||||
<div className="rounded-2xl border border-gray-100 bg-white p-6 dark:border-gray-800 dark:bg-gray-900">
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-gray-100">{t('packages.feature_highlights')}</h3>
|
||||
<ul className="mt-4 space-y-3 text-sm text-gray-700 dark:text-gray-200">
|
||||
{highlightFeatures.map((feature) => (
|
||||
<li key={feature} className="flex items-start gap-2">
|
||||
<Check className="mt-1 h-4 w-4 text-gray-900" />
|
||||
<Check className="mt-1 h-4 w-4 text-gray-900 dark:text-gray-100" />
|
||||
<span>{t(`packages.feature_${feature}`)}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="rounded-2xl border border-gray-100 bg-white p-6">
|
||||
<h3 className="text-lg font-semibold text-gray-900">{t('packages.more_details_tab')}</h3>
|
||||
<div className="rounded-2xl border border-gray-100 bg-white p-6 dark:border-gray-800 dark:bg-gray-900">
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-gray-100">{t('packages.more_details_tab')}</h3>
|
||||
<Tabs defaultValue="breakdown">
|
||||
<TabsList className="grid grid-cols-2 rounded-full bg-gray-100 p-1 text-sm">
|
||||
<TabsList className="grid grid-cols-2 rounded-full bg-gray-100 p-1 text-sm dark:bg-gray-800">
|
||||
<TabsTrigger value="breakdown" className="rounded-full">
|
||||
{t('packages.breakdown_label')}
|
||||
</TabsTrigger>
|
||||
@@ -795,28 +795,28 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
||||
{packageData.description_breakdown?.length ? (
|
||||
<Accordion type="multiple" className="space-y-4">
|
||||
{packageData.description_breakdown.map((entry, index) => (
|
||||
<AccordionItem key={index} value={`detail-${index}`} className="rounded-2xl border border-gray-100 bg-white px-4">
|
||||
<AccordionTrigger className="text-left text-base font-medium text-gray-900 hover:no-underline">
|
||||
<AccordionItem key={index} value={`detail-${index}`} className="rounded-2xl border border-gray-100 bg-white px-4 dark:border-gray-800 dark:bg-gray-900">
|
||||
<AccordionTrigger className="text-left text-base font-medium text-gray-900 hover:no-underline dark:text-gray-100">
|
||||
{entry.title ?? t('packages.limits_label')}
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="pb-4 text-sm text-gray-600 whitespace-pre-line">
|
||||
<AccordionContent className="pb-4 text-sm text-gray-600 whitespace-pre-line dark:text-gray-300">
|
||||
{entry.value}
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
) : (
|
||||
<p className="text-sm text-gray-500">{t('packages.breakdown_label_hint')}</p>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">{t('packages.breakdown_label_hint')}</p>
|
||||
)}
|
||||
</TabsContent>
|
||||
<TabsContent value="testimonials" className="mt-6">
|
||||
<div className="space-y-4">
|
||||
{testimonials.map((testimonial, index) => (
|
||||
<div key={index} className="rounded-2xl border border-gray-100 bg-white p-5 shadow-sm">
|
||||
<div key={index} className="rounded-2xl border border-gray-100 bg-white p-5 shadow-sm dark:border-gray-800 dark:bg-gray-900">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm font-semibold text-gray-900">{testimonial.name}</p>
|
||||
<p className="text-xs text-gray-500">{packageData.name}</p>
|
||||
<p className="text-sm font-semibold text-gray-900 dark:text-gray-100">{testimonial.name}</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">{packageData.name}</p>
|
||||
</div>
|
||||
<div className="flex gap-1 text-amber-400">
|
||||
{[...Array(testimonial.rating)].map((_, i) => (
|
||||
@@ -824,10 +824,10 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-3 text-sm text-gray-600">“{testimonial.text}”</p>
|
||||
<p className="mt-3 text-sm text-gray-600 dark:text-gray-300">“{testimonial.text}”</p>
|
||||
</div>
|
||||
))}
|
||||
<Button variant="outline" className="w-full rounded-full border-gray-200 text-sm font-medium text-gray-700" onClick={close}>
|
||||
<Button variant="outline" className="w-full rounded-full border-gray-200 text-sm font-medium text-gray-700 dark:border-gray-700 dark:text-gray-100" onClick={close}>
|
||||
{t('packages.close')}
|
||||
</Button>
|
||||
</div>
|
||||
@@ -1022,7 +1022,7 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
<SheetContent
|
||||
side="bottom"
|
||||
className="h-[90vh] overflow-hidden rounded-t-[32px] border border-gray-200 bg-white p-0"
|
||||
className="h-[90vh] overflow-hidden rounded-t-[32px] border border-gray-200 bg-white p-0 dark:border-gray-800 dark:bg-gray-900"
|
||||
onOpenAutoFocus={handleDetailAutoFocus}
|
||||
>
|
||||
{renderDetailBody('h-full overflow-y-auto space-y-8 p-6')}
|
||||
@@ -1031,7 +1031,7 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
||||
) : (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogContent
|
||||
className="max-w-6xl border border-gray-100 bg-white px-0 py-0 sm:rounded-[32px]"
|
||||
className="max-w-6xl border border-gray-100 bg-white px-0 py-0 sm:rounded-[32px] dark:border-gray-800 dark:bg-gray-900"
|
||||
onOpenAutoFocus={handleDetailAutoFocus}
|
||||
>
|
||||
{renderDetailBody('max-h-[88vh] overflow-y-auto space-y-8 p-6 md:p-10')}
|
||||
|
||||
Reference in New Issue
Block a user