diff --git a/design/uiux/prototype/01-회원가입.html b/design/uiux/prototype/01-회원가입.html new file mode 100644 index 0000000..c92e52f --- /dev/null +++ b/design/uiux/prototype/01-회원가입.html @@ -0,0 +1,324 @@ + + + + + + + 회원가입 - KT 이벤트 마케팅 + + + + + + + + + + + + + +
+ +
+ +

회원가입

+
+ + +
+
+ +
+

KT 이벤트 마케팅

+

환영합니다 🎉

+
+ + +
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + +
+ + +
+

+ 이미 계정이 있으신가요? + 로그인 +

+
+
+
+
+ + + + + + diff --git a/design/uiux/prototype/02-매장정보등록.html b/design/uiux/prototype/02-매장정보등록.html new file mode 100644 index 0000000..195dc28 --- /dev/null +++ b/design/uiux/prototype/02-매장정보등록.html @@ -0,0 +1,755 @@ + + + + + + + 매장정보등록 - KT 이벤트 마케팅 + + + + + + + + + + + + + +
+ +
+ +

매장정보등록

+
+ + +
+
+ +
+
진행상황
+
+
+
+ 2/2 +
+
+ + +
+ +
+

필수 정보

+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+ + +
+
+ + +
+ +
+ + +
+
+
+
+ + +
+

선택 정보

+

+ 이벤트 맞춤화를 위해 추가 정보를 입력해주세요 +

+ + +
+ + + +
+ + +
+ + +
+ 0/200 +
+
+ + +
+ +
+ + + +
+
+
+ + + +
+
+
+
+ + + + + + + + diff --git a/design/uiux/prototype/03-이벤트목적선택.html b/design/uiux/prototype/03-이벤트목적선택.html new file mode 100644 index 0000000..b3d3bc3 --- /dev/null +++ b/design/uiux/prototype/03-이벤트목적선택.html @@ -0,0 +1,494 @@ + + + + + + + 이벤트 목적 선택 - KT 이벤트 마케팅 + + + + + + + + + + + + + +
+ +
+ +

새 이벤트 기획

+
+ + +
+
+ +
+
단계 1/6: 목적 선택
+
+
+
+
+
+
+
+
+
+ + +
+

이벤트 목적을 선택하세요

+

선택한 목적에 맞춰 AI가 최적의 이벤트를 기획합니다

+
+ + +
+ + + + + + + + + + + +
+ + + +
+
+
+ + + + + + + + diff --git a/design/uiux/prototype/04-AI트렌드분석결과.html b/design/uiux/prototype/04-AI트렌드분석결과.html new file mode 100644 index 0000000..02ce2dd --- /dev/null +++ b/design/uiux/prototype/04-AI트렌드분석결과.html @@ -0,0 +1,413 @@ + + + + + + + AI 트렌드 분석 - KT 이벤트 마케팅 + + + + + + + + + + + + + +
+ +
+ +

AI 트렌드 분석

+
+ + +
+
+ +
+
단계 2/6: 트렌드 분석
+
+
+
+
+
+
+
+
+
+ + +
+
+

🤖 AI가 분석중입니다...

+

업종, 지역, 시즌을 고려한 트렌드를 분석하고 있습니다

+
+
+
+
분석 시작 중...
+
+ + + +
+
+
+ + + + + + + + diff --git a/design/uiux/prototype/05-AI경품추천.html b/design/uiux/prototype/05-AI경품추천.html new file mode 100644 index 0000000..fee56af --- /dev/null +++ b/design/uiux/prototype/05-AI경품추천.html @@ -0,0 +1,563 @@ + + + + + + + AI 경품 추천 - KT 이벤트 마케팅 + + + + + + + + + + + + + +
+ +
+ +

AI 경품 추천

+
+ + +
+
+ +
+
단계 3/6: 경품 선택
+
+
+
+
+
+
+
+
+
+ + +
+

예산 설정

+ +
+
+
+ 100,000원 +
+
+ + + +
+ 1만원 + 500만원 +
+
+
+ + +
+

+ 🤖 + AI 추천 경품 (Top 5) +

+ +
+ +
+
+ + + + + + + + + +
+
+
+ + + + + + + + diff --git a/design/uiux/prototype/06-AI참여방법설계.html b/design/uiux/prototype/06-AI참여방법설계.html new file mode 100644 index 0000000..0274df2 --- /dev/null +++ b/design/uiux/prototype/06-AI참여방법설계.html @@ -0,0 +1,507 @@ + + + + + + + AI 참여방법 설계 - KT 이벤트 마케팅 + + + + + + + + + + + + + +
+ +
+ +

AI 참여방법 설계

+
+ + +
+
+ +
+
단계 4/6: 참여방법 선택
+
+
+
+
+
+
+
+
+
+ + +
+

+ 🤖 + AI 추천 참여방법 +

+

이벤트 목적에 맞는 최적의 참여 방법을 선택하세요

+
+ + +
+ +
+
+
+
+
옵션 1: 간편형
+
📱 QR 코드 스캔
+
+
+ + check_circle + +
+
+ +
+
+ 난이도: ⭐ (쉬움) +
+
+ 예상참여율: + 60% +
+
+ 재방문율: + 20% +
+
+ +
+
+ check + 빠른 참여 +
+
+ check + 매장 방문 불필요 +
+
+ + +
+
+ + +
+
+
+
+
옵션 2: 재방문 유도형
+
🏪 매장 방문 + 리뷰
+
+
+ + check_circle + +
+
+ +
+
+ 난이도: ⭐⭐ (보통) +
+
+ 예상참여율: + 35% +
+
+ 재방문율: + 80% +
+
+ +
+
+ check + 높은 재방문율 +
+
+ check + 리뷰 축적 +
+
+ + +
+
+ + +
+
+
+
+
옵션 3: 바이럴형
+
📢 SNS 공유 + 태그
+
+
+ + check_circle + +
+
+ +
+
+ 난이도: ⭐⭐⭐ (어려움) +
+
+ 예상참여율: + 25% +
+
+ 바이럴 확산: + 150% +
+
+ +
+
+ check + 입소문 효과 +
+
+ check + 신규고객 유입 +
+
+ + +
+
+
+ + + + + + +
+
+
+ + + + + + + + diff --git a/design/uiux/prototype/07-AI홍보문구생성.html b/design/uiux/prototype/07-AI홍보문구생성.html new file mode 100644 index 0000000..460a511 --- /dev/null +++ b/design/uiux/prototype/07-AI홍보문구생성.html @@ -0,0 +1,501 @@ + + + + + + + AI 홍보문구 생성 - KT 이벤트 마케팅 + + + + + + + + + + + + + +
+ +
+ +

