UI Phase 2 (L0): shared layout primitives + chrome standardization

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>
This commit is contained in:
2026-09-26 15:42:26 +08:00
parent 57377b1b21
commit 9f764150a2
10 changed files with 428 additions and 325 deletions
+10 -16
View File
@@ -16,6 +16,7 @@ import '../../providers/chat_provider.dart';
import '../../providers/ramadan_provider.dart';
import '../../providers/notifications_provider.dart';
import '../../widgets/app_page_header.dart';
import '../../widgets/app_section_header.dart';
import '../../widgets/app_state_view.dart';
import '../../widgets/responsive_body.dart';
import '../../theme/app_surfaces.dart';
@@ -126,22 +127,15 @@ class _SchedulePanel extends ConsumerWidget {
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Row(
children: [
Text(
'Duty Schedules',
style: Theme.of(
context,
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w700),
),
const Spacer(),
FilterChip(
label: const Text('Show past'),
selected: showPast,
onSelected: (v) =>
ref.read(showPastSchedulesProvider.notifier).state = v,
),
],
child: AppSectionHeader(
'Duty Schedules',
padding: EdgeInsets.zero,
trailing: FilterChip(
label: const Text('Show past'),
selected: showPast,
onSelected: (v) =>
ref.read(showPastSchedulesProvider.notifier).state = v,
),
),
),
const SizedBox(height: 4),