feat: 글래스모피즘 디자인 시스템 및 색상 가이드 전면 적용

- @doc/color.md 가이드라인에 따른 색상 시스템 전면 개편
- 딥 블루(#2563EB), 스카이 블루(#60A5FA) 메인 컬러로 변경
- 모든 화면과 위젯에 글래스모피즘 효과 일관성 있게 적용
- darkNavy, navyGray 등 새로운 텍스트 색상 체계 도입
- 공통 스낵바 및 다이얼로그 컴포넌트 추가
- Claude AI 프로젝트 컨텍스트 파일(CLAUDE.md) 추가

영향받은 컴포넌트:
- 10개 스크린 (main, settings, detail, splash 등)
- 30개 이상 위젯 (buttons, cards, forms 등)
- 테마 시스템 (AppColors, AppTheme)

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
JiWoong Sul
2025-07-11 18:41:05 +09:00
parent 83c5e3d64e
commit 2f60ef585a
46 changed files with 1096 additions and 580 deletions

View File

@@ -2,12 +2,12 @@ import 'package:flutter/material.dart';
class AppColors {
// 메인 컬러 (Metronic Tailwind 스타일)
static const primaryColor = Color(0xFF3B82F6); // 메트로닉 블루
static const secondaryColor = Color(0xFF64748B); // 슬레이트 600
static const successColor = Color(0xFF10B981); // 그린
static const primaryColor = Color(0xFF2563EB); // 블루
static const secondaryColor = Color(0xFF60A5FA); // 스카이 블루
static const successColor = Color(0xFF38BDF8); // 소프트 민트
static const infoColor = Color(0xFF6366F1); // 인디고
static const warningColor = Color(0xFFF59E0B); // 앰버
static const dangerColor = Color(0xFFEF4444); // 레드
static const dangerColor = Color(0xFFF472B6); // 핑크 액센트
// 배경색
static const backgroundColor = Color(0xFFF1F5F9); // 슬레이트 100
@@ -17,18 +17,24 @@ class AppColors {
// 텍스트 컬러
static const textPrimary = Color(0xFF1E293B); // 슬레이트 800
static const textSecondary = Color(0xFF64748B); // 슬레이트 600
static const textMuted = Color(0xFF94A3B8); // 슬레이트 400
static const darkNavy = Color(0xFF1E293B); // 메인 텍스트 (color.md 가이드)
static const textSecondary = Color(0xFF334155); // 네이비 그레이
static const navyGray = Color(0xFF334155); // 서브 텍스트 (color.md 가이드)
static const textMuted = Color(0xFF334155); // 네이비 그레이
static const textLight = Color(0xFFFFFFFF); // 화이트
static const pureWhite = Color(0xFFFFFFFF); // 버튼 텍스트용 (color.md 가이드)
// 보더 & 디바이더
static const borderColor = Color(0xFFE2E8F0); // 슬레이트 200
static const dividerColor = Color(0xFFE2E8F0); // 슬레이트 200
// 그림자 (color.md 가이드)
static const shadowBlack = Color(0x14000000); // rgba(0,0,0,0.08) - 8% opacity
// 그라데이션 컬러 - 다양한 효과를 위한 조합
static const List<Color> blueGradient = [
Color(0xFF3B82F6),
Color(0xFF2563EB)
Color(0xFF2563EB), // 딥 블루
Color(0xFF60A5FA) // 스카이 블루
];
static const List<Color> tealGradient = [
Color(0xFF14B8A6),
@@ -48,10 +54,10 @@ class AppColors {
];
// Glassmorphism 효과를 위한 색상
static const glassSurface = Color(0x0FFFFFFF); // 매우 연한 흰색 (6% opacity)
static const glassBackground = Color(0x1AFFFFFF); // 연한 흰색 (10% opacity)
static const glassSurface = Color(0x33FFFFFF); // 화이트 글래스 (20% opacity)
static const glassBackground = Color(0x33FFFFFF); // 화이트 글래스 (20% opacity)
static const glassCard = Color(0x33FFFFFF); // 반투명 흰색 (20% opacity)
static const glassBorder = Color(0x4DFFFFFF); // 반투명 테두리 (30% opacity)
static const glassBorder = Color(0xFF2563EB); // 딥 블루 테두리
static const glassOverlay = Color(0x0D000000); // 연한 검정 오버레이 (5% opacity)
// 다크 모드용 Glassmorphism 색상
@@ -62,8 +68,8 @@ class AppColors {
// 백드롭 블러 효과를 위한 그라디언트
static const List<Color> glassGradient = [
Color(0x33FFFFFF), // 20% white
Color(0x1AFFFFFF), // 10% white
Color(0x0FFFFFFF), // 6% white
];
static const List<Color> glassGradientDark = [
@@ -71,6 +77,18 @@ class AppColors {
Color(0x0F000000), // 6% black
];
// 메인 그라데이션
static const List<Color> mainGradient = [
Color(0xFF2563EB), // 딥 블루
Color(0xFF60A5FA), // 스카이 블루
Color(0xFFE0E7EF), // 라이트 그레이
];
static const List<Color> accentGradient = [
Color(0xFF38BDF8), // 소프트 민트
Color(0xFF60A5FA), // 스카이 블루
];
// 시간대별 배경 그라디언트
static const List<Color> morningGradient = [
Color(0xFFFED7AA), // 따뜻한 오렌지

View File

@@ -17,22 +17,22 @@ class AppTheme {
// 기본 배경색
scaffoldBackgroundColor: AppColors.backgroundColor,
// 카드 스타일 - 부드러운 그림자, 둥근 모서리
// 카드 스타일 - 글래스모피즘 효과
cardTheme: CardTheme(
color: AppColors.cardColor,
elevation: 1,
shadowColor: Colors.black.withValues(alpha: 0.04),
color: AppColors.glassCard,
elevation: 0,
shadowColor: AppColors.shadowBlack,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: const BorderSide(color: AppColors.borderColor, width: 0.5),
side: const BorderSide(color: AppColors.glassBorder, width: 1),
),
clipBehavior: Clip.antiAlias,
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
),
// 앱바 스타일 - 깔끔하고 투명한 디자인
// 앱바 스타일 - 글래스모피즘 디자인
appBarTheme: const AppBarTheme(
backgroundColor: AppColors.surfaceColor,
backgroundColor: Colors.transparent,
foregroundColor: AppColors.textPrimary,
elevation: 0,
centerTitle: false,
@@ -43,7 +43,7 @@ class AppTheme {
letterSpacing: -0.2,
),
iconTheme: const IconThemeData(
color: AppColors.secondaryColor,
color: AppColors.primaryColor,
size: 24,
),
),
@@ -52,21 +52,21 @@ class AppTheme {
textTheme: const TextTheme(
// 헤드라인 - 페이지 제목
headlineLarge: const TextStyle(
color: AppColors.textPrimary,
color: AppColors.darkNavy, // color.md 가이드: 메인 텍스트
fontSize: 32,
fontWeight: FontWeight.w700,
letterSpacing: -0.5,
height: 1.2,
),
headlineMedium: const TextStyle(
color: AppColors.textPrimary,
color: AppColors.darkNavy, // color.md 가이드: 메인 텍스트
fontSize: 28,
fontWeight: FontWeight.w700,
letterSpacing: -0.5,
height: 1.2,
),
headlineSmall: const TextStyle(
color: AppColors.textPrimary,
color: AppColors.darkNavy, // color.md 가이드: 메인 텍스트
fontSize: 24,
fontWeight: FontWeight.w600,
letterSpacing: -0.25,
@@ -75,21 +75,21 @@ class AppTheme {
// 타이틀 - 카드, 섹션 제목
titleLarge: const TextStyle(
color: AppColors.textPrimary,
color: AppColors.darkNavy, // color.md 가이드: 메인 텍스트
fontSize: 20,
fontWeight: FontWeight.w600,
letterSpacing: -0.2,
height: 1.4,
),
titleMedium: TextStyle(
color: AppColors.textPrimary,
color: AppColors.darkNavy, // color.md 가이드: 메인 텍스트
fontSize: 18,
fontWeight: FontWeight.w600,
letterSpacing: -0.1,
height: 1.4,
),
titleSmall: TextStyle(
color: AppColors.textPrimary,
color: AppColors.darkNavy, // color.md 가이드: 메인 텍스트
fontSize: 16,
fontWeight: FontWeight.w600,
letterSpacing: 0,
@@ -98,21 +98,21 @@ class AppTheme {
// 본문 텍스트
bodyLarge: TextStyle(
color: AppColors.textPrimary,
color: AppColors.darkNavy, // color.md 가이드: 메인 텍스트
fontSize: 16,
fontWeight: FontWeight.w400,
letterSpacing: 0.1,
height: 1.5,
),
bodyMedium: TextStyle(
color: AppColors.textSecondary,
color: AppColors.navyGray, // color.md 가이드: 서브 텍스트
fontSize: 14,
fontWeight: FontWeight.w400,
letterSpacing: 0.1,
height: 1.5,
),
bodySmall: TextStyle(
color: AppColors.textMuted,
color: AppColors.navyGray, // color.md 가이드: 서브 텍스트
fontSize: 12,
fontWeight: FontWeight.w400,
letterSpacing: 0.2,
@@ -121,21 +121,21 @@ class AppTheme {
// 라벨 텍스트
labelLarge: TextStyle(
color: AppColors.textPrimary,
color: AppColors.darkNavy, // color.md 가이드: 메인 텍스트
fontSize: 14,
fontWeight: FontWeight.w600,
letterSpacing: 0.1,
height: 1.4,
),
labelMedium: TextStyle(
color: AppColors.textSecondary,
color: AppColors.navyGray, // color.md 가이드: 서브 텍스트
fontSize: 12,
fontWeight: FontWeight.w600,
letterSpacing: 0.2,
height: 1.4,
),
labelSmall: TextStyle(
color: AppColors.textMuted,
color: AppColors.navyGray, // color.md 가이드: 서브 텍스트
fontSize: 11,
fontWeight: FontWeight.w500,
letterSpacing: 0.2,
@@ -143,10 +143,10 @@ class AppTheme {
),
),
// 입력 필드 스타일 - 깔끔하고 현대적인 디자인
// 입력 필드 스타일 - 글래스모피즘 디자인
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: AppColors.surfaceColorAlt,
fillColor: AppColors.glassBackground,
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
@@ -154,7 +154,7 @@ class AppTheme {
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: AppColors.borderColor, width: 1),
borderSide: const BorderSide(color: AppColors.textSecondary, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
@@ -224,13 +224,13 @@ class AppTheme {
// 아웃라인 버튼 스타일
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.textPrimary,
foregroundColor: AppColors.primaryColor,
minimumSize: const Size(0, 48),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
side: const BorderSide(color: AppColors.borderColor, width: 1),
side: const BorderSide(color: AppColors.secondaryColor, width: 1),
textStyle: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
@@ -265,7 +265,7 @@ class AppTheme {
}),
trackColor: MaterialStateProperty.resolveWith<Color>((states) {
if (states.contains(MaterialState.selected)) {
return AppColors.primaryColor.withValues(alpha: 0.5);
return AppColors.secondaryColor.withValues(alpha: 0.5);
}
return AppColors.borderColor;
}),
@@ -282,7 +282,7 @@ class AppTheme {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
side: const BorderSide(color: AppColors.borderColor, width: 1.5),
side: const BorderSide(color: AppColors.secondaryColor, width: 1.5),
),
// 라디오 버튼 스타일
@@ -291,16 +291,16 @@ class AppTheme {
if (states.contains(MaterialState.selected)) {
return AppColors.primaryColor;
}
return AppColors.borderColor;
return AppColors.textSecondary;
}),
),
// 슬라이더 스타일
sliderTheme: SliderThemeData(
activeTrackColor: AppColors.primaryColor,
inactiveTrackColor: AppColors.borderColor,
inactiveTrackColor: AppColors.textSecondary,
thumbColor: AppColors.primaryColor,
overlayColor: AppColors.primaryColor.withValues(alpha: 0.2),
overlayColor: AppColors.primaryColor.withValues(alpha: 0.3),
trackHeight: 4,
thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 10),
overlayShape: const RoundSliderOverlayShape(overlayRadius: 20),