/// 状态徽章(UI-01 §3.1):图标 + 文案 + 颜色三重表达,不只靠颜色。 /// /// 跨页面复用的语义变体(上传状态、公开/关闭等);文案由调用方传入 /// (本地化),图标按变体内置、可显式覆盖。两档尺寸:compact 高 24 /// (卡片角标行)、默认高 32(列表/详情行)。 library; import 'package:flutter/material.dart'; import '../tokens.dart'; /// 徽章语义变体。 enum BadgeVariant { /// 成功/完成事实(绿)。 success, /// 等待中(琥珀)。 warning, /// 需要处理的错误(红)。 error, /// 中性/关闭/未启用(灰)。 neutral, /// 信息提示(主色蓝)。 info, } /// 状态徽章:`图标 + 文案`,浅底色块(语义色 12% 透明度)+ 语义色文字。 class StateBadge extends StatelessWidget { const StateBadge({ required this.variant, required this.label, this.icon, this.compact = false, super.key, }); /// 语义变体(决定图标与颜色)。 final BadgeVariant variant; /// 展示文案(调用方本地化)。 final String label; /// 显式覆盖图标(默认按变体内置)。 final IconData? icon; /// 紧凑档:高 24、字号 12;默认高 32、字号 13。 final bool compact; @override Widget build(BuildContext context) { final theme = Theme.of(context); final (defaultIcon, color) = _resolve(variant, theme.brightness); return Container( height: compact ? 24.0 : 32.0, padding: EdgeInsets.symmetric(horizontal: compact ? 8 : 10), decoration: BoxDecoration( color: color.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(kRadiusBadge), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon ?? defaultIcon, size: compact ? 14 : 16, color: color), // 图标-文字光学间距(非布局节奏,不进令牌)。 SizedBox(width: compact ? kSpace4 : 6), Flexible( child: Text( label, maxLines: 1, overflow: TextOverflow.ellipsis, style: (compact ? theme.textTheme.labelSmall : theme.textTheme.bodySmall) ?.copyWith(color: color, fontWeight: FontWeight.w600), ), ), ], ), ); } /// 变体 → (图标, 语义色);深色主题取提亮变体保证对比度。 static (IconData, Color) _resolve( BadgeVariant variant, Brightness brightness, ) => switch (variant) { BadgeVariant.success => brightness == Brightness.light ? (Icons.check_circle, kColorSuccess) : (Icons.check_circle, kColorSuccessDark), BadgeVariant.warning => brightness == Brightness.light ? (Icons.hourglass_top, kColorWaiting) : (Icons.hourglass_top, kColorWaitingDark), BadgeVariant.error => brightness == Brightness.light ? (Icons.error_outline, kColorError) : (Icons.error_outline, kColorErrorDark), BadgeVariant.neutral => brightness == Brightness.light ? (Icons.remove_circle_outline, kColorTextSecondary) : (Icons.remove_circle_outline, kColorTextSecondaryDark), BadgeVariant.info => brightness == Brightness.light ? (Icons.info_outline, kColorInfo) : (Icons.info_outline, kColorInfoDark), }; }