- 네트워크 레이어 구현 (Dio 기반 ApiClient) - 환경별 설정 관리 시스템 구축 - 의존성 주입 설정 (GetIt) - API 엔드포인트 상수 정의 - 인터셉터 구현 (Auth, Error, Logging) - 프로젝트 아키텍처 개선 (core, data, di 디렉토리 구조) - API 통합 계획서 및 요구사항 문서 작성 - 필요 패키지 추가 (dio, flutter_secure_storage, get_it 등)
190 lines
5.7 KiB
Dart
190 lines
5.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
/// Metronic Admin 테일윈드 테마 (데모6 스타일)
|
|
class AppThemeTailwind {
|
|
// 메인 컬러 팔레트
|
|
static const Color primary = Color(0xFF5867DD);
|
|
static const Color secondary = Color(0xFF34BFA3);
|
|
static const Color success = Color(0xFF1BC5BD);
|
|
static const Color info = Color(0xFF8950FC);
|
|
static const Color warning = Color(0xFFFFA800);
|
|
static const Color danger = Color(0xFFF64E60);
|
|
static const Color light = Color(0xFFF3F6F9);
|
|
static const Color dark = Color(0xFF181C32);
|
|
static const Color muted = Color(0xFFB5B5C3);
|
|
|
|
// 배경 컬러
|
|
static const Color surface = Color(0xFFF7F8FA);
|
|
static const Color cardBackground = Colors.white;
|
|
|
|
// 테마 데이터
|
|
static ThemeData get lightTheme {
|
|
return ThemeData(
|
|
primaryColor: primary,
|
|
colorScheme: const ColorScheme.light(
|
|
primary: primary,
|
|
secondary: secondary,
|
|
background: surface,
|
|
surface: cardBackground,
|
|
error: danger,
|
|
),
|
|
scaffoldBackgroundColor: surface,
|
|
fontFamily: 'Poppins',
|
|
|
|
// AppBar 테마
|
|
appBarTheme: const AppBarTheme(
|
|
backgroundColor: Colors.white,
|
|
foregroundColor: dark,
|
|
elevation: 0,
|
|
centerTitle: false,
|
|
titleTextStyle: TextStyle(
|
|
color: dark,
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
iconTheme: IconThemeData(color: dark),
|
|
),
|
|
|
|
// 버튼 테마
|
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: primary,
|
|
foregroundColor: Colors.white,
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)),
|
|
),
|
|
),
|
|
|
|
// 카드 테마
|
|
cardTheme: CardThemeData(
|
|
color: Colors.white,
|
|
elevation: 1,
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
margin: const EdgeInsets.symmetric(vertical: 8),
|
|
),
|
|
|
|
// 입력 폼 테마
|
|
inputDecorationTheme: InputDecorationTheme(
|
|
filled: true,
|
|
fillColor: Colors.white,
|
|
contentPadding: const EdgeInsets.symmetric(
|
|
horizontal: 16,
|
|
vertical: 12,
|
|
),
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(6),
|
|
borderSide: const BorderSide(color: Color(0xFFE5E7EB)),
|
|
),
|
|
enabledBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(6),
|
|
borderSide: const BorderSide(color: Color(0xFFE5E7EB)),
|
|
),
|
|
focusedBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(6),
|
|
borderSide: const BorderSide(color: primary),
|
|
),
|
|
errorBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(6),
|
|
borderSide: const BorderSide(color: danger),
|
|
),
|
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
|
),
|
|
|
|
// 데이터 테이블 테마
|
|
dataTableTheme: const DataTableThemeData(
|
|
headingRowColor: WidgetStatePropertyAll(light),
|
|
dividerThickness: 1,
|
|
columnSpacing: 24,
|
|
headingTextStyle: TextStyle(
|
|
color: dark,
|
|
fontWeight: FontWeight.w600,
|
|
fontSize: 14,
|
|
),
|
|
dataTextStyle: TextStyle(color: Color(0xFF6C7293), fontSize: 14),
|
|
),
|
|
);
|
|
}
|
|
|
|
// 스타일 - 헤딩 및 텍스트
|
|
static const TextStyle headingStyle = TextStyle(
|
|
fontSize: 20,
|
|
fontWeight: FontWeight.bold,
|
|
color: dark,
|
|
);
|
|
|
|
static const TextStyle subheadingStyle = TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
color: dark,
|
|
);
|
|
|
|
static const TextStyle bodyStyle = TextStyle(
|
|
fontSize: 14,
|
|
color: Color(0xFF6C7293),
|
|
);
|
|
|
|
// 굵은 본문 텍스트
|
|
static const TextStyle bodyBoldStyle = TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w600,
|
|
color: dark,
|
|
);
|
|
|
|
static const TextStyle smallText = TextStyle(fontSize: 12, color: muted);
|
|
|
|
// 버튼 스타일
|
|
static final ButtonStyle primaryButtonStyle = ElevatedButton.styleFrom(
|
|
backgroundColor: primary,
|
|
foregroundColor: Colors.white,
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)),
|
|
);
|
|
|
|
// 라벨 스타일
|
|
static const TextStyle formLabelStyle = TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w600,
|
|
color: dark,
|
|
);
|
|
|
|
static final ButtonStyle secondaryButtonStyle = ElevatedButton.styleFrom(
|
|
backgroundColor: secondary,
|
|
foregroundColor: Colors.white,
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)),
|
|
);
|
|
|
|
static final ButtonStyle outlineButtonStyle = OutlinedButton.styleFrom(
|
|
foregroundColor: primary,
|
|
side: const BorderSide(color: primary),
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)),
|
|
);
|
|
|
|
// 카드 장식
|
|
static final BoxDecoration cardDecoration = BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(8),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withAlpha(13),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
);
|
|
|
|
// 기타 장식
|
|
static final BoxDecoration containerDecoration = BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(8),
|
|
border: Border.all(color: const Color(0xFFE5E7EB)),
|
|
);
|
|
|
|
static const EdgeInsets cardPadding = EdgeInsets.all(20);
|
|
static const EdgeInsets listPadding = EdgeInsets.symmetric(
|
|
vertical: 8,
|
|
horizontal: 16,
|
|
);
|
|
}
|