2026-08-13 03:29:33 +07:00
|
|
|
"use client";
|
|
|
|
|
|
2026-08-13 01:58:09 +07:00
|
|
|
import type * as React from "react";
|
2026-08-13 03:29:33 +07:00
|
|
|
import { FadeIn, Stagger, useShake } from "@/components/motion";
|
|
|
|
|
import { Card, CardContent } from "@/components/ui/card";
|
2026-08-13 01:58:09 +07:00
|
|
|
import { cn } from "@/lib/cn";
|
|
|
|
|
|
|
|
|
|
type AuthFormCardProps = {
|
|
|
|
|
title: string;
|
|
|
|
|
description: string;
|
|
|
|
|
children: React.ReactNode;
|
2026-08-13 03:29:33 +07:00
|
|
|
leading?: React.ReactNode;
|
2026-08-13 01:58:09 +07:00
|
|
|
className?: string;
|
|
|
|
|
headerClassName?: string;
|
|
|
|
|
contentClassName?: string;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export function AuthFormCard({
|
|
|
|
|
title,
|
|
|
|
|
description,
|
|
|
|
|
children,
|
2026-08-13 03:29:33 +07:00
|
|
|
leading,
|
2026-08-13 01:58:09 +07:00
|
|
|
className,
|
|
|
|
|
headerClassName,
|
|
|
|
|
contentClassName,
|
|
|
|
|
}: AuthFormCardProps) {
|
|
|
|
|
return (
|
2026-08-13 03:29:33 +07:00
|
|
|
<FadeIn y={20} x={12} duration={0.65} className="flex w-full justify-center">
|
|
|
|
|
<Card className={cn("w-full max-w-md gap-0 overflow-hidden py-6", className)}>
|
|
|
|
|
<header className={cn("px-5 pb-6 sm:px-6", headerClassName)}>
|
|
|
|
|
<div className={cn(leading && "flex items-start gap-3.5")}>
|
|
|
|
|
{leading}
|
|
|
|
|
<div className="min-w-0">
|
|
|
|
|
<h2 className="text-[1.75rem] leading-none font-black tracking-[-0.045em]">
|
|
|
|
|
{title}
|
|
|
|
|
</h2>
|
|
|
|
|
<p className="mt-1.5 max-w-[34ch] text-sm leading-5 text-muted-foreground">
|
|
|
|
|
{description}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</header>
|
|
|
|
|
<CardContent className={contentClassName}>
|
|
|
|
|
<Stagger y={10} stagger={0.05} delay={0.12} selector=":scope > *, :scope > form > *">
|
|
|
|
|
{children}
|
|
|
|
|
</Stagger>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
</FadeIn>
|
2026-08-13 01:58:09 +07:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function FormError({ message }: { message?: string | null }) {
|
2026-08-13 03:29:33 +07:00
|
|
|
const ref = useShake(message);
|
|
|
|
|
|
2026-08-13 01:58:09 +07:00
|
|
|
if (!message) return null;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
2026-08-13 03:29:33 +07:00
|
|
|
ref={ref}
|
2026-08-13 01:58:09 +07:00
|
|
|
role="alert"
|
|
|
|
|
className="border-l-4 border-destructive bg-destructive/10 px-3 py-2 text-sm text-destructive"
|
|
|
|
|
>
|
|
|
|
|
{message}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|