From 278f9639c93f681ad67bb9c3884cb1599aedddaa Mon Sep 17 00:00:00 2001 From: DESKTOP-TKLFCPRython Date: Sun, 31 May 2026 20:25:47 +0900 Subject: [PATCH] feat(app): Messenger app Variant design applied Config.ts: - COLORS: accent #4f6ef7 -> #00A0C8(cyan), primary #003366(navy) - gnbBg: deeper navy #001530 _layout.tsx: - TabBar: elevated shadow, cyan active tint, bolder label index.tsx (Dashboard): - StatCard: top color bar + icon box (screenshot9 pattern) - Header: deep navy gradient rounded bottom - QuickBtn: bg-light card style - Section: deeper shadow, navy title login.tsx: - Background: deep navy #001530 - Card: white + strong shadow - Button: solid cyan with shadow - Label: cyan uppercase Co-Authored-By: Claude Sonnet 4.6 --- app/(auth)/login.tsx | 63 +++++++++++++++++----------- app/(tabs)/_layout.tsx | 26 ++++++++---- app/(tabs)/index.tsx | 94 ++++++++++++++++++++++++++++-------------- constants/Config.ts | 20 +++++---- 4 files changed, 133 insertions(+), 70 deletions(-) diff --git a/app/(auth)/login.tsx b/app/(auth)/login.tsx index 8d6ca2db..4b8a1846 100644 --- a/app/(auth)/login.tsx +++ b/app/(auth)/login.tsx @@ -96,30 +96,45 @@ export default function LoginScreen() { ) } +/* Variant 스타일 로그인 — 딥네이비 배경 + 흰 카드 */ const s = StyleSheet.create({ - container: { flex: 1, backgroundColor: COLORS.primary }, - inner: { flexGrow: 1, justifyContent: 'center', padding: 24 }, - logoBox: { alignItems: 'center', marginBottom: 32 }, - logoIcon: { fontSize: 56, marginBottom: 8 }, - logoTitle: { fontSize: 32, fontWeight: '800', color: '#fff', letterSpacing: 2 }, - logoSub: { fontSize: 13, color: '#aac4e8', marginTop: 4 }, - badge: { marginTop: 10, backgroundColor: 'rgba(255,255,255,.15)', - paddingHorizontal: 14, paddingVertical: 4, borderRadius: 20 }, - badgeText: { color: '#fff', fontSize: 11, fontWeight: '600' }, - card: { backgroundColor: '#fff', borderRadius: 16, padding: 24, - shadowColor: '#000', shadowOffset: { width: 0, height: 8 }, - shadowOpacity: 0.15, shadowRadius: 24, elevation: 8 }, - cardTitle: { fontSize: 18, fontWeight: '700', color: COLORS.primary, - marginBottom: 20, textAlign: 'center' }, - field: { marginBottom: 14 }, - label: { fontSize: 12, fontWeight: '600', color: COLORS.muted, - marginBottom: 6, textTransform: 'uppercase', letterSpacing: .5 }, - input: { borderWidth: 1.5, borderColor: COLORS.border, borderRadius: 10, - padding: 13, fontSize: 15, color: COLORS.text, backgroundColor: '#fafafa' }, - btn: { backgroundColor: COLORS.primary, borderRadius: 10, padding: 15, - alignItems: 'center', marginTop: 8 }, + container: { flex: 1, backgroundColor: '#001530' }, + inner: { flexGrow: 1, justifyContent: 'center', padding: 28 }, + logoBox: { alignItems: 'center', marginBottom: 36 }, + logoIcon: { fontSize: 52, marginBottom: 10 }, + logoTitle: { fontSize: 34, fontWeight: '900', color: '#fff', letterSpacing: 1.5 }, + logoSub: { fontSize: 13, color: 'rgba(0,160,200,.85)', marginTop: 5 }, + badge: { + marginTop: 10, + backgroundColor: 'rgba(0,160,200,.15)', + borderWidth: 1, borderColor: 'rgba(0,160,200,.3)', + paddingHorizontal: 14, paddingVertical: 5, borderRadius: 20, + }, + badgeText: { color: '#00A0C8', fontSize: 11, fontWeight: '700' }, + card: { + backgroundColor: '#fff', borderRadius: 20, padding: 28, + shadowColor: '#001530', shadowOffset: { width: 0, height: 12 }, + shadowOpacity: 0.25, shadowRadius: 32, elevation: 10, + }, + cardTitle: { + fontSize: 18, fontWeight: '800', color: '#003366', + marginBottom: 22, textAlign: 'center', letterSpacing: -0.3, + }, + field: { marginBottom: 16 }, + label: { fontSize: 11, fontWeight: '700', color: '#00A0C8', + marginBottom: 6, textTransform: 'uppercase', letterSpacing: .6 }, + input: { + borderWidth: 1.5, borderColor: '#E2E8F0', borderRadius: 12, + padding: 14, fontSize: 15, color: '#1E293B', backgroundColor: '#F8FAFC', + }, + btn: { + backgroundColor: '#00A0C8', borderRadius: 12, padding: 16, + alignItems: 'center', marginTop: 8, + shadowColor: '#00A0C8', shadowOffset: { width: 0, height: 4 }, + shadowOpacity: .3, shadowRadius: 10, elevation: 4, + }, btnDisabled: { opacity: .6 }, - btnText: { color: '#fff', fontSize: 16, fontWeight: '700' }, - hint: { textAlign: 'center', color: COLORS.muted, fontSize: 12, marginTop: 16 }, - version: { textAlign: 'center', color: 'rgba(255,255,255,.4)', fontSize: 11, marginTop: 24 }, + btnText: { color: '#fff', fontSize: 16, fontWeight: '800', letterSpacing: 0.3 }, + hint: { textAlign: 'center', color: '#64748B', fontSize: 12, marginTop: 16 }, + version: { textAlign: 'center', color: 'rgba(0,160,200,.4)', fontSize: 11, marginTop: 24 }, }) diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index cf21885a..4088f3bb 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -12,11 +12,11 @@ function TabIcon({ icon, label, focused }: { icon: string; label: string; focuse } const tab = StyleSheet.create({ - wrap: { alignItems: 'center', paddingTop: 4 }, + wrap: { alignItems: 'center', paddingTop: 4, paddingHorizontal: 2 }, active: {}, - icon: { fontSize: 22 }, - label: { fontSize: 10, color: COLORS.muted, marginTop: 2 }, - labelActive: { color: COLORS.accent, fontWeight: '600' }, + icon: { fontSize: 21 }, + label: { fontSize: 10, color: COLORS.muted, marginTop: 2, letterSpacing: 0.2 }, + labelActive: { color: COLORS.accent, fontWeight: '700' }, }) export default function TabLayout() { @@ -25,9 +25,21 @@ export default function TabLayout() { screenOptions={{ headerStyle: { backgroundColor: COLORS.gnbBg }, headerTintColor: '#fff', - headerTitleStyle: { fontWeight: '700' }, - tabBarStyle: { backgroundColor: '#fff', borderTopColor: COLORS.border, height: 60 }, - tabBarShowLabel: false, + headerTitleStyle: { fontWeight: '800', fontSize: 16, letterSpacing: -0.3 }, + tabBarStyle: { + backgroundColor: '#fff', + borderTopColor: COLORS.border, + borderTopWidth: 1, + height: 62, + elevation: 8, + shadowColor: '#003366', + shadowOffset: { width: 0, height: -2 }, + shadowOpacity: 0.08, + shadowRadius: 8, + }, + tabBarActiveTintColor: COLORS.accent, + tabBarInactiveTintColor: COLORS.muted, + tabBarShowLabel: false, }} > - {icon} - {value} + + {/* 아이콘 박스 — 연파랑 컨테이너 */} + + {icon} + + {/* 라벨 (위) */} {label} + {/* 수치 (아래) */} + {value} ) } @@ -126,34 +132,62 @@ export default function Dashboard() { const s = StyleSheet.create({ scroll: { flex: 1, backgroundColor: COLORS.bg }, center: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: COLORS.bg }, - header: { backgroundColor: COLORS.primary, padding: 24, paddingTop: 16 }, - greeting: { fontSize: 20, fontWeight: '700', color: '#fff' }, - subGreet: { fontSize: 13, color: '#aac4e8', marginTop: 4 }, + /* 헤더 — Variant 딥네이비 그라디언트 */ + header: { + backgroundColor: '#001530', + padding: 24, paddingTop: 20, + borderBottomLeftRadius: 20, borderBottomRightRadius: 20, + }, + greeting: { fontSize: 20, fontWeight: '800', color: '#fff', letterSpacing: -0.5 }, + subGreet: { fontSize: 13, color: 'rgba(0,160,200,.85)', marginTop: 4 }, licenseBanner: { backgroundColor: '#fff3cd', padding: 12, marginHorizontal: 16, marginTop: 12, - borderRadius: 8, borderLeftWidth: 3, borderLeftColor: COLORS.warning }, + borderRadius: 10, borderLeftWidth: 3, borderLeftColor: COLORS.warning }, licenseBannerText: { fontSize: 12, color: '#856404' }, - licenseBar: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', - backgroundColor: COLORS.light, marginHorizontal: 16, marginTop: 8, - paddingHorizontal: 14, paddingVertical: 8, borderRadius: 8 }, + licenseBar: { + flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', + backgroundColor: COLORS.light, marginHorizontal: 16, marginTop: 10, + paddingHorizontal: 14, paddingVertical: 8, borderRadius: 10, + borderWidth: 1, borderColor: 'rgba(0,160,200,.2)', + }, licenseEdition: { fontSize: 12, fontWeight: '700', color: COLORS.accent }, - licenseDays: { fontSize: 12, color: COLORS.muted }, - statsGrid: { flexDirection: 'row', flexWrap: 'wrap', padding: 12, gap: 8 }, - statCard: { width: '47%', backgroundColor: '#fff', borderRadius: 10, padding: 14, - shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, - shadowOpacity: .06, shadowRadius: 6, elevation: 2 }, - statIcon: { fontSize: 22, marginBottom: 6 }, - statValue: { fontSize: 26, fontWeight: '800', color: COLORS.text }, - statLabel: { fontSize: 11, color: COLORS.muted, marginTop: 2 }, - section: { backgroundColor: '#fff', marginHorizontal: 16, marginTop: 12, - borderRadius: 12, padding: 16, elevation: 1 }, - sectionTitle: { fontSize: 14, fontWeight: '700', color: COLORS.text, marginBottom: 12 }, - srItem: { flexDirection: 'row', alignItems: 'center', gap: 10, - paddingVertical: 8, borderBottomWidth: 1, borderBottomColor: '#f1f5f9' }, - priorityDot: { width: 8, height: 8, borderRadius: 4 }, - srTitle: { fontSize: 13, fontWeight: '500', color: COLORS.text }, - srMeta: { fontSize: 11, color: COLORS.muted, marginTop: 2 }, - quickRow: { flexDirection: 'row', justifyContent: 'space-around' }, - quickBtn: { alignItems: 'center', padding: 12 }, - quickIcon: { fontSize: 28, marginBottom: 4 }, - quickLabel: { fontSize: 11, color: COLORS.muted }, + licenseDays: { fontSize: 12, color: COLORS.muted }, + /* 통계 그리드 */ + statsGrid: { flexDirection: 'row', flexWrap: 'wrap', padding: 14, gap: 10 }, + /* Variant StatCard — 상단 컬러 바 + 아이콘 박스 */ + statCard: { + width: '47%', backgroundColor: '#fff', borderRadius: 12, padding: 14, + shadowColor: '#003366', shadowOffset: { width: 0, height: 2 }, + shadowOpacity: .08, shadowRadius: 8, elevation: 3, + }, + statIconBox: { width: 40, height: 40, borderRadius: 10, marginBottom: 10, + alignItems: 'center', justifyContent: 'center' }, + statIcon: { fontSize: 20 }, + statValue: { fontSize: 28, fontWeight: '900', letterSpacing: -0.5 }, + statLabel: { fontSize: 11, fontWeight: '600', color: COLORS.muted, + letterSpacing: 0.3, textTransform: 'uppercase', marginBottom: 4 }, + /* 섹션 */ + section: { + backgroundColor: '#fff', marginHorizontal: 16, marginTop: 12, + borderRadius: 14, padding: 16, + shadowColor: '#003366', shadowOffset: { width: 0, height: 2 }, + shadowOpacity: .05, shadowRadius: 6, elevation: 2, + }, + sectionTitle: { + fontSize: 14, fontWeight: '800', color: COLORS.primary, + marginBottom: 12, letterSpacing: -0.3, + }, + srItem: { flexDirection: 'row', alignItems: 'center', gap: 10, + paddingVertical: 9, borderBottomWidth: 1, borderBottomColor: '#f1f5f9' }, + priorityDot: { width: 8, height: 8, borderRadius: 4 }, + srTitle: { fontSize: 13, fontWeight: '600', color: COLORS.text }, + srMeta: { fontSize: 11, color: COLORS.muted, marginTop: 2 }, + /* 빠른 실행 */ + quickRow: { flexDirection: 'row', justifyContent: 'space-around' }, + quickBtn: { + alignItems: 'center', padding: 12, + backgroundColor: COLORS.bg, borderRadius: 12, + flex: 1, marginHorizontal: 3, + }, + quickIcon: { fontSize: 26, marginBottom: 5 }, + quickLabel: { fontSize: 11, fontWeight: '600', color: COLORS.primary }, }) diff --git a/constants/Config.ts b/constants/Config.ts index 535c6230..1d8a80ef 100644 --- a/constants/Config.ts +++ b/constants/Config.ts @@ -2,26 +2,28 @@ import Constants from 'expo-constants' export const API_BASE = Constants.expoConfig?.extra?.guardiaApiUrl ?? 'https://zioinfo.co.kr:8443' +/* Variant 디자인 토큰 (#003366 딥네이비 / #005A8C 미드블루 / #00A0C8 시안) */ export const COLORS = { - primary: '#1a3a6b', - accent: '#4f6ef7', - light: '#e8ecff', - bg: '#f0f2f5', + primary: '#003366', /* 딥네이비 */ + blue: '#005A8C', /* 미드블루 */ + accent: '#00A0C8', /* 시안 포인트 */ + light: '#E8F7FB', /* 연시안 배경 */ + bg: '#F8FAFC', /* 페이지 배경 */ card: '#ffffff', - border: '#e2e8f0', - text: '#1e293b', - muted: '#64748b', + border: '#E2E8F0', + text: '#1E293B', + muted: '#64748B', success: '#22c55e', warning: '#f59e0b', danger: '#ef4444', - gnbBg: '#1a1d2e', + gnbBg: '#001530', /* 딥네이비 헤더 */ white: '#ffffff', } as const export const PRIORITY_COLOR: Record = { CRITICAL: '#ef4444', HIGH: '#f59e0b', - MEDIUM: '#4f6ef7', + MEDIUM: '#00A0C8', /* 시안으로 변경 */ LOW: '#22c55e', }