import type { ComponentProps, ReactNode } from "react"; import { twClassNames } from "~/ui/utils"; import { Card } from "~/ui/components/Card"; import { IconWithBackground } from "~/ui/components/IconWithBackground"; import { Logo } from "~/ui/components/Logo"; type StatusTone = "positive" | "negative" | "neutral"; type CardSize = "small" | "medium" | "large" | "extra-large"; type SubtitleVariant = "regular-0" | "regular-150" | "medium-150"; const SUBTITLE_CLS: Record = { "regular-0": "text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-secondary", "regular-150": "text-body-small-regular-150 font-body-small-regular-150 text-text-neutral-secondary", "medium-150": "text-body-small-medium-150 font-body-small-medium-150 text-text-neutral-secondary", }; // Gemeinsames Auth-Layout nach Davids WF-P2-Subframe-Auth-Screens (Login/Signup/Reset/2FA/Magic-Link): // optionales Logo (64) + Davids ECHTE Card-Komponente (~/ui) + optionaler Footer. min-h-screen statt Davids // h-full (Auth-Routen ohne full-height-Parent). Card-Groesse/Logo-Sichtbarkeit/Header-Abstand/Untertitel-Stil // variieren je Screen in Davids Designs -> als Props (cardSize/showLogo/headerGap/subtitleVariant/titleAlign). // Card statt Inline-Nachbau beseitigt Token-Drift (rounded-md/px-6/items-start kommen jetzt aus der Card). // `items-stretch`-Override haelt Form-Kinder auf voller Breite (Davids Card-Root ist items-start). export function AuthShell({ title, subtitle, children, footer, cardSize = "large", cardClassName = "max-w-[448px]", showLogo = true, logoIconOnly = false, logoSize = "64", titleAlign = "center", headerGap = "gap-1.5", subtitleVariant = "regular-150", dataUiId, }: { title: ReactNode; subtitle?: ReactNode; children: ReactNode; footer?: ReactNode; /** Davids Card-Groesse. S01 Login/V01/V02 = large, S04 2FA = extra-large. */ cardSize?: CardSize; /** Breite/Overrides der Card; Forms = max-w-[400px] (Default). */ cardClassName?: string; /** Logo ueber der Card zeigen. Davids S01 Login/V01/V02 = ohne Logo. */ showLogo?: boolean; /** Icon-only-Logo (wie Davids Auth-Screens, Logo size=64 hideText) statt vollem Wortmarken-Logo. */ logoIconOnly?: boolean; /** Visuelle Logo-Groesse. Auth-Defaults bleiben bei 64; breite Mehrschritt-Flows duerfen kompakter sein. */ logoSize?: ComponentProps["size"]; /** Titel-/Untertitel-Ausrichtung. David: Login=center, Signup/Forgot/Reset/2FA=start. */ titleAlign?: "center" | "start"; /** Abstand Titel<->Untertitel. David: S01 Login = gap-1.5, sonst gap-1. */ headerGap?: string; /** Untertitel-Stil. David: S01 Login = regular-150, 2FA/Forgot = medium-150, sonst regular-0. */ subtitleVariant?: SubtitleVariant; dataUiId?: string; }) { return (
{showLogo ? : null}

{title}

{subtitle ? (

{subtitle}

) : null}
{children}
{footer ?
{footer}
: null}
); } // Status-Screen nach Davids Auth-Status-Design (Magic-Link Sent/Invalid, Forgot Sent, Reset Success ...): // volles Logo + Card mit farbigem Icon-Badge + Titel + Nachricht + optionalem Hinweis + Aktionen. export function AuthStatus({ icon, tone = "neutral", title, message, hint, children, dataUiId, }: { icon: ReactNode; tone?: StatusTone; title: ReactNode; message: ReactNode; hint?: ReactNode; /** Aktions-Buttons (vertikal gestapelt, zentriert). */ children?: ReactNode; dataUiId?: string; }) { return (

{title}

{message}

{hint ? (

{hint}

) : null}
{children ?
{children}
: null}
); } // Davids "oder"-Trenner zwischen Primär- und Sekundär-Aktion (z.B. Login vs. Magic-Link). export function AuthDivider({ label, labelSize = "small" }: { label: ReactNode; labelSize?: "small" | "extra-small" }) { return (
{label}
); }