// ChainDataRow — Linear-style dense list row used by the audit // stream. Hover-elevation, accent-coloured leading stripe, mono // timestamp, expressive type badge. import 'package:flutter/material.dart'; import '../theme/theme.dart'; import '../theme/tokens.dart'; class ChainDataRow extends StatefulWidget { /// Coloured leading stripe (4px). Used to encode event type /// (success / warning / failure) at a glance. final Color accent; /// Left-most column: a short, monospaced label (timestamp, id). final String leading; /// Title in the middle. Usually the event type, in mono. final String title; /// Subtitle on the right of title. Free-form, lighter colour. final String subtitle; /// Right-most column: trailing label (duration, etc). final String? trailing; /// Optional tap handler. final VoidCallback? onTap; const ChainDataRow({ super.key, required this.accent, required this.leading, required this.title, required this.subtitle, this.trailing, this.onTap, }); @override State createState() => _FaiDataRowState(); } class _FaiDataRowState extends State { bool _hovered = false; @override Widget build(BuildContext context) { final theme = Theme.of(context); return MouseRegion( onEnter: (_) => setState(() => _hovered = true), onExit: (_) => setState(() => _hovered = false), cursor: widget.onTap != null ? SystemMouseCursors.click : SystemMouseCursors.basic, child: GestureDetector( onTap: widget.onTap, behavior: HitTestBehavior.opaque, child: AnimatedContainer( duration: ChainMotion.fast, decoration: BoxDecoration( color: _hovered ? theme.colorScheme.surfaceContainerHigh : theme.colorScheme.surfaceContainer, borderRadius: BorderRadius.circular(ChainRadius.sm), border: Border.all( color: _hovered ? theme.colorScheme.outline : theme.colorScheme.outlineVariant, ), ), padding: const EdgeInsets.symmetric( horizontal: ChainSpace.md, vertical: ChainSpace.sm, ), child: Row( children: [ Container( width: 3, height: 24, decoration: BoxDecoration( color: widget.accent, borderRadius: BorderRadius.circular(2), ), ), const SizedBox(width: ChainSpace.md), SizedBox( width: 88, child: Text( widget.leading, style: ChainTheme.mono( size: 11, color: theme.colorScheme.onSurfaceVariant, ), ), ), SizedBox( width: 200, child: Text( widget.title, style: ChainTheme.mono( size: 12, weight: FontWeight.w500, color: theme.colorScheme.onSurface, ), ), ), Expanded( child: Text( widget.subtitle, style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), overflow: TextOverflow.ellipsis, ), ), if (widget.trailing != null) Padding( padding: const EdgeInsets.only(left: ChainSpace.md), child: Text( widget.trailing!, style: ChainTheme.mono( size: 11, color: theme.colorScheme.onSurfaceVariant, ), ), ), ], ), ), ), ); } }