/// 검색 결과 카드 위젯 library; import 'package:flutter/material.dart'; import '../../../core/constants.dart'; import '../../../models/schedule.dart'; import 'member_chip.dart'; import 'schedule_card.dart' show decodeHtmlEntities; /// 검색 결과 카드 (웹과 동일한 디자인 - 왼쪽에 날짜, 오른쪽에 내용) class SearchScheduleCard extends StatelessWidget { final Schedule schedule; final Color categoryColor; const SearchScheduleCard({ super.key, required this.schedule, required this.categoryColor, }); /// 날짜 파싱 Map? _parseDate(String? dateStr) { if (dateStr == null) return null; try { final date = DateTime.parse(dateStr); const weekdays = ['일', '월', '화', '수', '목', '금', '토']; return { 'year': date.year, 'month': date.month, 'day': date.day, 'weekday': weekdays[date.weekday % 7], 'isSunday': date.weekday == 7, 'isSaturday': date.weekday == 6, }; } catch (_) { return null; } } @override Widget build(BuildContext context) { final memberList = schedule.memberList; final dateInfo = _parseDate(schedule.date); return Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.04), blurRadius: 12, offset: const Offset(0, 2), ), ], border: Border.all( color: AppColors.border.withValues(alpha: 0.5), width: 1, ), ), child: IntrinsicHeight( child: Row( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // 왼쪽 날짜 영역 (카드 높이에 맞춤) if (dateInfo != null) Container( width: 72, padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 6), decoration: const BoxDecoration( color: AppColors.background, borderRadius: BorderRadius.only( topLeft: Radius.circular(7), bottomLeft: Radius.circular(7), ), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 년도 Text( '${dateInfo['year']}', style: const TextStyle( fontFamily: 'Pretendard', fontSize: 10, color: AppColors.textTertiary, ), ), // 월.일 (줄바꿈 방지) FittedBox( fit: BoxFit.scaleDown, child: Text( '${dateInfo['month']}.${dateInfo['day']}', style: const TextStyle( fontFamily: 'Pretendard', fontSize: 18, fontWeight: FontWeight.bold, color: AppColors.textPrimary, ), ), ), // 요일 Text( '${dateInfo['weekday']}요일', style: TextStyle( fontFamily: 'Pretendard', fontSize: 11, fontWeight: FontWeight.w500, color: dateInfo['isSunday'] == true ? Colors.red.shade500 : dateInfo['isSaturday'] == true ? Colors.blue.shade500 : AppColors.textSecondary, ), ), ], ), ), // 오른쪽 콘텐츠 영역 Expanded( child: Padding( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 시간 및 카테고리 뱃지 Row( children: [ // 시간 뱃지 if (schedule.formattedTime != null) Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 2, ), decoration: BoxDecoration( color: categoryColor, borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.access_time, size: 10, color: Colors.white, ), const SizedBox(width: 4), Text( schedule.formattedTime!, style: const TextStyle( fontFamily: 'Pretendard', fontSize: 10, fontWeight: FontWeight.w500, color: Colors.white, ), ), ], ), ), if (schedule.formattedTime != null) const SizedBox(width: 6), // 카테고리 뱃지 if (schedule.categoryName != null) Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 2, ), decoration: BoxDecoration( color: categoryColor.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(12), ), child: Text( schedule.categoryName!, style: TextStyle( fontFamily: 'Pretendard', fontSize: 10, fontWeight: FontWeight.w500, color: categoryColor, ), ), ), ], ), const SizedBox(height: 8), // 제목 Text( decodeHtmlEntities(schedule.title), style: const TextStyle( fontFamily: 'Pretendard', fontSize: 14, fontWeight: FontWeight.bold, color: AppColors.textPrimary, height: 1.4, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), // 출처 (빈 문자열이 아닌 경우에만 표시) if (schedule.sourceName != null && schedule.sourceName!.isNotEmpty) ...[ const SizedBox(height: 6), Row( children: [ const Icon( Icons.link, size: 12, color: AppColors.textTertiary, ), const SizedBox(width: 4), Expanded( child: Text( schedule.sourceName!, style: const TextStyle( fontFamily: 'Pretendard', fontSize: 12, color: AppColors.textTertiary, ), overflow: TextOverflow.ellipsis, ), ), ], ), ], // 멤버 if (memberList.isNotEmpty) ...[ const SizedBox(height: 10), // divider (전체 너비) Container( width: double.infinity, height: 1, color: AppColors.divider, ), const SizedBox(height: 10), Wrap( spacing: 4, runSpacing: 4, children: memberList.length >= 5 ? [ const SearchMemberChip(name: '프로미스나인'), ] : memberList .map((name) => SearchMemberChip(name: name)) .toList(), ), ], ], ), ), ), ], ), ), ); } }