feat: ERP 시스템 UI/UX 전면 재설계
색채 심리학 기반 컬러 시스템 구축: - Primary Color를 신뢰감 있는 블루(#2563EB)로 변경 - 비즈니스 상태별 의미 있는 색상 체계 도입 (본사/지점/파트너사/고객사) - 장비 상태별 색상 정의 (입고/출고/대여/폐기/수리중) - 정보 계층을 명확히 하는 그레이 스케일 시스템 F-Pattern 레이아웃 적용: - 1차 시선: 상단 헤더 (로고, 검색, 알림, 프로필) - 2차 시선: 페이지 헤더 (제목, 브레드크럼, 주요 액션) - 주요 작업 영역: 중앙 콘텐츠 1920x1080 해상도 최적화: - 최대 콘텐츠 너비 1440px 제한 - 12컬럼 그리드 시스템 적용 - 수평 스크롤 제거 컴포넌트 시스템 개선: - 호버 효과 및 마이크로 애니메이션 추가 - 비즈니스 상태별 배지 컴포넌트 - 향상된 입력 필드 인터랙션 - 프로그레스바, 칩 컴포넌트 추가 사이드바 UX 개선: - 부드러운 접기/펼치기 애니메이션 - 활성 상태 아이콘 변화 - 알림 배지 표시 기능 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,192 +1,341 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
/// shadcn/ui 스타일 테마 시스템
|
||||
/// ERP 시스템에 최적화된 색채 심리학 기반 테마 시스템
|
||||
class ShadcnTheme {
|
||||
// Teal 기반 색상 시스템
|
||||
// ============= 기본 색상 팔레트 =============
|
||||
// 배경 및 표면 색상
|
||||
static const Color background = Color(0xFFFFFFFF);
|
||||
static const Color foreground = Color(0xFF0F172A);
|
||||
static const Color card = Color(0xFFFFFFFF);
|
||||
static const Color cardForeground = Color(0xFF0F172A);
|
||||
static const Color popover = Color(0xFFFFFFFF);
|
||||
static const Color popoverForeground = Color(0xFF0F172A);
|
||||
static const Color primary = Color(0xFF0D9488); // teal-600
|
||||
static const Color primaryForeground = Color(0xFFFFFFFF);
|
||||
static const Color secondary = Color(0xFFF0FDFA); // teal-50
|
||||
static const Color secondaryForeground = Color(0xFF134E4A); // teal-900
|
||||
static const Color muted = Color(0xFFF1F5F9); // slate-100
|
||||
static const Color mutedForeground = Color(0xFF64748B); // slate-500
|
||||
static const Color accent = Color(0xFF14B8A6); // teal-500
|
||||
static const Color accentForeground = Color(0xFFFFFFFF);
|
||||
static const Color destructive = Color(0xFFEF4444); // red-500
|
||||
static const Color destructiveForeground = Color(0xFFFFFFFF);
|
||||
static const Color border = Color(0xFFE5E7EB); // gray-200 (기본 border는 연한 회색)
|
||||
static const Color input = Color(0xFFE5E7EB); // gray-200
|
||||
static const Color ring = Color(0xFF14B8A6); // teal-500
|
||||
static const Color radius = Color(0xFF000000); // 사용하지 않음
|
||||
|
||||
// Teal 그라데이션 색상
|
||||
static const Color gradient1 = Color(0xFF14B8A6); // teal-500
|
||||
static const Color gradient2 = Color(0xFF0D9488); // teal-600
|
||||
static const Color gradient3 = Color(0xFF0F766E); // teal-700
|
||||
|
||||
// 상태 색상
|
||||
static const Color success = Color(0xFF10B981); // emerald-500
|
||||
static const Color warning = Color(0xFFF59E0B); // amber-500
|
||||
static const Color error = Color(0xFFEF4444); // red-500
|
||||
static const Color info = Color(0xFF0891B2); // cyan-600
|
||||
static const Color backgroundSecondary = Color(0xFFF9FAFB); // 보조 배경
|
||||
static const Color surface = Color(0xFFFFFFFF);
|
||||
static const Color surfaceHover = Color(0xFFF3F4F6); // 호버 상태
|
||||
|
||||
// 추가 색상 (회사 구분용)
|
||||
static const Color blue = Color(0xFF3B82F6); // blue-500
|
||||
static const Color purple = Color(0xFF8B5CF6); // purple-500
|
||||
static const Color green = Color(0xFF22C55E); // green-500
|
||||
|
||||
// 그림자 설정
|
||||
static List<BoxShadow> get cardShadow => [
|
||||
// 텍스트 색상
|
||||
static const Color foreground = Color(0xFF111827); // 주요 텍스트 (진한 검정)
|
||||
static const Color foregroundSecondary = Color(0xFF374151); // 보조 텍스트
|
||||
static const Color foregroundMuted = Color(0xFF6B7280); // 비활성 텍스트
|
||||
static const Color foregroundSubtle = Color(0xFF9CA3AF); // 희미한 텍스트
|
||||
|
||||
// Primary 색상 (신뢰감 있는 블루)
|
||||
static const Color primary = Color(0xFF2563EB); // blue-600
|
||||
static const Color primaryDark = Color(0xFF1E40AF); // blue-800
|
||||
static const Color primaryLight = Color(0xFFDBEAFE); // blue-100
|
||||
static const Color primaryForeground = Color(0xFFFFFFFF);
|
||||
|
||||
// Secondary 색상 (중립 그레이)
|
||||
static const Color secondary = Color(0xFF6B7280); // gray-500
|
||||
static const Color secondaryDark = Color(0xFF374151); // gray-700
|
||||
static const Color secondaryLight = Color(0xFFF9FAFB); // gray-50
|
||||
static const Color secondaryForeground = Color(0xFF111827);
|
||||
|
||||
// ============= 시맨틱 색상 =============
|
||||
static const Color success = Color(0xFF059669); // emerald-600
|
||||
static const Color successLight = Color(0xFFD1FAE5); // emerald-100
|
||||
static const Color successForeground = Color(0xFFFFFFFF);
|
||||
|
||||
static const Color warning = Color(0xFFD97706); // amber-600
|
||||
static const Color warningLight = Color(0xFFFEF3C7); // amber-100
|
||||
static const Color warningForeground = Color(0xFFFFFFFF);
|
||||
|
||||
static const Color error = Color(0xFFDC2626); // red-600
|
||||
static const Color errorLight = Color(0xFFFEE2E2); // red-100
|
||||
static const Color errorForeground = Color(0xFFFFFFFF);
|
||||
|
||||
static const Color info = Color(0xFF0891B2); // cyan-600
|
||||
static const Color infoLight = Color(0xFFCFFAFE); // cyan-100
|
||||
static const Color infoForeground = Color(0xFFFFFFFF);
|
||||
|
||||
// ============= 비즈니스 상태 색상 =============
|
||||
// 회사 구분 색상
|
||||
static const Color companyHeadquarters = Color(0xFF2563EB); // 본사 - Primary Blue (권위)
|
||||
static const Color companyBranch = Color(0xFF7C3AED); // 지점 - Purple (연결성)
|
||||
static const Color companyPartner = Color(0xFF059669); // 파트너사 - Green (협력)
|
||||
static const Color companyCustomer = Color(0xFFEA580C); // 고객사 - Orange (활력)
|
||||
|
||||
// 장비 상태 색상
|
||||
static const Color equipmentIn = Color(0xFF059669); // 입고 - Green (진입/추가)
|
||||
static const Color equipmentOut = Color(0xFF0891B2); // 출고 - Cyan (이동/프로세스)
|
||||
static const Color equipmentRent = Color(0xFF7C3AED); // 대여 - Purple (임시 상태)
|
||||
static const Color equipmentDisposal = Color(0xFF6B7280); // 폐기 - Gray (비활성)
|
||||
static const Color equipmentRepair = Color(0xFFD97706); // 수리중 - Amber (주의 필요)
|
||||
static const Color equipmentUnknown = Color(0xFF9CA3AF); // 알수없음 - Light Gray
|
||||
|
||||
// ============= UI 요소 색상 =============
|
||||
static const Color border = Color(0xFFE5E7EB); // gray-200
|
||||
static const Color borderStrong = Color(0xFFD1D5DB); // gray-300
|
||||
static const Color borderFocus = Color(0xFF2563EB); // primary
|
||||
static const Color divider = Color(0xFFF3F4F6); // gray-100
|
||||
|
||||
static const Color card = Color(0xFFFFFFFF);
|
||||
static const Color cardForeground = Color(0xFF111827);
|
||||
static const Color cardHover = Color(0xFFF9FAFB);
|
||||
|
||||
static const Color input = Color(0xFFFFFFFF);
|
||||
static const Color inputBorder = Color(0xFFD1D5DB); // gray-300
|
||||
static const Color inputHover = Color(0xFFF9FAFB);
|
||||
static const Color inputFocus = Color(0xFF2563EB);
|
||||
|
||||
// 기존 호환성을 위한 별칭
|
||||
static const Color destructive = error;
|
||||
static const Color destructiveForeground = errorForeground;
|
||||
static const Color muted = backgroundSecondary;
|
||||
static const Color mutedForeground = foregroundMuted;
|
||||
static const Color accent = primary;
|
||||
static const Color accentForeground = primaryForeground;
|
||||
static const Color ring = primaryDark;
|
||||
static const Color popover = card;
|
||||
static const Color popoverForeground = cardForeground;
|
||||
|
||||
// Teal 그라데이션 색상 (기존 호환)
|
||||
static const Color gradient1 = primary;
|
||||
static const Color gradient2 = primaryDark;
|
||||
static const Color gradient3 = Color(0xFF1D4ED8); // blue-700
|
||||
|
||||
// 추가 색상 (기존 호환)
|
||||
static const Color blue = primary;
|
||||
static const Color purple = companyBranch;
|
||||
static const Color green = companyPartner;
|
||||
|
||||
static const Color radius = Color(0xFF000000); // 사용하지 않음
|
||||
|
||||
// ============= 그림자 시스템 =============
|
||||
static List<BoxShadow> get shadowXs => [
|
||||
BoxShadow(
|
||||
color: primary.withValues(alpha: 0.08),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.04),
|
||||
blurRadius: 16,
|
||||
offset: const Offset(0, 8),
|
||||
color: Colors.black.withValues(alpha: 0.05),
|
||||
blurRadius: 2,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
];
|
||||
|
||||
static List<BoxShadow> get buttonShadow => [
|
||||
|
||||
static List<BoxShadow> get shadowSm => [
|
||||
BoxShadow(
|
||||
color: primary.withValues(alpha: 0.2),
|
||||
color: Colors.black.withValues(alpha: 0.05),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
];
|
||||
|
||||
// 간격 시스템
|
||||
|
||||
static List<BoxShadow> get shadowMd => [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.08),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
];
|
||||
|
||||
static List<BoxShadow> get shadowLg => [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.10),
|
||||
blurRadius: 16,
|
||||
offset: const Offset(0, 8),
|
||||
),
|
||||
];
|
||||
|
||||
static List<BoxShadow> get shadowXl => [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.15),
|
||||
blurRadius: 24,
|
||||
offset: const Offset(0, 12),
|
||||
),
|
||||
];
|
||||
|
||||
// 카드 및 버튼 그림자 (기존 호환)
|
||||
static List<BoxShadow> get cardShadow => shadowMd;
|
||||
static List<BoxShadow> get buttonShadow => shadowSm;
|
||||
|
||||
// ============= 간격 시스템 (8px 기반) =============
|
||||
static const double spacing0 = 0.0;
|
||||
static const double spacing1 = 4.0;
|
||||
static const double spacing2 = 8.0;
|
||||
static const double spacing3 = 12.0;
|
||||
static const double spacing4 = 16.0;
|
||||
static const double spacing5 = 20.0;
|
||||
static const double spacing6 = 24.0;
|
||||
static const double spacing7 = 28.0;
|
||||
static const double spacing8 = 32.0;
|
||||
static const double spacing9 = 36.0;
|
||||
static const double spacing10 = 40.0;
|
||||
static const double spacing12 = 48.0;
|
||||
static const double spacing14 = 56.0;
|
||||
static const double spacing16 = 64.0;
|
||||
static const double spacing20 = 80.0;
|
||||
|
||||
// 라운드 설정
|
||||
static const double spacing24 = 96.0;
|
||||
|
||||
// ============= 라운드 설정 =============
|
||||
static const double radiusNone = 0.0;
|
||||
static const double radiusSm = 2.0;
|
||||
static const double radiusXs = 2.0;
|
||||
static const double radiusSm = 4.0;
|
||||
static const double radiusMd = 6.0;
|
||||
static const double radiusLg = 8.0;
|
||||
static const double radiusXl = 12.0;
|
||||
static const double radius2xl = 16.0;
|
||||
static const double radius3xl = 24.0;
|
||||
static const double radiusFull = 9999.0;
|
||||
|
||||
// 타이포그래피 시스템 (통일된 크기)
|
||||
|
||||
// ============= 타이포그래피 시스템 =============
|
||||
// 헤딩 스타일
|
||||
static TextStyle get headingH1 => GoogleFonts.inter(
|
||||
fontSize: 32,
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: foreground,
|
||||
letterSpacing: -0.02,
|
||||
height: 1.2,
|
||||
);
|
||||
|
||||
|
||||
static TextStyle get headingH2 => GoogleFonts.inter(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: foreground,
|
||||
letterSpacing: -0.01,
|
||||
height: 1.3,
|
||||
);
|
||||
|
||||
static TextStyle get headingH3 => GoogleFonts.inter(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: foreground,
|
||||
letterSpacing: -0.01,
|
||||
height: 1.35,
|
||||
);
|
||||
|
||||
static TextStyle get headingH3 => GoogleFonts.inter(
|
||||
|
||||
static TextStyle get headingH4 => GoogleFonts.inter(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: foreground,
|
||||
letterSpacing: -0.01,
|
||||
letterSpacing: 0,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
static TextStyle get headingH4 => GoogleFonts.inter(
|
||||
|
||||
static TextStyle get headingH5 => GoogleFonts.inter(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: foreground,
|
||||
letterSpacing: 0,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
static TextStyle get headingH6 => GoogleFonts.inter(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: foreground,
|
||||
letterSpacing: 0,
|
||||
height: 1.5,
|
||||
);
|
||||
|
||||
|
||||
// 본문 스타일
|
||||
static TextStyle get bodyLarge => GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: foreground,
|
||||
letterSpacing: 0,
|
||||
height: 1.6,
|
||||
);
|
||||
|
||||
|
||||
static TextStyle get bodyMedium => GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: foreground,
|
||||
letterSpacing: 0,
|
||||
height: 1.6,
|
||||
);
|
||||
|
||||
|
||||
static TextStyle get bodySmall => GoogleFonts.inter(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: foregroundSecondary,
|
||||
letterSpacing: 0,
|
||||
height: 1.5,
|
||||
);
|
||||
|
||||
static TextStyle get bodyXs => GoogleFonts.inter(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: mutedForeground,
|
||||
color: foregroundMuted,
|
||||
letterSpacing: 0,
|
||||
height: 1.5,
|
||||
);
|
||||
|
||||
|
||||
// 기타 스타일
|
||||
static TextStyle get bodyMuted => GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: mutedForeground,
|
||||
color: foregroundMuted,
|
||||
letterSpacing: 0,
|
||||
height: 1.6,
|
||||
);
|
||||
|
||||
|
||||
static TextStyle get labelLarge => GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: foreground,
|
||||
letterSpacing: 0,
|
||||
letterSpacing: 0.02,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
|
||||
static TextStyle get labelMedium => GoogleFonts.inter(
|
||||
fontSize: 12,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: foreground,
|
||||
letterSpacing: 0,
|
||||
letterSpacing: 0.02,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
|
||||
static TextStyle get labelSmall => GoogleFonts.inter(
|
||||
fontSize: 10,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: mutedForeground,
|
||||
letterSpacing: 0,
|
||||
color: foregroundSecondary,
|
||||
letterSpacing: 0.02,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
// Flutter 테마 데이터
|
||||
|
||||
static TextStyle get caption => GoogleFonts.inter(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: foregroundMuted,
|
||||
letterSpacing: 0.02,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
// 코드/모노스페이스
|
||||
static TextStyle get code => GoogleFonts.jetBrainsMono(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: foreground,
|
||||
letterSpacing: 0,
|
||||
height: 1.5,
|
||||
);
|
||||
|
||||
// ============= Flutter 테마 데이터 =============
|
||||
static ThemeData get lightTheme {
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: const ColorScheme.light(
|
||||
primary: primary,
|
||||
primaryContainer: primaryLight,
|
||||
secondary: secondary,
|
||||
secondaryContainer: secondaryLight,
|
||||
surface: background,
|
||||
surfaceContainerHighest: card,
|
||||
onSurface: foreground,
|
||||
onPrimary: primaryForeground,
|
||||
onSecondary: secondaryForeground,
|
||||
error: destructive,
|
||||
onError: destructiveForeground,
|
||||
error: error,
|
||||
errorContainer: errorLight,
|
||||
onError: errorForeground,
|
||||
outline: border,
|
||||
outlineVariant: input,
|
||||
outlineVariant: divider,
|
||||
),
|
||||
scaffoldBackgroundColor: background,
|
||||
textTheme: TextTheme(
|
||||
headlineLarge: headingH1,
|
||||
headlineMedium: headingH2,
|
||||
headlineSmall: headingH3,
|
||||
titleLarge: headingH4,
|
||||
displayLarge: headingH1,
|
||||
displayMedium: headingH2,
|
||||
displaySmall: headingH3,
|
||||
headlineLarge: headingH3,
|
||||
headlineMedium: headingH4,
|
||||
headlineSmall: headingH5,
|
||||
titleLarge: headingH6,
|
||||
titleMedium: labelLarge,
|
||||
titleSmall: labelMedium,
|
||||
bodyLarge: bodyLarge,
|
||||
bodyMedium: bodyMedium,
|
||||
bodySmall: bodySmall,
|
||||
@@ -198,11 +347,16 @@ class ShadcnTheme {
|
||||
backgroundColor: background,
|
||||
foregroundColor: foreground,
|
||||
elevation: 0,
|
||||
scrolledUnderElevation: 1,
|
||||
shadowColor: Colors.black.withValues(alpha: 0.1),
|
||||
scrolledUnderElevation: 0,
|
||||
shadowColor: Colors.transparent,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
titleTextStyle: headingH4,
|
||||
iconTheme: const IconThemeData(color: foreground),
|
||||
centerTitle: false,
|
||||
titleTextStyle: headingH5,
|
||||
toolbarHeight: 64,
|
||||
iconTheme: const IconThemeData(
|
||||
color: foregroundSecondary,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
cardTheme: CardThemeData(
|
||||
color: card,
|
||||
@@ -211,86 +365,234 @@ class ShadcnTheme {
|
||||
borderRadius: BorderRadius.circular(radiusLg),
|
||||
side: const BorderSide(color: border, width: 1),
|
||||
),
|
||||
shadowColor: Colors.black.withValues(alpha: 0.05),
|
||||
shadowColor: Colors.transparent,
|
||||
margin: EdgeInsets.zero,
|
||||
),
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: primary,
|
||||
foregroundColor: primaryForeground,
|
||||
disabledBackgroundColor: backgroundSecondary,
|
||||
disabledForegroundColor: foregroundMuted,
|
||||
elevation: 0,
|
||||
shadowColor: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
),
|
||||
minimumSize: const Size(64, 40),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: spacing4,
|
||||
horizontal: spacing6,
|
||||
vertical: spacing2,
|
||||
),
|
||||
textStyle: labelMedium,
|
||||
textStyle: labelMedium.copyWith(fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
outlinedButtonTheme: OutlinedButtonThemeData(
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: foreground,
|
||||
side: const BorderSide(color: border),
|
||||
disabledForegroundColor: foregroundMuted,
|
||||
side: const BorderSide(color: border, width: 1),
|
||||
elevation: 0,
|
||||
shadowColor: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
),
|
||||
minimumSize: const Size(64, 40),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: spacing4,
|
||||
horizontal: spacing6,
|
||||
vertical: spacing2,
|
||||
),
|
||||
textStyle: labelMedium,
|
||||
textStyle: labelMedium.copyWith(fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: foreground,
|
||||
foregroundColor: primary,
|
||||
disabledForegroundColor: foregroundMuted,
|
||||
elevation: 0,
|
||||
shadowColor: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
),
|
||||
minimumSize: const Size(64, 40),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: spacing4,
|
||||
vertical: spacing2,
|
||||
),
|
||||
textStyle: labelMedium,
|
||||
textStyle: labelMedium.copyWith(fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: background,
|
||||
fillColor: input,
|
||||
hoverColor: inputHover,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: spacing3,
|
||||
vertical: spacing2,
|
||||
vertical: spacing3,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
borderSide: const BorderSide(color: input),
|
||||
borderSide: const BorderSide(color: inputBorder, width: 1),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
borderSide: const BorderSide(color: input),
|
||||
borderSide: const BorderSide(color: inputBorder, width: 1),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
borderSide: const BorderSide(color: ring, width: 2),
|
||||
borderSide: const BorderSide(color: inputFocus, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
borderSide: const BorderSide(color: destructive),
|
||||
borderSide: const BorderSide(color: error, width: 1),
|
||||
),
|
||||
focusedErrorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
borderSide: const BorderSide(color: destructive, width: 2),
|
||||
borderSide: const BorderSide(color: error, width: 2),
|
||||
),
|
||||
hintStyle: bodyMedium.copyWith(color: mutedForeground),
|
||||
labelStyle: labelMedium,
|
||||
disabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
borderSide: BorderSide(color: border.withValues(alpha: 0.5), width: 1),
|
||||
),
|
||||
hintStyle: bodyMedium.copyWith(color: foregroundSubtle),
|
||||
labelStyle: labelMedium.copyWith(color: foregroundSecondary),
|
||||
helperStyle: bodySmall.copyWith(color: foregroundMuted),
|
||||
errorStyle: bodySmall.copyWith(color: error),
|
||||
prefixIconColor: foregroundMuted,
|
||||
suffixIconColor: foregroundMuted,
|
||||
),
|
||||
dividerTheme: const DividerThemeData(
|
||||
color: divider,
|
||||
thickness: 1,
|
||||
space: 1,
|
||||
),
|
||||
chipTheme: ChipThemeData(
|
||||
backgroundColor: backgroundSecondary,
|
||||
disabledColor: backgroundSecondary.withValues(alpha: 0.5),
|
||||
selectedColor: primaryLight,
|
||||
secondarySelectedColor: primaryLight,
|
||||
labelStyle: labelSmall,
|
||||
secondaryLabelStyle: labelSmall,
|
||||
padding: const EdgeInsets.symmetric(horizontal: spacing2, vertical: spacing1),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(radiusFull),
|
||||
side: const BorderSide(color: Colors.transparent),
|
||||
),
|
||||
),
|
||||
dialogTheme: DialogThemeData(
|
||||
backgroundColor: card,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(radiusLg),
|
||||
),
|
||||
titleTextStyle: headingH5,
|
||||
contentTextStyle: bodyMedium,
|
||||
),
|
||||
tooltipTheme: TooltipThemeData(
|
||||
decoration: BoxDecoration(
|
||||
color: foreground,
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
),
|
||||
textStyle: bodySmall.copyWith(color: background),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: spacing3,
|
||||
vertical: spacing2,
|
||||
),
|
||||
),
|
||||
snackBarTheme: SnackBarThemeData(
|
||||
backgroundColor: foreground,
|
||||
contentTextStyle: bodyMedium.copyWith(color: background),
|
||||
actionTextColor: primaryLight,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
),
|
||||
),
|
||||
dataTableTheme: DataTableThemeData(
|
||||
headingRowColor: WidgetStateProperty.all(backgroundSecondary),
|
||||
headingTextStyle: labelMedium.copyWith(
|
||||
color: foreground,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
dataTextStyle: bodyMedium,
|
||||
dividerThickness: 1,
|
||||
horizontalMargin: spacing4,
|
||||
columnSpacing: spacing6,
|
||||
headingRowHeight: 48,
|
||||
dataRowMinHeight: 56,
|
||||
dataRowMaxHeight: 56,
|
||||
),
|
||||
dividerTheme: const DividerThemeData(color: border, thickness: 1),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============= 유틸리티 메서드 =============
|
||||
/// 회사 타입에 따른 색상 반환
|
||||
static Color getCompanyColor(String type) {
|
||||
switch (type.toLowerCase()) {
|
||||
case '본사':
|
||||
case 'headquarters':
|
||||
return companyHeadquarters;
|
||||
case '지점':
|
||||
case 'branch':
|
||||
return companyBranch;
|
||||
case '파트너사':
|
||||
case 'partner':
|
||||
return companyPartner;
|
||||
case '고객사':
|
||||
case 'customer':
|
||||
return companyCustomer;
|
||||
default:
|
||||
return secondary;
|
||||
}
|
||||
}
|
||||
|
||||
/// 장비 상태에 따른 색상 반환
|
||||
static Color getEquipmentStatusColor(String status) {
|
||||
switch (status.toLowerCase()) {
|
||||
case '입고':
|
||||
case 'in':
|
||||
return equipmentIn;
|
||||
case '출고':
|
||||
case 'out':
|
||||
return equipmentOut;
|
||||
case '대여':
|
||||
case 'rent':
|
||||
return equipmentRent;
|
||||
case '폐기':
|
||||
case 'disposal':
|
||||
return equipmentDisposal;
|
||||
case '수리중':
|
||||
case 'repair':
|
||||
return equipmentRepair;
|
||||
case '알수없음':
|
||||
case 'unknown':
|
||||
return equipmentUnknown;
|
||||
default:
|
||||
return secondary;
|
||||
}
|
||||
}
|
||||
|
||||
/// 상태별 배경색 반환 (연한 버전)
|
||||
static Color getStatusBackgroundColor(String status) {
|
||||
switch (status.toLowerCase()) {
|
||||
case 'success':
|
||||
case '성공':
|
||||
case '완료':
|
||||
return successLight;
|
||||
case 'warning':
|
||||
case '경고':
|
||||
case '주의':
|
||||
return warningLight;
|
||||
case 'error':
|
||||
case '오류':
|
||||
case '실패':
|
||||
return errorLight;
|
||||
case 'info':
|
||||
case '정보':
|
||||
case '알림':
|
||||
return infoLight;
|
||||
default:
|
||||
return backgroundSecondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user