马良AI写作初始化仓库
This commit is contained in:
210
AINoval/lib/widgets/common/context_badge.dart
Normal file
210
AINoval/lib/widgets/common/context_badge.dart
Normal file
@@ -0,0 +1,210 @@
|
||||
import 'package:flutter/material.dart';
|
||||
// import 'package:ainoval/utils/web_theme.dart';
|
||||
|
||||
/// 上下文数据
|
||||
class ContextData {
|
||||
/// 构造函数
|
||||
const ContextData({
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
this.icon,
|
||||
this.id,
|
||||
});
|
||||
|
||||
/// 标题
|
||||
final String title;
|
||||
|
||||
/// 副标题(可选)
|
||||
final String? subtitle;
|
||||
|
||||
/// 图标(可选,如果不提供会根据内容自动判断)
|
||||
final IconData? icon;
|
||||
|
||||
/// 唯一标识(可选)
|
||||
final String? id;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
return other is ContextData &&
|
||||
other.title == title &&
|
||||
other.subtitle == subtitle &&
|
||||
other.icon == icon &&
|
||||
other.id == id;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return title.hashCode ^
|
||||
subtitle.hashCode ^
|
||||
icon.hashCode ^
|
||||
id.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
/// 上下文标签组件
|
||||
/// 显示上下文信息,支持删除操作,风格简洁现代
|
||||
class ContextBadge extends StatelessWidget {
|
||||
/// 构造函数
|
||||
const ContextBadge({
|
||||
super.key,
|
||||
required this.data,
|
||||
this.onDelete,
|
||||
this.maxWidth = 200,
|
||||
this.showDeleteButton = true,
|
||||
this.globalKey,
|
||||
});
|
||||
|
||||
/// 上下文数据
|
||||
final ContextData data;
|
||||
|
||||
/// 删除回调
|
||||
final VoidCallback? onDelete;
|
||||
|
||||
/// 最大宽度
|
||||
final double maxWidth;
|
||||
|
||||
/// 是否显示删除按钮
|
||||
final bool showDeleteButton;
|
||||
|
||||
/// 全局Key,用于定位
|
||||
final GlobalKey? globalKey;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// final isDark = WebTheme.isDarkMode(context);
|
||||
|
||||
return Container(
|
||||
key: globalKey,
|
||||
constraints: BoxConstraints(maxWidth: maxWidth),
|
||||
height: 36, // h-9 equivalent
|
||||
decoration: BoxDecoration(
|
||||
color: _getBackgroundColor(context),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// 图标
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 8, right: 8),
|
||||
child: Icon(
|
||||
_getIcon(),
|
||||
size: 16, // size-4 equivalent
|
||||
color: _getIconColor(context),
|
||||
),
|
||||
),
|
||||
|
||||
// 内容
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 4),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 标题
|
||||
Text(
|
||||
data.title,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600, // font-semibold
|
||||
color: _getTextColor(context),
|
||||
height: 1.2, // leading-tight
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
||||
// 副标题
|
||||
if (data.subtitle != null && data.subtitle!.isNotEmpty) ...[
|
||||
const SizedBox(height: 1),
|
||||
Text(
|
||||
data.subtitle!,
|
||||
style: TextStyle(
|
||||
fontSize: 10, // text-xs
|
||||
color: _getSubtitleColor(context),
|
||||
height: 1.2, // leading-tight
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// 删除按钮
|
||||
if (showDeleteButton)
|
||||
Material(
|
||||
type: MaterialType.transparency,
|
||||
child: InkWell(
|
||||
onTap: onDelete,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: Container(
|
||||
width: 20, // h-5 w-5
|
||||
height: 20,
|
||||
margin: const EdgeInsets.only(right: 6),
|
||||
child: Icon(
|
||||
Icons.close,
|
||||
size: 14, // h-3.5 w-3.5
|
||||
color: _getDeleteButtonColor(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 获取图标
|
||||
IconData _getIcon() {
|
||||
// 如果提供了自定义图标,直接使用
|
||||
if (data.icon != null) {
|
||||
return data.icon!;
|
||||
}
|
||||
|
||||
// 根据标题内容自动判断图标
|
||||
final title = data.title.toLowerCase();
|
||||
|
||||
if (title.contains('act') || title.contains('chapter') || title.contains('scene')) {
|
||||
return Icons.menu_book_outlined; // block-quote equivalent
|
||||
} else if (title.contains('novel') || title.contains('book') || title.contains('text')) {
|
||||
return Icons.menu_book; // book-open equivalent
|
||||
} else if (title.contains('folder') || title.contains('directory')) {
|
||||
return Icons.folder_outlined; // folder-closed equivalent
|
||||
} else {
|
||||
return Icons.description_outlined; // 默认文档图标
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取背景颜色
|
||||
Color _getBackgroundColor(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final title = data.title.toLowerCase();
|
||||
final bool isContent = title.contains('novel') || title.contains('book') || title.contains('text');
|
||||
return isContent ? scheme.surfaceContainerHigh : scheme.surfaceContainer;
|
||||
}
|
||||
|
||||
/// 获取图标颜色
|
||||
Color _getIconColor(BuildContext context) {
|
||||
return Theme.of(context).colorScheme.onSurfaceVariant;
|
||||
}
|
||||
|
||||
/// 获取文字颜色
|
||||
Color _getTextColor(BuildContext context) {
|
||||
return Theme.of(context).colorScheme.onSurface;
|
||||
}
|
||||
|
||||
/// 获取副标题颜色
|
||||
Color _getSubtitleColor(BuildContext context) {
|
||||
return Theme.of(context).colorScheme.onSurfaceVariant;
|
||||
}
|
||||
|
||||
/// 获取删除按钮颜色
|
||||
Color _getDeleteButtonColor(BuildContext context) {
|
||||
return Theme.of(context).colorScheme.onSurfaceVariant;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user