import 'package:flutter/material.dart'; import '../theme/m3_motion.dart'; /// Standardized M3 Expressive page header with animated entrance. /// /// Replaces the ad-hoc `Padding(Align(Text(...)))` pattern found across /// screens. Provides: /// * `headlineSmall` typography — correct M3 size for a top-level page title. /// * [M3FadeSlideIn] entrance animation — 400 ms with emphasized easing. /// * Optional [subtitle] in `bodyMedium` / `onSurfaceVariant`. /// * Optional [actions] row rendered at the trailing end. /// * Responsive alignment: left-aligned on desktop (≥600 dp), centered on /// mobile to match the existing navigation-bar-centric layout. class AppPageHeader extends StatelessWidget { const AppPageHeader({ super.key, required this.title, this.subtitle, this.actions, this.padding = const EdgeInsets.only(top: 20, bottom: 12), }); final String title; final String? subtitle; /// Optional trailing action widgets (e.g. filter chip, icon button). final List? actions; /// Vertical padding around the header. Horizontal padding is handled by /// the parent [ResponsiveBody] so only top/bottom should be set here. final EdgeInsetsGeometry padding; @override Widget build(BuildContext context) { final tt = Theme.of(context).textTheme; final cs = Theme.of(context).colorScheme; final titleWidget = Text( title, style: tt.headlineSmall?.copyWith( fontWeight: FontWeight.w700, letterSpacing: -0.3, color: cs.onSurface, ), textAlign: TextAlign.center, ); final subtitleWidget = subtitle == null ? null : Text( subtitle!, style: tt.bodyMedium?.copyWith(color: cs.onSurfaceVariant), textAlign: TextAlign.center, ); final hasActions = actions != null && actions!.isNotEmpty; Widget content; if (!hasActions) { content = Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ titleWidget, if (subtitleWidget != null) ...[ const SizedBox(height: 4), subtitleWidget, ], ], ); } else { // With actions — centered title/subtitle, actions sit to the right. content = Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ titleWidget, if (subtitleWidget != null) ...[ const SizedBox(height: 4), subtitleWidget, ], ], ), ), const SizedBox(width: 8), Row(mainAxisSize: MainAxisSize.min, children: actions!), ], ); } return M3FadeSlideIn( duration: M3Motion.standard, child: Padding(padding: padding, child: content), ); } }