메일송신 mailJS , 영/한 전환 적용ㅁ
This commit is contained in:
297
html/assets/js/i18n.js
Normal file
297
html/assets/js/i18n.js
Normal file
@@ -0,0 +1,297 @@
|
||||
// ============================================================
|
||||
// 다국어 지원 (한국어 / 영어)
|
||||
// ============================================================
|
||||
const translations = {
|
||||
en: {
|
||||
// NAV
|
||||
'nav.home' : 'Home',
|
||||
'nav.dcs' : 'DCS',
|
||||
'nav.batch' : 'Batch Process',
|
||||
'nav.dbsvr' : 'Database Server',
|
||||
'nav.products' : 'Instruments',
|
||||
'nav.services' : 'Services',
|
||||
'nav.about' : 'About',
|
||||
'nav.contact' : 'Contact',
|
||||
'nav.quote' : 'Request Quote',
|
||||
|
||||
// HERO
|
||||
'hero.badge' : 'Precision Industrial Control',
|
||||
'hero.title' : 'Engineering <span class="text-blue-500 font-normal">Precision</span> <br class="hidden md:block"/> Industrial Control',
|
||||
'hero.desc' : 'Hanmo Control & Network Co., Ltd. provides elite-tier DCS and SCADA architectures for critical infrastructure and modern digital transformation.',
|
||||
'hero.btn1' : 'Explore Expertise',
|
||||
'hero.btn2' : 'Consultation',
|
||||
'stat.nodes' : 'Active Nodes',
|
||||
'stat.uptime' : 'System Uptime',
|
||||
'stat.engineers': 'Engineers',
|
||||
'stat.years' : 'Years Excellence',
|
||||
|
||||
// DCS
|
||||
'dcs.badge' : 'Advanced Control Systems',
|
||||
'dcs.title' : 'DCS Integration',
|
||||
'dcs.desc' : 'Enterprise-grade Distributed Control System architecture designed for the most critical industrial applications.',
|
||||
'dcs.f1.title' : 'Redundant Architecture',
|
||||
'dcs.f1.desc' : 'Fault-tolerant systems with dual processing units ensuring 99.99% uptime',
|
||||
'dcs.f2.title' : 'Real-time Communication',
|
||||
'dcs.f2.desc' : 'Sub-millisecond response times with synchronized control across multiple nodes',
|
||||
'dcs.f3.title' : 'Security Certified',
|
||||
'dcs.f3.desc' : 'IEC 62443 compliance with military-grade encryption protocols',
|
||||
'dcs.btn' : 'Request Technical Specs',
|
||||
|
||||
// BATCH
|
||||
'batch.badge' : 'Process Automation',
|
||||
'batch.title' : 'Batch Process Control',
|
||||
'batch.desc' : 'Sophisticated batch automation for pharmaceutical, chemical, and specialty manufacturing operations.',
|
||||
'batch.f1.title': 'Recipe Management',
|
||||
'batch.f1.desc' : 'Dynamic recipe engine with version control and audit trail capabilities',
|
||||
'batch.f2.title': 'Performance Analytics',
|
||||
'batch.f2.desc' : 'Real-time batch tracking with predictive quality monitoring',
|
||||
'batch.f3.title': 'GMP Compliant',
|
||||
'batch.f3.desc' : 'FDA 21 CFR Part 11 compliance and complete data integrity',
|
||||
'batch.btn' : 'Start Implementation',
|
||||
|
||||
// DBSVR
|
||||
'db.badge' : 'Data Infrastructure',
|
||||
'db.title' : 'Database Server Solutions',
|
||||
'db.desc' : 'Mission-critical historian and data management infrastructure for continuous industrial operations.',
|
||||
'db.c1.title' : 'High-Performance Historian',
|
||||
'db.c1.desc' : 'SQL Server-based architecture optimized for 1M+ data points per second with sub-second query response',
|
||||
'db.c2.title' : 'Disaster Recovery',
|
||||
'db.c2.desc' : 'Geo-redundant replication with RTO < 15 minutes and RPO < 5 minutes',
|
||||
'db.c3.title' : 'Security & Compliance',
|
||||
'db.c3.desc' : 'Role-based access control, encryption at rest/transit, and full audit logging',
|
||||
'db.btn' : 'Get Infrastructure Consultation',
|
||||
|
||||
// INSTRUMENTS
|
||||
'inst.badge' : 'Precision Measurement',
|
||||
'inst.title' : 'Control Instruments',
|
||||
'inst.desc' : 'Smart field instruments engineered for accuracy and reliability in demanding industrial environments.',
|
||||
'inst.i1.title' : 'Flow Transmitters',
|
||||
'inst.i1.desc' : 'Magnetic, Coriolis, and vortex flow meters with ±0.5% accuracy',
|
||||
'inst.i2.title' : 'Pressure Transmitters',
|
||||
'inst.i2.desc' : 'Differential and absolute pressure sensors for ultra-high sensitivity',
|
||||
'inst.i3.title' : 'Temperature Sensors',
|
||||
'inst.i3.desc' : 'RTD, thermocouple, and infrared temperature measurement',
|
||||
'inst.i4.title' : 'Level Transmitters',
|
||||
'inst.i4.desc' : 'Ultrasonic, radar, and capacitive level sensors',
|
||||
'inst.i5.title' : 'Analytical Sensors',
|
||||
'inst.i5.desc' : 'pH, conductivity, oxygen, and dissolved gas analyzers',
|
||||
'inst.i6.title' : 'Control Valves',
|
||||
'inst.i6.desc' : 'Smart positioners with HART communication',
|
||||
'inst.i7.title' : 'Vibration Monitors',
|
||||
'inst.i7.desc' : 'Accelerometers and velocity sensors for predictive maintenance',
|
||||
'inst.i8.title' : 'Smart Data Loggers',
|
||||
'inst.i8.desc' : 'IoT-enabled data acquisition units with cloud connectivity',
|
||||
'inst.custom.title' : 'Custom Integration Available',
|
||||
'inst.custom.desc' : 'All instruments integrate seamlessly with our DCS and SCADA platforms. Custom configurations available for specialized applications.',
|
||||
'inst.custom.btn' : 'Request Custom Configuration',
|
||||
'inst.quote' : 'Get Quote →',
|
||||
|
||||
// SERVICES
|
||||
'svc.badge' : 'Our Capabilities',
|
||||
'svc.title' : 'World-Class Automation',
|
||||
'svc.desc' : 'Specialized engineering for complex physical operations through advanced data integration and distributed control systems.',
|
||||
'svc.s1.title' : 'DCS Integration',
|
||||
'svc.s1.desc' : 'Redundant control architectures for utility-scale industries including power and chemical plants.',
|
||||
'svc.s1.link' : 'Learn More',
|
||||
'svc.s2.title' : 'SCADA Design',
|
||||
'svc.s2.desc' : 'Real-time monitoring platforms with advanced HMI and secure remote access protocols.',
|
||||
'svc.s2.link' : 'Case Studies',
|
||||
'svc.s3.title' : 'Data Historians',
|
||||
'svc.s3.desc' : 'Mission-critical SQL infrastructure optimized for massive industrial time-series data storage.',
|
||||
'svc.s3.link' : 'Data Security',
|
||||
'svc.s4.title' : 'Control Instruments',
|
||||
'svc.s4.desc' : 'Smart field sensors for flow, pressure, and temperature with high-accuracy calibration.',
|
||||
'svc.s4.link' : 'Product Catalog',
|
||||
|
||||
// ABOUT
|
||||
'about.badge' : 'About Hanmo',
|
||||
'about.title' : 'Trusted Partner in Industrial Automation',
|
||||
'about.p1' : 'Since our founding, Hanmo Control & Network Co., Ltd. has been at the forefront of industrial automation engineering. We specialize in designing, implementing, and maintaining mission-critical control systems for the world\'s most demanding industries.',
|
||||
'about.p2' : 'Our team of 60+ certified engineers brings decades of combined experience in DCS, SCADA, and industrial networking, ensuring your operations run with unmatched precision and reliability.',
|
||||
'about.cert' : 'Certified',
|
||||
'about.support' : 'Support',
|
||||
'about.years' : 'Years of Industrial Excellence',
|
||||
|
||||
// CONTACT
|
||||
'contact.badge' : 'Get In Touch',
|
||||
'contact.title' : 'Start Your Project',
|
||||
'contact.desc' : 'Contact our engineering team for a detailed consultation and project assessment.',
|
||||
'contact.name' : 'Full Name',
|
||||
'contact.email' : 'Email Address',
|
||||
'contact.company': 'Company Name',
|
||||
'contact.msg' : 'Describe your project requirements...',
|
||||
'contact.btn' : 'Send Message',
|
||||
'contact.sending': 'Sending...',
|
||||
'contact.success': '✅ Message sent successfully. We will get back to you shortly.',
|
||||
'contact.error.required': '⚠ Name, email, and message are required.',
|
||||
'contact.error.email' : '⚠ Please enter a valid email address.',
|
||||
'contact.error.fail' : '❌ Failed to send. Please try again later.',
|
||||
|
||||
// FOOTER
|
||||
'footer.copy' : '© 2024 Hanmo Control & Network Co., Ltd. All rights reserved.',
|
||||
},
|
||||
|
||||
ko: {
|
||||
// NAV
|
||||
'nav.home' : '홈',
|
||||
'nav.dcs' : 'DCS',
|
||||
'nav.batch' : '배치 프로세스',
|
||||
'nav.dbsvr' : '데이터베이스 서버',
|
||||
'nav.products' : '계측기기',
|
||||
'nav.services' : '서비스',
|
||||
'nav.about' : '회사소개',
|
||||
'nav.contact' : '문의하기',
|
||||
'nav.quote' : '견적 요청',
|
||||
|
||||
// HERO
|
||||
'hero.badge' : '정밀 공정 제어 시스템',
|
||||
'hero.title' : '<span class="text-blue-500 font-normal">정밀함</span>을 설계하는<br class="hidden md:block"/> 공정 제어 전문기업',
|
||||
'hero.desc' : '(주)한모씨앤앤은 핵심 인프라와 디지털 전환을 위한 최고 수준의 DCS 및 SCADA BATCH CONTROL 시스템을 제공합니다.',
|
||||
'hero.btn1' : '전문 분야 보기',
|
||||
'hero.btn2' : '상담 신청',
|
||||
'stat.nodes' : '운영 노드',
|
||||
'stat.uptime' : '시스템 가동률',
|
||||
'stat.engineers': '전문 엔지니어',
|
||||
'stat.years' : '년 업계 경력',
|
||||
|
||||
// DCS
|
||||
'dcs.badge' : '고급 제어 시스템',
|
||||
'dcs.title' : 'DCS 통합 솔루션',
|
||||
'dcs.desc' : '가장 중요한 공정 현장을 위한 엔터프라이즈급 분산 제어 시스템(DCS) 아키텍처를 설계합니다.',
|
||||
'dcs.f1.title' : '이중화 아키텍처',
|
||||
'dcs.f1.desc' : '듀얼 처리 장치로 99.99% 가동률을 보장하는 내결함성 시스템',
|
||||
'dcs.f2.title' : '실시간 통신',
|
||||
'dcs.f2.desc' : '밀리초 미만의 응답 시간으로 다중 노드 간 동기화된 제어 실현',
|
||||
'dcs.f3.title' : '보안 인증',
|
||||
'dcs.f3.desc' : 'IEC 62443 준수 및 군사 수준 암호화 프로토콜 적용',
|
||||
'dcs.btn' : '기술 사양 요청',
|
||||
|
||||
// BATCH
|
||||
'batch.badge' : '프로세스 자동화',
|
||||
'batch.title' : '배치 프로세스 제어',
|
||||
'batch.desc' : '제약, 화학 및 특수 제조 공정을 위한 정교한 배치 자동화 시스템을 구축합니다.',
|
||||
'batch.f1.title': '레시피 관리',
|
||||
'batch.f1.desc' : '버전 관리 및 감사 추적 기능을 갖춘 동적 레시피 엔진',
|
||||
'batch.f2.title': '성능 분석',
|
||||
'batch.f2.desc' : '예측 품질 모니터링을 통한 실시간 배치 추적',
|
||||
'batch.f3.title': 'GMP 준수',
|
||||
'batch.f3.desc' : 'FDA 21 CFR Part 11 준수 및 완전한 데이터 무결성 보장',
|
||||
'batch.btn' : '구축 상담 신청',
|
||||
|
||||
// DBSVR
|
||||
'db.badge' : '데이터 인프라',
|
||||
'db.title' : '데이터베이스 서버 솔루션',
|
||||
'db.desc' : '지속적인 공정 운영을 위한 미션 크리티컬 히스토리안 및 데이터 관리 인프라를 제공합니다.',
|
||||
'db.c1.title' : '고성능 히스토리안',
|
||||
'db.c1.desc' : '초당 100만+ 데이터 포인트를 처리하는 SQL Server 기반 아키텍처',
|
||||
'db.c2.title' : '재해 복구',
|
||||
'db.c2.desc' : 'RTO 15분 미만, RPO 5분 미만의 지역 이중화 복제 시스템',
|
||||
'db.c3.title' : '보안 및 컴플라이언스',
|
||||
'db.c3.desc' : '역할 기반 접근 제어, 저장/전송 암호화 및 완전한 감사 로깅',
|
||||
'db.btn' : '인프라 상담 신청',
|
||||
|
||||
// INSTRUMENTS
|
||||
'inst.badge' : '정밀 계측',
|
||||
'inst.title' : '계측 제어 기기',
|
||||
'inst.desc' : '가혹한 공정 환경에서도 정확성과 신뢰성을 발휘하는 스마트 현장 계측기기를 공급합니다.',
|
||||
'inst.i1.title' : '유량 변환기',
|
||||
'inst.i1.desc' : '±0.5% 정확도의 전자식, 코리올리스, 와류식 유량계',
|
||||
'inst.i2.title' : '압력 변환기',
|
||||
'inst.i2.desc' : '초고감도 차압 및 절대압력 센서',
|
||||
'inst.i3.title' : '온도 센서',
|
||||
'inst.i3.desc' : 'RTD, 열전대, 적외선 온도 측정기',
|
||||
'inst.i4.title' : '레벨 트랜스미터',
|
||||
'inst.i4.desc' : '초음파, 레이더, 정전용량식 레벨 센서',
|
||||
'inst.i5.title' : '분석 센서',
|
||||
'inst.i5.desc' : 'pH, 전도도, 산소, 용존 가스 분석기',
|
||||
'inst.i6.title' : '컨트롤 밸브',
|
||||
'inst.i6.desc' : 'HART 통신 지원 스마트 포지셔너',
|
||||
'inst.i7.title' : '진동 모니터',
|
||||
'inst.i7.desc' : '예측 유지보수를 위한 가속도계 및 속도 센서',
|
||||
'inst.i8.title' : '스마트 데이터 로거',
|
||||
'inst.i8.desc' : '클라우드 연결 기능을 갖춘 IoT 데이터 수집 장치',
|
||||
'inst.custom.title' : '맞춤형 통합 솔루션 제공',
|
||||
'inst.custom.desc' : '모든 계측기기는 당사의 DCS 및 SCADA 플랫폼과 원활하게 통합됩니다. 특수 응용 분야에 맞는 커스텀 구성이 가능합니다.',
|
||||
'inst.custom.btn' : '맞춤 구성 요청',
|
||||
'inst.quote' : '견적 요청 →',
|
||||
|
||||
// SERVICES
|
||||
'svc.badge' : '서비스 역량',
|
||||
'svc.title' : '세계 최고 수준의 자동화',
|
||||
'svc.desc' : '고급 데이터 통합 및 분산 제어 시스템을 통해 복잡한 공정 공정을 위한 특화된 엔지니어링을 제공합니다.',
|
||||
'svc.s1.title' : 'DCS 통합',
|
||||
'svc.s1.desc' : '발전소, 화학 플랜트 등 대규모 공정을 위한 이중화 제어 아키텍처',
|
||||
'svc.s1.link' : '자세히 보기',
|
||||
'svc.s2.title' : 'SCADA 설계',
|
||||
'svc.s2.desc' : '고급 HMI 및 보안 원격 접속 프로토콜을 갖춘 실시간 모니터링 플랫폼',
|
||||
'svc.s2.link' : '사례 연구',
|
||||
'svc.s3.title' : '데이터 히스토리안',
|
||||
'svc.s3.desc' : '대규모 공정 시계열 데이터 저장에 최적화된 미션 크리티컬 SQL 인프라',
|
||||
'svc.s3.link' : '데이터 보안',
|
||||
'svc.s4.title' : '제어 계측기기',
|
||||
'svc.s4.desc' : '고정밀 교정을 통한 유량, 압력, 온도 스마트 현장 센서',
|
||||
'svc.s4.link' : '제품 카탈로그',
|
||||
|
||||
// ABOUT
|
||||
'about.badge' : '회사 소개',
|
||||
'about.title' : '공정 자동화의 신뢰할 수 있는 파트너',
|
||||
'about.p1' : '(주)한모씨앤앤는 창립 이래 공정 자동화 엔지니어링의 최전선에서 활동하고 있습니다. 세계에서 가장 까다로운 공정 현장을 위한 미션 크리티컬 제어 시스템 설계, 구현 및 유지보수를 전문으로 합니다.',
|
||||
'about.p2' : '60여 명의 공인 엔지니어로 구성된 팀이 DCS, SCADA, 공정 네트워킹 분야에서 수십 년의 경험을 바탕으로 최고의 정밀도와 신뢰성을 보장합니다.',
|
||||
'about.cert' : '인증',
|
||||
'about.support' : '지원',
|
||||
'about.years' : '년 공정 분야 우수성',
|
||||
|
||||
// CONTACT
|
||||
'contact.badge' : '문의하기',
|
||||
'contact.title' : '프로젝트를 시작하세요',
|
||||
'contact.desc' : '엔지니어링 팀에 문의하여 상세 상담 및 프로젝트 평가를 받아보세요.',
|
||||
'contact.name' : '성명',
|
||||
'contact.email' : '이메일 주소',
|
||||
'contact.company': '회사명',
|
||||
'contact.msg' : '프로젝트 요구사항을 설명해 주세요...',
|
||||
'contact.btn' : '메시지 보내기',
|
||||
'contact.sending': '전송 중...',
|
||||
'contact.success': '✅ 메시지가 성공적으로 전송되었습니다. 빠른 시일 내에 회신 드리겠습니다.',
|
||||
'contact.error.required': '⚠ 이름, 이메일, 메시지는 필수 항목입니다.',
|
||||
'contact.error.email' : '⚠ 올바른 이메일 주소를 입력해 주세요.',
|
||||
'contact.error.fail' : '❌ 전송에 실패했습니다. 잠시 후 다시 시도해 주세요.',
|
||||
|
||||
// FOOTER
|
||||
'footer.copy' : '© 2024 (주)한모씨앤앤. All rights reserved.',
|
||||
}
|
||||
};
|
||||
|
||||
// ── 현재 언어 (로컬스토리지 유지) ──────────────────────────
|
||||
let currentLang = localStorage.getItem('hmLang') || 'en';
|
||||
|
||||
function t(key) {
|
||||
return translations[currentLang][key] || translations['en'][key] || key;
|
||||
}
|
||||
|
||||
function applyTranslations() {
|
||||
document.querySelectorAll('[data-i18n]').forEach(el => {
|
||||
const key = el.getAttribute('data-i18n');
|
||||
const type = el.getAttribute('data-i18n-type') || 'text';
|
||||
if (type === 'html') {
|
||||
el.innerHTML = t(key);
|
||||
} else if (type === 'placeholder') {
|
||||
el.setAttribute('placeholder', t(key));
|
||||
} else {
|
||||
el.textContent = t(key);
|
||||
}
|
||||
});
|
||||
// <html lang> 업데이트
|
||||
document.documentElement.lang = currentLang;
|
||||
// 버튼 활성 상태 업데이트
|
||||
document.querySelectorAll('.lang-btn').forEach(btn => {
|
||||
btn.classList.toggle('active-lang', btn.dataset.lang === currentLang);
|
||||
});
|
||||
}
|
||||
|
||||
function switchLang(lang) {
|
||||
currentLang = lang;
|
||||
localStorage.setItem('hmLang', lang);
|
||||
applyTranslations();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', applyTranslations);
|
||||
@@ -1,123 +1,89 @@
|
||||
// Header scroll effect
|
||||
// ============================================================
|
||||
// ★ EmailJS 설정 - 아래 3가지 값을 본인 계정으로 교체하세요 ★
|
||||
// ============================================================
|
||||
const EMAILJS_PUBLIC_KEY = 'HO6i369gX6X5HEXtJ';
|
||||
const EMAILJS_SERVICE_ID = 'service_4ur5lqd';
|
||||
const EMAILJS_TEMPLATE_ID = 'template_jp0v5qv';
|
||||
// ============================================================
|
||||
|
||||
emailjs.init(EMAILJS_PUBLIC_KEY);
|
||||
|
||||
// ── Contact Form ─────────────────────────────────────────────
|
||||
document.getElementById('contact-submit').addEventListener('click', function () {
|
||||
const name = document.getElementById('contact-name').value.trim();
|
||||
const email = document.getElementById('contact-email').value.trim();
|
||||
const company = document.getElementById('contact-company').value.trim();
|
||||
const message = document.getElementById('contact-message').value.trim();
|
||||
const btn = document.getElementById('contact-submit');
|
||||
|
||||
if (!name || !email || !message) {
|
||||
showStatus('error', t('contact.error.required')); return;
|
||||
}
|
||||
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
||||
showStatus('error', t('contact.error.email')); return;
|
||||
}
|
||||
|
||||
btn.disabled = true;
|
||||
btn.textContent = t('contact.sending');
|
||||
|
||||
const templateParams = {
|
||||
name : name,
|
||||
message : 'Email : ' + email + '\nCompany : ' + (company || 'N/A') + '\n\n' + message,
|
||||
reply_to : email
|
||||
};
|
||||
|
||||
emailjs.send(EMAILJS_SERVICE_ID, EMAILJS_TEMPLATE_ID, templateParams)
|
||||
.then(function () {
|
||||
showStatus('success', t('contact.success'));
|
||||
document.getElementById('contact-name').value = '';
|
||||
document.getElementById('contact-email').value = '';
|
||||
document.getElementById('contact-company').value = '';
|
||||
document.getElementById('contact-message').value = '';
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error('EmailJS error:', error);
|
||||
showStatus('error', t('contact.error.fail'));
|
||||
})
|
||||
.finally(function () {
|
||||
btn.disabled = false;
|
||||
btn.textContent = t('contact.btn');
|
||||
});
|
||||
});
|
||||
|
||||
function showStatus(type, msg) {
|
||||
const status = document.getElementById('contact-status');
|
||||
status.classList.remove('hidden', 'bg-green-500/20', 'text-green-400', 'bg-red-500/20', 'text-red-400');
|
||||
status.classList.add(type === 'success' ? 'bg-green-500/20' : 'bg-red-500/20',
|
||||
type === 'success' ? 'text-green-400' : 'text-red-400');
|
||||
status.textContent = msg;
|
||||
}
|
||||
|
||||
// ── Header scroll ────────────────────────────────────────────
|
||||
const mainHeader = document.getElementById('main-header');
|
||||
const brandName = document.getElementById('brand-name');
|
||||
const navLinks = document.querySelectorAll('.nav-link');
|
||||
const brandName = document.getElementById('brand-name');
|
||||
const navLinks = document.querySelectorAll('.nav-link');
|
||||
|
||||
window.addEventListener('scroll', () => {
|
||||
if (window.scrollY > 50) {
|
||||
mainHeader.classList.add('glass-effect', 'py-3');
|
||||
mainHeader.classList.remove('py-6');
|
||||
if (brandName) brandName.classList.replace('text-white', 'text-slate-900');
|
||||
navLinks.forEach(link => {
|
||||
link.classList.replace('text-slate-100', 'text-slate-700');
|
||||
});
|
||||
navLinks.forEach(link => link.classList.replace('text-slate-100', 'text-slate-700'));
|
||||
} else {
|
||||
mainHeader.classList.remove('glass-effect', 'py-3');
|
||||
mainHeader.classList.add('py-6');
|
||||
if (brandName) brandName.classList.replace('text-slate-900', 'text-white');
|
||||
navLinks.forEach(link => {
|
||||
link.classList.replace('text-slate-700', 'text-slate-100');
|
||||
});
|
||||
navLinks.forEach(link => link.classList.replace('text-slate-700', 'text-slate-100'));
|
||||
}
|
||||
});
|
||||
|
||||
// Mobile menu open
|
||||
// ── Mobile menu ───────────────────────────────────────────────
|
||||
const mobileMenuBtn = document.getElementById('mobile-menu-btn');
|
||||
const mobileMenu = document.getElementById('mobile-menu');
|
||||
const closeMenuBtn = document.getElementById('close-menu-btn');
|
||||
const mobileMenu = document.getElementById('mobile-menu');
|
||||
const closeMenuBtn = document.getElementById('close-menu-btn');
|
||||
|
||||
if (mobileMenuBtn) {
|
||||
mobileMenuBtn.addEventListener('click', () => {
|
||||
mobileMenu.classList.remove('translate-x-full');
|
||||
});
|
||||
}
|
||||
if (mobileMenuBtn) mobileMenuBtn.addEventListener('click', () => mobileMenu.classList.remove('translate-x-full'));
|
||||
if (closeMenuBtn) closeMenuBtn.addEventListener('click', () => mobileMenu.classList.add('translate-x-full'));
|
||||
|
||||
// Mobile menu close
|
||||
if (closeMenuBtn) {
|
||||
closeMenuBtn.addEventListener('click', () => {
|
||||
mobileMenu.classList.add('translate-x-full');
|
||||
});
|
||||
}
|
||||
|
||||
// Close on nav link click
|
||||
const mobileNavLinks = mobileMenu ? mobileMenu.querySelectorAll('a') : [];
|
||||
mobileNavLinks.forEach(link => {
|
||||
link.addEventListener('click', () => {
|
||||
mobileMenu.classList.add('translate-x-full');
|
||||
});
|
||||
});
|
||||
|
||||
// Contact form handler
|
||||
const contactSubmitBtn = document.getElementById('contact-submit');
|
||||
const contactForm = {
|
||||
name: document.getElementById('contact-name'),
|
||||
email: document.getElementById('contact-email'),
|
||||
company: document.getElementById('contact-company'),
|
||||
message: document.getElementById('contact-message')
|
||||
};
|
||||
const contactStatus = document.getElementById('contact-status');
|
||||
|
||||
if (contactSubmitBtn) {
|
||||
contactSubmitBtn.addEventListener('click', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
// 폼 데이터 수집
|
||||
const formData = {
|
||||
name: contactForm.name.value,
|
||||
email: contactForm.email.value,
|
||||
company: contactForm.company.value,
|
||||
message: contactForm.message.value
|
||||
};
|
||||
|
||||
// 로딩 상태 표시
|
||||
contactSubmitBtn.disabled = true;
|
||||
contactSubmitBtn.textContent = 'Sending...';
|
||||
contactStatus.classList.add('hidden');
|
||||
|
||||
try {
|
||||
// FastAPI 엔드포인트로 요청 (nginx 프록시를 통함)
|
||||
const response = await fetch('/api/contact', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(formData),
|
||||
mode: 'cors',
|
||||
credentials: 'omit'
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
// 응답 처리
|
||||
contactStatus.classList.remove('hidden');
|
||||
|
||||
if (response.ok && result.success !== false) {
|
||||
// 성공 메시지
|
||||
contactStatus.classList.remove('bg-red-900/50', 'text-red-200');
|
||||
contactStatus.classList.add('bg-green-900/50', 'text-green-200');
|
||||
contactStatus.textContent = result.message;
|
||||
|
||||
// 폼 초기화
|
||||
contactForm.name.value = '';
|
||||
contactForm.email.value = '';
|
||||
contactForm.company.value = '';
|
||||
contactForm.message.value = '';
|
||||
} else {
|
||||
// 오류 메시지
|
||||
contactStatus.classList.remove('bg-green-900/50', 'text-green-200');
|
||||
contactStatus.classList.add('bg-red-900/50', 'text-red-200');
|
||||
contactStatus.textContent = result.detail || result.message || 'Failed to send message';
|
||||
}
|
||||
} catch (error) {
|
||||
// 네트워크 오류
|
||||
contactStatus.classList.remove('hidden', 'bg-green-900/50', 'text-green-200');
|
||||
contactStatus.classList.add('bg-red-900/50', 'text-red-200');
|
||||
contactStatus.textContent = 'Error: Could not send message. Please try again later.';
|
||||
console.error('Contact form error:', error);
|
||||
} finally {
|
||||
// 버튼 상태 복구
|
||||
contactSubmitBtn.disabled = false;
|
||||
contactSubmitBtn.textContent = 'Send Message';
|
||||
}
|
||||
});
|
||||
}
|
||||
mobileNavLinks.forEach(link => link.addEventListener('click', () => mobileMenu.classList.add('translate-x-full')));
|
||||
|
||||
Reference in New Issue
Block a user