import 'package:flutter/material.dart'; import 'package:flutter_remix/flutter_remix.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import '../theme/app_text.dart'; import '../theme/spacing.dart'; // ───────────────────────────────────────────────────────────────────────── // 详情/主页通用卡片语言。 // ───────────────────────────────────────────────────────────────────────── /// 白底描边卡片(demo `.mcard`)。 class DetailCard extends StatelessWidget { const DetailCard({super.key, required this.child, this.color}); final Widget child; /// 卡片底色,默认白 `card`。 final Color? color; @override Widget build(BuildContext context) { final cs = ShadTheme.of(context).colorScheme; return Container( width: double.infinity, padding: const EdgeInsets.all(Spacing.cardPadding), decoration: BoxDecoration( color: color ?? cs.card, border: Border.all(color: cs.border), borderRadius: BorderRadius.circular(Spacing.radiusCard), ), child: child, ); } } /// 卡片头部:编号圆角块(或图标)+ 标题(demo `.mh > .mnum + h2`)。 class DetailSectionHeader extends StatelessWidget { const DetailSectionHeader({ super.key, this.number, this.icon, required this.title, }); final int? number; final IconData? icon; final String title; @override Widget build(BuildContext context) { final cs = ShadTheme.of(context).colorScheme; return Row( children: [ Container( width: 26, height: 26, alignment: Alignment.center, decoration: BoxDecoration( color: cs.accent, borderRadius: BorderRadius.circular(7), ), child: number != null ? Text( '$number', style: TextStyle( fontSize: 13, fontWeight: FontWeight.w700, color: cs.accentForeground, ), ) : Icon(icon, size: 15, color: cs.accentForeground), ), const SizedBox(width: 10), Expanded( child: Text( title, style: AppText.listTitle.copyWith( fontSize: 17, fontWeight: FontWeight.w700, color: cs.foreground, ), ), ), ], ); } } /// 徽标(demo `.badge` secondary / outline / 实底)。 class DetailBadge extends StatelessWidget { const DetailBadge( this.label, { super.key, this.bg, this.fg, this.outline = false, this.icon, }); final String label; final Color? bg; final Color? fg; final bool outline; final IconData? icon; @override Widget build(BuildContext context) { final cs = ShadTheme.of(context).colorScheme; return Container( padding: const EdgeInsets.symmetric(horizontal: 9, vertical: 3), decoration: BoxDecoration( color: outline ? Colors.transparent : (bg ?? cs.secondary), borderRadius: BorderRadius.circular(Spacing.radiusBadge), // 实底也带 1px 透明描边,与 outline 徽标等高等宽 border: outline ? Border.all(color: cs.border) : Border.all(color: Colors.transparent), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ if (icon != null) ...[ Icon( icon, size: 10, color: outline ? cs.mutedForeground : (fg ?? cs.foreground), ), const SizedBox(width: 3), ], Text( label, style: AppText.badge.copyWith( color: outline ? cs.mutedForeground : (fg ?? cs.foreground), ), ), ], ), ); } } /// 键值行(demo `.crow > .cl + .cv`)。value 可选链接样式 + 右上箭头,点击回调。 class DetailKeyValueRow extends StatelessWidget { const DetailKeyValueRow({ super.key, required this.label, required this.value, this.link = false, this.onTap, }); final String label; final String value; final bool link; final VoidCallback? onTap; @override Widget build(BuildContext context) { final cs = ShadTheme.of(context).colorScheme; final valueWidget = Row( mainAxisSize: MainAxisSize.min, children: [ Flexible( child: Text( value, textAlign: TextAlign.right, style: AppText.meta.copyWith( fontSize: 13.5, // 链接用深绿 accentForeground(lime 只做底色,不做文字色) color: link ? cs.accentForeground : cs.foreground, fontWeight: FontWeight.w500, ), ), ), if (link) ...[ const SizedBox(width: 3), Icon( FlutterRemix.external_link_line, size: 13, color: cs.accentForeground, ), ], ], ); return Container( padding: const EdgeInsets.symmetric(vertical: 11), decoration: BoxDecoration( border: Border(bottom: BorderSide(color: cs.border)), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: AppText.meta.copyWith( fontSize: 13.5, color: cs.mutedForeground, ), ), const SizedBox(width: 14), Expanded( child: Align( alignment: Alignment.centerRight, child: link && onTap != null ? GestureDetector( onTap: onTap, behavior: HitTestBehavior.opaque, child: valueWidget, ) : valueWidget, ), ), ], ), ); } } /// 合规提示条(demo `.disc`:⚠ 图标 + 灰字)。 class DetailDisclaimer extends StatelessWidget { const DetailDisclaimer({super.key, required this.text}); final String text; @override Widget build(BuildContext context) { final cs = ShadTheme.of(context).colorScheme; return Container( width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), decoration: BoxDecoration( color: cs.secondary, borderRadius: BorderRadius.circular(Spacing.radiusBase), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon( FlutterRemix.error_warning_line, size: 15, color: cs.mutedForeground, ), const SizedBox(width: 8), Expanded( child: Text( text, style: AppText.meta.copyWith( fontSize: 12, color: cs.mutedForeground, height: 1.5, ), ), ), ], ), ); } }