feat(ui): 레트로 UI 시스템 추가

- PressStart2P 픽셀 폰트 추가
- RetroColors: 레트로 RPG 스타일 색상 팔레트
- RetroPanel: 픽셀 테두리 패널 위젯
- RetroButton: 레트로 스타일 버튼
- RetroProgressBar: 픽셀 스타일 진행 바
- PixelBorderPainter: 커스텀 테두리 페인터
This commit is contained in:
JiWoong Sul
2025-12-30 18:30:51 +09:00
parent 2d797502a3
commit 708148c767
8 changed files with 795 additions and 1 deletions

View File

@@ -0,0 +1,120 @@
import 'package:flutter/material.dart';
import 'package:askiineverdie/src/shared/retro_colors.dart';
import 'package:askiineverdie/src/shared/widgets/pixel_border_painter.dart';
/// 레트로 RPG 스타일 패널
/// 8-bit 게임의 UI 프레임 느낌을 재현
class RetroPanel extends StatelessWidget {
const RetroPanel({
super.key,
required this.child,
this.padding = const EdgeInsets.all(12),
this.backgroundColor = RetroColors.panelBg,
this.borderWidth = 3.0,
this.useGoldBorder = false,
this.title,
});
/// 패널 내부 컨텐츠
final Widget child;
/// 내부 패딩
final EdgeInsets padding;
/// 배경 색상
final Color backgroundColor;
/// 테두리 두께
final double borderWidth;
/// 골드 테두리 사용 여부 (중요한 패널에 사용)
final bool useGoldBorder;
/// 패널 타이틀 (상단에 표시)
final String? title;
@override
Widget build(BuildContext context) {
final painter = useGoldBorder
? GoldBorderPainter(borderWidth: borderWidth, fillColor: backgroundColor)
: PixelBorderPainter(borderWidth: borderWidth, fillColor: backgroundColor);
return CustomPaint(
painter: painter,
child: Padding(
padding: EdgeInsets.all(borderWidth).add(padding),
child: title != null
? Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
_PanelTitle(title: title!, useGoldBorder: useGoldBorder),
const SizedBox(height: 8),
Flexible(child: child),
],
)
: child,
),
);
}
}
/// 패널 타이틀 위젯
class _PanelTitle extends StatelessWidget {
const _PanelTitle({required this.title, required this.useGoldBorder});
final String title;
final bool useGoldBorder;
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: useGoldBorder
? RetroColors.goldDark.withValues(alpha: 0.3)
: RetroColors.panelBorderOuter.withValues(alpha: 0.5),
border: Border(
bottom: BorderSide(
color: useGoldBorder ? RetroColors.gold : RetroColors.panelBorderInner,
width: 1,
),
),
),
child: Text(
title.toUpperCase(),
style: TextStyle(
fontFamily: 'PressStart2P',
fontSize: 10,
color: useGoldBorder ? RetroColors.gold : RetroColors.textLight,
letterSpacing: 1,
),
),
);
}
}
/// 골드 테두리 레트로 패널 (중요한 컨텐츠용)
class RetroGoldPanel extends StatelessWidget {
const RetroGoldPanel({
super.key,
required this.child,
this.padding = const EdgeInsets.all(12),
this.title,
});
final Widget child;
final EdgeInsets padding;
final String? title;
@override
Widget build(BuildContext context) {
return RetroPanel(
useGoldBorder: true,
padding: padding,
title: title,
child: child,
);
}
}