New components: - RegisterForm — name, email, password, confirm, terms, password strength - ForgotPasswordForm — email input with success/error states, back link - ResetPasswordForm — new password + confirm with strength indicator - VerifyEmailForm — 6-digit code input with resend, numeric-only filter - OnboardingShell — step indicator, progress bar, back/next/complete nav - AuthPageLayout — full-page centered card with product branding - PasswordStrengthBar — visual bar + label (weak/fair/good/strong) Existing components preserved: LoginForm, MfaChallenge, SocialButtons All styled via --bl-* CSS custom properties for product theming 54 tests (13 existing + 41 new) — all passing
102 lines
2.7 KiB
TypeScript
102 lines
2.7 KiB
TypeScript
import type { AuthPageLayoutProps } from './types.js';
|
|
|
|
/**
|
|
* Full-page auth layout — centered card with product branding.
|
|
* Wraps any auth form (LoginForm, RegisterForm, etc.).
|
|
* Styled via CSS custom properties (inherits --bl-* from host app).
|
|
*/
|
|
export function AuthPageLayout({
|
|
productName,
|
|
logo,
|
|
title,
|
|
subtitle,
|
|
children,
|
|
footer,
|
|
className,
|
|
}: AuthPageLayoutProps) {
|
|
return (
|
|
<div
|
|
className={className}
|
|
data-testid="bl-auth-page"
|
|
style={{
|
|
display: 'flex',
|
|
minHeight: '100vh',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
padding: '16px',
|
|
background: 'var(--bl-page-bg, #f5f5f5)',
|
|
fontFamily: 'var(--bl-font, system-ui, -apple-system, sans-serif)',
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
width: '100%',
|
|
maxWidth: '400px',
|
|
background: 'var(--bl-surface, #fff)',
|
|
borderRadius: 'var(--bl-card-radius, 12px)',
|
|
boxShadow: 'var(--bl-card-shadow, 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06))',
|
|
padding: '32px',
|
|
}}
|
|
>
|
|
{/* Branding */}
|
|
<div style={{ textAlign: 'center', marginBottom: '24px' }}>
|
|
{logo && (
|
|
<div style={{ marginBottom: '12px' }} data-testid="bl-auth-logo">
|
|
{typeof logo === 'string' ? (
|
|
<img src={logo} alt={productName} style={{ height: '48px' }} />
|
|
) : (
|
|
logo
|
|
)}
|
|
</div>
|
|
)}
|
|
<div
|
|
style={{ fontSize: '20px', fontWeight: 700, color: 'var(--bl-text, #111)' }}
|
|
data-testid="bl-auth-product-name"
|
|
>
|
|
{productName}
|
|
</div>
|
|
<div
|
|
style={{
|
|
fontSize: '16px',
|
|
fontWeight: 600,
|
|
color: 'var(--bl-text, #333)',
|
|
marginTop: '8px',
|
|
}}
|
|
data-testid="bl-auth-title"
|
|
>
|
|
{title}
|
|
</div>
|
|
{subtitle && (
|
|
<div
|
|
style={{ fontSize: '14px', color: 'var(--bl-muted, #666)', marginTop: '4px' }}
|
|
data-testid="bl-auth-subtitle"
|
|
>
|
|
{subtitle}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Form content */}
|
|
{children}
|
|
|
|
{/* Footer */}
|
|
{footer && (
|
|
<div
|
|
style={{
|
|
marginTop: '20px',
|
|
paddingTop: '16px',
|
|
borderTop: '1px solid var(--bl-border, #eee)',
|
|
textAlign: 'center',
|
|
fontSize: '13px',
|
|
color: 'var(--bl-muted, #999)',
|
|
}}
|
|
data-testid="bl-auth-footer"
|
|
>
|
|
{footer}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|