AI 홍보문구 생성

+
+ + +
+
+ +
+
단계 5/6: 홍보문구 선택
+
+
+
+
+
+
+
+
+
+ + +
+
+

🤖 AI가 생성중입니다...

+

매장과 이벤트에 맞는 홍보 문구를 작성하고 있습니다

+
+
+
+
문구 생성 준비 중...
+
+ + + +
+
+
+ + + + + + + + diff --git a/design/uiux/prototype/08-이벤트기획안승인.html b/design/uiux/prototype/08-이벤트기획안승인.html new file mode 100644 index 0000000..0bc15ed --- /dev/null +++ b/design/uiux/prototype/08-이벤트기획안승인.html @@ -0,0 +1,614 @@ + + + + + + 이벤트 기획안 승인 - KT AI 이벤트 + + + + + + + + + + + + +
+
+
6/6 단계
+
+ + +
+ +
+
+ schedule + + 소요 시간: 0초 + +
+

+ 목표 시간(10초) 대비 +

+
+ + +
+

기획안 요약

+ + +
+
+
+ store +

매장명

+
+
+
+ 업종 + 음식점 +
+
+ 위치 + 서울 강남구 +
+
+
+
+ + +
+
+
+ flag +

이벤트 목적

+
+
신규 고객 유치
+
+
+ + +
+
+
+
+ card_giftcard +

경품 정보

+
+ +
+
+
+
+ + +
+
+
+
+ how_to_reg +

참여 방법

+
+ +
+
+
간편 QR 참여
+
매장 방문 시 QR 코드 스캔으로 즉시 참여
+
+
+
예상 참여율
+
60%
+
+
+
재방문율
+
20%
+
+
+
+
+
+ + +
+
+
+
+ campaign +

홍보 문구

+
+ +
+
+
홍보 문구가 여기에 표시됩니다.
+
+
+
+
+
+ + +
+

예상 비용

+
+
+
+
+ 경품 총 비용 + 0원 +
+
+ 플랫폼 이용료 + 무료 +
+
+
+
+ 총 예상 비용 + 0원 +
+
+
+
+
+ + +
+

예상 효과

+
+
+
+
+
+ people +
+
+
예상 참여자
+
0명
+
+
+
+
+ trending_up +
+
+
예상 ROI
+
0%
+
+
+
+
+ monetization_on +
+
+
예상 매출 증대
+
0원
+
+
+
+
+ repeat +
+
+
재방문 고객
+
0명
+
+
+
+
+
+
+ + +
+

AI 분석 및 조언

+
+
+ lightbulb +
+
최적화 제안
+
    +
  • 현재 기획안은 목적에 부합하는 최적의 조합입니다.
  • +
+
+
+
+
+
+ + +
+ + +
+ + + + + diff --git a/design/uiux/prototype/10-AI영상제작.html b/design/uiux/prototype/10-AI영상제작.html new file mode 100644 index 0000000..c9d241b --- /dev/null +++ b/design/uiux/prototype/10-AI영상제작.html @@ -0,0 +1,648 @@ + + + + + + AI 영상 제작 - KT AI 이벤트 + + + + + + + + + + + + +
+
+
콘텐츠 2/5: 영상
+
+ + +
+ +
+

영상 설정

+ + +
+
+ +
+ + + +
+
+
+ + +
+
+ +
+

+ 🎉 연말 대박 이벤트! +

+
+ +
+
+ + +
+
+ +

+ 선택한 채널별로 영상이 생성됩니다. +

+
+ + +
+
+
+ + + +
+ + + + + + +
+ + + + + + + + + + + + + diff --git a/design/uiux/prototype/11-SNS콘텐츠생성.html b/design/uiux/prototype/11-SNS콘텐츠생성.html new file mode 100644 index 0000000..598bd11 --- /dev/null +++ b/design/uiux/prototype/11-SNS콘텐츠생성.html @@ -0,0 +1,483 @@ + + + + + + SNS 콘텐츠 생성 - KT AI 이벤트 + + + + + + + + + + + + +
+
+
콘텐츠 3/5: SNS
+
+ + +
+ +
+

플랫폼 선택

+

+ 각 플랫폼에 최적화된 콘텐츠가 생성됩니다. +

+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + + +
+ + + +
+ + + + + + + + + + + + + diff --git a/design/uiux/prototype/12-QR포스터생성.html b/design/uiux/prototype/12-QR포스터생성.html new file mode 100644 index 0000000..3cb73c9 --- /dev/null +++ b/design/uiux/prototype/12-QR포스터생성.html @@ -0,0 +1,240 @@ + + + + + + QR 포스터 생성 - KT AI 이벤트 + + + + + + + + + +
+
+
콘텐츠 4/5: QR 포스터
+
+ +
+
+

QR 코드 설정

+ +
+
+ +
+
+ ktevnt.co/abc123 +
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ +
+
+ +
+ + +
+
+
+ + +
+ + +
+ + + + + + + + + diff --git a/design/uiux/prototype/13-콘텐츠편집.html b/design/uiux/prototype/13-콘텐츠편집.html new file mode 100644 index 0000000..446b66a --- /dev/null +++ b/design/uiux/prototype/13-콘텐츠편집.html @@ -0,0 +1,325 @@ + + + + + + 콘텐츠 편집 - KT AI 이벤트 + + + + + + + + + +
+
+

편집할 콘텐츠 선택

