diff --git a/lib/widgets/knowledge_item_card.dart b/lib/widgets/knowledge_item_card.dart new file mode 100644 index 0000000..ca5b09c --- /dev/null +++ b/lib/widgets/knowledge_item_card.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +import '../data/models/knowledge_item.dart'; + +class KnowledgeItemCard extends StatelessWidget { + final KnowledgeItem item; + const KnowledgeItemCard({super.key, required this.item}); + + IconData get _icon => switch (item.noteType) { + 'person' => Icons.person_outlined, + 'place' => Icons.place_outlined, + 'list' => Icons.checklist_outlined, + 'task' => Icons.task_alt_outlined, + _ => Icons.description_outlined, + }; + + Color _statusColor(BuildContext context) { + if (item.noteType != 'task') return Theme.of(context).colorScheme.primary; + return switch (item.status) { + 'done' => Colors.green, + 'in_progress' => Colors.orange, + 'cancelled' => Colors.grey, + _ => Theme.of(context).colorScheme.primary, + }; + } + + String? get _subtitle { + if (item.noteType == 'task') { + if (item.dueDate != null) return 'Due ${item.dueDate}'; + return item.status; + } + if (item.body.trim().isEmpty) return null; + final preview = item.body.trim().replaceAll('\n', ' '); + return preview.length > 120 ? '${preview.substring(0, 120)}…' : preview; + } + + @override + Widget build(BuildContext context) { + return ListTile( + leading: Icon(_icon, color: _statusColor(context)), + title: Text( + item.title.isEmpty ? '(untitled)' : item.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + subtitle: _subtitle != null + ? Text( + _subtitle!, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.bodySmall, + ) + : null, + trailing: item.tags.isNotEmpty ? _TagChips(tags: item.tags) : null, + onTap: () { + if (item.noteType == 'task') { + context.push('/tasks/${item.id}/edit'); + } else { + context.push('/notes/${item.id}'); + } + }, + ); + } +} + +class _TagChips extends StatelessWidget { + final List tags; + const _TagChips({required this.tags}); + + @override + Widget build(BuildContext context) { + final shown = tags.take(2).toList(); + final extra = tags.length - shown.length; + return Wrap( + spacing: 4, + children: [ + for (final t in shown) + Chip( + label: Text(t, style: const TextStyle(fontSize: 10)), + padding: EdgeInsets.zero, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: VisualDensity.compact, + ), + if (extra > 0) + Chip( + label: Text('+$extra', style: const TextStyle(fontSize: 10)), + padding: EdgeInsets.zero, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: VisualDensity.compact, + ), + ], + ); + } +}