From e27ee29dccc4fb5849ba0caacd27fc228bba5eea Mon Sep 17 00:00:00 2001
From: KINDNICK <68893236+KINDNICK@users.noreply.github.com>
Date: Thu, 7 Aug 2025 01:20:11 +0900
Subject: [PATCH] =?UTF-8?q?Fix=20:=20=EA=B5=AC=EA=B8=80=20=EC=84=9C?=
=?UTF-8?q?=EC=B9=98=EC=96=B4=EB=93=9C=EB=B0=94=EC=9D=B4=EC=A0=80=EC=97=90?=
=?UTF-8?q?=EC=84=9C=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=83=89=EC=9D=B8=20?=
=?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.htaccess | 63 ++++++++++++++++++++++++++++++++++
robots.txt | 18 ++++++++++
script.js | 97 +++++++++++++++++++++++++++++++++++++++++------------
sitemap.xml | 9 +++++
4 files changed, 165 insertions(+), 22 deletions(-)
create mode 100644 .htaccess
create mode 100644 robots.txt
create mode 100644 sitemap.xml
diff --git a/.htaccess b/.htaccess
new file mode 100644
index 0000000..5db8815
--- /dev/null
+++ b/.htaccess
@@ -0,0 +1,63 @@
+# Enable URL rewriting
+RewriteEngine On
+
+# Force HTTPS (if SSL is available)
+# RewriteCond %{HTTPS} off
+# RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
+
+# Remove trailing slashes
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteRule ^(.*)/$ /$1 [L,R=301]
+
+# Remove .html extension
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteRule ^([^\.]+)$ $1.html [NC,L]
+
+# Handle SPA routing - redirect all non-file requests to index.html
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteRule ^(.*)$ /index.html [L]
+
+# Handle 404 errors
+ErrorDocument 404 /index.html
+
+# Enable compression
+
+ AddOutputFilterByType DEFLATE text/plain
+ AddOutputFilterByType DEFLATE text/html
+ AddOutputFilterByType DEFLATE text/xml
+ AddOutputFilterByType DEFLATE text/css
+ AddOutputFilterByType DEFLATE application/xml
+ AddOutputFilterByType DEFLATE application/xhtml+xml
+ AddOutputFilterByType DEFLATE application/rss+xml
+ AddOutputFilterByType DEFLATE application/javascript
+ AddOutputFilterByType DEFLATE application/x-javascript
+
+
+# Set browser caching
+
+ ExpiresActive on
+ ExpiresByType text/css "access plus 1 year"
+ ExpiresByType application/javascript "access plus 1 year"
+ ExpiresByType image/png "access plus 1 year"
+ ExpiresByType image/jpg "access plus 1 year"
+ ExpiresByType image/jpeg "access plus 1 year"
+ ExpiresByType image/gif "access plus 1 year"
+ ExpiresByType image/webp "access plus 1 year"
+ ExpiresByType image/svg+xml "access plus 1 year"
+
+
+# Security headers
+
+ Header always set X-Content-Type-Options nosniff
+ Header always set X-Frame-Options DENY
+ Header always set X-XSS-Protection "1; mode=block"
+ Header always set Referrer-Policy "strict-origin-when-cross-origin"
+
+
+# Prevent access to sensitive files
+
+ Order Allow,Deny
+ Deny from all
+
\ No newline at end of file
diff --git a/robots.txt b/robots.txt
new file mode 100644
index 0000000..679158e
--- /dev/null
+++ b/robots.txt
@@ -0,0 +1,18 @@
+User-agent: *
+Allow: /
+
+# Sitemap
+Sitemap: https://minglestudio.co.kr/sitemap.xml
+
+# Disallow specific files and patterns
+Disallow: /cgi-bin/
+Disallow: /tmp/
+Disallow: /private/
+Disallow: /*#*
+
+# Allow important files
+Allow: /index.html
+Allow: /styles.css
+Allow: /script.js
+Allow: /mingle-logo.webp
+Allow: /Studio_Image/
\ No newline at end of file
diff --git a/script.js b/script.js
index bb47b81..422f2a6 100644
--- a/script.js
+++ b/script.js
@@ -5,42 +5,93 @@ document.addEventListener('DOMContentLoaded', function() {
const hamburger = document.querySelector('.hamburger');
const navMenu = document.querySelector('.nav-menu');
- hamburger.addEventListener('click', function() {
- hamburger.classList.toggle('active');
- navMenu.classList.toggle('active');
- });
+ if (hamburger) {
+ hamburger.addEventListener('click', function() {
+ hamburger.classList.toggle('active');
+ navMenu.classList.toggle('active');
+ });
+ }
// 네비게이션 링크 클릭 시 모바일 메뉴 닫기
document.querySelectorAll('.nav-link').forEach(link => {
link.addEventListener('click', () => {
- hamburger.classList.remove('active');
- navMenu.classList.remove('active');
+ if (hamburger) hamburger.classList.remove('active');
+ if (navMenu) navMenu.classList.remove('active');
});
});
- // 스무스 스크롤
+ // 스무스 스크롤 (리디렉션 방지) - 개선된 버전
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
- const target = document.querySelector(this.getAttribute('href'));
+ const targetId = this.getAttribute('href');
+ const target = document.querySelector(targetId);
+
if (target) {
- target.scrollIntoView({
- behavior: 'smooth',
- block: 'start'
+ // URL 업데이트 (히스토리 API 사용) - 리디렉션 방지
+ if (history.pushState) {
+ history.pushState(null, null, targetId);
+ }
+
+ // 스무스 스크롤
+ const headerOffset = 80; // 네비게이션 높이 고려
+ const elementPosition = target.getBoundingClientRect().top;
+ const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
+
+ window.scrollTo({
+ top: offsetPosition,
+ behavior: 'smooth'
});
}
});
});
+ // 브라우저 뒤로가기/앞으로가기 처리
+ window.addEventListener('popstate', function(e) {
+ const hash = window.location.hash;
+ if (hash) {
+ const target = document.querySelector(hash);
+ if (target) {
+ const headerOffset = 80;
+ const elementPosition = target.getBoundingClientRect().top;
+ const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
+
+ window.scrollTo({
+ top: offsetPosition,
+ behavior: 'smooth'
+ });
+ }
+ }
+ });
+
+ // 페이지 로드 시 해시가 있으면 해당 섹션으로 스크롤
+ if (window.location.hash) {
+ setTimeout(() => {
+ const target = document.querySelector(window.location.hash);
+ if (target) {
+ const headerOffset = 80;
+ const elementPosition = target.getBoundingClientRect().top;
+ const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
+
+ window.scrollTo({
+ top: offsetPosition,
+ behavior: 'smooth'
+ });
+ }
+ }, 100);
+ }
+
// 네비게이션 스크롤 효과
window.addEventListener('scroll', function() {
const navbar = document.querySelector('.navbar');
- if (window.scrollY > 100) {
- navbar.style.background = 'rgba(255, 255, 255, 0.98)';
- navbar.style.boxShadow = '0 2px 20px rgba(0, 0, 0, 0.1)';
- } else {
- navbar.style.background = 'rgba(255, 255, 255, 0.95)';
- navbar.style.boxShadow = 'none';
+ if (navbar) {
+ if (window.scrollY > 100) {
+ navbar.style.background = 'rgba(255, 255, 255, 0.98)';
+ navbar.style.boxShadow = '0 2px 20px rgba(0, 0, 0, 0.1)';
+ } else {
+ navbar.style.background = 'rgba(255, 255, 255, 0.95)';
+ navbar.style.boxShadow = 'none';
+ }
}
});
@@ -52,10 +103,10 @@ document.addEventListener('DOMContentLoaded', function() {
// 폼 데이터 수집
const formData = new FormData(this);
- const name = this.querySelector('input[type="text"]').value;
- const email = this.querySelector('input[type="email"]').value;
- const subject = this.querySelectorAll('input[type="text"]')[1].value;
- const message = this.querySelector('textarea').value;
+ const name = this.querySelector('input[type="text"]')?.value || '';
+ const email = this.querySelector('input[type="email"]')?.value || '';
+ const subject = this.querySelectorAll('input[type="text"]')[1]?.value || '';
+ const message = this.querySelector('textarea')?.value || '';
// 간단한 유효성 검사
if (!name || !email || !subject || !message) {
@@ -119,7 +170,9 @@ document.addEventListener('DOMContentLoaded', function() {
setTimeout(() => {
notification.style.transform = 'translateX(100%)';
setTimeout(() => {
- notification.remove();
+ if (notification.parentNode) {
+ notification.remove();
+ }
}, 300);
}, 3000);
}
diff --git a/sitemap.xml b/sitemap.xml
new file mode 100644
index 0000000..3980824
--- /dev/null
+++ b/sitemap.xml
@@ -0,0 +1,9 @@
+
+
+
+ https://minglestudio.co.kr/
+ 2025-01-27
+ weekly
+ 1.0
+
+
\ No newline at end of file