Files
sxchnge/frontend/app/lib/auth/brand_panel.dart
T
Stephan D 10a278c65a Deliver localized auth app with verification and go_router
Integrate themed login/signup, EN/RU localization, shared dummy providers, verification recovery screens and named URL routes. Store frontend guidelines, workflow skills, validation and delivery documentation. Related to #2, #3, #5 and #6.
2026-09-11 15:37:07 +02:00

159 lines
4.5 KiB
Dart

import 'package:flutter/material.dart';
import '../generated/i18n/app_localizations.dart';
class BrandWordmark extends StatelessWidget {
const BrandWordmark({super.key});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: theme.colorScheme.primary,
borderRadius: BorderRadius.circular(9),
),
child: Icon(Icons.bolt, color: theme.colorScheme.onPrimary, size: 26),
),
const SizedBox(width: 9),
Flexible(
child: Text(
'sxchnge',
style: theme.textTheme.headlineMedium!.copyWith(
letterSpacing: -1.5,
fontWeight: FontWeight.w800,
),
),
),
],
);
}
}
class BrandPanel extends StatelessWidget {
const BrandPanel({super.key});
@override
Widget build(BuildContext context) {
final l = AppLocalizations.of(context)!;
final theme = Theme.of(context);
final colors = theme.colorScheme;
return ColoredBox(
color: colors.surface,
child: Padding(
padding: const EdgeInsets.all(48),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const BrandWordmark(),
const SizedBox(height: 64),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l.brandEyebrow,
style: theme.textTheme.labelMedium!.copyWith(
letterSpacing: 1.5,
color: colors.primary,
),
),
const SizedBox(height: 24),
Text(
l.brandHeading,
style: theme.textTheme.displayLarge!.copyWith(
fontSize: 68,
height: 1.03,
letterSpacing: -3,
),
),
const SizedBox(height: 32),
Text(
l.brandIntro,
style: theme.textTheme.bodyLarge!.copyWith(
color: colors.onSurfaceVariant,
),
),
const SizedBox(height: 48),
const _MotionCard(),
],
),
const SizedBox(height: 64),
Text(
l.brandFooter,
style: theme.textTheme.labelSmall!.copyWith(
letterSpacing: 1,
color: colors.onSurfaceVariant,
),
),
],
),
),
);
}
}
class _MotionCard extends StatelessWidget {
const _MotionCard();
@override
Widget build(BuildContext context) {
final l = AppLocalizations.of(context)!;
final theme = Theme.of(context);
final colors = theme.colorScheme;
return TweenAnimationBuilder<double>(
tween: Tween(begin: 0, end: 1),
duration: MediaQuery.disableAnimationsOf(context)
? Duration.zero
: const Duration(milliseconds: 700),
curve: Curves.easeOutCubic,
builder: (context, value, child) => Opacity(
opacity: value,
child: Transform.translate(
offset: Offset(0, (1 - value) * 24),
child: child,
),
),
child: Transform.rotate(
angle: -0.035,
child: Card(
color: colors.primaryContainer,
child: Padding(
padding: const EdgeInsets.all(28),
child: Row(
children: [
Expanded(
child: Text(
l.brandCard,
style: theme.textTheme.headlineSmall!.copyWith(
color: colors.onPrimaryContainer,
),
),
),
const SizedBox(width: 12),
Container(
padding: const EdgeInsets.all(18),
decoration: BoxDecoration(
color: colors.tertiaryContainer,
shape: BoxShape.circle,
),
child: Icon(
Icons.north_east,
size: 38,
color: colors.onTertiaryContainer,
),
),
],
),
),
),
),
);
}
}