import 'package:flutter/material.dart'; import 'package:superport/screens/common/components/shadcn_components.dart'; /// 폼 화면의 일관된 레이아웃을 제공하는 템플릿 위젯 class FormLayoutTemplate extends StatelessWidget { final String title; final Widget child; final VoidCallback? onSave; final VoidCallback? onCancel; final String saveButtonText; final bool isLoading; final bool showBottomButtons; final Widget? customActions; const FormLayoutTemplate({ super.key, required this.title, required this.child, this.onSave, this.onCancel, this.saveButtonText = '저장', this.isLoading = false, this.showBottomButtons = true, this.customActions, }); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Color(0xFFF5F7FA), appBar: AppBar( title: Text( title, style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xFF1A1F36), ), ), backgroundColor: Colors.white, elevation: 0, leading: IconButton( icon: Icon(Icons.arrow_back_ios, color: Color(0xFF6B7280), size: 20), onPressed: onCancel ?? () => Navigator.of(context).pop(), ), actions: customActions != null ? [customActions!] : null, bottom: PreferredSize( preferredSize: Size.fromHeight(1), child: Container( color: Color(0xFFE5E7EB), height: 1, ), ), ), body: child, bottomNavigationBar: showBottomButtons ? _buildBottomBar(context) : null, ); } Widget _buildBottomBar(BuildContext context) { return Container( decoration: BoxDecoration( color: Colors.white, border: Border( top: BorderSide(color: Color(0xFFE5E7EB), width: 1), ), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), offset: Offset(0, -2), blurRadius: 4, ), ], ), padding: EdgeInsets.fromLTRB(24, 16, 24, 24), child: Row( children: [ Expanded( child: ShadcnButton( text: '취소', onPressed: isLoading ? null : (onCancel ?? () => Navigator.of(context).pop()), variant: ShadcnButtonVariant.secondary, size: ShadcnButtonSize.large, ), ), SizedBox(width: 12), Expanded( flex: 2, child: ShadcnButton( text: saveButtonText, onPressed: isLoading ? null : onSave, variant: ShadcnButtonVariant.primary, size: ShadcnButtonSize.large, loading: isLoading, ), ), ], ), ); } } /// 폼 필드를 감싸는 일관된 카드 레이아웃 class FormSection extends StatelessWidget { final String? title; final String? subtitle; final List children; final EdgeInsetsGeometry? padding; const FormSection({ super.key, this.title, this.subtitle, required this.children, this.padding, }); @override Widget build(BuildContext context) { return ShadcnCard( padding: padding ?? EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (title != null) ...[ Text( title!, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xFF1A1F36), ), ), if (subtitle != null) ...[ SizedBox(height: 4), Text( subtitle!, style: TextStyle( fontSize: 14, color: Color(0xFF6B7280), ), ), ], SizedBox(height: 20), Divider(color: Color(0xFFE5E7EB), height: 1), SizedBox(height: 20), ], if (children.isNotEmpty) ...children.asMap().entries.map((entry) { final index = entry.key; final child = entry.value; if (index < children.length - 1) { return Padding( padding: EdgeInsets.only(bottom: 16), child: child, ); } else { return child; } }), ], ), ); } } /// 일관된 폼 필드 스타일 class FormFieldWrapper extends StatelessWidget { final String label; final String? hint; final bool required; final Widget child; const FormFieldWrapper({ super.key, required this.label, this.hint, this.required = false, required this.child, }); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( label, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: Color(0xFF374151), ), ), if (required) Text( ' *', style: TextStyle( fontSize: 14, color: Color(0xFFEF4444), ), ), ], ), if (hint != null) ...[ SizedBox(height: 4), Text( hint!, style: TextStyle( fontSize: 12, color: Color(0xFF6B7280), ), ), ], SizedBox(height: 8), child, ], ); } } /// UI 상수 정의 class UIConstants { static const double formPadding = 24.0; static const double buttonHeight = 48.0; static const double borderRadius = 8.0; static const double cardSpacing = 16.0; // 테이블 컬럼 너비 static const double columnWidthSmall = 100.0; // 구분, 유형 static const double columnWidthMedium = 150.0; // 일반 필드 static const double columnWidthLarge = 200.0; // 긴 텍스트 // 색상 static const Color backgroundColor = Color(0xFFF5F7FA); static const Color cardBackground = Colors.white; static const Color borderColor = Color(0xFFE5E7EB); static const Color textPrimary = Color(0xFF1A1F36); static const Color textSecondary = Color(0xFF6B7280); static const Color textMuted = Color(0xFF9CA3AF); }