feat(mobile): UI-01 theme system, shared components and navigation
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
/// 状态徽章(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),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user