der tenant admin hat eine neue, mobil unterstützende UI, login redirect funktioniert, typescript fehler wurden bereinigt. Neue Blog Posts von ChatGPT eingebaut, übersetzt von Gemini 2.5

This commit is contained in:
Codex Agent
2025-11-05 19:27:10 +01:00
parent adb93b5f9d
commit c6ac04eb15
44 changed files with 1995 additions and 1949 deletions

View File

@@ -3,6 +3,8 @@ import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
import { LucideIcon } from 'lucide-react';
import { FrostedSurface } from '../../components/tenant';
export interface OnboardingAction {
id: string;
label: string;
@@ -28,30 +30,30 @@ export function OnboardingCTAList({ actions, className }: OnboardingCTAListProps
return (
<div className={cn('grid gap-4 md:grid-cols-2', className)}>
{actions.map(({ id, label, description, href, onClick, icon: Icon, variant = 'primary', disabled, buttonLabel }) => (
<div
<FrostedSurface
key={id}
className="flex flex-col gap-3 rounded-2xl border border-brand-rose-soft bg-brand-card p-5 shadow-brand-primary backdrop-blur"
className="flex flex-col gap-3 border border-white/20 p-5 text-slate-900 shadow-md shadow-rose-200/20 dark:border-slate-800/70 dark:bg-slate-950/80"
>
<div className="flex items-center gap-3">
{Icon && (
<span className="flex size-10 items-center justify-center rounded-full bg-brand-rose-soft text-brand-rose shadow-inner">
{Icon ? (
<span className="flex size-10 items-center justify-center rounded-full bg-rose-100/80 text-rose-500 shadow-inner shadow-rose-200/60 dark:bg-rose-500/20 dark:text-rose-200">
<Icon className="size-5" />
</span>
)}
<span className="text-base font-semibold text-brand-slate">{label}</span>
) : null}
<span className="text-base font-semibold text-slate-900 dark:text-slate-100">{label}</span>
</div>
{description && (
<p className="text-sm text-brand-navy/80">{description}</p>
)}
{description ? (
<p className="text-sm text-slate-600 dark:text-slate-400">{description}</p>
) : null}
<div>
<Button
variant="default"
size="lg"
className={cn(
'w-full rounded-full transition-all',
'w-full rounded-full transition-colors',
variant === 'secondary'
? 'bg-brand-gold text-brand-slate shadow-md shadow-amber-200/40 hover:bg-[var(--brand-gold-soft)]'
: 'bg-brand-rose text-white shadow-md shadow-rose-400/30 hover:bg-[var(--brand-rose-strong)]'
? 'bg-slate-900/80 text-white shadow-md shadow-slate-900/30 hover:bg-slate-900 dark:bg-slate-800'
: 'bg-gradient-to-r from-[#ff5f87] via-[#ec4899] to-[#6366f1] text-white shadow-lg shadow-rose-300/30 hover:from-[#ff4470] hover:via-[#ec4899] hover:to-[#4f46e5]'
)}
disabled={disabled}
onClick={onClick}
@@ -60,7 +62,7 @@ export function OnboardingCTAList({ actions, className }: OnboardingCTAListProps
{href ? <a href={href}>{buttonLabel ?? label}</a> : buttonLabel ?? label}
</Button>
</div>
</div>
</FrostedSurface>
))}
</div>
);

View File

@@ -1,8 +1,10 @@
import React from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { LucideIcon } from 'lucide-react';
import { cn } from '@/lib/utils';
import { FrostedSurface } from '../../components/tenant';
export interface HighlightItem {
id: string;
icon: LucideIcon;
@@ -24,27 +26,27 @@ export function OnboardingHighlightsGrid({ items, className }: OnboardingHighlig
return (
<div className={cn('grid gap-4 md:grid-cols-3', className)}>
{items.map(({ id, icon: Icon, title, description, badge }) => (
<Card
<FrostedSurface
key={id}
className="relative overflow-hidden rounded-3xl border border-white/70 bg-white/90 shadow-xl shadow-rose-100/40"
className="relative overflow-hidden rounded-3xl border border-white/20 p-6 text-slate-900 shadow-md shadow-rose-200/20 dark:border-slate-800/70 dark:bg-slate-950/80"
>
<CardHeader className="space-y-3">
<div className="flex items-center justify-between">
<span className="flex size-12 items-center justify-center rounded-full bg-rose-100 text-rose-500 shadow-inner">
<span className="flex size-12 items-center justify-center rounded-full bg-rose-100/80 text-rose-500 shadow-inner shadow-rose-200/60 dark:bg-rose-500/20 dark:text-rose-200">
<Icon className="size-6" />
</span>
{badge && (
<span className="rounded-full bg-rose-100 px-3 py-1 text-xs font-semibold uppercase tracking-wide text-rose-500">
<span className="rounded-full bg-rose-100 px-3 py-1 text-xs font-semibold uppercase tracking-wide text-rose-500 dark:bg-rose-500/20 dark:text-rose-200">
{badge}
</span>
)}
</div>
<CardTitle className="text-lg font-semibold text-slate-900">{title}</CardTitle>
<CardTitle className="text-lg font-semibold text-slate-900 dark:text-slate-100">{title}</CardTitle>
</CardHeader>
<CardContent>
<p className="text-sm text-slate-600">{description}</p>
<p className="text-sm text-slate-600 dark:text-slate-400">{description}</p>
</CardContent>
</Card>
</FrostedSurface>
))}
</div>
);

View File

@@ -1,5 +1,6 @@
import React from 'react';
import { LanguageSwitcher } from '../../components/LanguageSwitcher';
import { FrostedSurface } from '../../components/tenant';
export interface TenantWelcomeLayoutProps {
eyebrow?: string;
@@ -27,24 +28,28 @@ export function TenantWelcomeLayout({
}, []);
return (
<div className="min-h-screen w-full bg-brand-gradient text-brand-slate transition-colors duration-500 ease-out">
<div className="mx-auto flex min-h-screen w-full max-w-5xl px-6 py-12 md:py-16 lg:px-10">
<div className="flex w-full flex-col gap-10 rounded-[40px] border border-brand-rose-soft bg-brand-card p-8 shadow-brand-primary backdrop-blur-xl md:gap-14 md:p-14">
<div className="relative min-h-svh w-full overflow-hidden bg-slate-950 text-white">
<div
aria-hidden
className="pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_at_top,_rgba(255,137,170,0.28),_transparent_60%),radial-gradient(ellipse_at_bottom,_rgba(99,102,241,0.25),_transparent_65%)] motion-safe:animate-[aurora_20s_ease-in-out_infinite]"
/>
<div aria-hidden className="absolute inset-0 bg-gradient-to-br from-slate-950 via-slate-900/70 to-[#1d1130]" />
<div className="relative z-10 mx-auto flex min-h-svh w-full max-w-5xl flex-col gap-10 px-6 py-12 sm:px-8 md:py-16 lg:px-12">
<FrostedSurface className="flex w-full flex-1 flex-col gap-10 rounded-[36px] border border-white/15 p-8 text-slate-900 shadow-2xl shadow-rose-300/20 backdrop-blur-2xl transition-colors duration-200 dark:text-slate-100 md:gap-14 md:p-14">
<header className="flex flex-col gap-6 md:flex-row md:items-start md:justify-between">
<div className="max-w-xl">
{eyebrow && (
<p className="text-xs uppercase tracking-[0.35em] text-brand-rose">{eyebrow}</p>
)}
{title && (
<h1 className="mt-2 font-display text-4xl font-semibold tracking-tight text-brand-slate md:text-5xl">
<div className="max-w-xl space-y-4">
{eyebrow ? (
<p className="text-xs uppercase tracking-[0.35em] text-rose-300 dark:text-rose-200">{eyebrow}</p>
) : null}
{title ? (
<h1 className="font-display text-3xl font-semibold tracking-tight text-slate-900 dark:text-slate-100 md:text-5xl">
{title}
</h1>
)}
{subtitle && (
<p className="mt-4 text-base font-sans-marketing text-brand-navy/80 md:text-lg">
{subtitle}
</p>
)}
) : null}
{subtitle ? (
<p className="text-base text-slate-600 dark:text-slate-300 md:text-lg">{subtitle}</p>
) : null}
</div>
<div className="flex shrink-0 items-center gap-2">
<LanguageSwitcher />
@@ -56,12 +61,12 @@ export function TenantWelcomeLayout({
{children}
</main>
{footer && (
<footer className="flex flex-col items-center gap-4 text-sm text-brand-navy/70 md:flex-row md:justify-between">
{footer ? (
<footer className="flex flex-col items-center gap-4 text-sm text-slate-600 dark:text-slate-400 md:flex-row md:justify-between">
{footer}
</footer>
)}
</div>
) : null}
</FrostedSurface>
</div>
</div>
);

View File

@@ -2,6 +2,7 @@ import React from 'react';
import { Button } from '@/components/ui/button';
import { LucideIcon } from 'lucide-react';
import { cn } from '@/lib/utils';
import { FrostedSurface } from '../../components/tenant';
interface ActionProps {
label: string;
@@ -29,28 +30,32 @@ export function WelcomeHero({
className,
}: WelcomeHeroProps) {
return (
<section
<FrostedSurface
className={cn(
'rounded-3xl border border-brand-rose-soft bg-brand-card p-8 shadow-brand-primary backdrop-blur-xl',
'relative overflow-hidden rounded-3xl border border-white/15 p-8 text-slate-900 shadow-2xl shadow-rose-300/20 backdrop-blur-2xl transition-colors duration-200 dark:text-slate-100 md:p-12',
className
)}
>
<div className="space-y-4 text-center md:space-y-6">
<div
aria-hidden
className="pointer-events-none absolute inset-x-0 top-[-30%] h-[220px] bg-[radial-gradient(circle,_rgba(255,137,170,0.35),_transparent_60%)]"
/>
<div className="relative space-y-4 text-center md:space-y-6">
{eyebrow && (
<p className="text-xs uppercase tracking-[0.35em] text-brand-rose md:text-sm">
<p className="text-xs uppercase tracking-[0.35em] text-rose-300 dark:text-rose-200 md:text-sm">
{eyebrow}
</p>
)}
<h2 className="font-display text-3xl font-semibold tracking-tight text-brand-slate md:text-4xl">
<h2 className="font-display text-3xl font-semibold tracking-tight text-slate-900 dark:text-slate-100 md:text-4xl">
{title}
</h2>
{scriptTitle && (
<p className="font-script text-2xl text-brand-rose md:text-3xl">
<p className="font-script text-2xl text-rose-300 md:text-3xl">
{scriptTitle}
</p>
)}
{description && (
<p className="mx-auto max-w-2xl text-base font-sans-marketing text-brand-navy/80 md:text-lg">
<p className="mx-auto max-w-2xl text-base text-slate-600 dark:text-slate-300 md:text-lg">
{description}
</p>
)}
@@ -62,10 +67,10 @@ export function WelcomeHero({
size="lg"
variant={variant === 'outline' ? 'outline' : 'default'}
className={cn(
'min-w-[220px] rounded-full px-6',
'min-w-[220px] rounded-full px-6 transition-colors',
variant === 'outline'
? 'border-brand-rose-soft text-brand-rose hover:bg-brand-rose-soft/40'
: 'bg-brand-rose text-white shadow-md shadow-rose-400/40 hover:bg-[var(--brand-rose-strong)]'
? 'border-white/60 bg-white/20 text-slate-900 hover:bg-white/40 dark:border-slate-700 dark:bg-slate-900/40 dark:text-slate-100'
: 'bg-gradient-to-r from-[#ff5f87] via-[#ec4899] to-[#6366f1] text-white shadow-lg shadow-rose-300/30 hover:from-[#ff4470] hover:via-[#ec4899] hover:to-[#4f46e5]'
)}
onClick={onClick}
{...(href ? { asChild: true } : {})}
@@ -86,7 +91,7 @@ export function WelcomeHero({
</div>
)}
</div>
</section>
</FrostedSurface>
);
}

View File

@@ -1,9 +1,11 @@
import React from 'react';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Progress } from '@/components/ui/progress';
import { LucideIcon } from 'lucide-react';
import { cn } from '@/lib/utils';
import { FrostedCard } from '../../components/tenant';
export interface WelcomeStepCardProps {
step: number;
totalSteps: number;
@@ -27,16 +29,16 @@ export function WelcomeStepCard({
const percent = totalSteps <= 1 ? 100 : Math.round((progress / totalSteps) * 100);
return (
<Card
<FrostedCard
className={cn(
'relative overflow-hidden rounded-3xl border border-brand-rose-soft bg-brand-card shadow-brand-primary',
'relative overflow-hidden rounded-3xl border border-white/20 text-slate-900 shadow-lg shadow-rose-200/20 dark:text-slate-100',
className
)}
>
<div className="absolute inset-x-0 top-0 h-1 bg-gradient-to-r from-brand-rose-soft via-[var(--brand-gold-soft)] to-brand-sky-soft" />
<div className="absolute inset-x-0 top-0 h-1 bg-gradient-to-r from-[#ff5f87] via-[#ec4899] to-[#6366f1]" />
<CardHeader className="space-y-4 pt-8">
<div className="flex items-center justify-between gap-3">
<span className="text-xs font-semibold uppercase tracking-[0.4em] text-brand-rose">
<span className="text-xs font-semibold uppercase tracking-[0.4em] text-rose-300 dark:text-rose-200">
Step {progress} / {totalSteps}
</span>
<div className="w-28">
@@ -45,20 +47,20 @@ export function WelcomeStepCard({
</div>
<div className="flex items-start gap-4">
{Icon && (
<span className="flex size-12 items-center justify-center rounded-full bg-brand-rose-soft text-brand-rose shadow-inner">
<span className="flex size-12 items-center justify-center rounded-full bg-rose-100/90 text-rose-500 shadow-inner shadow-rose-200/60 dark:bg-rose-500/20 dark:text-rose-200">
<Icon className="size-5" />
</span>
)}
<div className="space-y-2">
<CardTitle className="font-display text-2xl font-semibold text-brand-slate md:text-3xl">{title}</CardTitle>
<CardTitle className="font-display text-2xl font-semibold text-slate-900 dark:text-slate-100 md:text-3xl">{title}</CardTitle>
{description && (
<CardDescription className="text-base font-sans-marketing text-brand-navy/80">{description}</CardDescription>
<CardDescription className="text-base text-slate-600 dark:text-slate-400">{description}</CardDescription>
)}
</div>
</div>
</CardHeader>
<CardContent className="space-y-6 pb-10">{children}</CardContent>
</Card>
<CardContent className="space-y-6 pb-10 text-slate-700 dark:text-slate-300">{children}</CardContent>
</FrostedCard>
);
}