+ +
+ + + + + +
+
+ + + +
+ +
+
+ + + + + + + + + + + + + diff --git a/design/uiux/prototype/14-콘텐츠최종승인.html b/design/uiux/prototype/14-콘텐츠최종승인.html new file mode 100644 index 0000000..6128c89 --- /dev/null +++ b/design/uiux/prototype/14-콘텐츠최종승인.html @@ -0,0 +1,279 @@ + + + + + + 콘텐츠 최종 승인 - KT AI 이벤트 + + + + + + + + + +
+
+
콘텐츠 5/5: 최종 승인
+
+ +
+
+
+
+ check_circle + 콘텐츠 생성 완료! +
+
+
+ +
+

생성된 콘텐츠 (갤러리)

+ +
+ + + + + + + + + + + +
+ + +
+ +
+
+
+
+ schedule + 콘텐츠 생성 시간 +
+
+
7분
+
목표: 5-8분 이내
+
✓ 목표 달성!
+
+
+
+
+
+ +
+ + +
+ + + + + + + + + diff --git a/design/uiux/prototype/16-배포진행상태.html b/design/uiux/prototype/16-배포진행상태.html new file mode 100644 index 0000000..45c9c5d --- /dev/null +++ b/design/uiux/prototype/16-배포진행상태.html @@ -0,0 +1,364 @@ + + + + + + 배포 진행 중 - KT AI 이벤트 + + + + + + + + + +
+
+
배포 2/3: 진행 상태
+
+ +
+
+
+
🚀
+

배포 진행 중...

+
+
+ +
+ +
+
+
+
+ check +
+
+
Instagram
+
✅ 배포 완료 (3초)
+
+ +
+
+
+ + +
+
+
+
+ sync +
+
+
우리동네TV
+
🔄 배포 중... (15초)
+
+
+
+
+
+
+
+ + +
+
+
+
+ schedule +
+
+
지니TV
+
⏳ 대기 중...
+
+
+
+
+ + +
+
+
+
+ error +
+
+
Naver Blog
+
❌ 배포 실패 (재시도 중)
+
1/3 재시도
+
+ +
+
+
+
+ +
+
+
+
+
+ 전체 진행률 + 50% +
+
+ 예상 소요 + 45초 +
+
+
+
+
+ +
+ + +
+
+ + + + + + + + + diff --git a/design/uiux/prototype/17-오프라인자료다운로드.html b/design/uiux/prototype/17-오프라인자료다운로드.html new file mode 100644 index 0000000..3761e51 --- /dev/null +++ b/design/uiux/prototype/17-오프라인자료다운로드.html @@ -0,0 +1,166 @@ + + + + + + 오프라인 자료 다운로드 - KT AI 이벤트 + + + + + + + + + +
+
+
배포 3/3: 자료 다운로드
+
+ +
+
+
+
+ check_circle + 배포 완료! +
+
+
+ +
+

오프라인 홍보 자료

+ +
+
+
+
+ description +
+
+
QR 포스터 (A4)
+
2.1MB PDF
+
+ +
+
+
+ +
+
+
+
+ description +
+
+
QR 포스터 (A3)
+
4.5MB PDF
+
+ +
+
+
+ +
+
+
+
+ qr_code +
+
+
QR 코드 이미지
+
150KB PNG
+
+ +
+
+
+ +
+
+
+
+ collections +
+
+
고해상도 이미지 (3종)
+
8.3MB ZIP
+
+ +
+
+
+ + +
+
+ +
+ +
+ + + + + diff --git a/design/uiux/prototype/20-당첨자명단관리.html b/design/uiux/prototype/20-당첨자명단관리.html new file mode 100644 index 0000000..bfbd7f9 --- /dev/null +++ b/design/uiux/prototype/20-당첨자명단관리.html @@ -0,0 +1,432 @@ + + + + + + 이벤트 관리 대시보드 - KT AI 이벤트 + + + + + + + + + + + + +
+ +
+
+
+
+
마지막 업데이트: 15:35
+
+ +
+ +
+
+
연말 대박 이벤트
+
D-5 (2025-12-31까지)
+
+
+
+ +
+
+
+
+
총 참여자
+
1,234명
+
+45 (오늘)
+
+
+ +
+
+
총 노출 수
+
15,678회
+
+230 (1시간)
+
+
+ +
+
+
매출 증가율
+
+42%
+
(이벤트 전 대비)
+
+
+ +
+
+
예상 ROI
+
245%
+
(투자 대비)
+
+
+
+
+ +
+

채널별 참여 현황

