58 lines
2.2 KiB
Dart
58 lines
2.2 KiB
Dart
import 'package:flutter/material.dart';
|
|||
|
|
|
||
|
|
import '../theme/status_colors.dart';
|
||
|
|
import '../theme/theme_x.dart';
|
||
|
|
|
||
|
|
/// A dot + label badge encoding state — service up/down/unknown, backup or
|
||
|
|
/// update success/fail, node reachable/unreachable. The same component
|
||
|
|
/// everywhere a status appears so a given [Severity] always reads the same
|
||
|
|
/// color, matching the design rule that status color is reserved and never
|
||
|
|
/// doubles as the brand accent.
|
||
|
|
class StatusPill extends StatelessWidget {
|
||
|
|
const StatusPill({super.key, required this.label, required this.severity});
|
||
|
|
|
||
|
|
final String label;
|
||
|
|
final Severity severity;
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
final color = severity.resolve(context.status, muted: context.colors.outline);
|
||
|
|
|
||
|
|
return Container(
|
||
|
|
padding: const EdgeInsets.fromLTRB(7, 3, 9, 3),
|
||
|
|
decoration: BoxDecoration(
|
||
|
|
// 8% tint, not 14% — measured against the dark surface, a same-hue
|
||
|
|
// tint background caps critical's text contrast around ~3.5:1 no
|
||
|
|
// matter the blend ratio (text and background converge toward the
|
||
|
|
// same hue as alpha rises, and approach the plain-surface ceiling
|
||
|
|
// as it falls); 8% is close to that ceiling while keeping
|
||
|
|
// good/warning/serious comfortably at 4.5:1+. Below AA-for-text on
|
||
|
|
// its own, mitigated the same way the design system's status
|
||
|
|
// palette always mitigates this: label text, never color alone.
|
||
|
|
color: severity == Severity.neutral
|
||
|
|
? context.colors.surfaceContainerHighest
|
||
|
|
: Color.alphaBlend(color.withValues(alpha: 0.08), context.colors.surface),
|
||
|
|
borderRadius: BorderRadius.circular(999),
|
||
|
|
),
|
||
|
|
child: Row(
|
||
|
|
mainAxisSize: MainAxisSize.min,
|
||
|
|
children: [
|
||
|
|
Container(
|
||
|
|
width: 6,
|
||
|
|
height: 6,
|
||
|
|
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
|
||
|
|
),
|
||
|
|
const SizedBox(width: 6),
|
||
|
|
Text(
|
||
|
|
label,
|
||
|
|
style: context.text.labelMedium?.copyWith(
|
||
|
|
color: severity == Severity.neutral ? context.colors.onSurfaceVariant : color,
|
||
|
|
fontWeight: FontWeight.w600,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|