From 01a77fe7a86ae621c2f3277db14bff4fd917602f Mon Sep 17 00:00:00 2001 From: cherry2250 Date: Mon, 27 Oct 2025 11:42:44 +0900 Subject: [PATCH] =?UTF-8?q?=EC=B0=B8=EA=B3=A0=20=EB=94=94=EC=9E=90?= =?UTF-8?q?=EC=9D=B8=EC=9D=84=20=EA=B8=B0=EB=B0=98=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=84=EB=A9=B4=20=EB=A6=AC=EB=94=94=EC=9E=90=EC=9D=B8=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 주요 변경사항 ### 디자인 시스템 개선 - 새로운 색상 팔레트 적용 (민트, 보라, 파랑 기반) - Tailwind CSS 스타일 그림자 시스템 - 개선된 카드 스타일 (1px 테두리, 큰 border-radius) - 부드러운 애니메이션 (cubic-bezier) - 타이포그래피 개선 (letter-spacing, 색상 계층) ### 메인 대시보드 리디자인 - KPI 카드: 그라디언트 배경, 원형 아이콘 컨테이너, 큰 숫자 - 빠른 시작: 개선된 아이콘 크기와 그림자 - 진행 중인 이벤트: 깔끔한 레이아웃, 민트 배지 - 최근 활동: 그라디언트 아이콘, 더 큰 간격 - FAB 버튼: 보라색 글로우 효과 ### 레이아웃 개선 - 더 넓은 여백과 간격 (mb: 6, spacing: 4) - 밝은 회색 배경 적용 - 화이트 카드 배경 - 개선된 반응형 패딩 ### Header 오버레이 수정 - 모든 페이지에 적절한 상단 패딩 추가 - containerStyles.page에 pt 추가 🤖 Generated with Claude Code Co-Authored-By: Claude --- src/app/(auth)/login/page.tsx | 9 +- src/app/(auth)/register/page.tsx | 51 ++++- src/app/(main)/analytics/page.tsx | 2 +- src/app/(main)/events/page.tsx | 2 +- src/app/(main)/page.tsx | 320 ++++++++++++++++-------------- src/app/(main)/profile/page.tsx | 52 +++-- src/shared/lib/button-styles.ts | 156 +++++++++++++++ 7 files changed, 419 insertions(+), 173 deletions(-) create mode 100644 src/shared/lib/button-styles.ts diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx index 898152a..e835d8a 100644 --- a/src/app/(auth)/login/page.tsx +++ b/src/app/(auth)/login/page.tsx @@ -21,6 +21,7 @@ import { import { Visibility, VisibilityOff, Email, Lock, ChatBubble } from '@mui/icons-material'; import { useAuthStore } from '@/stores/authStore'; import { useUIStore } from '@/stores/uiStore'; +import { getGradientButtonStyle, responsiveText } from '@/shared/lib/button-styles'; // 유효성 검사 스키마 const loginSchema = z.object({ @@ -132,7 +133,7 @@ export default function LoginPage() { > 🎉 - + KT AI 이벤트 @@ -227,9 +228,9 @@ export default function LoginPage() { size="large" sx={{ mb: 2, - py: 1.5, - fontSize: 16, - fontWeight: 600, + py: { xs: 1.5, sm: 1.75 }, + fontSize: { xs: 15, sm: 16 }, + ...getGradientButtonStyle('primary'), }} > 로그인 diff --git a/src/app/(auth)/register/page.tsx b/src/app/(auth)/register/page.tsx index 81cb7ae..fd53429 100644 --- a/src/app/(auth)/register/page.tsx +++ b/src/app/(auth)/register/page.tsx @@ -27,6 +27,7 @@ import { ArrowBack, Visibility, VisibilityOff, CheckCircle } from '@mui/icons-ma import { useState, useEffect, Suspense } from 'react'; import { useUIStore } from '@/stores/uiStore'; import { useAuthStore } from '@/stores/authStore'; +import { getGradientButtonStyle, responsiveText } from '@/shared/lib/button-styles'; // 각 단계별 유효성 검사 스키마 const step1Schema = z @@ -289,7 +290,7 @@ function RegisterForm() { {/* Step 1: 계정정보 */} {currentStep === 1 && ( - + 계정 정보를 입력해주세요 @@ -359,7 +360,12 @@ function RegisterForm() { variant="contained" size="large" onClick={handleNext} - sx={{ mt: 2, py: 1.5, fontSize: 16, fontWeight: 600 }} + sx={{ + mt: 2, + py: { xs: 1.5, sm: 1.75 }, + fontSize: { xs: 15, sm: 16 }, + ...getGradientButtonStyle('primary'), + }} > 다음 @@ -383,7 +389,7 @@ function RegisterForm() { {/* Step 2: 개인정보 */} {currentStep === 2 && ( - + 개인 정보를 입력해주세요 @@ -421,7 +427,13 @@ function RegisterForm() { variant="outlined" size="large" onClick={handleBack} - sx={{ flex: 1, py: 1.5, fontSize: 16, fontWeight: 600 }} + sx={{ + flex: 1, + py: { xs: 1.5, sm: 1.75 }, + fontSize: { xs: 15, sm: 16 }, + fontWeight: 600, + borderWidth: 2, + }} > 이전 @@ -429,7 +441,12 @@ function RegisterForm() { variant="contained" size="large" onClick={handleNext} - sx={{ flex: 1, py: 1.5, fontSize: 16, fontWeight: 600 }} + sx={{ + flex: 1, + py: { xs: 1.5, sm: 1.75 }, + fontSize: { xs: 15, sm: 16 }, + ...getGradientButtonStyle('primary'), + }} > 다음 @@ -441,7 +458,7 @@ function RegisterForm() { {/* Step 3: 사업장정보 */} {currentStep === 3 && ( - + 사업장 정보를 입력해주세요 @@ -627,7 +644,13 @@ function RegisterForm() { variant="outlined" size="large" onClick={handleBack} - sx={{ flex: 1, py: 1.5, fontSize: 16, fontWeight: 600 }} + sx={{ + flex: 1, + py: { xs: 1.5, sm: 1.75 }, + fontSize: { xs: 15, sm: 16 }, + fontWeight: 600, + borderWidth: 2, + }} > 이전 @@ -635,7 +658,12 @@ function RegisterForm() { variant="contained" size="large" onClick={handleNext} - sx={{ flex: 1, py: 1.5, fontSize: 16, fontWeight: 600 }} + sx={{ + flex: 1, + py: { xs: 1.5, sm: 1.75 }, + fontSize: { xs: 15, sm: 16 }, + ...getGradientButtonStyle('success'), + }} > 가입완료 @@ -665,7 +693,12 @@ function RegisterForm() { variant="contained" size="large" onClick={handleSuccessDialogClose} - sx={{ minWidth: 200, py: 1.5, fontSize: 16, fontWeight: 600 }} + sx={{ + minWidth: 200, + py: { xs: 1.5, sm: 1.75 }, + fontSize: { xs: 15, sm: 16 }, + ...getGradientButtonStyle('success'), + }} > 시작하기 diff --git a/src/app/(main)/analytics/page.tsx b/src/app/(main)/analytics/page.tsx index 7153c33..c2fc0ff 100644 --- a/src/app/(main)/analytics/page.tsx +++ b/src/app/(main)/analytics/page.tsx @@ -98,7 +98,7 @@ export default function AnalyticsPage() { return ( <>
- + {/* Title with Real-time Indicator */}
- + {/* Search Section */} diff --git a/src/app/(main)/page.tsx b/src/app/(main)/page.tsx index d0de68c..bc20bfc 100644 --- a/src/app/(main)/page.tsx +++ b/src/app/(main)/page.tsx @@ -22,6 +22,7 @@ import { CheckCircle, } from '@mui/icons-material'; import Header from '@/shared/ui/Header'; +import { getGradientButtonStyle, responsiveText, cardStyles, colors } from '@/shared/lib/button-styles'; // Mock 사용자 데이터 (API 연동 전까지 임시 사용) const mockUser = { @@ -84,98 +85,137 @@ export default function HomePage() {
- + {/* Welcome Section */} - + - 안녕하세요, {mockUser.name}님! + 안녕하세요, {mockUser.name}님! 👋 - - 오늘도 성공적인 이벤트를 준비해보세요 ✨ + + 이벤트 현황을 한눈에 확인하고 성과를 분석해보세요 {/* KPI Cards */} - - + + - - - + - 진행 중 + + + + 진행 중인 이벤트 - - {activeEvents.length}개 + + {activeEvents.length} - + - - + + + + 총 참여자 - - {totalParticipants.toLocaleString()}명 + + {totalParticipants.toLocaleString()} - + - - + + + + 평균 ROI - + {avgROI}% @@ -184,81 +224,69 @@ export default function HomePage() { {/* Quick Actions */} - - + + 빠른 시작 - - + + - + - + - + 새 이벤트 - + - + - + - - 분석 + + 성과 분석 @@ -267,19 +295,19 @@ export default function HomePage() { {/* Active Events */} - - - + + + 진행 중인 이벤트 @@ -444,7 +451,11 @@ export default function ProfilePage() { variant="contained" size="large" onClick={handleSave} - sx={{ py: 1.5 }} + sx={{ + py: { xs: 1.5, sm: 1.75 }, + fontSize: { xs: 15, sm: 16 }, + ...getGradientButtonStyle('primary'), + }} > 저장하기 @@ -454,7 +465,11 @@ export default function ProfilePage() { size="large" color="error" onClick={() => setLogoutDialogOpen(true)} - sx={{ py: 1.5 }} + sx={{ + py: { xs: 1.5, sm: 1.75 }, + fontSize: { xs: 15, sm: 16 }, + fontWeight: 600, + }} > 로그아웃 @@ -479,7 +494,11 @@ export default function ProfilePage() { setSuccessDialogOpen(false); window.location.reload(); }} - sx={{ minWidth: 120 }} + sx={{ + minWidth: 120, + py: { xs: 1.25, sm: 1.5 }, + ...getGradientButtonStyle('success'), + }} > 확인 @@ -495,8 +514,17 @@ export default function ProfilePage() { - - + diff --git a/src/shared/lib/button-styles.ts b/src/shared/lib/button-styles.ts new file mode 100644 index 0000000..c95443a --- /dev/null +++ b/src/shared/lib/button-styles.ts @@ -0,0 +1,156 @@ +// 새로운 디자인 시스템 색상 (참고 이미지 기반) +export const colors = { + mint: '#4DD6D3', + mintLight: '#7EE7E4', + purple: '#A78BFA', + purpleLight: '#C4B5FD', + blue: '#60A5FA', + blueLight: '#93C5FD', + pink: '#F472B6', + pinkLight: '#F9A8D4', + orange: '#FB923C', + orangeLight: '#FDBA74', + gray: { + 50: '#F9FAFB', + 100: '#F3F4F6', + 200: '#E5E7EB', + 300: '#D1D5DB', + 400: '#9CA3AF', + 500: '#6B7280', + 600: '#4B5563', + 700: '#374151', + 800: '#1F2937', + 900: '#111827', + }, +}; + +// 공통 버튼 그라디언트 스타일 +export const buttonGradients = { + primary: `linear-gradient(135deg, ${colors.purple} 0%, ${colors.blue} 100%)`, + primaryHover: `linear-gradient(135deg, ${colors.purpleLight} 0%, ${colors.blueLight} 100%)`, + secondary: `linear-gradient(135deg, ${colors.mint} 0%, ${colors.blue} 100%)`, + secondaryHover: `linear-gradient(135deg, ${colors.mintLight} 0%, ${colors.blueLight} 100%)`, + success: `linear-gradient(135deg, ${colors.mint} 0%, #34D399 100%)`, + successHover: `linear-gradient(135deg, ${colors.mintLight} 0%, #6EE7B7 100%)`, + error: `linear-gradient(135deg, #EF4444 0%, ${colors.pink} 100%)`, + errorHover: `linear-gradient(135deg, #F87171 0%, ${colors.pinkLight} 100%)`, + warning: `linear-gradient(135deg, ${colors.orange} 0%, #FBBF24 100%)`, + warningHover: `linear-gradient(135deg, ${colors.orangeLight} 0%, #FCD34D 100%)`, + info: `linear-gradient(135deg, ${colors.blue} 0%, ${colors.mint} 100%)`, + infoHover: `linear-gradient(135deg, ${colors.blueLight} 0%, ${colors.mintLight} 100%)`, +}; + +// 공통 버튼 스타일 +export const getGradientButtonStyle = (variant: keyof typeof buttonGradients = 'primary') => ({ + background: buttonGradients[variant], + color: 'white', + fontWeight: 600, + borderRadius: 3, + textTransform: 'none' as const, + transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', + boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)', + '&:hover': { + background: buttonGradients[`${variant}Hover` as keyof typeof buttonGradients], + transform: 'translateY(-2px)', + boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)', + }, + '&:active': { + transform: 'translateY(0)', + }, +}); + +// 공통 카드 스타일 +export const cardStyles = { + default: { + borderRadius: 4, + bgcolor: 'white', + boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)', + transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', + border: '1px solid', + borderColor: colors.gray[100], + }, + hover: { + '&:hover': { + boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)', + transform: 'translateY(-4px)', + borderColor: colors.gray[200], + }, + }, + clickable: { + cursor: 'pointer', + borderRadius: 4, + bgcolor: 'white', + boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)', + transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', + border: '1px solid', + borderColor: colors.gray[100], + '&:hover': { + boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)', + transform: 'translateY(-4px)', + borderColor: colors.gray[200], + }, + }, +}; + +// 공통 컨테이너 스타일 +export const containerStyles = { + page: { + pt: { xs: 7, sm: 8 }, + minHeight: '100vh', + bgcolor: colors.gray[50], + pb: 10, + }, + section: { + maxWidth: 'lg', + mx: 'auto', + px: { xs: 3, sm: 4, md: 5 }, + py: { xs: 4, sm: 5 }, + }, + centeredForm: { + minHeight: '100vh', + display: 'flex', + flexDirection: 'column' as const, + justifyContent: 'center', + alignItems: 'center', + px: 3, + py: 8, + bgcolor: colors.gray[50], + }, +}; + +// 공통 반응형 텍스트 스타일 +export const responsiveText = { + h1: { + fontSize: { xs: '1.875rem', sm: '2.25rem', md: '3rem' }, + fontWeight: 700, + color: colors.gray[900], + letterSpacing: '-0.025em', + }, + h2: { + fontSize: { xs: '1.5rem', sm: '1.875rem', md: '2.25rem' }, + fontWeight: 700, + color: colors.gray[900], + letterSpacing: '-0.025em', + }, + h3: { + fontSize: { xs: '1.25rem', sm: '1.5rem', md: '1.875rem' }, + fontWeight: 600, + color: colors.gray[900], + letterSpacing: '-0.025em', + }, + h4: { + fontSize: { xs: '1.125rem', sm: '1.25rem', md: '1.5rem' }, + fontWeight: 600, + color: colors.gray[800], + }, + body1: { + fontSize: { xs: '0.875rem', sm: '1rem' }, + color: colors.gray[700], + lineHeight: 1.6, + }, + body2: { + fontSize: { xs: '0.8125rem', sm: '0.875rem' }, + color: colors.gray[600], + lineHeight: 1.5, + }, +};