import 'package:flutter/material.dart'; import '../../core/theme/tokens.dart'; import '../../core/ui/app_icons.dart'; import '../../core/ui/relative_time.dart'; import '../home/home_screen.dart' show formatPop; import 'inside_data.dart'; /// INSIDE 화면군이 같이 쓰는 시안 조각 — 아이콘 · 글자 · 작성자 줄 · 현상금 칩 · 반응 줄. /// /// 아이콘은 Figma Iconset(Lucide) 을 3배 PNG 로 둔 것이다. 공용 [AppIcons] 로 올릴 때까지 /// 여기 둔다(디자인 일치 2단계 「공유 변경 요청」). /// 시안 INSIDE 의 회색 단계. abstract final class InsideColors { static const stat = Color(0xFF4F4F4F); static const avatar = Color(0xFFD9D9D9); static const rule = Color(0xFF1A1A1A); static const hint = Color(0xFF6B6B6B); static const chipLabel = Color(0xFFD5D7D9); } /// 42dot Sans · 자간 -2.5% · 행간 130%(시안 INSIDE 본문 기본값). TextStyle insideText( double size, { FontWeight weight = FontWeight.w500, Color color = AppColors.onCosmic, double height = 1.3, }) => TextStyle( fontFamily: AppFonts.body, fontSize: size, fontWeight: weight, height: height, letterSpacing: -0.025 * size, color: color, ); /// 작성자 닉네임 — ABeeZee 12(한글은 42dot 대체). const insideNameStyle = TextStyle( fontFamily: AppFonts.display, fontFamilyFallback: [AppFonts.body], fontSize: 12, height: 1.3, letterSpacing: -0.3, color: AppColors.onCosmic, ); /// 첨부 이미지. `assets/` 로 시작하면 번들 표본이다. ImageProvider insideImage(String url) => url.startsWith('assets/') ? AssetImage(url) : NetworkImage(url); /// 아바타 26 · 이름 · (있으면) 시각 줄. class InsideAuthor extends StatelessWidget { const InsideAuthor({super.key, required this.name, this.meta}); final String name; final String? meta; @override Widget build(BuildContext context) => Row( mainAxisSize: MainAxisSize.min, children: [ Container( width: 26, height: 26, decoration: const BoxDecoration( color: InsideColors.avatar, shape: BoxShape.circle, ), ), const SizedBox(width: 9), Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text(name, style: insideNameStyle), if (meta != null) Text(meta!, style: insideText(10, color: AppColors.onCosmicMuted)), ], ), ], ); } /// 현상금 칩 — 시안 58×24 · 모서리 2 · 번개 + 「500 P」. 채택이 끝난 질문은 회색이다. class InsideBountyChip extends StatelessWidget { const InsideBountyChip({super.key, required this.question}); final InsideQuestion question; @override Widget build(BuildContext context) { final c = question.isSolved ? InsideColors.stat : AppColors.cosmicBlue; return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: c.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(2), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ ImageIcon(AppIcons.bolt, size: 10, color: c), const SizedBox(width: 4), Text( '${formatPop(question.bountyPop)} P', style: insideText(12, color: c), ), ], ), ); } } /// 좋아요 · 댓글 · 조회 줄. 0 이면 숫자를 빼고 아이콘만 둔다(시안 「아미보이」 카드). class InsideStats extends StatelessWidget { const InsideStats({ super.key, required this.question, this.size = 14, this.textSize = 12, this.color = InsideColors.stat, }); final InsideQuestion question; final double size; final double textSize; final Color color; @override Widget build(BuildContext context) { Widget stat(ImageProvider icon, int n) => Row( mainAxisSize: MainAxisSize.min, children: [ ImageIcon(icon, size: size, color: color), if (n > 0) ...[ const SizedBox(width: 4), Text( formatReaction(n), style: insideText(textSize, color: color, height: 1), ), ], ], ); return Row( children: [ stat(AppIcons.heart, question.likeCount), const SizedBox(width: 12), stat(AppIcons.messageCircle, question.answerCount), const SizedBox(width: 12), stat(AppIcons.eye, question.viewCount), ], ); } }