import 'package:flutter/material.dart'; import '../../../core/theme/tokens.dart'; /// 상단 라이브 띠 — Figma 「[LIVE] …님의 아이템 사용으로 버프가 발동되었습니다!」. /// /// 사본 `Frame 1984081132`(「홈」 `2097:16428`) — 헤더 바로 아래 전폭 띠(높이 22 · 패딩 4/0 · /// 바탕 없음), 가운데 한 줄(42dot Medium 12 · 행간 14 흰색). 실시간 소셜 프루프(견적서 4주차)의 /// 표면이다. /// /// 명세 `516:87664` *동작: 이벤트 발생 시 텍스트 우측에서 좌측으로 1회 슬라이드* — 문구가 /// 바뀔 때마다 오른쪽 밖에서 한 번 미끄러져 들어와 멈춘다. /// /// [action] 이 있으면 문구 뒤에 행동 문구를 붙이고 띠 전체를 [onTap] 으로 누를 수 있다 — /// UX·FX v1.5 §6 전광판 「HERO TIME 진행 중 CTA · 탭 시 해당 Planet 의 진행 중 HERO TIME 으로 이동」. class LiveTicker extends StatelessWidget { const LiveTicker({super.key, required this.text, this.action, this.onTap}); final String text; final String? action; final VoidCallback? onTap; static const _style = TextStyle( fontFamily: AppFonts.body, fontSize: 12, fontWeight: FontWeight.w500, height: 14 / 12, letterSpacing: -0.3, color: AppColors.onCosmic, ); @override Widget build(BuildContext context) { final line = Text.rich( TextSpan( text: text, children: [ if (action case final cta?) TextSpan( text: ' $cta', style: const TextStyle( fontWeight: FontWeight.w700, color: AppColors.cosmicAccent, ), ), ], ), maxLines: 1, overflow: TextOverflow.ellipsis, style: _style, ); final ticker = _slide(line); return onTap == null ? ticker : Semantics( button: true, child: GestureDetector( behavior: HitTestBehavior.opaque, onTap: onTap, child: ticker, ), ); } Widget _slide(Widget line) => ClipRect( child: Container( height: 22, padding: const EdgeInsets.symmetric(horizontal: AppSpace.s4), alignment: Alignment.center, child: TweenAnimationBuilder( key: ValueKey(text), tween: Tween(begin: 1, end: 0), duration: const Duration(milliseconds: 600), curve: Curves.easeOutCubic, // 띠 너비만큼 오른쪽 밖에서 출발한다. builder: (context, dx, child) => LayoutBuilder( builder: (context, box) => Transform.translate( offset: Offset(dx * box.maxWidth, 0), child: child, ), ), child: line, ), ), ); }