feat(auth): redesign visual das páginas de autenticação

O sidebar de autenticação ganha mockup animado de faturas e três itens
de funcionalidade no rodapé, substituindo o texto descritivo anterior.

As páginas de login e cadastro recebem gradiente decorativo de fundo e
exibem o logo no topo em viewports mobile.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Felipe Coutinho
2026-04-01 14:14:01 +00:00
parent 0ab3298cef
commit 1f8a97bd16
4 changed files with 157 additions and 13 deletions

View File

@@ -1,9 +1,19 @@
import { LoginForm } from "@/features/auth/components/login-form"; import { LoginForm } from "@/features/auth/components/login-form";
import { Logo } from "@/shared/components/logo";
export default function LoginPage() { export default function LoginPage() {
return ( return (
<div className="flex min-h-svh flex-col items-center justify-center bg-linear-to-b from-background via-background to-muted/20 px-5 py-8 md:px-8 md:py-10"> <div className="relative flex min-h-svh flex-col items-center justify-center overflow-hidden bg-linear-to-b from-background via-background to-muted/20 px-5 py-8 md:px-8 md:py-10">
<div className="w-full max-w-sm md:max-w-5xl"> <div className="pointer-events-none absolute inset-0">
<div className="absolute -right-32 -top-32 h-72 w-72 rounded-full bg-primary/10 blur-3xl" />
<div className="absolute -bottom-32 -left-32 h-72 w-72 rounded-full bg-primary/7 blur-3xl" />
</div>
<div className="relative mb-6 flex md:hidden">
<Logo variant="compact" colorIcon />
</div>
<div className="relative w-full max-w-sm md:max-w-5xl">
<LoginForm /> <LoginForm />
</div> </div>
</div> </div>

View File

@@ -1,9 +1,19 @@
import { SignupForm } from "@/features/auth/components/signup-form"; import { SignupForm } from "@/features/auth/components/signup-form";
import { Logo } from "@/shared/components/logo";
export default function Page() { export default function SignupPage() {
return ( return (
<div className="flex min-h-svh flex-col items-center justify-center bg-linear-to-b from-background via-background to-muted/20 px-5 py-8 md:px-8 md:py-10"> <div className="relative flex min-h-svh flex-col items-center justify-center overflow-hidden bg-linear-to-b from-background via-background to-muted/20 px-5 py-8 md:px-8 md:py-10">
<div className="w-full max-w-sm md:max-w-5xl"> <div className="pointer-events-none absolute inset-0">
<div className="absolute -right-32 -top-32 h-72 w-72 rounded-full bg-primary/10 blur-3xl" />
<div className="absolute -bottom-32 -left-32 h-72 w-72 rounded-full bg-primary/7 blur-3xl" />
</div>
<div className="relative mb-6 flex md:hidden">
<Logo variant="compact" colorIcon />
</div>
<div className="relative w-full max-w-sm md:max-w-5xl">
<SignupForm /> <SignupForm />
</div> </div>
</div> </div>

View File

@@ -0,0 +1,89 @@
import Image from "next/image";
import { resolveLogoSrc } from "@/shared/lib/logo";
import { formatCurrency } from "@/shared/utils/currency";
type MockInvoice = {
cardName: string;
logo: string;
amount: number;
dueLabel: string;
};
const MOCK_INVOICES: MockInvoice[] = [
{
cardName: "Nubank",
logo: "nubank.png",
amount: 1898,
dueLabel: "Vence em 3 dias",
},
{
cardName: "Itaú",
logo: "itau.png",
amount: 1923,
dueLabel: "Vence em 8 dias",
},
];
function MockInvoiceItem({
invoice,
divider,
}: {
invoice: MockInvoice;
divider: boolean;
}) {
const logoSrc = resolveLogoSrc(invoice.logo);
return (
<div className={divider ? "border-b border-border/60" : undefined}>
<div className="flex items-center justify-between py-2.5">
<div className="flex min-w-0 flex-1 items-center gap-2.5 py-0.5">
<div className="flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-full">
{logoSrc && (
<Image
src={logoSrc}
alt={`Logo ${invoice.cardName}`}
width={36}
height={36}
className="h-full w-full object-contain"
/>
)}
</div>
<div className="min-w-0">
<p className="text-sm font-medium text-foreground">
{invoice.cardName}
</p>
<p className="text-xs text-muted-foreground">{invoice.dueLabel}</p>
</div>
</div>
<div className="flex shrink-0 flex-col items-end gap-0.5">
<span className="text-sm font-medium tracking-tighter text-foreground">
{formatCurrency(invoice.amount)}
</span>
<span className="text-xs font-medium text-primary">Pagar</span>
</div>
</div>
</div>
);
}
export function AuthSidebarInvoicesMock() {
return (
<div className="rounded-xl border bg-card shadow-sm">
<div className="border-b px-4 py-3">
<span className="text-sm font-medium text-foreground">Faturas</span>
<p className="mt-0.5 text-xs text-muted-foreground">
Resumo das faturas do período
</p>
</div>
<div className="px-4">
{MOCK_INVOICES.map((invoice, index) => (
<MockInvoiceItem
key={invoice.cardName}
invoice={invoice}
divider={index < MOCK_INVOICES.length - 1}
/>
))}
</div>
</div>
);
}

View File

@@ -1,5 +1,28 @@
import {
RiBankCardLine,
RiBarChart2Line,
RiShieldCheckLine,
} from "@remixicon/react";
import { Logo } from "@/shared/components/logo"; import { Logo } from "@/shared/components/logo";
import { DotPattern } from "@/shared/components/ui/dot-pattern"; import { DotPattern } from "@/shared/components/ui/dot-pattern";
import { AuthSidebarInvoicesMock } from "./auth-sidebar-invoices-mock";
function FeatureItem({
icon: Icon,
text,
}: {
icon: React.ComponentType<{ className?: string }>;
text: string;
}) {
return (
<div className="flex items-center gap-3">
<div className="flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-black/12">
<Icon className="h-3.5 w-3.5 text-black/55" />
</div>
<span className="text-sm font-medium text-black/68">{text}</span>
</div>
);
}
function AuthSidebar() { function AuthSidebar() {
return ( return (
@@ -15,6 +38,7 @@ function AuthSidebar() {
/> />
<div className="absolute inset-0 bg-linear-to-br from-white/9 via-transparent to-black/7" /> <div className="absolute inset-0 bg-linear-to-br from-white/9 via-transparent to-black/7" />
</div> </div>
<div className="relative flex flex-1 flex-col justify-between p-10 lg:p-12"> <div className="relative flex flex-1 flex-col justify-between p-10 lg:p-12">
<Logo <Logo
variant="compact" variant="compact"
@@ -22,14 +46,25 @@ function AuthSidebar() {
className="opacity-92 [&_img]:brightness-0 [&_img]:saturate-0" className="opacity-92 [&_img]:brightness-0 [&_img]:saturate-0"
/> />
<div className="max-w-sm space-y-4.5"> <div className="flex flex-1 items-center justify-center py-10">
<h2 className="text-[2rem] font-semibold leading-[1.04] tracking-[-0.03em] text-black/84 lg:text-[2.35rem]"> <div className="w-full rotate-[1.5deg]">
Controle suas finanças com clareza e foco diário. <AuthSidebarInvoicesMock />
</h2> </div>
<p className="max-w-2xs text-sm leading-6 text-black/68"> </div>
Centralize despesas, organize cartões e acompanhe metas mensais em
um painel inteligente feito para o seu dia a dia. <div className="space-y-3">
</p> <FeatureItem
icon={RiBarChart2Line}
text="Controle de gastos por categoria"
/>
<FeatureItem
icon={RiBankCardLine}
text="Faturas e cartões centralizados"
/>
<FeatureItem
icon={RiShieldCheckLine}
text="Seus dados, sem rastreamento"
/>
</div> </div>
</div> </div>
</div> </div>