diff --git a/.Backup/docker-compose.yml b/.Backup/docker-compose.yml deleted file mode 100644 index 2cf583c..0000000 --- a/.Backup/docker-compose.yml +++ /dev/null @@ -1,22 +0,0 @@ -version: '3.8' -services: - # 1. 관리 도구 (Nginx Proxy Manager) - npm: - image: 'jc21/nginx-proxy-manager:latest' - container_name: npm-admin - restart: unless-stopped - ports: - - '80:80' # HTTP 외부 접속용 - - '81:81' # 관리자 화면 접속용 (HMI 역할) - - '443:443' # HTTPS 보안 접속용 - volumes: - - ./npm/data:/data - - ./npm/letsencrypt:/etc/letsencrypt - - # 2. 실제 홈페이지 (공사 중 페이지) - web-server: - image: nginx:alpine - container_name: hanmo-home - restart: unless-stopped - volumes: - - ./html:/usr/share/nginx/html:ro diff --git a/.Backup/html/.gitignore b/.Backup/html /.gitignore similarity index 100% rename from .Backup/html/.gitignore rename to .Backup/html /.gitignore diff --git a/.Backup/html/assets/css/style.css b/.Backup/html /assets/css/style.css similarity index 52% rename from .Backup/html/assets/css/style.css rename to .Backup/html /assets/css/style.css index 0f553b3..9a90a1e 100644 --- a/.Backup/html/assets/css/style.css +++ b/.Backup/html /assets/css/style.css @@ -38,16 +38,70 @@ body { filter: grayscale(0); } +/* ── 헤더 & 네비게이션 ───────────────────────────────────── */ +/* 기본 상태: 투명 배경 위 (흰색 텍스트) */ +.nav-link { + color: white; +} + +#brand-name { + color: white; +} + +/* 스크롤 시: 흰색 배경 (어두운 텍스트) */ +#main-header.scrolled { + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(16px); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); +} + +#main-header.scrolled .nav-link { + color: #1e293b; +} + +#main-header.scrolled #brand-name { + color: #1e293b; +} + /* ── 언어 전환 버튼 ───────────────────────────────────────── */ +/* 기본 상태: 투명 배경 위 (흰색) */ .lang-btn { background: transparent; - opacity: 0.5; - transition: all 0.2s; + color: white; + opacity: 0.85; + transition: all 0.3s; } + .lang-btn:hover { - opacity: 0.8; -} -.lang-btn.active-lang { - background: #2563eb; opacity: 1; } + +.lang-btn.active-lang { + background: rgba(37, 99, 235, 0.9); + opacity: 1; +} + +/* 스크롤 시: 흰색 배경 (어두운 텍스트) */ +#main-header.scrolled .lang-btn { + color: #1e293b; + opacity: 0.7; +} + +#main-header.scrolled .lang-btn:hover { + opacity: 1; +} + +#main-header.scrolled .lang-btn.active-lang { + background: #2563eb; + color: white; + opacity: 1; +} + +/* 언어 버튼 컨테이너 테두리 */ +#lang-container { + border-color: rgba(255, 255, 255, 0.3); +} + +#main-header.scrolled #lang-container { + border-color: rgba(0, 0, 0, 0.15); +} diff --git a/.Backup/html/assets/images/BatchControl.png b/.Backup/html /assets/images/BatchControl.png similarity index 100% rename from .Backup/html/assets/images/BatchControl.png rename to .Backup/html /assets/images/BatchControl.png diff --git a/.Backup/html/assets/images/ControlRoom1.png b/.Backup/html /assets/images/ControlRoom1.png similarity index 100% rename from .Backup/html/assets/images/ControlRoom1.png rename to .Backup/html /assets/images/ControlRoom1.png diff --git a/.Backup/html/assets/images/ControlRoom2.png b/.Backup/html /assets/images/ControlRoom2.png similarity index 100% rename from .Backup/html/assets/images/ControlRoom2.png rename to .Backup/html /assets/images/ControlRoom2.png diff --git a/.Backup/html/assets/images/ControlRoom3.png b/.Backup/html /assets/images/ControlRoom3.png similarity index 100% rename from .Backup/html/assets/images/ControlRoom3.png rename to .Backup/html /assets/images/ControlRoom3.png diff --git a/.Backup/html/assets/images/ControlRoom4.png b/.Backup/html /assets/images/ControlRoom4.png similarity index 100% rename from .Backup/html/assets/images/ControlRoom4.png rename to .Backup/html /assets/images/ControlRoom4.png diff --git a/.Backup/html/assets/images/ControlRoom5.png b/.Backup/html /assets/images/ControlRoom5.png similarity index 100% rename from .Backup/html/assets/images/ControlRoom5.png rename to .Backup/html /assets/images/ControlRoom5.png diff --git a/.Backup/html/assets/images/ControlRoom6.png b/.Backup/html /assets/images/ControlRoom6.png similarity index 100% rename from .Backup/html/assets/images/ControlRoom6.png rename to .Backup/html /assets/images/ControlRoom6.png diff --git a/.Backup/html/assets/images/ControlRoom7.png b/.Backup/html /assets/images/ControlRoom7.png similarity index 100% rename from .Backup/html/assets/images/ControlRoom7.png rename to .Backup/html /assets/images/ControlRoom7.png diff --git a/.Backup/html/assets/images/bearing.png b/.Backup/html /assets/images/bearing.png similarity index 100% rename from .Backup/html/assets/images/bearing.png rename to .Backup/html /assets/images/bearing.png diff --git a/.Backup/html/assets/images/dcsintegration.png b/.Backup/html /assets/images/dcsintegration.png similarity index 100% rename from .Backup/html/assets/images/dcsintegration.png rename to .Backup/html /assets/images/dcsintegration.png diff --git a/.Backup/html/assets/images/favicon.ico b/.Backup/html /assets/images/favicon.ico similarity index 100% rename from .Backup/html/assets/images/favicon.ico rename to .Backup/html /assets/images/favicon.ico diff --git a/.Backup/html/assets/images/honeywell-logo.svg b/.Backup/html /assets/images/honeywell-logo.svg similarity index 100% rename from .Backup/html/assets/images/honeywell-logo.svg rename to .Backup/html /assets/images/honeywell-logo.svg diff --git a/.Backup/html /assets/images/icons/icons.svg b/.Backup/html /assets/images/icons/icons.svg new file mode 100644 index 0000000..cac35f2 --- /dev/null +++ b/.Backup/html /assets/images/icons/icons.svg @@ -0,0 +1,56 @@ + diff --git a/.Backup/html /assets/images/icons/orginalSVG/CV.svg b/.Backup/html /assets/images/icons/orginalSVG/CV.svg new file mode 100644 index 0000000..3f0e153 --- /dev/null +++ b/.Backup/html /assets/images/icons/orginalSVG/CV.svg @@ -0,0 +1,243 @@ + + + + diff --git a/.Backup/html /assets/images/icons/orginalSVG/XV.svg b/.Backup/html /assets/images/icons/orginalSVG/XV.svg new file mode 100644 index 0000000..83bc5ed --- /dev/null +++ b/.Backup/html /assets/images/icons/orginalSVG/XV.svg @@ -0,0 +1,227 @@ + + + + diff --git a/.Backup/html /assets/images/icons/path.png b/.Backup/html /assets/images/icons/path.png new file mode 100644 index 0000000..f14cebd Binary files /dev/null and b/.Backup/html /assets/images/icons/path.png differ diff --git a/.Backup/html /assets/images/icons/path좌표문자.md b/.Backup/html /assets/images/icons/path좌표문자.md new file mode 100644 index 0000000..8b08c15 --- /dev/null +++ b/.Backup/html /assets/images/icons/path좌표문자.md @@ -0,0 +1,26 @@ +이제 SVG 명령어들을 한눈에 볼 수 있는 요약표를 만들어드릴게요. 과 처럼 대문자/소문자의 차이는 절대 좌표 vs 상대 좌표라는 점을 기억하시면 됩니다. + +🔹 주요 Path 명령어 요약표 + + + +🔹 주요 Path 명령어 요약표 + +| 명령어 | 의미 | 대문자(절대) | 소문자(상대) | 예시 | +|--------|------|--------------|--------------|------| +| **M / m** | Move To (좌표 이동) | 지정한 좌표로 이동 | 현재 위치 기준으로 이동 | `M 10 20` / `m 10 20` | +| **L / l** | Line To (직선 그리기) | 지정 좌표까지 직선 | 현재 위치에서 상대 이동 직선 | `L 30 40` / `l 30 40` | +| **H / h** | Horizontal Line | 지정 x좌표까지 수평선 | 현재 위치에서 x축 상대 이동 | `H 50` / `h 50` | +| **V / v** | Vertical Line | 지정 y좌표까지 수직선 | 현재 위치에서 y축 상대 이동 | `V 60` / `v 60` | +| **C / c** | Cubic Bézier Curve | 절대 좌표로 곡선 제어점 지정 | 상대 좌표로 곡선 제어점 지정 | `C x1 y1, x2 y2, x y` | +| **Q / q** | Quadratic Bézier Curve | 절대 좌표로 곡선 제어점 지정 | 상대 좌표로 곡선 제어점 지정 | `Q x1 y1, x y` | +| **A / a** | Arc (호 그리기) | 절대 좌표로 원호 | 상대 좌표로 원호 | `A rx ry x-axis-rotation large-arc-flag sweep-flag x y` | +| **Z / z** | Close Path | 현재 경로를 시작점과 연결해 닫기 | 동일 | `Z` | + + + + +🔹 핵심 정리 +• 대문자 → 절대 좌표 (캔버스 기준) +• 소문자 → 상대 좌표 (현재 위치 기준) +• /은 시작점 이동, /은 직선, /는 곡선, 는 닫기 diff --git a/.Backup/html/assets/images/instrument.png b/.Backup/html /assets/images/instrument.png similarity index 100% rename from .Backup/html/assets/images/instrument.png rename to .Backup/html /assets/images/instrument.png diff --git a/.Backup/html/assets/images/reactor.png b/.Backup/html /assets/images/reactor.png similarity index 100% rename from .Backup/html/assets/images/reactor.png rename to .Backup/html /assets/images/reactor.png diff --git a/.Backup/html/assets/js/i18n.js b/.Backup/html /assets/js/i18n.js similarity index 90% rename from .Backup/html/assets/js/i18n.js rename to .Backup/html /assets/js/i18n.js index f94936b..dfea10d 100644 --- a/.Backup/html/assets/js/i18n.js +++ b/.Backup/html /assets/js/i18n.js @@ -12,7 +12,7 @@ const translations = { 'nav.services' : 'References', 'nav.about' : 'About', 'nav.contact' : 'Contact', - 'nav.quote' : 'Request Quote', + 'nav.quote' : 'Inquiry', // HERO 'hero.badge' : 'Precision Industrial Control', @@ -68,23 +68,23 @@ const translations = { 'db.btn' : 'Get Infrastructure Consultation', // INSTRUMENTS - 'inst.badge' : 'Precision Measurement', + 'inst.badge' : 'Precision Measurement & Actuation', 'inst.title' : 'Control Instruments', - 'inst.desc' : 'Smart field instruments engineered for accuracy and reliability in demanding industrial environments.', + 'inst.desc' : 'Optimal Precision Starts with Understanding of Your Environment', 'inst.i1.title' : 'Flow Transmitters', - 'inst.i1.desc' : 'Magnetic, Coriolis, and vortex flow meters with ±0.5% accuracy', + 'inst.i1.desc' : 'Magnetic, Coriolis, and Vortex, traditional flowmeters', '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.i4.desc' : 'Ultrasonic, radar, capacitive and float level sensors', 'inst.i5.title' : 'Analytical Sensors', - 'inst.i5.desc' : 'pH, conductivity, oxygen, and dissolved gas analyzers', + 'inst.i5.desc' : 'pH, conductivity, oxygen, and dissolved gas analyzer', '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.i7.title' : 'Shutoff Valves', + 'inst.i7.desc' : 'Pneumatic, Electrical on/off valves with Explosion proof', 'inst.i8.title' : 'Smart Data Loggers', 'inst.i8.desc' : 'IoT-enabled data acquisition units with cloud connectivity', 'inst.custom.title' : 'Custom Integration Available', @@ -94,30 +94,30 @@ const translations = { // REFERENCES 'svc.badge' : 'Referenced Plant Varieties', - 'svc.title' : 'Versatile Automation References', - 'svc.desc' : 'From Deep Understanding of various industry references to Seamless Execution.', + 'svc.title' : 'Versatile Process References', + 'svc.desc' : 'From deep understanding of various industry references to Seamless Execution.', 'svc.s1.title' : 'DCS / SCADA', 'svc.s1.desc' : 'Semiconductor Solvent Recovery Plant., 80% Hydrazin Plant, SNCR & SCR Envirionmental Plant, etc', 'svc.s1.item1' : 'Semiconductor Solvent Recovery Plant', 'svc.s1.item2' : '80% Hydrazin Plant', 'svc.s1.item3' : 'SNCR & SCR in Power Plant', 'svc.s1.item4' : 'Oil Tank Terminal', - 'svc.s1.link' : 'Learn More', + //'svc.s1.link' : 'Learn More', 'svc.s2.title' : 'Batch Plant', 'svc.s2.desc' : 'Real-time monitoring platforms with advanced HMI and secure remote access protocols.', 'svc.s2.item1' : 'Micro Capsule forming agent plant', 'svc.s2.item2' : 'ADCA,HDCA Plant', 'svc.s2.item3' : 'Vacuum Furnace Plant - Decorative Stainless Plate', - 'svc.s2.link' : 'Case Studies', + //'svc.s2.link' : 'Case Studies', 'svc.s3.title' : 'Other Projects', 'svc.s3.desc' : 'Various industrial automation projects.', - 'svc.s3.item1' : 'Waste to Energy Incineration Plant', - 'svc.s3.item2' : 'Copper Rod Continuous Casting Plant', - 'svc.s3.item3' : 'Bearing Continuous Heat Treatment Plant', - 'svc.s3.item4' : 'High Speed Cold Rolling Continuous Casting Plant', - 'svc.s3.link' : 'CASE STUDIES', + 'svc.s3.item1' : 'Waste to Energy Incinerator Plant', + 'svc.s3.item2' : 'Copper Continuous Casting Plant', + 'svc.s3.item3' : 'Bearing Heat Treatment Plant', + 'svc.s3.item4' : 'Chlor-Alkali Plant', + //'svc.s3.link' : 'CASE STUDIES', 'svc.s4.title' : 'Instruments', 'svc.s4.desc' : 'Smart field sensors for flow, pressure, and temperature with high-accuracy calibration.', @@ -127,7 +127,7 @@ const translations = { 'svc.s4.item4' : 'Flownics', 'svc.s4.item5' : 'Komoto - (Motoyama Korea)', 'svc.s4.item6' : 'Autonics - (Konics)', - 'svc.s4.link' : 'Product Catalog', + //'svc.s4.link' : 'Product Catalog', // ABOUT 'about.badge' : 'About Hanmo', @@ -164,10 +164,10 @@ const translations = { 'nav.batch' : '배치 프로세스', 'nav.dbsvr' : '데이터베이스 서버', 'nav.products' : '계측기기', - 'nav.services' : '실적 플랜트 분야', + 'nav.services' : '실적 플랜트', 'nav.about' : '회사소개', 'nav.contact' : '문의하기', - 'nav.quote' : '견적 요청', + 'nav.quote' : '상담 신청', // HERO 'hero.badge' : '정밀 공정 제어 시스템', @@ -238,14 +238,14 @@ const translations = { 'inst.i5.desc' : 'pH, 전도도, 산소, 용존 가스 분석기', 'inst.i6.title' : '컨트롤 밸브', 'inst.i6.desc' : 'HART 통신 지원 스마트 포지셔너', - 'inst.i7.title' : '진동 모니터', - 'inst.i7.desc' : '예측 유지보수를 위한 가속도계 및 속도 센서', + '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' : '견적 요청 →', + 'inst.quote' : '상담 신청 →', // REFERENCES 'svc.badge' : '실적 플랜트 분야', @@ -257,20 +257,20 @@ const translations = { 'svc.s1.item2' : '80% 하이드라진 플랜트', 'svc.s1.item3' : '발전소 SNCR & SCR 플랜트', 'svc.s1.item4' : '오일 탱크 터미널 플랜트', - 'svc.s1.link' : '자세히 보기', + // 'svc.s1.link' : '자세히 보기', 'svc.s2.title' : '배치 플랜트', 'svc.s2.desc' : '실시간 모니터링 플랫폼과 고급 HMI, 안전한 원격 액세스 프로토콜을 갖춘 배치 플랜트 제어 시스템', 'svc.s2.item1' : '마이크로 캡슐 발포제 플랜트', 'svc.s2.item2' : 'ADCA,HDCA 플랜트', 'svc.s2.item3' : '진공 열처리로 플랜트', - 'svc.s2.link' : '사례 연구', + // 'svc.s2.link' : '사례 연구', 'svc.s3.title' : '기타 프로젝트', 'svc.s3.desc' : '기타 핵심 산업 자동화', 'svc.s3.item1' : '쓰레기 소각장 플랜트', 'svc.s3.item2' : '구리 환재 연속 주조로', 'svc.s3.item3' : '베어링 연속 열처리로 플랜트', - 'svc.s3.item4' : '고속 냉간 연속 주조로 플랜트', - 'svc.s3.link' : '데이터 보안', + 'svc.s3.item4' : '가성소다, 염소 전해 플랜트', + // 'svc.s3.link' : '데이터 보안', 'svc.s4.title' : '제어 계측기기 협력사', 'svc.s4.desc' : '고객 현장에 대한 깊은 이해를 바탕으로 최적 계측기 선정', 'svc.s4.item1' : '한국하니웰(주)', @@ -279,16 +279,16 @@ const translations = { 'svc.s4.item4' : '플로우닉스(주)', 'svc.s4.item5' : '(주)코모토', 'svc.s4.item6' : '오토닉스(주)', - 'svc.s4.link' : '제품 카탈로그', + // 'svc.s4.link' : '제품 카탈로그', // ABOUT 'about.badge' : '회사 소개', 'about.title' : '공정 자동화의 신뢰할 수 있는 파트너', 'about.p1' : '(주)한모씨앤앤는 창립 이래 공정 자동화 엔지니어링의 최전선에서 활동하고 있습니다. 세계에서 가장 까다로운 공정 현장을 위한 미션 크리티컬 제어 시스템 설계, 구현 및 유지보수를 전문으로 합니다.', - 'about.p2' : 'DCS, SCADA, 계측기기, 공정 네트워킹 분야에서 수십 년의 경험을 바탕으로 최고의 정밀도와 신뢰성을 보장합니다.', + 'about.p2' : 'DCS, SCADA, 계측기기, 제어반 설계 및 제작, 공정 네트워킹 분야에서 수십 년의 경험을 바탕으로 최고의 정밀도와 신뢰성을 보장합니다.', 'about.cert' : '인증', 'about.support' : '지원', - 'about.years' : '여년간의 공정 제어 전문성', + 'about.years' : 'Years of Industrial Excellence', // CONTACT 'contact.badge' : '문의하기', @@ -329,8 +329,10 @@ function applyTranslations() { el.textContent = t(key); } }); + // 업데이트 document.documentElement.lang = currentLang; + // 버튼 활성 상태 업데이트 document.querySelectorAll('.lang-btn').forEach(btn => { btn.classList.toggle('active-lang', btn.dataset.lang === currentLang); @@ -343,4 +345,5 @@ function switchLang(lang) { applyTranslations(); } +// DOMContentLoaded 시 번역 적용 document.addEventListener('DOMContentLoaded', applyTranslations); diff --git a/.Backup/html /assets/js/script.js b/.Backup/html /assets/js/script.js new file mode 100644 index 0000000..b1a4c39 --- /dev/null +++ b/.Backup/html /assets/js/script.js @@ -0,0 +1,149 @@ +// ============================================================ +// ★ 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; +} + +// ============================================================ +// 메인 스크립트 (전체 기능 포함) +// ============================================================ + +// DOMContentLoaded 이벤트 +document.addEventListener('DOMContentLoaded', () => { + + // ============================================================ + // 메뉴 토글 + // ============================================================ + const menuBtn = document.querySelector('#mobile-menu-btn'); + const navMenu = document.querySelector('#mobile-menu'); + const closeBtn = document.querySelector('#close-menu-btn'); + if (menuBtn && navMenu) { + // 메뉴열기 + menuBtn.addEventListener('click', () => { + navMenu.classList.remove('translate-x-full'); + menuBtn.classList.toggle('open'); + }); + //메뉴닫기 + if (closeBtn) { + closeBtn.addEventListener('click', () => { + navMenu.classList.add('translate-x-full'); + }); + } + //메뉴 링크 클릭 시 닫기 + navMenu.querySelectorAll('a').forEach(link => { + link.addEventListener('click',() => { + navMenu.classList.add('translate-x-full'); + }); + }); + } + + // ============================================================ + // 스크롤 애니메이션 + // ============================================================ + const scrollElems = document.querySelectorAll('[data-scroll]'); + const observerOptions = { + root: null, + rootMargin: '0px', + threshold: 0.1 + }; + const scrollObserver = new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('animate'); + observer.unobserve(entry.target); + } + }); + }, observerOptions); + + scrollElems.forEach(el => scrollObserver.observe(el)); + + // ============================================================ + // 상단 버튼/헤더 스크롤 효과 + // ============================================================ + const header = document.querySelector('header'); + const topBtn = document.querySelector('.back-to-top'); + window.addEventListener('scroll', () => { + if (window.scrollY > 50) { + header?.classList.add('scrolled'); + topBtn?.classList.add('visible'); + } else { + header?.classList.remove('scrolled'); + topBtn?.classList.remove('visible'); + } + }); + + topBtn?.addEventListener('click', () => window.scrollTo({ top: 0, behavior: 'smooth' })); + + // ============================================================ + // 기타 커스텀 이벤트/버튼 + // ============================================================ + // 예: 상담 신청 모달 열기 + document.querySelectorAll('.open-consult').forEach(btn => { + btn.addEventListener('click', () => { + const modal = document.querySelector('#consult-modal'); + modal?.classList.add('open'); + }); + }); + + // 예: 모달 닫기 + document.querySelectorAll('.modal .close-btn').forEach(btn => { + btn.addEventListener('click', () => { + const modal = btn.closest('.modal'); + modal?.classList.remove('open'); + }); + }); +}); diff --git a/.Backup/html /assets/js/모바일메뉴 사라짐.md b/.Backup/html /assets/js/모바일메뉴 사라짐.md new file mode 100644 index 0000000..cc5adce --- /dev/null +++ b/.Backup/html /assets/js/모바일메뉴 사라짐.md @@ -0,0 +1,198 @@ +모바일 메뉴가 동작하지 않는 문제를 찾았습니다! 🔍 +🔴 문제점 발견 +1. 클래스명 불일치 (가장 큰 문제!) +script.js: +javascriptconst menuBtn = document.querySelector('.menu-btn'); // ❌ .menu-btn +const navMenu = document.querySelector('.nav-menu'); // ❌ .nav-menu +index.html: +html + +
+→ .menu-btn과 .nav-menu 클래스가 HTML에 없습니다! + +2. 닫기 버튼도 작동 안 함 +script.js: +javascriptdocument.querySelectorAll('.modal .close-btn').forEach(btn => { + // ❌ .close-btn 클래스를 찾지만... +}); +index.html: +html + + +3. 이벤트 핸들러 중복 +script.js 하단: +javascript// 메뉴 토글 코드가 있는데... +const menuBtn = document.querySelector('.menu-btn'); +index.html 하단: +html + +📋 문제 요약 +요소script.js에서 찾는 것index.html 실제메뉴 버튼.menu-btn#mobile-menu-btn (클래스 없음)메뉴.nav-menu#mobile-menu (클래스 없음)닫기 버튼.modal .close-btn#close-menu-btn (클래스 없음) + +✅ 해결 방법 (3가지 옵션) +옵션 1: script.js 수정 (권장) +ID로 찾도록 변경: +javascriptconst menuBtn = document.querySelector('#mobile-menu-btn'); // ID로 변경 +const navMenu = document.querySelector('#mobile-menu'); // ID로 변경 +옵션 2: index.html 수정 +클래스 추가: +html