+
+
+
+
+
+ QR코드 + 45% +
+
+
+
+
+
+
+ Instagram + 30% +
+
+
+
+
+
+
+ 우리동네TV + 15% +
+
+
+
+
+
+
+ Naver Blog + 10% +
+
+
+
+
+
+
+
+
+
+ + + + + + +
+ + + + + + + diff --git a/design/uiux/prototype/css/common.css b/design/uiux/prototype/css/common.css new file mode 100644 index 0000000..66ff121 --- /dev/null +++ b/design/uiux/prototype/css/common.css @@ -0,0 +1,870 @@ +/** + * KT AI 기반 소상공인 이벤트 자동 생성 서비스 + * 공통 스타일시트 + * + * 작성일: 2025-01-20 + * 버전: 1.0 + * 디자인 원칙: Mobile First, 접근성 우선, 일관성 + */ + +/* ============================================ + 1. CSS Variables (Design Tokens) + ============================================ */ +:root { + /* Primary Colors */ + --color-primary-main: #E31E24; + --color-primary-light: #FF4D52; + --color-primary-dark: #C71820; + + /* Secondary Colors */ + --color-secondary-main: #0066FF; + --color-secondary-light: #4D94FF; + --color-secondary-dark: #004DBF; + + /* Grayscale */ + --color-black: #1A1A1A; + --color-gray-700: #4A4A4A; + --color-gray-500: #9E9E9E; + --color-gray-300: #D9D9D9; + --color-gray-100: #F5F5F5; + --color-white: #FFFFFF; + + /* Semantic Colors */ + --color-success: #00C853; + --color-warning: #FFA000; + --color-error: #D32F2F; + --color-info: #0288D1; + + /* Typography */ + --font-family-base: 'Pretendard', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', system-ui, sans-serif; + + /* Font Sizes (Mobile First) */ + --font-size-display: 28px; + --font-size-h1: 24px; + --font-size-h2: 20px; + --font-size-h3: 18px; + --font-size-body-l: 16px; + --font-size-body-m: 14px; + --font-size-body-s: 12px; + --font-size-button: 16px; + + /* Font Weights */ + --font-weight-regular: 400; + --font-weight-medium: 500; + --font-weight-semibold: 600; + --font-weight-bold: 700; + + /* Line Heights */ + --line-height-tight: 1.3; + --line-height-normal: 1.4; + --line-height-relaxed: 1.5; + + /* Spacing (4px Grid System) */ + --spacing-xs: 4px; + --spacing-s: 8px; + --spacing-m: 16px; + --spacing-l: 24px; + --spacing-xl: 32px; + --spacing-2xl: 48px; + + /* Border Radius */ + --radius-sm: 8px; + --radius-md: 12px; + --radius-lg: 16px; + --radius-xl: 24px; + --radius-full: 50%; + + /* Shadows */ + --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.08); + --shadow-md: 0 2px 8px rgba(0, 0, 0, 0.08); + --shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.12); + --shadow-xl: 0 8px 24px rgba(0, 0, 0, 0.2); + + /* Transitions */ + --transition-fast: 100ms ease-out; + --transition-normal: 200ms ease-out; + --transition-slow: 300ms ease-out; + + /* Z-index */ + --z-dropdown: 1000; + --z-sticky: 1020; + --z-fixed: 1030; + --z-modal-backdrop: 1040; + --z-modal: 1050; + --z-toast: 1060; +} + +/* Tablet */ +@media (min-width: 768px) { + :root { + --font-size-display: 32px; + --font-size-h1: 28px; + --font-size-h2: 22px; + --font-size-h3: 20px; + --font-size-body-l: 18px; + --font-size-body-m: 16px; + --font-size-body-s: 14px; + } +} + +/* Desktop */ +@media (min-width: 1024px) { + :root { + --font-size-display: 36px; + --font-size-h1: 32px; + --font-size-h2: 24px; + } +} + +/* ============================================ + 2. Reset & Base Styles + ============================================ */ +*, *::before, *::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + font-size: 16px; + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: transparent; +} + +body { + font-family: var(--font-family-base); + font-size: var(--font-size-body-m); + font-weight: var(--font-weight-regular); + line-height: var(--line-height-relaxed); + color: var(--color-black); + background-color: var(--color-gray-100); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* ============================================ + 3. Typography System + ============================================ */ +.display { + font-size: var(--font-size-display); + font-weight: var(--font-weight-bold); + line-height: var(--line-height-tight); + letter-spacing: -0.5px; +} + +h1, .h1 { + font-size: var(--font-size-h1); + font-weight: var(--font-weight-bold); + line-height: var(--line-height-tight); + letter-spacing: -0.3px; +} + +h2, .h2 { + font-size: var(--font-size-h2); + font-weight: var(--font-weight-bold); + line-height: var(--line-height-normal); + letter-spacing: -0.2px; +} + +h3, .h3 { + font-size: var(--font-size-h3); + font-weight: var(--font-weight-semibold); + line-height: var(--line-height-normal); +} + +.body-l { + font-size: var(--font-size-body-l); + font-weight: var(--font-weight-regular); + line-height: var(--line-height-relaxed); +} + +.body-m { + font-size: var(--font-size-body-m); + font-weight: var(--font-weight-regular); + line-height: var(--line-height-relaxed); +} + +.body-s { + font-size: var(--font-size-body-s); + font-weight: var(--font-weight-regular); + line-height: var(--line-height-relaxed); +} + +/* ============================================ + 4. Layout + ============================================ */ +.container { + width: 100%; + margin: 0 auto; + padding: 0 20px; +} + +@media (min-width: 768px) { + .container { + padding: 0 40px; + } +} + +@media (min-width: 1024px) { + .container { + max-width: 1200px; + padding: 0 80px; + } +} + +/* App Layout */ +.app-wrapper { + min-height: 100vh; + display: flex; + flex-direction: column; + background-color: var(--color-gray-100); +} + +.app-content { + flex: 1; + padding-bottom: 80px; /* Bottom Navigation 공간 */ +} + +/* ============================================ + 5. Top App Bar + ============================================ */ +.app-bar { + position: sticky; + top: 0; + z-index: var(--z-sticky); + background-color: var(--color-white); + border-bottom: 1px solid var(--color-gray-300); + height: 56px; + display: flex; + align-items: center; + padding: 0 var(--spacing-s); +} + +.app-bar__back { + width: 48px; + height: 48px; + display: flex; + align-items: center; + justify-content: center; + border: none; + background: none; + cursor: pointer; + color: var(--color-gray-700); + border-radius: var(--radius-full); + transition: background-color var(--transition-fast); +} + +.app-bar__back:hover { + background-color: var(--color-gray-100); +} + +.app-bar__title { + flex: 1; + font-size: var(--font-size-h3); + font-weight: var(--font-weight-semibold); + text-align: center; + margin-right: 48px; /* 뒤로가기 버튼과 균형 */ +} + +/* ============================================ + 6. Bottom Navigation + ============================================ */ +.bottom-nav { + position: fixed; + bottom: 0; + left: 0; + right: 0; + z-index: var(--z-fixed); + background-color: var(--color-white); + border-top: 1px solid var(--color-gray-300); + box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.08); + height: 60px; + display: flex; +} + +.bottom-nav__item { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: var(--spacing-xs); + border: none; + background: none; + color: var(--color-gray-500); + cursor: pointer; + text-decoration: none; + transition: color var(--transition-fast); + min-width: 44px; + min-height: 44px; +} + +.bottom-nav__item:hover { + color: var(--color-primary-main); +} + +.bottom-nav__item.active { + color: var(--color-primary-main); +} + +.bottom-nav__icon { + font-size: 24px; + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + display: inline-block; +} + +.bottom-nav__label { + font-size: var(--font-size-body-s); + font-weight: var(--font-weight-regular); +} + +/* ============================================ + 7. Buttons + ============================================ */ +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: var(--spacing-s); + font-family: var(--font-family-base); + font-size: var(--font-size-button); + font-weight: var(--font-weight-semibold); + line-height: 1.5; + text-align: center; + text-decoration: none; + border: none; + border-radius: var(--radius-sm); + cursor: pointer; + transition: all var(--transition-normal); + min-width: 44px; + min-height: 44px; +} + +.btn:disabled { + cursor: not-allowed; + opacity: 0.6; +} + +/* Primary Button */ +.btn-primary { + background-color: var(--color-primary-main); + color: var(--color-white); + box-shadow: var(--shadow-sm); +} + +.btn-primary:hover:not(:disabled) { + background-color: var(--color-primary-light); +} + +.btn-primary:active:not(:disabled) { + background-color: var(--color-primary-dark); + transform: scale(0.95); +} + +.btn-primary:disabled { + background-color: var(--color-gray-300); + color: var(--color-gray-500); +} + +/* Secondary Button */ +.btn-secondary { + background-color: var(--color-white); + color: var(--color-primary-main); + border: 2px solid var(--color-primary-main); +} + +.btn-secondary:hover:not(:disabled) { + background-color: rgba(227, 30, 36, 0.05); +} + +.btn-secondary:active:not(:disabled) { + background-color: rgba(227, 30, 36, 0.1); + transform: scale(0.95); +} + +/* Text Button */ +.btn-text { + background-color: transparent; + color: var(--color-primary-main); +} + +.btn-text:hover:not(:disabled) { + background-color: rgba(227, 30, 36, 0.05); +} + +/* Button Sizes */ +.btn-lg { + padding: 16px 24px; + height: 48px; +} + +.btn-md { + padding: 12px 20px; + height: 44px; + font-size: var(--font-size-body-m); +} + +.btn-sm { + padding: 8px 16px; + height: 36px; + font-size: var(--font-size-body-s); +} + +/* Full Width Button */ +.btn-block { + width: 100%; +} + +/* ============================================ + 8. Cards + ============================================ */ +.card { + background-color: var(--color-white); + border: 1px solid rgba(224, 224, 224, 1); + border-radius: var(--radius-md); + padding: var(--spacing-l); + box-shadow: var(--shadow-md); + transition: all var(--transition-normal); +} + +.card:hover { + border-color: var(--color-primary-main); + box-shadow: var(--shadow-lg); +} + +.card.selected { + border: 2px solid var(--color-primary-main); + background-color: rgba(227, 30, 36, 0.02); +} + +.card__header { + margin-bottom: var(--spacing-m); +} + +.card__title { + font-size: var(--font-size-h3); + font-weight: var(--font-weight-semibold); + margin-bottom: var(--spacing-s); +} + +.card__body { + color: var(--color-gray-700); + font-size: var(--font-size-body-m); +} + +.card__footer { + margin-top: var(--spacing-m); + padding-top: var(--spacing-m); + border-top: 1px solid var(--color-gray-300); +} + +/* ============================================ + 9. Form Elements + ============================================ */ +.form-group { + margin-bottom: var(--spacing-m); +} + +.form-label { + display: block; + font-size: var(--font-size-body-m); + font-weight: var(--font-weight-medium); + color: var(--color-black); + margin-bottom: var(--spacing-s); +} + +.form-label.required::after { + content: '*'; + color: var(--color-error); + margin-left: var(--spacing-xs); +} + +.form-input { + width: 100%; + height: 48px; + padding: var(--spacing-m); + font-family: var(--font-family-base); + font-size: var(--font-size-body-l); + font-weight: var(--font-weight-regular); + color: var(--color-black); + background-color: var(--color-white); + border: 1px solid var(--color-gray-300); + border-radius: var(--radius-sm); + transition: all var(--transition-normal); +} + +.form-input::placeholder { + color: var(--color-gray-500); +} + +.form-input:focus { + outline: none; + border: 2px solid var(--color-secondary-main); + box-shadow: 0 0 0 4px rgba(0, 102, 255, 0.1); +} + +.form-input:disabled { + background-color: var(--color-gray-100); + color: var(--color-gray-500); + cursor: not-allowed; +} + +.form-input.error { + border: 2px solid var(--color-error); + box-shadow: 0 0 0 4px rgba(211, 47, 47, 0.1); +} + +.form-error { + display: block; + margin-top: var(--spacing-s); + font-size: var(--font-size-body-s); + color: var(--color-error); +} + +/* Textarea */ +.form-textarea { + min-height: 120px; + resize: vertical; + padding: var(--spacing-m); + font-size: var(--font-size-body-m); + line-height: var(--line-height-relaxed); +} + +/* Checkbox & Radio */ +.form-check { + display: flex; + align-items: center; + gap: var(--spacing-s); + cursor: pointer; + min-height: 44px; +} + +.form-check input[type="checkbox"], +.form-check input[type="radio"] { + width: 24px; + height: 24px; + cursor: pointer; + accent-color: var(--color-primary-main); +} + +/* ============================================ + 10. Progress & Loading + ============================================ */ +.progress-bar { + width: 100%; + height: 8px; + background-color: var(--color-gray-100); + border-radius: 4px; + overflow: hidden; +} + +.progress-bar__fill { + height: 100%; + background-color: var(--color-primary-main); + transition: width var(--transition-slow); +} + +.spinner { + width: 32px; + height: 32px; + border: 3px solid var(--color-gray-100); + border-top-color: var(--color-primary-main); + border-radius: var(--radius-full); + animation: spin 0.8s linear infinite; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +.loading-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: var(--z-modal); +} + +/* ============================================ + 11. Toast Notification + ============================================ */ +.toast { + position: fixed; + bottom: 80px; + left: 50%; + transform: translateX(-50%); + z-index: var(--z-toast); + background-color: rgba(26, 26, 26, 0.9); + color: var(--color-white); + padding: var(--spacing-m) var(--spacing-l); + border-radius: var(--radius-sm); + font-size: var(--font-size-body-m); + box-shadow: var(--shadow-xl); + animation: toast-show 200ms ease-out; + max-width: calc(100% - 40px); +} + +@keyframes toast-show { + from { + opacity: 0; + transform: translateX(-50%) translateY(20px); + } + to { + opacity: 1; + transform: translateX(-50%) translateY(0); + } +} + +.toast.hide { + animation: toast-hide 200ms ease-in forwards; +} + +@keyframes toast-hide { + to { + opacity: 0; + transform: translateX(-50%) translateY(20px); + } +} + +/* ============================================ + 12. Modal + ============================================ */ +.modal-backdrop { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.6); + z-index: var(--z-modal-backdrop); + animation: fade-in 250ms ease-out; +} + +@keyframes fade-in { + from { opacity: 0; } + to { opacity: 1; } +} + +.modal { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: var(--z-modal); + background-color: var(--color-white); + border-radius: var(--radius-lg); + padding: var(--spacing-l); + max-width: 400px; + width: calc(100% - 40px); + box-shadow: var(--shadow-xl); + animation: modal-show 250ms ease-out; +} + +@keyframes modal-show { + from { + opacity: 0; + transform: translate(-50%, -50%) scale(0.95); + } + to { + opacity: 1; + transform: translate(-50%, -50%) scale(1); + } +} + +.modal__header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: var(--spacing-m); +} + +.modal__title { + font-size: var(--font-size-h2); + font-weight: var(--font-weight-bold); +} + +.modal__close { + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + border: none; + background: none; + cursor: pointer; + color: var(--color-gray-700); + border-radius: var(--radius-full); + transition: background-color var(--transition-fast); +} + +.modal__close:hover { + background-color: var(--color-gray-100); +} + +.modal__body { + margin-bottom: var(--spacing-l); + color: var(--color-gray-700); +} + +.modal__footer { + display: flex; + gap: var(--spacing-s); + justify-content: flex-end; +} + +/* ============================================ + 13. Bottom Sheet + ============================================ */ +.bottom-sheet-backdrop { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + z-index: var(--z-modal-backdrop); + animation: fade-in 300ms ease-out; +} + +.bottom-sheet { + position: fixed; + bottom: 0; + left: 0; + right: 0; + z-index: var(--z-modal); + background-color: var(--color-white); + border-radius: var(--radius-xl) var(--radius-xl) 0 0; + max-height: 80vh; + overflow-y: auto; + box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.15); + animation: slide-up 300ms ease-out; +} + +@keyframes slide-up { + from { + transform: translateY(100%); + } + to { + transform: translateY(0); + } +} + +.bottom-sheet__handle { + width: 40px; + height: 4px; + background-color: var(--color-gray-300); + border-radius: 2px; + margin: var(--spacing-m) auto; +} + +.bottom-sheet__content { + padding: 0 var(--spacing-l) var(--spacing-l); +} + +/* ============================================ + 14. Utility Classes + ============================================ */ +/* Display */ +.d-none { display: none !important; } +.d-block { display: block !important; } +.d-flex { display: flex !important; } +.d-grid { display: grid !important; } + +/* Flex */ +.flex-column { flex-direction: column !important; } +.flex-wrap { flex-wrap: wrap !important; } +.justify-center { justify-content: center !important; } +.justify-between { justify-content: space-between !important; } +.align-center { align-items: center !important; } +.gap-xs { gap: var(--spacing-xs) !important; } +.gap-s { gap: var(--spacing-s) !important; } +.gap-m { gap: var(--spacing-m) !important; } +.gap-l { gap: var(--spacing-l) !important; } + +/* Spacing */ +.mt-s { margin-top: var(--spacing-s) !important; } +.mt-m { margin-top: var(--spacing-m) !important; } +.mt-l { margin-top: var(--spacing-l) !important; } +.mb-s { margin-bottom: var(--spacing-s) !important; } +.mb-m { margin-bottom: var(--spacing-m) !important; } +.mb-l { margin-bottom: var(--spacing-l) !important; } +.p-m { padding: var(--spacing-m) !important; } +.p-l { padding: var(--spacing-l) !important; } + +/* Text */ +.text-center { text-align: center !important; } +.text-right { text-align: right !important; } +.text-primary { color: var(--color-primary-main) !important; } +.text-secondary { color: var(--color-secondary-main) !important; } +.text-success { color: var(--color-success) !important; } +.text-error { color: var(--color-error) !important; } +.text-muted { color: var(--color-gray-500) !important; } + +/* Background */ +.bg-white { background-color: var(--color-white) !important; } +.bg-gray { background-color: var(--color-gray-100) !important; } +.bg-primary { background-color: var(--color-primary-main) !important; } + +/* Border */ +.border { border: 1px solid var(--color-gray-300) !important; } +.border-top { border-top: 1px solid var(--color-gray-300) !important; } +.border-bottom { border-bottom: 1px solid var(--color-gray-300) !important; } + +/* Visibility */ +.hidden { visibility: hidden !important; } +.sr-only { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; +} + +/* ============================================ + 15. Accessibility + ============================================ */ +/* Focus Visible */ +*:focus-visible { + outline: 2px solid var(--color-secondary-main); + outline-offset: 2px; +} + +/* Skip Link */ +.skip-link { + position: absolute; + top: -40px; + left: 0; + background-color: var(--color-primary-main); + color: var(--color-white); + padding: var(--spacing-s) var(--spacing-m); + text-decoration: none; + z-index: 9999; +} + +.skip-link:focus { + top: 0; +} + +/* ============================================ + 16. Animations + ============================================ */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} diff --git a/design/uiux/prototype/js/common.js b/design/uiux/prototype/js/common.js new file mode 100644 index 0000000..63a68e8 --- /dev/null +++ b/design/uiux/prototype/js/common.js @@ -0,0 +1,552 @@ +/** + * KT AI 기반 소상공인 이벤트 자동 생성 서비스 + * 공통 JavaScript 유틸리티 + * + * 작성일: 2025-01-20 + * 버전: 1.0 + */ + +(function() { + 'use strict'; + + // ============================================ + // 1. 상태 관리 + // ============================================ + window.AppState = { + // 사용자 정보 + user: null, + + // 매장 정보 + store: null, + + // 현재 이벤트 정보 + currentEvent: null, + + // localStorage에서 데이터 로드 + load() { + try { + this.user = JSON.parse(localStorage.getItem('kt_user') || 'null'); + this.store = JSON.parse(localStorage.getItem('kt_store') || 'null'); + this.currentEvent = JSON.parse(localStorage.getItem('kt_current_event') || 'null'); + } catch (e) { + console.error('Failed to load app state:', e); + } + }, + + // localStorage에 데이터 저장 + save() { + try { + localStorage.setItem('kt_user', JSON.stringify(this.user)); + localStorage.setItem('kt_store', JSON.stringify(this.store)); + localStorage.setItem('kt_current_event', JSON.stringify(this.currentEvent)); + } catch (e) { + console.error('Failed to save app state:', e); + } + }, + + // 상태 초기화 + clear() { + this.user = null; + this.store = null; + this.currentEvent = null; + localStorage.removeItem('kt_user'); + localStorage.removeItem('kt_store'); + localStorage.removeItem('kt_current_event'); + } + }; + + // 페이지 로드 시 상태 복원 + document.addEventListener('DOMContentLoaded', function() { + window.AppState.load(); + }); + + // ============================================ + // 2. Toast 알림 + // ============================================ + window.Toast = { + show(message, duration = 3000) { + // 기존 토스트 제거 + const existingToast = document.querySelector('.toast'); + if (existingToast) { + existingToast.remove(); + } + + // 새 토스트 생성 + const toast = document.createElement('div'); + toast.className = 'toast'; + toast.textContent = message; + toast.setAttribute('role', 'status'); + toast.setAttribute('aria-live', 'polite'); + + document.body.appendChild(toast); + + // 자동 제거 + setTimeout(() => { + toast.classList.add('hide'); + setTimeout(() => { + toast.remove(); + }, 200); + }, duration); + }, + + success(message) { + this.show('✓ ' + message); + }, + + error(message) { + this.show('✕ ' + message); + }, + + info(message) { + this.show('ℹ ' + message); + } + }; + + // ============================================ + // 3. Modal 다이얼로그 + // ============================================ + window.Modal = { + show(options) { + const { + title = '', + body = '', + confirmText = '확인', + cancelText = '취소', + onConfirm = () => {}, + onCancel = () => {}, + showCancel = true + } = options; + + // 백드롭 생성 + const backdrop = document.createElement('div'); + backdrop.className = 'modal-backdrop'; + + // 모달 생성 + const modal = document.createElement('div'); + modal.className = 'modal'; + modal.setAttribute('role', 'dialog'); + modal.setAttribute('aria-labelledby', 'modal-title'); + modal.setAttribute('aria-modal', 'true'); + + modal.innerHTML = ` + + + + `; + + // 닫기 함수 + const close = () => { + backdrop.remove(); + modal.remove(); + document.body.style.overflow = ''; + }; + + // 이벤트 리스너 + modal.querySelector('.modal__close').addEventListener('click', () => { + close(); + onCancel(); + }); + + if (showCancel) { + modal.querySelector('.modal__cancel').addEventListener('click', () => { + close(); + onCancel(); + }); + } + + modal.querySelector('.modal__confirm').addEventListener('click', () => { + close(); + onConfirm(); + }); + + backdrop.addEventListener('click', (e) => { + if (e.target === backdrop) { + close(); + onCancel(); + } + }); + + // 추가 + document.body.appendChild(backdrop); + document.body.appendChild(modal); + document.body.style.overflow = 'hidden'; + + // 첫 번째 버튼에 포커스 + modal.querySelector('button').focus(); + }, + + confirm(title, body, onConfirm) { + this.show({ + title, + body, + confirmText: '확인', + cancelText: '취소', + onConfirm, + showCancel: true + }); + }, + + alert(title, body, onConfirm = () => {}) { + this.show({ + title, + body, + confirmText: '확인', + onConfirm, + showCancel: false + }); + } + }; + + // ============================================ + // 4. Bottom Sheet + // ============================================ + window.BottomSheet = { + show(content, options = {}) { + const { + onClose = () => {} + } = options; + + // 백드롭 생성 + const backdrop = document.createElement('div'); + backdrop.className = 'bottom-sheet-backdrop'; + + // Bottom Sheet 생성 + const sheet = document.createElement('div'); + sheet.className = 'bottom-sheet'; + sheet.setAttribute('role', 'dialog'); + sheet.setAttribute('aria-modal', 'true'); + + sheet.innerHTML = ` +
+
+ ${content} +
+ `; + + // 닫기 함수 + const close = () => { + backdrop.remove(); + sheet.remove(); + document.body.style.overflow = ''; + onClose(); + }; + + // 이벤트 리스너 + backdrop.addEventListener('click', close); + + // Handle 드래그로 닫기 (간단한 구현) + let startY = 0; + const handle = sheet.querySelector('.bottom-sheet__handle'); + + handle.addEventListener('touchstart', (e) => { + startY = e.touches[0].clientY; + }); + + handle.addEventListener('touchend', (e) => { + const endY = e.changedTouches[0].clientY; + if (endY - startY > 50) { // 50px 이상 드래그하면 닫기 + close(); + } + }); + + // 추가 + document.body.appendChild(backdrop); + document.body.appendChild(sheet); + document.body.style.overflow = 'hidden'; + + return { close }; + } + }; + + // ============================================ + // 5. 로딩 인디케이터 + // ============================================ + window.Loading = { + show(message = '처리중...') { + // 기존 로딩 제거 + this.hide(); + + const overlay = document.createElement('div'); + overlay.className = 'loading-overlay'; + overlay.id = 'app-loading'; + overlay.innerHTML = ` +
+
+
${message}
+
+ `; + + document.body.appendChild(overlay); + document.body.style.overflow = 'hidden'; + }, + + hide() { + const overlay = document.getElementById('app-loading'); + if (overlay) { + overlay.remove(); + document.body.style.overflow = ''; + } + } + }; + + // ============================================ + // 6. 폼 검증 유틸리티 + // ============================================ + window.FormValidator = { + // 이메일 검증 + isValidEmail(email) { + const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return re.test(email); + }, + + // 전화번호 검증 (010-XXXX-XXXX) + isValidPhone(phone) { + const re = /^010-\d{4}-\d{4}$/; + return re.test(phone); + }, + + // 사업자번호 검증 (XXX-XX-XXXXX) + isValidBusinessNumber(number) { + const re = /^\d{3}-\d{2}-\d{5}$/; + return re.test(number); + }, + + // 이름 검증 (2자 이상) + isValidName(name) { + return name && name.length >= 2; + }, + + // 필드에 에러 표시 + showError(inputElement, message) { + inputElement.classList.add('error'); + + // 기존 에러 메시지 제거 + const existingError = inputElement.parentElement.querySelector('.form-error'); + if (existingError) { + existingError.remove(); + } + + // 새 에러 메시지 추가 + if (message) { + const errorDiv = document.createElement('div'); + errorDiv.className = 'form-error'; + errorDiv.textContent = message; + errorDiv.setAttribute('role', 'alert'); + inputElement.parentElement.appendChild(errorDiv); + } + }, + + // 필드에서 에러 제거 + clearError(inputElement) { + inputElement.classList.remove('error'); + const errorDiv = inputElement.parentElement.querySelector('.form-error'); + if (errorDiv) { + errorDiv.remove(); + } + }, + + // 전체 폼 검증 + validateForm(formElement) { + let isValid = true; + const inputs = formElement.querySelectorAll('[required]'); + + inputs.forEach(input => { + if (!input.value.trim()) { + this.showError(input, '필수 입력 항목입니다.'); + isValid = false; + } else { + this.clearError(input); + } + }); + + return isValid; + } + }; + + // ============================================ + // 7. 네비게이션 유틸리티 + // ============================================ + window.Navigation = { + // 페이지 이동 + goto(page) { + window.location.href = page; + }, + + // 뒤로가기 + back() { + window.history.back(); + }, + + // Bottom Navigation 활성화 상태 설정 + updateBottomNav(activePage) { + const navItems = document.querySelectorAll('.bottom-nav__item'); + navItems.forEach(item => { + if (item.getAttribute('data-page') === activePage) { + item.classList.add('active'); + } else { + item.classList.remove('active'); + } + }); + } + }; + + // ============================================ + // 8. 유틸리티 함수 + // ============================================ + window.Utils = { + // 숫자 포맷 (1000 -> 1,000) + formatNumber(num) { + return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); + }, + + // 날짜 포맷 (YYYY-MM-DD) + formatDate(date) { + const d = new Date(date); + const year = d.getFullYear(); + const month = String(d.getMonth() + 1).padStart(2, '0'); + const day = String(d.getDate()).padStart(2, '0'); + return `${year}-${month}-${day}`; + }, + + // 날짜 포맷 (YYYY.MM.DD) + formatDateDot(date) { + const d = new Date(date); + const year = d.getFullYear(); + const month = String(d.getMonth() + 1).padStart(2, '0'); + const day = String(d.getDate()).padStart(2, '0'); + return `${year}.${month}.${day}`; + }, + + // 랜덤 ID 생성 + generateId() { + return 'id-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9); + }, + + // Debounce 함수 + debounce(func, wait) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }, + + // AI 처리 시뮬레이션 + simulateAI(duration = 3000) { + return new Promise(resolve => { + setTimeout(resolve, duration); + }); + }, + + // 이미지 로드 체크 + preloadImage(src) { + return new Promise((resolve, reject) => { + const img = new Image(); + img.onload = () => resolve(img); + img.onerror = reject; + img.src = src; + }); + } + }; + + // ============================================ + // 9. 공통 이벤트 핸들러 + // ============================================ + + // 뒤로가기 버튼 + document.addEventListener('click', function(e) { + if (e.target.closest('.app-bar__back')) { + e.preventDefault(); + window.Navigation.back(); + } + }); + + // 입력 필드 실시간 검증 + document.addEventListener('input', function(e) { + const input = e.target; + + // 이메일 필드 + if (input.type === 'email' && input.value) { + if (!window.FormValidator.isValidEmail(input.value)) { + window.FormValidator.showError(input, '올바른 이메일 형식을 입력하세요.'); + } else { + window.FormValidator.clearError(input); + } + } + + // 전화번호 필드 + if (input.name === 'phone' && input.value) { + // 자동 하이픈 추가 + let value = input.value.replace(/[^0-9]/g, ''); + if (value.length > 3 && value.length <= 7) { + value = value.slice(0, 3) + '-' + value.slice(3); + } else if (value.length > 7) { + value = value.slice(0, 3) + '-' + value.slice(3, 7) + '-' + value.slice(7, 11); + } + input.value = value; + + // 검증 + if (value.length === 13) { + if (!window.FormValidator.isValidPhone(value)) { + window.FormValidator.showError(input, '올바른 전화번호 형식을 입력하세요.'); + } else { + window.FormValidator.clearError(input); + } + } + } + + // 사업자번호 필드 + if (input.name === 'business_number' && input.value) { + // 자동 하이픈 추가 + let value = input.value.replace(/[^0-9]/g, ''); + if (value.length > 3 && value.length <= 5) { + value = value.slice(0, 3) + '-' + value.slice(3); + } else if (value.length > 5) { + value = value.slice(0, 3) + '-' + value.slice(3, 5) + '-' + value.slice(5, 10); + } + input.value = value; + + // 검증 + if (value.length === 12) { + if (!window.FormValidator.isValidBusinessNumber(value)) { + window.FormValidator.showError(input, '올바른 사업자번호 형식을 입력하세요.'); + } else { + window.FormValidator.clearError(input); + } + } + } + }); + + // Material Icons 로드 확인 + if (!document.querySelector('link[href*="material-icons"]')) { + const link = document.createElement('link'); + link.href = 'https://fonts.googleapis.com/icon?family=Material+Icons'; + link.rel = 'stylesheet'; + document.head.appendChild(link); + } + + // Pretendard 폰트 로드 확인 + if (!document.querySelector('link[href*="pretendard"]')) { + const link = document.createElement('link'); + link.href = 'https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css'; + link.rel = 'stylesheet'; + document.head.appendChild(link); + } + + console.log('KT Event Marketing App - Common JS loaded'); + +})();