9f764150a2
Extract four shared layout widgets from the best existing implementations and adopt them across list/overview screens, deleting duplicated inline code. Layout/consistency only — no behavior change. New primitives (lib/widgets/): - app_section_header.dart — AppSectionHeader (azure accent bar + uppercase telemetry label; promoted from the dashboard's _sectionTitle). - app_metric_card.dart — AppMetricCard (uppercase label + mono value on a flat hairline surface; unifies KPI/stat tiles). - app_status_summary.dart — AppStatusSummaryRow/Item/Chip (dot + count + label, selectable; semantic AppStatusColors). - app_filter_bar.dart — AppFilterBar (responsive filter-row chrome). Adopted / de-duplicated: - Dashboard: _MetricCard now wraps AppMetricCard; section titles use AppSectionHeader (removed local _sectionTitle). - Tickets / Tasks / ISR: three separate summary-chip implementations (_StatusSummaryCard x2, _SummaryChip) collapsed into AppStatusSummaryRow. - Network Map overview: Sites/Devices tiles -> AppMetricCard (removed local _SummaryCard). - Workforce: "Duty Schedules" header -> AppSectionHeader with trailing chip. Verified: flutter analyze lib clean; flutter build web green; visual QA (tickets + ISR summary chips) in dark. Co-Authored-By: claude-flow <ruv@ruv.net>
59 lines
1.6 KiB
Dart
59 lines
1.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
/// Cyber/IT section header — a short accent bar + an uppercase, letter-spaced
|
|
/// "telemetry" label, with optional trailing actions.
|
|
///
|
|
/// This is the single shared treatment for in-page section titles (promoted
|
|
/// from the Dashboard's original `_sectionTitle`). Use it instead of ad-hoc
|
|
/// bold `Text` sub-headers so every screen's sections read the same way.
|
|
class AppSectionHeader extends StatelessWidget {
|
|
const AppSectionHeader(
|
|
this.title, {
|
|
super.key,
|
|
this.trailing,
|
|
this.padding = const EdgeInsets.only(bottom: 12),
|
|
});
|
|
|
|
final String title;
|
|
|
|
/// Optional trailing widget (e.g. a "Show past" button or filter chip),
|
|
/// pinned to the end of the header row.
|
|
final Widget? trailing;
|
|
|
|
final EdgeInsetsGeometry padding;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final cs = Theme.of(context).colorScheme;
|
|
return Padding(
|
|
padding: padding,
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
width: 3,
|
|
height: 16,
|
|
decoration: BoxDecoration(
|
|
color: cs.primary,
|
|
borderRadius: BorderRadius.circular(2),
|
|
),
|
|
),
|
|
const SizedBox(width: 10),
|
|
Expanded(
|
|
child: Text(
|
|
title.toUpperCase(),
|
|
style: Theme.of(context).textTheme.labelLarge?.copyWith(
|
|
fontWeight: FontWeight.w700,
|
|
letterSpacing: 0.8,
|
|
color: cs.onSurface,
|
|
),
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
?trailing,
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|