c94b9e5e58
Co-Authored-By: Claude Code <noreply@anthropic.com>
113 lines
3.4 KiB
Dart
113 lines
3.4 KiB
Dart
/// 状态徽章(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),
|
|
};
|
|
}
|