import 'package:flutter/material.dart'; import '../../../../core/theme/design_tokens.dart'; class AuthPageScaffold extends StatelessWidget { const AuthPageScaffold({ super.key, required this.mainContent, this.footer, this.mainContentKey, this.footerKey, this.resizeOnKeyboard = true, }); final Widget mainContent; final Widget? footer; final Key? mainContentKey; final Key? footerKey; final bool resizeOnKeyboard; @override Widget build(BuildContext context) { final keyboardInset = MediaQuery.viewInsetsOf(context).bottom; final colorScheme = Theme.of(context).colorScheme; return Scaffold( backgroundColor: colorScheme.surface, resizeToAvoidBottomInset: resizeOnKeyboard, body: DecoratedBox( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [colorScheme.surfaceContainerLow, colorScheme.surface], ), ), child: Stack( children: [ _AuthBackgroundOrbs( topColor: colorScheme.primary.withValues(alpha: 0.2), rightColor: colorScheme.primaryContainer.withValues(alpha: 0.25), bottomColor: colorScheme.tertiaryContainer.withValues(alpha: 0.3), ), SafeArea( maintainBottomViewPadding: !resizeOnKeyboard, child: LayoutBuilder( builder: (context, constraints) { if (!resizeOnKeyboard) { return Padding( padding: const EdgeInsets.symmetric( horizontal: AppSpacing.lg, ), child: Center( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ KeyedSubtree( key: mainContentKey, child: mainContent, ), if (footer != null) ...[ SizedBox(height: AppSpacing.md), KeyedSubtree(key: footerKey, child: footer!), ], ], ), ), ); } return SingleChildScrollView( keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, padding: EdgeInsets.fromLTRB( AppSpacing.lg, AppSpacing.md, AppSpacing.lg, keyboardInset + AppSpacing.md, ), child: ConstrainedBox( constraints: BoxConstraints( minHeight: constraints.maxHeight, ), child: Center( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ KeyedSubtree( key: mainContentKey, child: mainContent, ), if (footer != null) ...[ SizedBox(height: AppSpacing.md), KeyedSubtree(key: footerKey, child: footer!), ], ], ), ), ), ); }, ), ), ], ), ), ); } } class AuthHeroHeader extends StatelessWidget { const AuthHeroHeader({ super.key, this.title, this.subtitle, this.showBrand = false, }); final String? title; final String? subtitle; final bool showBrand; @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ if (showBrand) ...[ Container( width: 88, height: 88, decoration: BoxDecoration( color: colorScheme.surface, borderRadius: BorderRadius.circular(AppRadius.full), border: Border.all(color: colorScheme.outlineVariant), boxShadow: [ BoxShadow( color: colorScheme.primary.withValues(alpha: 0.28), blurRadius: 30, offset: const Offset(0, 16), ), ], ), child: Center( child: ClipRRect( borderRadius: BorderRadius.circular(AppRadius.full), child: Image.asset( 'assets/images/logo.png', width: 88, height: 88, fit: BoxFit.cover, ), ), ), ), SizedBox(height: AppSpacing.lg), Text( 'linksy', style: TextStyle( fontFamily: 'Playfair Display', fontSize: 34, fontWeight: FontWeight.w700, fontStyle: FontStyle.italic, color: colorScheme.onSurface, letterSpacing: 0.4, ), ), ], if (title != null) ...[ if (showBrand) SizedBox(height: AppSpacing.lg), Text( title!, textAlign: TextAlign.center, style: TextStyle( fontSize: 28, fontWeight: FontWeight.w700, color: colorScheme.onSurface, letterSpacing: -0.2, ), ), ], if (subtitle != null) ...[ SizedBox(height: AppSpacing.sm), Text( subtitle!, textAlign: TextAlign.center, style: TextStyle( fontSize: 14, height: 1.45, color: colorScheme.onSurfaceVariant, ), ), ], ], ); } } class AuthSurfaceCard extends StatelessWidget { const AuthSurfaceCard({super.key, required this.child}); final Widget child; @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Container( width: double.infinity, padding: const EdgeInsets.all(AppSpacing.xl), decoration: BoxDecoration( color: colorScheme.surface, borderRadius: BorderRadius.circular(AppRadius.xxl), border: Border.all(color: colorScheme.outlineVariant), boxShadow: [ BoxShadow( color: colorScheme.primary.withValues(alpha: 0.12), blurRadius: 34, offset: const Offset(0, 18), ), BoxShadow( color: colorScheme.shadow.withValues(alpha: 0.06), blurRadius: 20, offset: const Offset(0, 10), ), ], ), child: child, ); } } class AuthSection extends StatelessWidget { const AuthSection({ super.key, this.title, this.description, required this.child, }); final String? title; final String? description; final Widget child; @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (title != null) ...[ Text( title!, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w700, color: colorScheme.onSurface, ), ), if (description != null) ...[ SizedBox(height: AppSpacing.xs), Text( description!, style: TextStyle( fontSize: 13, height: 1.4, color: colorScheme.onSurfaceVariant, ), ), ], SizedBox(height: AppSpacing.md), ], child, ], ); } } class _AuthBackgroundOrbs extends StatelessWidget { const _AuthBackgroundOrbs({ required this.topColor, required this.rightColor, required this.bottomColor, }); final Color topColor; final Color rightColor; final Color bottomColor; @override Widget build(BuildContext context) { return IgnorePointer( child: Stack( children: [ Positioned( top: -72, left: -38, child: _Orb(size: 168, color: topColor), ), Positioned( top: 108, right: -32, child: _Orb(size: 120, color: rightColor), ), Positioned( bottom: 36, left: 24, child: _Orb(size: 92, color: bottomColor), ), ], ), ); } } class _Orb extends StatelessWidget { const _Orb({required this.size, required this.color}); final double size; final Color color; @override Widget build(BuildContext context) { return Container( width: size, height: size, decoration: BoxDecoration(shape: BoxShape.circle, color: color), ); } }