feat(02-01): brand auth pages with gradient bg, wordmark, and Alert errors

- LoginPage: pastel gradient background (saving/bill/investment light shades)
- LoginPage: gradient text wordmark with data-testid='wordmark'
- LoginPage: shadcn Alert destructive with AlertCircle icon for error display
- RegisterPage: mirrors LoginPage branding treatment exactly
- Both pages: Card shadow-lg for visual lift against gradient
- All 6 AUTH tests pass (AUTH-01 through AUTH-04)
This commit is contained in:
2026-03-11 21:49:16 +01:00
parent 9b57a1a4be
commit 381a06008b
2 changed files with 58 additions and 10 deletions

View File

@@ -1,8 +1,11 @@
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { AlertCircle } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
import { Alert, AlertDescription } from '@/components/ui/alert'
import { palette } from '@/lib/palette'
import type { AuthContext } from '@/hooks/useAuth'
interface Props {
@@ -31,15 +34,36 @@ export function LoginPage({ auth: { login }, onToggle }: Props) {
}
return (
<div className="flex min-h-screen items-center justify-center bg-background">
<Card className="w-full max-w-md">
<div
className="flex min-h-screen items-center justify-center"
style={{
background: `linear-gradient(135deg, ${palette.saving.light}, ${palette.bill.light}, ${palette.investment.light})`,
}}
>
<Card className="w-full max-w-md shadow-lg">
<CardHeader>
<CardTitle>{t('auth.login')}</CardTitle>
<CardDescription>{t('app.title')}</CardDescription>
<span
data-testid="wordmark"
className="text-2xl font-bold tracking-tight"
style={{
background: `linear-gradient(to right, oklch(0.50 0.12 260), oklch(0.50 0.12 320))`,
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
backgroundClip: 'text',
}}
>
{t('app.title')}
</span>
</CardHeader>
<form onSubmit={handleSubmit}>
<CardContent className="flex flex-col gap-4">
{error && <p className="text-sm text-destructive">{error}</p>}
{error && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
<Input
type="email"
placeholder={t('auth.email')}

View File

@@ -1,8 +1,11 @@
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { AlertCircle } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
import { Alert, AlertDescription } from '@/components/ui/alert'
import { palette } from '@/lib/palette'
import type { AuthContext } from '@/hooks/useAuth'
interface Props {
@@ -32,15 +35,36 @@ export function RegisterPage({ auth: { register }, onToggle }: Props) {
}
return (
<div className="flex min-h-screen items-center justify-center bg-background">
<Card className="w-full max-w-md">
<div
className="flex min-h-screen items-center justify-center"
style={{
background: `linear-gradient(135deg, ${palette.saving.light}, ${palette.bill.light}, ${palette.investment.light})`,
}}
>
<Card className="w-full max-w-md shadow-lg">
<CardHeader>
<CardTitle>{t('auth.register')}</CardTitle>
<CardDescription>{t('app.title')}</CardDescription>
<span
data-testid="wordmark"
className="text-2xl font-bold tracking-tight"
style={{
background: `linear-gradient(to right, oklch(0.50 0.12 260), oklch(0.50 0.12 320))`,
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
backgroundClip: 'text',
}}
>
{t('app.title')}
</span>
</CardHeader>
<form onSubmit={handleSubmit}>
<CardContent className="flex flex-col gap-4">
{error && <p className="text-sm text-destructive">{error}</p>}
{error && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
<Input
placeholder={t('auth.displayName')}
value={displayName}