import { motion, useReducedMotion } from 'framer-motion' import { ArrowRightLeft } from 'lucide-react' import type { PropsWithChildren, ReactNode } from 'react' import { Card, CardContent, CardHeader, cn } from 'ui' import { ProfileImage } from '@/components/ui/ProfileImage' import { BASE_PATH } from '@/lib/constants' const MotionCard = motion.create(Card) interface InterstitialLayoutProps { logo?: ReactNode title?: ReactNode description?: ReactNode /** Optional content rendered beneath the card (e.g. a terms disclaimer), at the card's width. */ footer?: ReactNode containerClassName?: string cardClassName?: string /** Shared max-width for the card and footer column. Defaults to `max-w-[400px]`. */ widthClassName?: string titleClassName?: string descriptionClassName?: string } /** * Minimal full-screen centered layout for interstitial flows: * partner authorization, org invites, CLI auth, credit redemption, etc. * * The logo, title, and description render inside the card (above children), * so every consumer gets a consistent header for free. */ export const InterstitialLayout = ({ logo, title, description, footer, containerClassName, cardClassName, widthClassName = 'max-w-[400px]', titleClassName, descriptionClassName, children, }: PropsWithChildren) => { const shouldReduceMotion = useReducedMotion() const TitleElement = typeof title === 'string' ? 'h1' : 'div' const DescriptionElement = typeof description === 'string' ? 'p' : 'div' const titleElement = title ? ( {title} ) : null const descriptionElement = description ? ( {description} ) : null const card = ( {(logo || title || description) && ( {logo &&
{logo}
} {(titleElement || descriptionElement) && (
{titleElement} {descriptionElement}
)}
)} {children}
) return (
{footer ? (
{card}
{footer}
) : ( card )}
) } /** * Standard rounded-rect logo container (48x48). * Partner logos fill edge-to-edge (see `PartnerLogo`); the Supabase symbol and * Lucide icons sit inset (sized at `size-7`). */ export const LogoBox = ({ children, className }: { children: ReactNode; className?: string }) => (
{children}
) /** Two pre-boxed logos side-by-side with a swap separator. */ export const LogoPair = ({ left, right }: { left: ReactNode; right: ReactNode }) => (
{left} {right}
) /** Partner logo rendered edge-to-edge inside a LogoBox by default. */ export const PartnerLogo = ({ src, alt, className, imageClassName, }: { src: string alt: string className?: string imageClassName?: string }) => ( {alt} ) /** * Sign-in destination mark, inset to match {@link SupabaseLogo}. Falls back to the destination's * initial when no icon is available. */ export const DestinationLogo = ({ icon, name }: { icon?: ReactNode; name: string }) => ( {icon ?? {name.slice(0, 1)}} ) /** Fixed light tile chrome for Connect pairs with unclassified (uploaded) marks. */ export const CONNECT_LOGO_LIGHT_TILE_CLASSNAME = 'border-black/10 bg-white' /** Supabase symbol (not the wordmark) rendered inset inside a LogoBox. */ export const SupabaseLogo = ({ forceLight = false }: { forceLight?: boolean } = {}) => ( Supabase ) export const InterstitialAccountRow = ({ avatarUrl, displayName, action, className, detail, }: { avatarUrl?: string displayName?: string action?: ReactNode className?: string detail?: string }) => (

Signed in as

{displayName || Loading account}

{detail &&

{detail}

}
{action}
) export const InterstitialActionError = ({ error }: { error?: ReactNode }) => { if (!error) return null return (

{error}

) }